diff --git a/pom.xml b/pom.xml
index 8fa4433..115f598 100644
--- a/pom.xml
+++ b/pom.xml
@@ -76,6 +76,14 @@
+
+
+
+ org.mapdb
+ mapdb
+ 3.0.8
+
+
\ No newline at end of file
diff --git a/src/main/java/component/CanBePrefix.java b/src/main/java/component/CanBePrefix.java
new file mode 100644
index 0000000..8cdae09
--- /dev/null
+++ b/src/main/java/component/CanBePrefix.java
@@ -0,0 +1,87 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示内容兴趣包中的组件 CanBePrefix
+ * @Version: 1.0.0
+ * @Date: 11:33 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class CanBePrefix implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 成员变量
+ private boolean canBePrefix;
+
+ // 函数
+ public void setCanBePrefix(boolean canBePrefix){
+ this.canBePrefix=canBePrefix;
+ this.doInitial();
+ }
+
+ public boolean getCanBePrefix(){
+ return this.canBePrefix;
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ * 将 CanBePrefix 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ // 这是一个存在性组件,所以如果值为false,则无需编码
+ if(!this.canBePrefix){
+ return 0;
+ }
+
+ int totalLength=0;
+
+ // 编码 TLV-LENGTH
+ int tmplen=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen=encoder.prependVarNumber(new VlInt(TLV.TlvCanBePrefix));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码一个 CanBePrefix
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvCanBePrefix))){
+ return false;
+ }
+
+ // 这是一个存在性组件,所以存在则为 true
+ this.canBePrefix=true;
+ return true;
+ }
+}
diff --git a/src/main/java/component/CongestionMark.java b/src/main/java/component/CongestionMark.java
new file mode 100644
index 0000000..f2d044b
--- /dev/null
+++ b/src/main/java/component/CongestionMark.java
@@ -0,0 +1,94 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description:表示一个拥塞标记 TLV 组件
+ * @Version: 1.0.0
+ * @Date: 15:54 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class CongestionMark implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 成员变量 todo: 越界问题
+ private long congestionMark;
+
+ // 函数
+ public long getCongestionLevel(){
+ return this.congestionMark;
+ }
+
+ public void setCongestionLevel(long congestionMark){
+ this.congestionMark=congestionMark;
+ this.doInitial();
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ * 将 CongestionMark 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+
+ // 编码 TLV-VALUE
+ int tmplen=encoder.prependNonNegativeInteger(this.congestionMark);
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-LENGTH
+ tmplen+=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen+=encoder.prependVarNumber(new VlInt(TLV.TlvCongestionMark));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 CongestionMark
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvCongestionMark))){
+ return false;
+ }
+
+ // 读取 CongestionMark
+ long value=TLV.readNonNegativeInteger(block.getValue(),0,block.getLength().getVlIntValue2Int());
+ if(value<0){
+ return false;
+ }
+ this.setCongestionLevel(value);
+
+ return true;
+ }
+}
diff --git a/src/main/java/component/FreshnessPeriod.java b/src/main/java/component/FreshnessPeriod.java
new file mode 100644
index 0000000..bb07c1c
--- /dev/null
+++ b/src/main/java/component/FreshnessPeriod.java
@@ -0,0 +1,94 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示一个内容的新鲜期 TLV 组件
+ * @Version: 1.0.0
+ * @Date: 16:10 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class FreshnessPeriod implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 成员变量
+ private long freshnessPeriod;
+
+ // 函数
+ public long getFreshnessPeriod() {
+ return this.freshnessPeriod;
+ }
+
+ public void setFreshnessPeriod(long freshnessPeriod) {
+ this.freshnessPeriod = freshnessPeriod;
+ this.doInitial();
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ * 将 FreshnessPeriod 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+
+ // 编码 TLV-VALUE
+ int tmplen=encoder.prependNonNegativeInteger(this.freshnessPeriod);
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-LENGTH
+ tmplen+=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen+=encoder.prependVarNumber(new VlInt(TLV.TlvFreshnessPeriod));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 FreshnessPeriod
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvFreshnessPeriod))){
+ return false;
+ }
+
+ // 读取 value
+ long value=TLV.readNonNegativeInteger(block.getValue(),0,block.getLength().getVlIntValue2Int());
+ if(value<0){
+ return false;
+ }
+ this.setFreshnessPeriod(value);
+
+ return true;
+ }
+}
diff --git a/src/main/java/component/HopLimit.java b/src/main/java/component/HopLimit.java
new file mode 100644
index 0000000..6c26e96
--- /dev/null
+++ b/src/main/java/component/HopLimit.java
@@ -0,0 +1,89 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 16:38 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class HopLimit implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 成员变量
+ private long hopLimit;
+
+ // 成员函数
+ public long getHopLimit() {
+ return hopLimit;
+ }
+
+ public void setHopLimit(long hopLimit) {
+ this.hopLimit = hopLimit;
+ this.doInitial();
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ *
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+
+ // 编码 TLV-VALUE
+ int tmplen=encoder.prependNonNegativeInteger(this.hopLimit);
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-LENGTH
+ tmplen+=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen+=encoder.prependVarNumber(new VlInt(TLV.TlvHopLimit));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvHopLimit))){
+ return false;
+ }
+
+ // 读取 HopLimit
+ long value=TLV.readNonNegativeInteger(block.getValue(),0,block.getLength().getVlIntValue2Int());
+ if(value<0){
+ return false;
+ }
+ this.setHopLimit(value);
+
+ return true;
+ }
+}
diff --git a/src/main/java/component/IdentifierComponent.java b/src/main/java/component/IdentifierComponent.java
new file mode 100644
index 0000000..d48540d
--- /dev/null
+++ b/src/main/java/component/IdentifierComponent.java
@@ -0,0 +1,47 @@
+package component;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 名称组件
+ * @Version: 1.0.0
+ * @Date: 21:26 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+
+import encoding.Block;
+import encoding.Encoder;
+import encoding.IEncodingAble;
+
+// @Description:
+// 1. 参考 => https://named-data.net/doc/tech-memos/naming-conventions.pdf ,借鉴但不是按这个实现的
+// 2. 格式如下:
+// IdentifierComponent = 100 TLV-LENGTH
+//
+// *OCTET
+// Marker = OCTET
+// 3. Marker 用来标记不同类型的 IdentifierComponent,目前分配如下
+// Marker value Description
+// 0x00 普通的UTF-8编码的字符串
+// 0x01 非负整数(可以用1、2、4、8个字节表示)
+// 0x02 任意字节数组
+public class IdentifierComponent implements TlvComponentBase, IEncodingAble {
+ private Block block;
+ private byte marker; // 标记 => 用来区分不同类型的 IdentifierComponent
+ private String stringValue; // 如果 Marker == 0x00,则本组件存储一个字符串
+ private long intValue; // 如果 Marker == 0x01,则本组件存储一个非负整型
+ private byte[] byteArrayValue; // 如果 Marker == 0x02,则本组件存储一个字节数组
+
+ public static final byte MarkerString = 0x00;
+ public static final byte MarkerNonNegativeInteger = 0x01;
+ public static final byte MarkerByteArray = 0x02;
+
+ @Override
+ public int wireEncode(Encoder encoder) {
+ return 0;
+ }
+
+ @Override
+ public boolean wireDecode(Block block) {
+ return false;
+ }
+}
diff --git a/src/main/java/component/InitialAble.java b/src/main/java/component/InitialAble.java
new file mode 100644
index 0000000..91d8a71
--- /dev/null
+++ b/src/main/java/component/InitialAble.java
@@ -0,0 +1,21 @@
+package component;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 指示当前组件是否有初始化,如果没有初始化,且组件是可选组件,则无需编码
+ * @Version: 1.0.0
+ * @Date: 10:15 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public interface InitialAble {
+ // 指示当前组件是否有初始化,如果没有初始化,且组件是可选组件,则无需编码.
+ // 接口中的变量都是final类型的(常量)。因此,如果需要一个变量,
+ // 需要在实现该接口的类中定义该变量。
+ // boolean initial = false;
+
+ // 将组件标记为已初始化
+ public void doInitial();
+
+ // 判断当前组件是否已经初始化
+ public boolean isInitial();
+}
diff --git a/src/main/java/component/InterestLifeTime.java b/src/main/java/component/InterestLifeTime.java
new file mode 100644
index 0000000..b7ec99f
--- /dev/null
+++ b/src/main/java/component/InterestLifeTime.java
@@ -0,0 +1,94 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 19:46 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class InterestLifeTime implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 变量
+ private long interestLifeTime;
+
+ // 方法
+ public long getInterestLifeTime() {
+ return interestLifeTime;
+ }
+
+ public void setInterestLifeTime(long interestLifeTime) {
+ this.interestLifeTime = interestLifeTime;
+ this.doInitial();
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ * 将 InterestLifeTime 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+
+ // 编码 TLV-VALUE
+ int tmplen=encoder.prependNonNegativeInteger(this.interestLifeTime);
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-LENGTH
+ tmplen+=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen+=encoder.prependVarNumber(new VlInt(TLV.TlvInterestLifeTime));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 InterestLifeTime
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvInterestLifeTime))){
+ return false;
+ }
+
+ // 读取 value
+ long value=TLV.readNonNegativeInteger(block.getValue(),0,block.getLength().getVlIntValue2Int());
+ if(value<0){
+ return false;
+ }
+ this.setInterestLifeTime(value);
+
+ return true;
+ }
+}
diff --git a/src/main/java/component/MustBeRefresh.java b/src/main/java/component/MustBeRefresh.java
new file mode 100644
index 0000000..c14ee00
--- /dev/null
+++ b/src/main/java/component/MustBeRefresh.java
@@ -0,0 +1,87 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示内容兴趣包中的组件 MustBeRefresh
+ * @Version: 1.0.0
+ * @Date: 16:30 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class MustBeRefresh implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 成员变量
+ private boolean mustBeRefresh;
+
+ // 函数
+ public boolean getMustBeRefresh() {
+ return mustBeRefresh;
+ }
+
+ public void setMustBeRefresh(boolean mustBeRefresh) {
+ this.mustBeRefresh = mustBeRefresh;
+ this.doInitial();
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ * 将 MustBeRefresh 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ // 这是一个存在性组件,所以如果值为false,则无需编码
+ if(!this.mustBeRefresh){
+ return 0;
+ }
+
+ int totalLength=0;
+
+ // 编码 TLV-LENGTH
+ int tmplen=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen=encoder.prependVarNumber(new VlInt(TLV.TlvMustBeRefresh));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 MustBeRefresh
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvMustBeRefresh))){
+ return false;
+ }
+
+ // 这是一个存在性组件,所以存在则为 true
+ this.mustBeRefresh=true;
+ return true;
+ }
+}
diff --git a/src/main/java/component/MutableDangerousField.java b/src/main/java/component/MutableDangerousField.java
new file mode 100644
index 0000000..04450a9
--- /dev/null
+++ b/src/main/java/component/MutableDangerousField.java
@@ -0,0 +1,114 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示一个MIN包格式中的可变非受保护区
+ * @Version: 1.0.0
+ * @Date: 20:34 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class MutableDangerousField implements TlvComponentBase, IEncodingAble {
+ private ElementContainer blocks;
+
+ /**
+ * 往可变非受保护区添加一个Block
+ * @param block
+ */
+ public void addBlock(Block block){
+ blocks.addElement(block);
+ }
+
+ /**
+ * 获取可变非受保护区指定位置的 Block
+ * @return
+ */
+ public Block getBlock(int index){
+ return this.blocks.getBlock(index);
+ }
+
+ /**
+ * 清空可变非受保护区中,所有的子 Block
+ */
+ public void clearBlocks(){
+ this.blocks.clear();
+ }
+
+ /**
+ * 获取可变非受保护区所有的 Block
+ * @return
+ */
+ public ElementContainer getBlocks(){
+ return this.blocks;
+ }
+
+ /**
+ * 获取可变非受保护区中,第一个指定TLV-TYPE的子 TLV Block
+ * @return
+ */
+ public Block getBlockByType(VlInt tlvType){
+ return this.blocks.getElement(tlvType);
+ }
+
+ /**
+ * 将可变非受保护区线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ // 如果可变非受保护区没有任何子 TLV,则可以去掉可变非受保护区 TLV
+ if(this.blocks.length()==0){
+ return 0;
+ }
+
+ int totalLength=0;
+ // 编码TLV-VALUE
+ // 反向遍历,可以保证解码的时候正向输出
+ for(int i=this.blocks.length()-1;i>=0;i++){
+ int tmplen=encoder.prependBlock(this.blocks.getBlock(i));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+ }
+
+ // 编码 TLV-LENGTH
+ int tmplen=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen=encoder.prependVarNumber(new VlInt(TLV.TlvReadOnlyField));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 ReadOnlyField
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvReadOnlyField))){
+ return false;
+ }
+
+ // 解析子 TLV
+ if(!block.parseSubElements()){
+ return false;
+ }
+
+ this.blocks=block.getSubElements();
+ return true;
+ }
+}
diff --git a/src/main/java/component/MutableField.java b/src/main/java/component/MutableField.java
new file mode 100644
index 0000000..546d6ab
--- /dev/null
+++ b/src/main/java/component/MutableField.java
@@ -0,0 +1,98 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示一个MIN包格式中的可变区
+ * @Version: 1.0.0
+ * @Date: 20:48 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class MutableField implements TlvComponentBase,IEncodingAble {
+ private MutableProtectField mutableProtectField;
+ private MutableDangerousField mutableDangerousField;
+
+ public MutableField(){
+ mutableProtectField=new MutableProtectField();
+ mutableDangerousField=new MutableDangerousField();
+ }
+
+ /**
+ * 将可变区线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+
+ // 编码 TLV—VALUE
+ int tmplen=this.mutableDangerousField.wireEncode(encoder);
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+ tmplen=this.mutableProtectField.wireEncode(encoder);
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 如果可变保护区和可变非受保护区均为空,则可以去掉可变区
+ if(totalLength==0){
+ return 0;
+ }
+
+ // 编码 TLV-LENGTH
+ tmplen=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen=encoder.prependVarNumber(new VlInt(TLV.TlvMutableField));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 MutableField
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvMutableField))){
+ return false;
+ }
+
+ // 解析子 TLV
+ if(!block.parseSubElements()){
+ return false;
+ }
+
+ for (int i = 0; i < block.getSubElements().length(); i++) {
+ Block subBlock=block.getSubElements().getBlock(i);
+ if(subBlock.getTlvType().isEqual(TLV.TlvMutableProtectField)){
+ if(!this.mutableProtectField.wireDecode(subBlock)){
+ return false;
+ }
+ }else if(subBlock.getTlvType().isEqual(TLV.TlvMutableDangerousField)){
+ if(!this.mutableDangerousField.wireDecode(subBlock)){
+ return false;
+ }
+ }else{
+ return false;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/component/MutableProtectField.java b/src/main/java/component/MutableProtectField.java
new file mode 100644
index 0000000..bf889b8
--- /dev/null
+++ b/src/main/java/component/MutableProtectField.java
@@ -0,0 +1,114 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示一个MIN包格式中的可变保护区
+ * @Version: 1.0.0
+ * @Date: 20:45 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class MutableProtectField implements TlvComponentBase, IEncodingAble {
+ private ElementContainer blocks;
+
+ /**
+ * 添加一个Block
+ * @param block
+ */
+ public void addBlock(Block block){
+ blocks.addElement(block);
+ }
+
+ /**
+ * 获取指定位置的 Block
+ * @return
+ */
+ public Block getBlock(int index){
+ return this.blocks.getBlock(index);
+ }
+
+ /**
+ * 清空所有的子 Block
+ */
+ public void clearBlocks(){
+ this.blocks.clear();
+ }
+
+ /**
+ * 获取所有的 Block
+ * @return
+ */
+ public ElementContainer getBlocks(){
+ return this.blocks;
+ }
+
+ /**
+ * 获取第一个指定TLV-TYPE的子 TLV Block
+ * @return
+ */
+ public Block getBlockByType(VlInt tlvType){
+ return this.blocks.getElement(tlvType);
+ }
+
+ /**
+ * 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ // 如果没有任何子 TLV,则可以去掉它
+ if(this.blocks.length()==0){
+ return 0;
+ }
+
+ int totalLength=0;
+ // 编码TLV-VALUE
+ // 反向遍历,可以保证解码的时候正向输出
+ for(int i=this.blocks.length()-1;i>=0;i++){
+ int tmplen=encoder.prependBlock(this.blocks.getBlock(i));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+ }
+
+ // 编码 TLV-LENGTH
+ int tmplen=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen=encoder.prependVarNumber(new VlInt(TLV.TlvReadOnlyField));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 ReadOnlyField
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvReadOnlyField))){
+ return false;
+ }
+
+ // 解析子 TLV
+ if(!block.parseSubElements()){
+ return false;
+ }
+
+ this.blocks=block.getSubElements();
+ return true;
+ }
+}
diff --git a/src/main/java/component/NackHeader.java b/src/main/java/component/NackHeader.java
new file mode 100644
index 0000000..a82de63
--- /dev/null
+++ b/src/main/java/component/NackHeader.java
@@ -0,0 +1,94 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 19:52 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class NackHeader implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 变量
+ private long nackReason;
+
+ // 函数
+ public long getNackReason() {
+ return nackReason;
+ }
+
+ public void setNackReason(long nackReason) {
+ this.nackReason = nackReason;
+ this.doInitial();
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ * 将 NackHeader 编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+
+ // 编码 TLV-VALUE
+ int tmplen=encoder.prependNonNegativeInteger(this.nackReason);
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-LENGTH
+ tmplen+=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen+=encoder.prependVarNumber(new VlInt(TLV.TlvNackHeader));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 Block TLV 中解码出一个 NackHeader
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvNackHeader))){
+ return false;
+ }
+
+ // 读取 value
+ long value=TLV.readNonNegativeInteger(block.getValue(),0,block.getLength().getVlIntValue2Int());
+ if(value<0){
+ return false;
+ }
+ this.setNackReason(value);
+
+ return true;
+ }
+}
diff --git a/src/main/java/component/Nonce.java b/src/main/java/component/Nonce.java
new file mode 100644
index 0000000..1a88535
--- /dev/null
+++ b/src/main/java/component/Nonce.java
@@ -0,0 +1,104 @@
+package component;
+
+import encoding.*;
+
+import java.util.Random;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示一个随机数 TLV 组件
+ * @Version: 1.0.0
+ * @Date: 17:13 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class Nonce implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 成员变量
+ private long nonce;
+
+ // 成员函数
+ public long getNonce() {
+ return this.nonce;
+ }
+
+ public void setNonce(long nonce) {
+ this.nonce = nonce;
+ this.doInitial();
+ }
+
+ /**
+ * 刷新Nonce,随机生成一个数值传递给Nonce
+ */
+ public void refreshNonce(){
+ long randomLong=Math.abs(new Random().nextLong());
+ this.setNonce(randomLong);
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ * 将 Nonce 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+
+ // 编码 TLV-VALUE
+ int tmplen=encoder.prependNonNegativeInteger(this.nonce);
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-LENGTH
+ tmplen+=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen+=encoder.prependVarNumber(new VlInt(TLV.TlvNonce));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 Nonce
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvNonce))){
+ return false;
+ }
+
+ // 读取 value
+ long value=TLV.readNonNegativeInteger(block.getValue(),0,block.getLength().getVlIntValue2Int());
+ if(value<0){
+ return false;
+ }
+ this.setNonce(value);
+
+ return true;
+ }
+}
diff --git a/src/main/java/component/Payload.java b/src/main/java/component/Payload.java
new file mode 100644
index 0000000..d26577a
--- /dev/null
+++ b/src/main/java/component/Payload.java
@@ -0,0 +1,107 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示网络包负载
+// 1. 格式如下:
+// Payload = PAYLOAD-TYPE TLV-LENGTH *OCTET
+// 2. 详情参见:http://gitea.qjm253.cn/PKUSZ-future-network-lab/minlib/src/branch/master/docs/PacketFormat.md#4-signature
+ * @Version: 1.0.0
+ * @Date: 19:26 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class Payload implements TlvComponentBase,InitialAble, IEncodingAble {
+ // 成员变量
+ private byte[] value;
+
+ // 函数
+ /**
+ * 根据 TLV Block 初始化一个 Payload
+ * @param block
+ * @return
+ */
+ public boolean buildPayloadByBlock(Block block){
+ return this.wireDecode(block);
+ }
+
+ /**
+ * 得到Payload TLV中实际包含的数据
+ * @return
+ */
+ public byte[] getValue() {
+ return value;
+ }
+
+ /**
+ * 设置 Payload TLV 中的Value
+ * @param value
+ */
+ public void setValue(byte[] value) {
+ this.value = value;
+ this.doInitial();
+ }
+
+ // 接口实现-变量区
+ private boolean initial=false;
+
+ // 接口实现-方法区
+ @Override
+ public void doInitial() {
+ initial=true;
+ }
+
+ @Override
+ public boolean isInitial() {
+ return initial;
+ }
+
+ /**
+ * 将 Payload 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+
+ // 编码 TLV-VALUE
+ int tmplen=encoder.prependByteArray(this.value,new SizeT(this.value.length));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-LENGTH
+ tmplen+=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen+=encoder.prependVarNumber(new VlInt(TLV.TlvPayload));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvPayload))){
+ return false;
+ }
+
+ // 存储Value
+// int len=block.getLength().getVlIntValue2Int();
+// byte[] bytes=new byte[len];
+// System.arraycopy(block.getValue(),0,bytes,0,len);
+ this.setValue(block.getValue());
+ return true;
+ }
+}
diff --git a/src/main/java/component/ReadOnlyField.java b/src/main/java/component/ReadOnlyField.java
new file mode 100644
index 0000000..78d019c
--- /dev/null
+++ b/src/main/java/component/ReadOnlyField.java
@@ -0,0 +1,114 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 表示一个MIN包格式中的只读区
+ * @Version: 1.0.0
+ * @Date: 19:58 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class ReadOnlyField implements TlvComponentBase, IEncodingAble {
+ private ElementContainer blocks;
+
+ /**
+ * 往只读区添加一个Block
+ * @param block
+ */
+ public void addBlock(Block block){
+ blocks.addElement(block);
+ }
+
+ /**
+ * 获取只读区指定位置的 Block
+ * @return
+ */
+ public Block getBlock(int index){
+ return this.blocks.getBlock(index);
+ }
+
+ /**
+ * 清空只读区中,所有的子 Block
+ */
+ public void clearBlocks(){
+ this.blocks.clear();
+ }
+
+ /**
+ * 获取只读区所有的 Block
+ * @return
+ */
+ public ElementContainer getBlocks(){
+ return this.blocks;
+ }
+
+ /**
+ * 获取只读区中,第一个指定TLV-TYPE的子 TLV Block
+ * @return
+ */
+ public Block getBlockByType(VlInt tlvType){
+ return this.blocks.getElement(tlvType);
+ }
+
+ /**
+ * 将只读区线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ // 如果只读区没有任何子 TLV,则可以去掉只读区 TLV
+ if(this.blocks.length()==0){
+ return 0;
+ }
+
+ int totalLength=0;
+ // 编码TLV-VALUE
+ // 反向遍历,可以保证解码的时候正向输出
+ for(int i=this.blocks.length()-1;i>=0;i++){
+ int tmplen=encoder.prependBlock(this.blocks.getBlock(i));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+ }
+
+ // 编码 TLV-LENGTH
+ int tmplen=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ // 编码 TLV-TYPE
+ tmplen=encoder.prependVarNumber(new VlInt(TLV.TlvReadOnlyField));
+ if(tmplen==0){
+ return 0;
+ }
+ totalLength+=tmplen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 ReadOnlyField
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查 Type 是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvReadOnlyField))){
+ return false;
+ }
+
+ // 解析子 TLV
+ if(!block.parseSubElements()){
+ return false;
+ }
+
+ this.blocks=block.getSubElements();
+ return true;
+ }
+}
diff --git a/src/main/java/component/TTL.java b/src/main/java/component/TTL.java
new file mode 100644
index 0000000..35fe92b
--- /dev/null
+++ b/src/main/java/component/TTL.java
@@ -0,0 +1,101 @@
+package component;
+
+import encoding.*;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 10:20 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class TTL implements IEncodingAble {
+ /**
+ * 表示一个 TTL Tlv
+ * todo: 后台使用的uint64,故这里用long表示,则理论上可能越界
+ * // @Description:
+ * 1. 格式如下:
+ * TTL = TTL-TYPE TLV-LENGTH NonNegativeInteger
+ */
+ private long ttl;
+
+ public TTL(Block block){
+ buildTTLByBlock(block);
+ }
+
+ /**
+ * 根据 TLV Block 初始化一个 TTL
+ * @param block
+ * @return
+ */
+ public boolean buildTTLByBlock(Block block){
+ return this.wireDecode(block);
+ }
+
+ /**
+ * 获取 TTL 值
+ * @return
+ */
+ public long ttl(){
+ return this.ttl;
+ }
+
+ /**
+ * 设置 TTL 值
+ * @param ttl
+ */
+ public void setTtl(long ttl){
+ this.ttl=ttl;
+ }
+
+ /**
+ * 将 TTL 线速编码为一个 TLV
+ * @param encoder
+ * @return
+ */
+ @Override
+ public int wireEncode(Encoder encoder) {
+ int totalLength=0;
+ // 编码 TLV-VALUE
+ int tmpLen=encoder.prependNonNegativeInteger(this.ttl);
+ if(tmpLen==0){
+ return 0;
+ }
+ totalLength+=tmpLen;
+
+ // 编码 TLV-LENGTH
+ tmpLen=encoder.prependVarNumber(new VlInt(totalLength));
+ if(tmpLen==0){
+ return 0;
+ }
+ totalLength+=tmpLen;
+
+ // 编码 TLV-TYPE
+ tmpLen=encoder.prependVarNumber(new VlInt(TLV.TlvTTL));
+ if(tmpLen==0){
+ return 0;
+ }
+ totalLength+=tmpLen;
+
+ return totalLength;
+ }
+
+ /**
+ * 从 TLV Block 中解码出一个 TTL
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean wireDecode(Block block) {
+ // 检查Type是否正确
+ if(!TLV.expectType(block.getTlvType(),new VlInt(TLV.TlvTTL))){
+ return false;
+ }
+ long value=TLV.readNonNegativeInteger(block.getValue(),0,block.getLength().getVlIntValue2Int());
+ if(value<0){
+ return false;
+ }
+ this.ttl=value;
+ return true;
+ }
+}
diff --git a/src/main/java/component/TlvComponentBase.java b/src/main/java/component/TlvComponentBase.java
new file mode 100644
index 0000000..b866156
--- /dev/null
+++ b/src/main/java/component/TlvComponentBase.java
@@ -0,0 +1,12 @@
+package component;
+
+/*
+ * @Author: Wang Feng
+ * @Description: 实现所有 TLV 组件需要的一些通用功能
+ * @Version: 1.0.0
+ * @Date: 21:49 2021/3/6
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public interface TlvComponentBase {
+
+}
diff --git a/src/main/java/encoding/Block.java b/src/main/java/encoding/Block.java
index 8fa9f36..ed95fcc 100644
--- a/src/main/java/encoding/Block.java
+++ b/src/main/java/encoding/Block.java
@@ -13,73 +13,6 @@ import java.util.List;
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
-// TLV 组件容器
-class ElementContainer{
- private List elementContainer;
- public ElementContainer(){
- elementContainer = new LinkedList<>();
- }
-
- /**
- * 获取所有Block
- * @return
- */
- public List getElements(){
- return elementContainer;
- }
-
- /**
- * 获取block个数
- * @return
- */
- public int length(){
- return elementContainer.size();
- }
-
- /**
- * 清除 elements 中所有的子TLV
- */
- public void clear(){
- elementContainer.clear();
- }
-
- /**
- * 往 elements 中添加一个子tlv
- * @param block
- */
- public void addElement(Block block){
- elementContainer.add(block);
- }
-
- /**
- * 移除所有指定type的子tlv
- * @param tlvType
- */
- public void removeElements(VlInt tlvType){
- List elementContainer=new LinkedList<>();
- for(Block block: this.elementContainer){
- if(!block.getTlvType().isEqual(tlvType)){
- elementContainer.add(block);
- }
- }
- this.elementContainer =elementContainer;
- }
-
- /**
- * 从 elements 中找到第一个指定type的子TLV
- * @param tlvType
- * @return
- */
- public Block getElement(VlInt tlvType){
- for(Block block: this.elementContainer){
- if(block.getTlvType().isEqual(tlvType)){
- return block;
- }
- }
- return null;
- }
-}
-
public class Block {
private VlInt tlvType; // TLV-TYPE
private VlInt length; // TLV-LENGTH
diff --git a/src/main/java/encoding/ElementContainer.java b/src/main/java/encoding/ElementContainer.java
new file mode 100644
index 0000000..c57f682
--- /dev/null
+++ b/src/main/java/encoding/ElementContainer.java
@@ -0,0 +1,86 @@
+package encoding;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 20:01 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+// TLV 组件容器
+public class ElementContainer{
+ private List elementContainer;
+ public ElementContainer(){
+ elementContainer = new LinkedList<>();
+ }
+
+ /**
+ * 获取所有Block
+ * @return
+ */
+ public List getElements(){
+ return elementContainer;
+ }
+
+ /**
+ * 获取block个数
+ * @return
+ */
+ public int length(){
+ return elementContainer.size();
+ }
+
+ /**
+ * 清除 elements 中所有的子TLV
+ */
+ public void clear(){
+ elementContainer.clear();
+ }
+
+ /**
+ * 往 elements 中添加一个子tlv
+ * @param block
+ */
+ public void addElement(Block block){
+ elementContainer.add(block);
+ }
+
+ /**
+ * 移除所有指定type的子tlv
+ * @param tlvType
+ */
+ public void removeElements(VlInt tlvType){
+ List elementContainer=new LinkedList<>();
+ for(Block block: this.elementContainer){
+ if(!block.getTlvType().isEqual(tlvType)){
+ elementContainer.add(block);
+ }
+ }
+ this.elementContainer =elementContainer;
+ }
+
+ /**
+ * 从 elements 中找到第一个指定type的子TLV
+ * @param tlvType
+ * @return
+ */
+ public Block getElement(VlInt tlvType){
+ for(Block block: this.elementContainer){
+ if(block.getTlvType().isEqual(tlvType)){
+ return block;
+ }
+ }
+ return null;
+ }
+
+ public Block getBlock(int index){
+ if(index>=this.length()){
+ return null;
+ }
+
+ return this.elementContainer.get(index);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/encoding/Encoder.java b/src/main/java/encoding/Encoder.java
index 4c1463b..0a2f870 100644
--- a/src/main/java/encoding/Encoder.java
+++ b/src/main/java/encoding/Encoder.java
@@ -122,6 +122,46 @@ public class Encoder {
}
+ /**
+ * 编码一个非负整数到一个数组当中
+ * todo: 越界问题
+ * @param uint64
+ * @return
+ */
+ public byte[] buildNonNegativeIntegerArr(long uint64){
+ VlInt vlInt=new VlInt(uint64);
+ int len=vlInt.getVlIntBytes().length;
+ if(len==1){
+ return vlInt.getVlIntBytes();
+ }else {
+ byte[] res = new byte[len - 1];
+ System.arraycopy(vlInt.getVlIntBytes(),1,res,0,len-1);
+ return res;
+ }
+ }
+
+ /**
+ * 在前向插入一个非负整数,最大为 uint64::Max
+ * todo: 越界问题
+ * @param uint64_value
+ * @return
+ */
+ public int prependNonNegativeInteger(long uint64_value){
+ byte[] bytes=buildNonNegativeIntegerArr(uint64_value);
+ return this.prependByteArray(bytes,new SizeT(bytes.length));
+ }
+
+ /**
+ * 在后向插入一个非负整数,最大为 uint64::Max
+ * todo: 越界问题
+ * @param uint64_value
+ * @return
+ */
+ public int appendNonNegativeInteger(long uint64_value){
+ byte[] bytes=buildNonNegativeIntegerArr(uint64_value);
+ return this.appendByteArray(bytes,new SizeT(bytes.length));
+ }
+
/**
* @param array
* @param size
diff --git a/src/main/java/encoding/IEncodingAble.java b/src/main/java/encoding/IEncodingAble.java
new file mode 100644
index 0000000..d1a23d5
--- /dev/null
+++ b/src/main/java/encoding/IEncodingAble.java
@@ -0,0 +1,27 @@
+package encoding;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 21:06 2021/3/7
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public interface IEncodingAble {
+ /**
+ * 线速编码,将一个包编码成网络可传输的格式
+ * @Description:
+ * 1. 可以使用 Encoder.getBuffer() 获取编码的结果
+ * @param encoder
+ * @return
+ */
+ public int wireEncode(Encoder encoder);
+
+ /**
+ * 线速解码,将一个TLV解码成一个网络包
+ * @param block
+ * @return
+ */
+ public boolean wireDecode(Block block);
+
+}
diff --git a/src/main/java/encoding/TLV.java b/src/main/java/encoding/TLV.java
index c6d89d0..4a55963 100644
--- a/src/main/java/encoding/TLV.java
+++ b/src/main/java/encoding/TLV.java
@@ -117,7 +117,32 @@ public class TLV {
return tlvType;
}
- // todo:从字节数组的指定位置中读取一个非负整型
+ /**
+ * 从字节数组的指定位置中读取一个非负整型
+ * todo: 越界问题
+ */
+ public static long readNonNegativeInteger(byte[] buffer,int start,int end){
+ if(start==end){
+ return -1;
+ }
+ if((start<0)||(end>buffer.length)){
+ return -1;
+ }
+ int len=end-start;
+ byte[] bytes=new byte[len];
+ System.arraycopy(buffer,start,bytes,0,len);
+ if(len==1){
+ return ByteHelper.uint8ToLong(buffer[start]);
+ }else if(len==2){
+ return ByteHelper.uint16ToLong(bytes);
+ }else if(len==4){
+ return ByteHelper.uint32ToLong(bytes);
+ }else if(len==8){
+ return ByteHelper.uint64ToLong(bytes);
+ }else{
+ return -1;
+ }
+ }
/**
* 检查某个type值是否是指定的 TLV-TYPE
diff --git a/src/main/java/minsecurity/certificate/X509/X509CertMaker.java b/src/main/java/minsecurity/certificate/X509/X509CertMaker.java
index dabc5ab..0333fce 100644
--- a/src/main/java/minsecurity/certificate/X509/X509CertMaker.java
+++ b/src/main/java/minsecurity/certificate/X509/X509CertMaker.java
@@ -1,7 +1,6 @@
package minsecurity.certificate.X509;
-import minsecurity.Common;
-import minsecurity.crypto.sm2.Sm2Base;
+import minsecurity.crypto.sm2.SM2Base;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
@@ -34,7 +33,7 @@ public class X509CertMaker {
String ou, String cn,
long expireTimeInMs, String signAlgo)
throws Exception {
- KeyPair rootKP = Sm2Base.generateKeyPair();
+ KeyPair rootKP = SM2Base.generateKeyPair();
return makeRootCA(rootKP, c, o, ou, cn, expireTimeInMs, signAlgo);
}
@@ -116,7 +115,7 @@ public class X509CertMaker {
public static void main(String[] args) {
try {
- KeyPair rootKP = Sm2Base.generateKeyPair();
+ KeyPair rootKP = SM2Base.generateKeyPair();
X509Certificate rootCA = makeRootCA(rootKP,"CN","MIN",
"MIN-GROUP","MIN ROOT CA",
365L * 24 * 60 * 60 * 1000, "SM3withSM2");
diff --git a/src/main/java/minsecurity/certificate/cert/CertUtils.java b/src/main/java/minsecurity/certificate/cert/CertUtils.java
index 3859630..8c95094 100644
--- a/src/main/java/minsecurity/certificate/cert/CertUtils.java
+++ b/src/main/java/minsecurity/certificate/cert/CertUtils.java
@@ -4,7 +4,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import minsecurity.Common;
import minsecurity.crypto.*;
-import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.slf4j.LoggerFactory;
import javax.crypto.BadPaddingException;
@@ -70,7 +69,7 @@ public class CertUtils {
certificate.setVersion(i.getTbsCertificate().getVersion());
certificate.setSerialNumber(i.getTbsCertificate().getSerialNumber());
- PublicKeyInterface publicKey = PublicKeyUtils.unMarshalPublicKey(i.getTbsCertificate().getPublicKey(),i.getSignatureAlgorithm());
+ PublicKeyInterface publicKey = KeyUtils.unMarshalPublicKey(i.getTbsCertificate().getPublicKey(),i.getSignatureAlgorithm());
certificate.setPublicKey(publicKey);
certificate.setSignature(i.getSignatureValue());
certificate.setSignatureAlgorithm(i.getTbsCertificate().getSignatureAlgorithm());
@@ -250,23 +249,17 @@ public class CertUtils {
byte[] bytesOfCert = serialization(CertUtils.parseCertToInnerCert(certificate));
byte[] ret;
if(passwd != null && passwd.length > 0){
- byte[] hashPasswd = HashAlgo.sm3(passwd);
- if( hashPasswd.length == 32){
- for(int i = 0; i < 16; i++){
- hashPasswd[i] += hashPasswd[i + 16];
- }
- }
- byte[] sm4Key = new byte[16];
- System.arraycopy(hashPasswd,0,sm4Key,0,16);
+ // byte[] sm4Key;
+ byte[] sm4Key = KeyUtils.get16bytePasswd(passwd);
switch (symAlgoMode){
case Common.SM4CBC:{
// TODO: PADDING??? IV?????
- ret = Sm4.encrypt_CBC_Padding(sm4Key, new byte[16],bytesOfCert);
+ ret = SM4.encrypt_CBC_Padding(sm4Key, new byte[16],bytesOfCert);
break;
}
case Common.SM4ECB:{
- ret = Sm4.encrypt_ECB_Padding(sm4Key, bytesOfCert);
+ ret = SM4.encrypt_ECB_Padding(sm4Key, bytesOfCert);
break;
}
default:
@@ -294,21 +287,13 @@ public class CertUtils {
byte[] bytesOfPem = Base64.getDecoder().decode(pemString);
byte[] bytesOfCert = new byte[0];
if(passwd != null && passwd.length > 0){
- byte[] hashPasswd = HashAlgo.sm3(passwd);
- if( hashPasswd.length == 32){
- for(int i = 0; i < 16; i++){
- hashPasswd[i] += hashPasswd[i + 16];
- }
- }
- byte[] sm4Key = new byte[16];
- System.arraycopy(hashPasswd,0,sm4Key,0,16);
-
+ byte[] sm4Key = KeyUtils.get16bytePasswd(passwd);
switch (symAlgoMode){
case Common.SM4CBC:
- bytesOfCert = Sm4.decrypt_CBC_Padding(sm4Key,new byte[16], bytesOfPem);
+ bytesOfCert = SM4.decrypt_CBC_Padding(sm4Key,new byte[16], bytesOfPem);
break;
case Common.SM4ECB:
- bytesOfCert = Sm4.decrypt_ECB_Padding(sm4Key, bytesOfPem);
+ bytesOfCert = SM4.decrypt_ECB_Padding(sm4Key, bytesOfPem);
break;
}
} else {
diff --git a/src/main/java/minsecurity/certificate/cert/Certificate.java b/src/main/java/minsecurity/certificate/cert/Certificate.java
index 2d19775..8c50bd4 100644
--- a/src/main/java/minsecurity/certificate/cert/Certificate.java
+++ b/src/main/java/minsecurity/certificate/cert/Certificate.java
@@ -1,26 +1,10 @@
package minsecurity.certificate.cert;
-import minsecurity.Common;
-import minsecurity.crypto.HashAlgo;
-import minsecurity.crypto.PrivateKeyInterface;
import minsecurity.crypto.PublicKeyInterface;
-import minsecurity.crypto.Sm4;
-import minsecurity.crypto.sm2.Sm2PublicKey;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.slf4j.LoggerFactory;
-import javax.crypto.BadPaddingException;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import java.lang.reflect.Array;
-import java.security.*;
-import java.util.Arrays;
-import java.util.Base64;
-
-import static minsecurity.certificate.cert.CertUtils.*;
-
-
/*
* @Author: hongyu guo
* @Description: 证书bean类
diff --git a/src/main/java/minsecurity/crypto/KeyUtils.java b/src/main/java/minsecurity/crypto/KeyUtils.java
new file mode 100644
index 0000000..71ae11a
--- /dev/null
+++ b/src/main/java/minsecurity/crypto/KeyUtils.java
@@ -0,0 +1,62 @@
+package minsecurity.crypto;
+
+import minsecurity.Common;
+import minsecurity.crypto.sm2.SM2PrivateKey;
+import minsecurity.crypto.sm2.SM2PublicKey;
+
+/*
+ * @Author: hongyu guo
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 16:02 2021/03/06
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class KeyUtils {
+ /**
+ * 返回的数据类型为PublicKeyInterface接口, 必要时调用者需要手动将类型强制转化为需要的类型
+ * @param bytesOfPublicKey 公钥的bytes数组
+ * @param algorithm 公钥类型
+ * @return minsecurity.crypto.PublicKeyInterface
+ * @author ghy
+ * @date 2021/3/7
+ **/
+ public static PublicKeyInterface unMarshalPublicKey(byte[] bytesOfPublicKey, int algorithm) {
+ if (bytesOfPublicKey == null || bytesOfPublicKey.length == 0) {
+ return null;
+ }
+ switch (algorithm) {
+ case Common.SM2:
+ SM2PublicKey sm2PublicKey = new SM2PublicKey();
+ sm2PublicKey.setBytes(bytesOfPublicKey);
+ return sm2PublicKey;
+ default:
+ return null;
+ }
+ }
+
+ public static PrivateKeyInterface unMarshalPrivateKey(byte[] bytesOfPrivateKey, int algorithm){
+ if(bytesOfPrivateKey == null || bytesOfPrivateKey.length == 0){
+ return null;
+ }
+ switch (algorithm) {
+ case Common.SM2:
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey();
+ sm2PrivateKey.setBytes(bytesOfPrivateKey);
+ return sm2PrivateKey;
+ default:
+ return null;
+ }
+ }
+
+ public static byte[] get16bytePasswd(byte[] passwd) {
+ byte[] hashPasswd = HashAlgo.sm3(passwd);
+ if( hashPasswd.length == 32){
+ for(int i = 0; i < 16; i++){
+ hashPasswd[i] += hashPasswd[i + 16];
+ }
+ }
+ byte[] sm4Key = new byte[16];
+ System.arraycopy(hashPasswd,0,sm4Key,0,16);
+ return sm4Key;
+ }
+}
diff --git a/src/main/java/minsecurity/crypto/PrivateKeyInterface.java b/src/main/java/minsecurity/crypto/PrivateKeyInterface.java
index 7cd3cbd..ecd7b31 100644
--- a/src/main/java/minsecurity/crypto/PrivateKeyInterface.java
+++ b/src/main/java/minsecurity/crypto/PrivateKeyInterface.java
@@ -13,6 +13,6 @@ import org.bouncycastle.crypto.InvalidCipherTextException;
public interface PrivateKeyInterface {
public byte[] getBytes();
public boolean setBytes(byte[] bytes);
- public byte[] decrypt(byte[] content) throws InvalidCipherTextException;
+ public byte[] decrypt(byte[] cipher) throws InvalidCipherTextException;
public byte[] sign(byte[] content) throws CryptoException;
}
diff --git a/src/main/java/minsecurity/crypto/PublicKeyUtils.java b/src/main/java/minsecurity/crypto/PublicKeyUtils.java
deleted file mode 100644
index bf5baa3..0000000
--- a/src/main/java/minsecurity/crypto/PublicKeyUtils.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package minsecurity.crypto;
-
-import minsecurity.Common;
-import minsecurity.crypto.sm2.Sm2PublicKey;
-
-/*
- * @Author: hongyu guo
- * @Description:
- * @Version: 1.0.0
- * @Date: 16:02 2021/03/06
- * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
- */
-public class PublicKeyUtils {
- /**
- * 返回的数据类型为PublicKeyInterface接口, 必要时调用者需要手动将类型强制转化为需要的类型
- * @param bytesOfPublicKey 公钥的bytes数组
- * @param algorithm 公钥类型
- * @return minsecurity.crypto.PublicKeyInterface
- * @author ghy
- * @date 2021/3/7
- **/
- public static PublicKeyInterface unMarshalPublicKey(byte[] bytesOfPublicKey, int algorithm) {
- if (bytesOfPublicKey == null || bytesOfPublicKey.length == 0) {
- return null;
- }
- switch (algorithm) {
- case Common.SM2:
- Sm2PublicKey sm2PublicKey = new Sm2PublicKey();
- sm2PublicKey.setBytes(bytesOfPublicKey);
- return sm2PublicKey;
- default:
- return null;
- }
- }
-}
diff --git a/src/main/java/minsecurity/crypto/Sm4.java b/src/main/java/minsecurity/crypto/SM4.java
similarity index 99%
rename from src/main/java/minsecurity/crypto/Sm4.java
rename to src/main/java/minsecurity/crypto/SM4.java
index d0cc585..6830489 100644
--- a/src/main/java/minsecurity/crypto/Sm4.java
+++ b/src/main/java/minsecurity/crypto/SM4.java
@@ -14,7 +14,7 @@ import java.security.*;
* @Date: 16:26 2021/03/04
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
-public class Sm4 {
+public class SM4 {
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
diff --git a/src/main/java/minsecurity/crypto/sm2/Sm2Base.java b/src/main/java/minsecurity/crypto/sm2/SM2Base.java
similarity index 98%
rename from src/main/java/minsecurity/crypto/sm2/Sm2Base.java
rename to src/main/java/minsecurity/crypto/sm2/SM2Base.java
index bf86b64..b52a2cb 100644
--- a/src/main/java/minsecurity/crypto/sm2/Sm2Base.java
+++ b/src/main/java/minsecurity/crypto/sm2/SM2Base.java
@@ -1,6 +1,5 @@
package minsecurity.crypto.sm2;
-import minsecurity.Common;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
@@ -17,7 +16,6 @@ import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
import org.slf4j.LoggerFactory;
-import javax.crypto.KeyGenerator;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
@@ -32,13 +30,13 @@ import static minsecurity.Common.ALGO_NAME_EC;
* @Date: 18:48 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
-public class Sm2Base {
+public class SM2Base {
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
- private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Sm2Base.class);
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SM2Base.class);
/*
* 以下为SM2推荐曲线参数
diff --git a/src/main/java/minsecurity/crypto/sm2/Sm2Exception.java b/src/main/java/minsecurity/crypto/sm2/SM2Exception.java
similarity index 77%
rename from src/main/java/minsecurity/crypto/sm2/Sm2Exception.java
rename to src/main/java/minsecurity/crypto/sm2/SM2Exception.java
index 0f31a91..79916b2 100644
--- a/src/main/java/minsecurity/crypto/sm2/Sm2Exception.java
+++ b/src/main/java/minsecurity/crypto/sm2/SM2Exception.java
@@ -7,8 +7,8 @@ package minsecurity.crypto.sm2;
* @Date: 19:00 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
-public class Sm2Exception extends java.lang.Exception {
- public Sm2Exception(String msg){
+public class SM2Exception extends java.lang.Exception {
+ public SM2Exception(String msg){
super(msg);
}
}
diff --git a/src/main/java/minsecurity/crypto/sm2/Sm2PrivateKey.java b/src/main/java/minsecurity/crypto/sm2/SM2PrivateKey.java
similarity index 84%
rename from src/main/java/minsecurity/crypto/sm2/Sm2PrivateKey.java
rename to src/main/java/minsecurity/crypto/sm2/SM2PrivateKey.java
index 9367ed5..51d4e1a 100644
--- a/src/main/java/minsecurity/crypto/sm2/Sm2PrivateKey.java
+++ b/src/main/java/minsecurity/crypto/sm2/SM2PrivateKey.java
@@ -20,9 +20,9 @@ import java.security.SecureRandom;
* @Date: 19:40 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
-public class Sm2PrivateKey implements PrivateKeyInterface {
+public class SM2PrivateKey implements PrivateKeyInterface {
- public Sm2PrivateKey(){}
+ public SM2PrivateKey(){}
/*
* @param d
@@ -37,24 +37,24 @@ public class Sm2PrivateKey implements PrivateKeyInterface {
* @author hongyu guo
* @date 2021/3/7
**/
- public Sm2PrivateKey(byte[] d) {
+ public SM2PrivateKey(byte[] d) {
if(d.length == 32 || d.length == 33)
- privateKey = new ECPrivateKeyParameters(new BigInteger(d), Sm2Base.DOMAIN_PARAMS);
+ privateKey = new ECPrivateKeyParameters(new BigInteger(d), SM2Base.DOMAIN_PARAMS);
else {
try {
- throw new Sm2Exception("SM2私钥中,参数d长度应为32/33");
- } catch (Sm2Exception e) {
+ throw new SM2Exception("SM2私钥中,参数d长度应为32/33");
+ } catch (SM2Exception e) {
e.printStackTrace();
}
}
}
- public Sm2PrivateKey(byte[] d, ECDomainParameters parameters){
+ public SM2PrivateKey(byte[] d, ECDomainParameters parameters){
if(d.length == 32 || d.length == 33)
privateKey = new ECPrivateKeyParameters(new BigInteger(d), parameters);
else {
try {
- throw new Sm2Exception("SM2私钥中,参数d长度应为32/33");
- } catch (Sm2Exception e) {
+ throw new SM2Exception("SM2私钥中,参数d长度应为32/33");
+ } catch (SM2Exception e) {
e.printStackTrace();
}
}
@@ -69,7 +69,7 @@ public class Sm2PrivateKey implements PrivateKeyInterface {
public boolean setBytes(byte[] d) {
if(d.length != 32 && d.length != 33)
return false;
- privateKey = new ECPrivateKeyParameters(new BigInteger(d), Sm2Base.DOMAIN_PARAMS);
+ privateKey = new ECPrivateKeyParameters(new BigInteger(d), SM2Base.DOMAIN_PARAMS);
return true;
}
diff --git a/src/main/java/minsecurity/crypto/sm2/Sm2PublicKey.java b/src/main/java/minsecurity/crypto/sm2/SM2PublicKey.java
similarity index 91%
rename from src/main/java/minsecurity/crypto/sm2/Sm2PublicKey.java
rename to src/main/java/minsecurity/crypto/sm2/SM2PublicKey.java
index 5b9e76a..cfdd7ce 100644
--- a/src/main/java/minsecurity/crypto/sm2/Sm2PublicKey.java
+++ b/src/main/java/minsecurity/crypto/sm2/SM2PublicKey.java
@@ -20,11 +20,11 @@ import java.security.SecureRandom;
* @Date: 17:32 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
-public class Sm2PublicKey implements PublicKeyInterface {
+public class SM2PublicKey implements PublicKeyInterface {
- public Sm2PublicKey(){}
+ public SM2PublicKey(){}
- public Sm2PublicKey(byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters){
+ public SM2PublicKey(byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters){
publicKey = createPublicKey(xBytes,yBytes,curve,domainParameters);
}
/**
@@ -35,11 +35,11 @@ public class Sm2PublicKey implements PublicKeyInterface {
* @author ghy
* @date 2021/3/7
**/
- public Sm2PublicKey(byte[] xBytes, byte[] yBytes){
- this(xBytes,yBytes, Sm2Base.CURVE, Sm2Base.DOMAIN_PARAMS);
+ public SM2PublicKey(byte[] xBytes, byte[] yBytes){
+ this(xBytes,yBytes, SM2Base.CURVE, SM2Base.DOMAIN_PARAMS);
}
- public Sm2PublicKey(byte[] bytes){
+ public SM2PublicKey(byte[] bytes){
setBytes(bytes);
}
@@ -105,7 +105,7 @@ public class Sm2PublicKey implements PublicKeyInterface {
}
private static ECPublicKeyParameters createPublicKey(byte[] xBytes, byte[] yBytes){
- return createPublicKey(xBytes,yBytes,Sm2Base.CURVE,Sm2Base.DOMAIN_PARAMS);
+ return createPublicKey(xBytes,yBytes, SM2Base.CURVE, SM2Base.DOMAIN_PARAMS);
}
private static int getCurveLength(ECDomainParameters domainParams) {
diff --git a/src/main/java/minsecurity/crypto/sm2/SM4Exception.java b/src/main/java/minsecurity/crypto/sm2/SM4Exception.java
new file mode 100644
index 0000000..c187c8c
--- /dev/null
+++ b/src/main/java/minsecurity/crypto/sm2/SM4Exception.java
@@ -0,0 +1,14 @@
+package minsecurity.crypto.sm2;
+
+/*
+ * @Author: hongyu guo
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 15:19 2021/03/09
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class SM4Exception extends Exception{
+ SM4Exception(String msg){
+ super(msg);
+ }
+}
diff --git a/src/main/java/minsecurity/identity/Identity.java b/src/main/java/minsecurity/identity/Identity.java
new file mode 100644
index 0000000..f678dd4
--- /dev/null
+++ b/src/main/java/minsecurity/identity/Identity.java
@@ -0,0 +1,270 @@
+package minsecurity.identity;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import minsecurity.Common;
+import minsecurity.certificate.cert.CertException;
+import minsecurity.certificate.cert.Certificate;
+import minsecurity.crypto.KeyUtils;
+import minsecurity.crypto.PrivateKeyInterface;
+import minsecurity.crypto.PublicKeyInterface;
+import minsecurity.crypto.SM4;
+import minsecurity.crypto.sm2.SM2PrivateKey;
+import minsecurity.crypto.sm2.SM2PublicKey;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.IOException;
+import java.io.Serializable;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.util.Arrays;
+import java.util.Base64;
+
+/*
+ * @Author: hongyu guo
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 20:25 2021/03/07
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class Identity {
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Identity.class);
+ private String Name;
+ private KeyParam KeyParam;
+ private PrivateKeyInterface Prikey;
+ private byte[] PrikeyRawByte;
+ private PublicKeyInterface Pubkey;
+ private String Passwd;
+ private Certificate Cert;
+ private boolean IsDefault;
+
+ public Identity(String name, KeyParam keyParam,
+ PrivateKeyInterface prikey, byte[] prikeyRawByte,
+ PublicKeyInterface pubkey, String passwd, Certificate cert,
+ boolean isDefault) {
+ Name = name;
+ KeyParam = keyParam;
+ Prikey = prikey;
+ PrikeyRawByte = prikeyRawByte;
+ Pubkey = pubkey;
+ Passwd = passwd;
+ Cert = cert;
+ IsDefault = isDefault;
+ }
+
+
+ public Identity(){}
+
+
+
+ public byte[] sign(byte[] digest) throws CryptoException {
+ if(this.Prikey == null)
+ return null;
+ switch (this.KeyParam.PublicKeyAlgorithm){
+ case Common.SM2:
+ SM2PrivateKey sm2PrivateKey = (SM2PrivateKey) this.Prikey;
+ switch (this.KeyParam.SignatureAlgorithm){
+ case Common.SM3withSM2:
+ return sm2PrivateKey.sign(digest);
+ default:
+ return null;
+ }
+ default:
+ return null;
+ }
+ }
+
+ public boolean verify(byte[] msg, byte[] digest) {
+ if(this.Pubkey == null)
+ return false;
+ switch (this.KeyParam.PublicKeyAlgorithm){
+ case Common.SM2:
+ SM2PublicKey sm2PublicKey = (SM2PublicKey) this.Pubkey;
+ switch (this.KeyParam.SignatureAlgorithm){
+ case Common.SM3withSM2:
+ return sm2PublicKey.verify(msg, digest);
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+ }
+
+ public byte[] decrypt(byte[] cipher) throws InvalidCipherTextException {
+ if(this.Prikey == null)
+ return null;
+ return this.Prikey.decrypt(cipher);
+ }
+
+ public byte[] encrypt(byte[] content) throws InvalidCipherTextException {
+ if(this.Pubkey == null)
+ return null;
+ return this.Pubkey.encrypt(content);
+ }
+
+ public byte[] dump(String passwd) throws NoSuchPaddingException, InvalidAlgorithmParameterException, CertException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, JsonProcessingException {
+ ObjectMapper mapper = new ObjectMapper();
+ InnerIdentity innerIdentity = IdentityUtil.parseIdentityToInner(this);
+ byte[] bytesOfInnerIdentity = mapper.writeValueAsBytes(innerIdentity);
+ // logger.debug(ByteUtils.toHexString(bytesOfInnerIdentity));
+ if(passwd != null && passwd.length() != 0) {
+ byte[] sm4key = KeyUtils.get16bytePasswd(passwd.getBytes());
+ byte[] cipher = SM4.encrypt_CBC_Padding(sm4key, new byte[16], bytesOfInnerIdentity);
+ return Base64.getEncoder().encode(cipher);
+ }
+ return Base64.getEncoder().encode(bytesOfInnerIdentity);
+ }
+
+ public static Identity load(byte[] data, String passwd)
+ throws BadPaddingException, NoSuchPaddingException, InvalidAlgorithmParameterException,
+ NoSuchAlgorithmException, IllegalBlockSizeException, NoSuchProviderException,
+ InvalidKeyException, CertException {
+ byte[] bytesOfIdentity = Base64.getDecoder().decode(data);
+ byte[] plain;
+ if(passwd != null && passwd.length() != 0){
+ byte[] sm4Key = KeyUtils.get16bytePasswd(passwd.getBytes());
+ plain = SM4.decrypt_CBC_Padding(sm4Key, new byte[16], bytesOfIdentity);
+ } else{
+ plain = bytesOfIdentity;
+ }
+ ObjectMapper mapper = new ObjectMapper();
+ InnerIdentity innerIdentity = null;
+ // logger.debug(ByteUtils.toHexString(plain));
+ try {
+ innerIdentity = mapper.readValue(plain, InnerIdentity.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return IdentityUtil.parseInnerToIdentity(innerIdentity);
+ }
+ // TODO: passwd ???
+ public boolean lock(String passwd, int algo) throws IdentityException {
+ switch (algo){
+ case Common.SM4ECB:
+ if (passwd.length() != 16){
+ throw new IdentityException("密码应为16位");
+ }
+ PrikeyRawByte = Prikey.getBytes();
+ Prikey = null;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isLocked(){
+ return PrikeyRawByte != null && PrikeyRawByte.length > 0;
+ }
+
+ // TODO: passwd ???
+ public boolean unLock(String passwd, int algo) throws IdentityException {
+ switch (algo) {
+ case Common.SM4ECB:
+ if(passwd == null || passwd.length() == 0)
+ return false;
+ PrivateKeyInterface privateKey = KeyUtils.unMarshalPrivateKey(PrikeyRawByte, KeyParam.PublicKeyAlgorithm);
+ Prikey = privateKey;
+ PrikeyRawByte = null;
+ return true;
+ default:
+ throw new IdentityException("未知对称加密算法");
+ }
+ }
+
+ public boolean hasPrivateKey() {
+ return Prikey != null || (PrikeyRawByte != null && PrikeyRawByte.length > 0);
+ }
+
+
+
+
+
+ public String getName() {
+ return Name;
+ }
+
+ public void setName(String name) {
+ Name = name;
+ }
+
+ public minsecurity.identity.KeyParam getKeyParam() {
+ return KeyParam;
+ }
+
+ public void setKeyParam(minsecurity.identity.KeyParam keyParam) {
+ KeyParam = keyParam;
+ }
+
+ public PrivateKeyInterface getPrikey() {
+ return Prikey;
+ }
+
+ public void setPrikey(PrivateKeyInterface prikey) {
+ Prikey = prikey;
+ }
+
+ public byte[] getPrikeyRawByte() {
+ return PrikeyRawByte;
+ }
+
+ public void setPrikeyRawByte(byte[] prikeyRawByte) {
+ PrikeyRawByte = prikeyRawByte;
+ }
+
+ public PublicKeyInterface getPubkey() {
+ return Pubkey;
+ }
+
+ public void setPubkey(PublicKeyInterface pubkey) {
+ Pubkey = pubkey;
+ }
+
+ public String getPasswd() {
+ return Passwd;
+ }
+
+ public void setPasswd(String passwd) {
+ Passwd = passwd;
+ }
+
+ public Certificate getCert() {
+ return Cert;
+ }
+
+ public void setCert(Certificate cert) {
+ Cert = cert;
+ }
+
+ public boolean isDefault() {
+ return IsDefault;
+ }
+
+ public void setDefault(boolean aDefault) {
+ IsDefault = aDefault;
+ }
+
+ @Override
+ public String toString() {
+ return "Identity{" +
+ "Name='" + Name + '\'' +
+ ", KeyParam.signAlgo=" + KeyParam.SignatureAlgorithm +
+ ", KeyParam.pubAlgo=" + KeyParam.PublicKeyAlgorithm +
+ ", Prikey=" + ByteUtils.toHexString(Prikey.getBytes()) +
+ ", pubKey=" + ByteUtils.toHexString(Pubkey.getBytes()) +
+ ", PrikeyRawByte=" + (PrikeyRawByte == null ? "null":ByteUtils.toHexString(PrikeyRawByte)) +
+ ", Pubkey=" + Pubkey +
+ ", Passwd='" + Passwd + '\'' +
+ ", Cert=" + Cert +
+ ", isDefault=" + IsDefault +
+ '}';
+ }
+}
diff --git a/src/main/java/minsecurity/identity/IdentityException.java b/src/main/java/minsecurity/identity/IdentityException.java
new file mode 100644
index 0000000..8bd2431
--- /dev/null
+++ b/src/main/java/minsecurity/identity/IdentityException.java
@@ -0,0 +1,14 @@
+package minsecurity.identity;
+
+/*
+ * @Author: hongyu guo
+ * @Description: Identity自定义异常
+ * @Version: 1.0.0
+ * @Date: 14:59 2021/03/09
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class IdentityException extends Exception{
+ public IdentityException(String msg){
+ super(msg);
+ }
+}
diff --git a/src/main/java/minsecurity/identity/IdentityUtil.java b/src/main/java/minsecurity/identity/IdentityUtil.java
new file mode 100644
index 0000000..87a0814
--- /dev/null
+++ b/src/main/java/minsecurity/identity/IdentityUtil.java
@@ -0,0 +1,72 @@
+package minsecurity.identity;
+
+import minsecurity.Common;
+import minsecurity.certificate.cert.CertException;
+import minsecurity.certificate.cert.CertUtils;
+import minsecurity.certificate.cert.Certificate;
+import minsecurity.crypto.KeyUtils;
+import minsecurity.crypto.PrivateKeyInterface;
+import minsecurity.crypto.PublicKeyInterface;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+/*
+ * @Author: hongyu guo
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 10:12 2021/03/09
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class IdentityUtil {
+ public static InnerIdentity parseIdentityToInner(Identity identity)
+ throws NoSuchPaddingException, InvalidKeyException, CertException,
+ IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException,
+ NoSuchProviderException, InvalidAlgorithmParameterException {
+ InnerIdentity innerIdentity = new InnerIdentity();
+ innerIdentity.setName(identity.getName());
+ innerIdentity.setKeyParam(identity.getKeyParam());
+ if(identity.getPrikey() != null){
+ innerIdentity.setPrikey(identity.getPrikey().getBytes());
+ }
+ if(identity.getPubkey() != null){
+ innerIdentity.setPubkey(identity.getPubkey().getBytes());
+ }
+ innerIdentity.setPasswd(identity.getPasswd());
+ innerIdentity.setCert(CertUtils.toPem(identity.getCert(), identity.getPasswd().getBytes(), Common.SM4CBC));
+ return innerIdentity;
+ }
+
+ public static Identity parseInnerToIdentity(InnerIdentity innerIdentity)
+ throws BadPaddingException, InvalidKeyException, CertException,
+ NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidAlgorithmParameterException, IllegalBlockSizeException {
+ Identity identity = new Identity();
+ identity.setName(innerIdentity.getName());
+ identity.setKeyParam(innerIdentity.getKeyParam());
+ if(innerIdentity.getPubkey() == null || innerIdentity.getPubkey().length == 0){
+ return null;
+ }
+ if(innerIdentity.getPrikey() == null || innerIdentity.getPrikey().length == 0){
+ return null;
+ }
+ PublicKeyInterface pub =
+ KeyUtils.unMarshalPublicKey(innerIdentity.getPubkey(), innerIdentity.getKeyParam().PublicKeyAlgorithm);
+ identity.setPubkey(pub);
+ PrivateKeyInterface priv =
+ KeyUtils.unMarshalPrivateKey(innerIdentity.getPrikey(), innerIdentity.getKeyParam().PublicKeyAlgorithm);
+ identity.setPrikey(priv);
+ identity.setPasswd(innerIdentity.getPasswd());
+ Certificate certificate =
+ CertUtils.fromPem(innerIdentity.getCert(), innerIdentity.getPasswd().getBytes(), Common.SM4CBC);
+ identity.setCert(certificate);
+ return identity;
+ }
+
+
+}
diff --git a/src/main/java/minsecurity/identity/InnerIdentity.java b/src/main/java/minsecurity/identity/InnerIdentity.java
new file mode 100644
index 0000000..927f46a
--- /dev/null
+++ b/src/main/java/minsecurity/identity/InnerIdentity.java
@@ -0,0 +1,96 @@
+package minsecurity.identity;
+
+import minsecurity.certificate.cert.Certificate;
+import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
+
+import java.util.Arrays;
+
+/*
+ * @Author: hongyu guo
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 09:41 2021/03/09
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class InnerIdentity {
+ private String Name;
+ private KeyParam KeyParam;
+ private byte[] Prikey;
+ private byte[] Pubkey;
+ private String Passwd;
+ private String Cert;
+
+ public InnerIdentity(String name, minsecurity.identity.KeyParam keyParam, byte[] prikey, byte[] pubkey, String passwd, String cert) {
+ Name = name;
+ KeyParam = keyParam;
+ Prikey = prikey;
+ Pubkey = pubkey;
+ Passwd = passwd;
+ Cert = cert;
+ }
+
+ public InnerIdentity() {
+ }
+
+ public String getName() {
+ return Name;
+ }
+
+ public void setName(String name) {
+ Name = name;
+ }
+
+ public minsecurity.identity.KeyParam getKeyParam() {
+ return KeyParam;
+ }
+
+ public void setKeyParam(minsecurity.identity.KeyParam keyParam) {
+ KeyParam = keyParam;
+ }
+
+ public byte[] getPrikey() {
+ return Prikey;
+ }
+
+ public void setPrikey(byte[] prikey) {
+ Prikey = prikey;
+ }
+
+ public byte[] getPubkey() {
+ return Pubkey;
+ }
+
+ public void setPubkey(byte[] pubkey) {
+ Pubkey = pubkey;
+ }
+
+ public String getPasswd() {
+ return Passwd;
+ }
+
+ public void setPasswd(String passwd) {
+ Passwd = passwd;
+ }
+
+ public String getCert() {
+ return Cert;
+ }
+
+ public void setCert(String cert) {
+ Cert = cert;
+ }
+
+ @Override
+ public String toString() {
+ return "InnerIdentity{" +
+ "Name='" + Name + '\'' +
+ ", KeyParam=" + KeyParam +
+ ", Prikey=" + (Prikey == null ? "null" : ByteUtils.toHexString(Prikey)) +
+ ", Pubkey=" + (Pubkey == null ? "null" : ByteUtils.toHexString(Pubkey)) +
+ ", Passwd='" + Passwd + '\'' +
+ ", Cert='" + Cert + '\'' +
+ '}';
+ }
+}
+
+
diff --git a/src/main/java/minsecurity/identity/KeyParam.java b/src/main/java/minsecurity/identity/KeyParam.java
new file mode 100644
index 0000000..7a3ef10
--- /dev/null
+++ b/src/main/java/minsecurity/identity/KeyParam.java
@@ -0,0 +1,21 @@
+package minsecurity.identity;
+
+/*
+ * @Author: hongyu guo
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 20:31 2021/03/07
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class KeyParam {
+ public int PublicKeyAlgorithm;
+ public int SignatureAlgorithm;
+
+ public KeyParam(int publicKeyAlgorithm, int signatureAlgorithm) {
+ this.PublicKeyAlgorithm = publicKeyAlgorithm;
+ this.SignatureAlgorithm = signatureAlgorithm;
+ }
+
+ public KeyParam() {
+ }
+}
diff --git a/src/main/java/minsecurity/identity/persist/IdentitySerializer.java b/src/main/java/minsecurity/identity/persist/IdentitySerializer.java
new file mode 100644
index 0000000..fea81d4
--- /dev/null
+++ b/src/main/java/minsecurity/identity/persist/IdentitySerializer.java
@@ -0,0 +1,97 @@
+package minsecurity.identity.persist;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import minsecurity.Common;
+import minsecurity.certificate.cert.CertException;
+import minsecurity.certificate.cert.CertUtils;
+import minsecurity.certificate.cert.Certificate;
+import minsecurity.crypto.sm2.SM2PrivateKey;
+import minsecurity.crypto.sm2.SM2PublicKey;
+import minsecurity.identity.Identity;
+import minsecurity.identity.KeyParam;
+import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
+import org.jetbrains.annotations.NotNull;
+import org.mapdb.DataInput2;
+import org.mapdb.DataOutput2;
+import org.mapdb.Serializer;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+/*
+ * @Author: hongyu guo
+ * @Description: mapDB需要自定义序列化、反序列化方法
+ * @Version: 1.0.0
+ * @Date: 20:50 2021/03/09
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class IdentitySerializer implements Serializer {
+
+
+ @Override
+ public void serialize(@NotNull DataOutput2 dataOutput2, @NotNull Identity identity) throws IOException {
+ String name = identity.getName();
+ String pub = ByteUtils.toHexString(identity.getPubkey().getBytes());
+ String priv = ByteUtils.toHexString(identity.getPrikey().getBytes());
+ int pubAlgo = identity.getKeyParam().PublicKeyAlgorithm;
+ int signAlgo = identity.getKeyParam().SignatureAlgorithm;
+ String passwd = identity.getPasswd();
+ String cert = "";
+ try {
+ cert = CertUtils.toPem(identity.getCert(),null, Common.SM4CBC);
+ } catch (CertException | NoSuchPaddingException | InvalidAlgorithmParameterException |
+ NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException |
+ NoSuchProviderException | InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ boolean isDefault = identity.isDefault();
+ String prikeyRawByte = identity.getPrikeyRawByte()== null ?
+ "" :ByteUtils.toHexString(identity.getPrikeyRawByte());
+
+
+ dataOutput2.writeUTF(name);
+ dataOutput2.writeUTF(pub);
+ dataOutput2.writeUTF(priv);
+ dataOutput2.writeInt(pubAlgo);
+ dataOutput2.writeInt(signAlgo);
+ dataOutput2.writeUTF(passwd);
+ dataOutput2.writeUTF(cert);
+ dataOutput2.writeBoolean(isDefault);
+ dataOutput2.writeUTF(prikeyRawByte);
+ }
+
+ @Override
+ public Identity deserialize(@NotNull DataInput2 dataInput2, int i) throws IOException {
+ String name = dataInput2.readUTF();
+ byte[] pub = ByteUtils.fromHexString(dataInput2.readUTF());
+ byte[] priv = ByteUtils.fromHexString(dataInput2.readUTF());
+ int pubAlgo = dataInput2.readInt();
+ int signAlgo = dataInput2.readInt();
+ String passwd = dataInput2.readUTF();
+ String certString = dataInput2.readUTF();
+ Certificate certificate = null;
+ try {
+ certificate = CertUtils.fromPem(certString, null, Common.SM4CBC);
+ } catch (CertException | BadPaddingException | NoSuchPaddingException |
+ InvalidAlgorithmParameterException | NoSuchAlgorithmException |
+ IllegalBlockSizeException | NoSuchProviderException | InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ boolean isDefault = dataInput2.readBoolean();
+ byte[] prikeyRawByte = dataInput2.readUTF().equals("") ?
+ null : ByteUtils.fromHexString(dataInput2.readUTF());
+ KeyParam keyParam = new KeyParam(pubAlgo, signAlgo);
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey();
+ sm2PrivateKey.setBytes(priv);
+ SM2PublicKey sm2PublicKey = new SM2PublicKey();
+ sm2PublicKey.setBytes(pub);
+ return new Identity(name,keyParam, sm2PrivateKey,prikeyRawByte, sm2PublicKey, passwd, certificate, isDefault);
+ }
+
+}
diff --git a/src/test/java/minsecurity/certificate/cert/TestCert.java b/src/test/java/minsecurity/certificate/cert/TestCert.java
index eb3f780..70f8249 100644
--- a/src/test/java/minsecurity/certificate/cert/TestCert.java
+++ b/src/test/java/minsecurity/certificate/cert/TestCert.java
@@ -1,9 +1,9 @@
package minsecurity.certificate.cert;
import minsecurity.Common;
-import minsecurity.crypto.sm2.Sm2Base;
-import minsecurity.crypto.sm2.Sm2PrivateKey;
-import minsecurity.crypto.sm2.Sm2PublicKey;
+import minsecurity.crypto.sm2.SM2Base;
+import minsecurity.crypto.sm2.SM2PrivateKey;
+import minsecurity.crypto.sm2.SM2PublicKey;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
@@ -22,15 +22,15 @@ public class TestCert {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestCert.class);
@Test
public void testCertSignAndVerify() throws Exception {
- AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
+ AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
// d = Arrays.copyOf(d,32);
byte[] x = pubKey.getQ().getAffineXCoord().getEncoded();
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
- Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey(d);
- Sm2PublicKey sm2PublicKey = new Sm2PublicKey(x,y);
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
+ SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
Certificate certificate = new Certificate(1,1,sm2PublicKey,
@@ -46,15 +46,15 @@ public class TestCert {
assertTrue(verify);
- AsymmetricCipherKeyPair keyPair2 = Sm2Base.generateKeyPairParameter();
+ AsymmetricCipherKeyPair keyPair2 = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey2 = (ECPrivateKeyParameters) keyPair2.getPrivate();
ECPublicKeyParameters pubKey2 = (ECPublicKeyParameters) keyPair2.getPublic();
byte[] d2 = priKey2.getD().toByteArray();
// d = Arrays.copyOf(d,32);
byte[] x2 = pubKey2.getQ().getAffineXCoord().getEncoded();
byte[] y2 = pubKey2.getQ().getAffineYCoord().getEncoded();
- Sm2PrivateKey sm2PrivateKey2 = new Sm2PrivateKey(d2);
- Sm2PublicKey sm2PublicKey2 = new Sm2PublicKey(x2, y2);
+ SM2PrivateKey sm2PrivateKey2 = new SM2PrivateKey(d2);
+ SM2PublicKey sm2PublicKey2 = new SM2PublicKey(x2, y2);
Certificate sub = new Certificate(1,2,sm2PublicKey2,
null, Common.SM3withSM2,Common.SM2,
@@ -69,15 +69,15 @@ public class TestCert {
@Test
public void testCert2Pem() throws Exception {
- AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
+ AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
// d = Arrays.copyOf(d,32);
byte[] x = pubKey.getQ().getAffineXCoord().getEncoded();
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
- Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey(d);
- Sm2PublicKey sm2PublicKey = new Sm2PublicKey(x,y);
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
+ SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
Certificate certificate = new Certificate(1,1,sm2PublicKey,
diff --git a/src/test/java/minsecurity/certificate/x509/TestX509.java b/src/test/java/minsecurity/certificate/x509/TestX509.java
index 920cdce..79514d9 100644
--- a/src/test/java/minsecurity/certificate/x509/TestX509.java
+++ b/src/test/java/minsecurity/certificate/x509/TestX509.java
@@ -3,7 +3,7 @@ package minsecurity.certificate.x509;
import minsecurity.Common;
import minsecurity.certificate.X509.X509CertMaker;
import minsecurity.certificate.X509.X509CertUtil;
-import minsecurity.crypto.sm2.Sm2Base;
+import minsecurity.crypto.sm2.SM2Base;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.io.pem.PemObject;
@@ -50,7 +50,7 @@ public class TestX509 {
public void testRebuildKeyPair(){
try {
- KeyPair rootKP = Sm2Base.generateKeyPair();
+ KeyPair rootKP = SM2Base.generateKeyPair();
X509Certificate rootCA = makeRootCA(rootKP,"CN","MIN",
"MIN-GROUP","MIN ROOT CA",
365L * 24 * 60 * 60 * 1000, "SM3withSM2");
@@ -77,7 +77,7 @@ public class TestX509 {
logger.debug("origin: {}", ByteUtils.toHexString(rootKP.getPublic().getEncoded()));
logger.debug("rebuild:{}", ByteUtils.toHexString(rootKeyPair.getPublic().getEncoded()));
- KeyPair subKeyPair = Sm2Base.generateKeyPair();
+ KeyPair subKeyPair = SM2Base.generateKeyPair();
X509Certificate subCert =
X509CertMaker.makeSubCACert(rootKeyPair,
cert,
diff --git a/src/test/java/minsecurity/crypto/TestSm2.java b/src/test/java/minsecurity/crypto/TestSM2.java
similarity index 88%
rename from src/test/java/minsecurity/crypto/TestSm2.java
rename to src/test/java/minsecurity/crypto/TestSM2.java
index 57e616c..274d45e 100644
--- a/src/test/java/minsecurity/crypto/TestSm2.java
+++ b/src/test/java/minsecurity/crypto/TestSM2.java
@@ -1,8 +1,8 @@
package minsecurity.crypto;
-import minsecurity.crypto.sm2.Sm2Base;
-import minsecurity.crypto.sm2.Sm2PrivateKey;
-import minsecurity.crypto.sm2.Sm2PublicKey;
+import minsecurity.crypto.sm2.SM2Base;
+import minsecurity.crypto.sm2.SM2PrivateKey;
+import minsecurity.crypto.sm2.SM2PublicKey;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
@@ -24,11 +24,11 @@ import java.util.List;
* @Date: 20:15 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
-public class TestSm2 {
- private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestSm2.class);
+public class TestSM2 {
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestSM2.class);
@Test
public void testSetGet() throws InvalidCipherTextException {
- AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
+ AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
@@ -36,8 +36,8 @@ public class TestSm2 {
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
logger.debug("d.len = {}, x.len = {}, y.len = {}",d.length, x.length, y.length);
// BigInteger bigInteger = priKey.getD();
- Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey();
- Sm2PublicKey sm2PublicKey = new Sm2PublicKey();
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey();
+ SM2PublicKey sm2PublicKey = new SM2PublicKey();
sm2PrivateKey.setBytes(d);
@@ -62,7 +62,7 @@ public class TestSm2 {
@Test
public void testEncAndDec() throws InvalidCipherTextException {
- AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
+ AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
@@ -71,8 +71,8 @@ public class TestSm2 {
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
logger.debug("d.len = {}, x.len = {}, y.len = {}",d.length, x.length, y.length);
// BigInteger bigInteger = priKey.getD();
- Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey(d);
- Sm2PublicKey sm2PublicKey = new Sm2PublicKey(x,y);
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
+ SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
String content = "hello world";
byte[] encBytes = sm2PublicKey.encrypt(content.getBytes());
@@ -83,7 +83,7 @@ public class TestSm2 {
@Test
public void testSignAndVerify() throws CryptoException {
- AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
+ AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
@@ -93,8 +93,8 @@ public class TestSm2 {
logger.debug("d.len = {}, x.len = {}, y.len = {}",d.length, x.length, y.length);
// BigInteger bigInteger = priKey.getD();
- Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey(d);
- Sm2PublicKey sm2PublicKey = new Sm2PublicKey(x,y);
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
+ SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
String content = "7b227462734365727469666963617465223a7b2276657273696f6e223a312c2273657269616c4e756d626572223a312c227075626c69634b6579223a22424a304d7047714e5958706b695879575a4d6e5838776d6b694a51326f576d37336257615932525473706b695058342f37705443666332764e7272596e766c6a644d3448647850537531753272616363506c74485245593d222c227369676e6174757265416c676f726974686d223a302c227075626c69634b6579416c676f726974686d223a302c226973737565546f223a226973737565546f222c22697373756572223a22697373756572222c226e6f744265666f7265223a313631353032303130393339352c226e6f744166746572223a313631353032303130393539352c226b65795573616765223a322c2274696d657374616d70223a313631353032303130393339352c226361223a747275657d2c227369676e6174757265416c676f726974686d223a302c227369676e617475726556616c7565223a6e756c6c7d";
byte[] digest = sm2PrivateKey.sign(ByteUtils.fromHexString(content));
boolean flag = sm2PublicKey.verify(ByteUtils.fromHexString(content), digest);
diff --git a/src/test/java/minsecurity/crypto/TestSm4.java b/src/test/java/minsecurity/crypto/TestSM4.java
similarity index 82%
rename from src/test/java/minsecurity/crypto/TestSm4.java
rename to src/test/java/minsecurity/crypto/TestSM4.java
index 34cd1a8..0bb09ac 100644
--- a/src/test/java/minsecurity/crypto/TestSm4.java
+++ b/src/test/java/minsecurity/crypto/TestSM4.java
@@ -2,7 +2,6 @@ package minsecurity.crypto;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.junit.Assert;
-import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
@@ -14,7 +13,7 @@ import java.util.Arrays;
* @Date: 16:28 2021/03/04
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
-public class TestSm4 {
+public class TestSM4 {
public static final byte[] SRC_DATA = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
public static final byte[] SRC_DATA_16B = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8};
public static final byte[] SRC_DATA_24B = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8};
@@ -25,42 +24,42 @@ public class TestSm4 {
@Test
public void testEncryptAndDecrypt() {
try {
- byte[] key = Sm4.generateKey();
- byte[] iv = Sm4.generateKey();
+ byte[] key = SM4.generateKey();
+ byte[] iv = SM4.generateKey();
byte[] cipherText = null;
byte[] decryptedData = null;
System.out.println("key: " + ByteUtils.toHexString(key));
System.out.println("iv: " + ByteUtils.toHexString(iv));
- cipherText = Sm4.encrypt_ECB_NoPadding(key, SRC_DATA_16B);
+ cipherText = SM4.encrypt_ECB_NoPadding(key, SRC_DATA_16B);
System.out.println("SM4 ECB NoPadding encrypt result:\n" + Arrays.toString(cipherText));
System.out.println(ByteUtils.toHexString(cipherText));
- decryptedData = Sm4.decrypt_ECB_NoPadding(key, cipherText);
+ decryptedData = SM4.decrypt_ECB_NoPadding(key, cipherText);
System.out.println("SM4 ECB NoPadding decrypt result:\n" + Arrays.toString(decryptedData));
if (!Arrays.equals(decryptedData, SRC_DATA_16B)) {
Assert.fail();
}
- cipherText = Sm4.encrypt_ECB_Padding(key, SRC_DATA_16B);
+ cipherText = SM4.encrypt_ECB_Padding(key, SRC_DATA_16B);
System.out.println("SM4 ECB Padding encrypt result:\n" + Arrays.toString(cipherText));
System.out.println(ByteUtils.toHexString(cipherText));
- decryptedData = Sm4.decrypt_ECB_Padding(key, cipherText);
+ decryptedData = SM4.decrypt_ECB_Padding(key, cipherText);
System.out.println("SM4 ECB Padding decrypt result:\n" + Arrays.toString(decryptedData));
if (!Arrays.equals(decryptedData, SRC_DATA_16B)) {
Assert.fail();
}
- cipherText = Sm4.encrypt_CBC_Padding(key, iv, SRC_DATA);
+ cipherText = SM4.encrypt_CBC_Padding(key, iv, SRC_DATA);
System.out.println("SM4 CBC Padding encrypt result:\n" + Arrays.toString(cipherText));
- decryptedData = Sm4.decrypt_CBC_Padding(key, iv, cipherText);
+ decryptedData = SM4.decrypt_CBC_Padding(key, iv, cipherText);
System.out.println("SM4 CBC Padding decrypt result:\n" + Arrays.toString(decryptedData));
if (!Arrays.equals(decryptedData, SRC_DATA)) {
Assert.fail();
}
- cipherText = Sm4.encrypt_CBC_NoPadding(key, iv, SRC_DATA_16B);
+ cipherText = SM4.encrypt_CBC_NoPadding(key, iv, SRC_DATA_16B);
System.out.println("SM4 CBC NoPadding encrypt result:\n" + Arrays.toString(cipherText));
- decryptedData = Sm4.decrypt_CBC_NoPadding(key, iv, cipherText);
+ decryptedData = SM4.decrypt_CBC_NoPadding(key, iv, cipherText);
System.out.println("SM4 CBC NoPadding decrypt result:\n" + Arrays.toString(decryptedData));
if (!Arrays.equals(decryptedData, SRC_DATA_16B)) {
Assert.fail();
diff --git a/src/test/java/minsecurity/identity/TestIdentity.java b/src/test/java/minsecurity/identity/TestIdentity.java
new file mode 100644
index 0000000..45394bc
--- /dev/null
+++ b/src/test/java/minsecurity/identity/TestIdentity.java
@@ -0,0 +1,81 @@
+package minsecurity.identity;
+
+import minsecurity.Common;
+import minsecurity.certificate.cert.CertUtils;
+import minsecurity.certificate.cert.Certificate;
+import minsecurity.crypto.TestSM2;
+import minsecurity.crypto.sm2.SM2Base;
+import minsecurity.crypto.sm2.SM2PrivateKey;
+import minsecurity.crypto.sm2.SM2PublicKey;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.slf4j.LoggerFactory;
+
+/*
+ * @Author: hongyu guo
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 15:24 2021/03/09
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class TestIdentity {
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestIdentity.class);
+
+
+ @Test
+ public void testIdentity1() throws Exception {
+ AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
+ ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
+ ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
+ byte[] d = priKey.getD().toByteArray();
+ // d = Arrays.copyOf(d,32);
+ byte[] x = pubKey.getQ().getAffineXCoord().getEncoded();
+ byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
+ logger.debug("d.len = {}, x.len = {}, y.len = {}",d.length, x.length, y.length);
+
+ // BigInteger bigInteger = priKey.getD();
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
+ SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
+ KeyParam keyParam = new KeyParam(Common.SM2, Common.SM3withSM2);
+ Identity identity = new Identity("root",keyParam,sm2PrivateKey,null,sm2PublicKey, "123456", null, false);
+ Certificate certificate = new Certificate(1, 1, sm2PublicKey, null,
+ Common.SM3withSM2, Common.SM2, "root", "root",
+ System.currentTimeMillis() - 1000, System.currentTimeMillis() + 5000,
+ Common.CertSign, true, System.currentTimeMillis());
+ CertUtils.signCert(certificate, sm2PrivateKey);
+ identity.setCert(certificate);
+
+ String text = "2020-03-09";
+ // test sign and verify
+ byte[] signature = identity.sign(text.getBytes());
+ boolean flag = identity.verify(text.getBytes(), signature);
+ logger.debug("identity verify: {}", flag);
+ assertTrue(flag);
+
+
+ // test enc and dec
+ byte[] cipher = identity.encrypt(text.getBytes());
+ byte[] bytesOfDec = identity.decrypt(cipher);
+ assertArrayEquals(bytesOfDec, text.getBytes());
+
+
+ // test dump and load
+ byte[] bytesOfDump = identity.dump(identity.getPasswd());
+ Identity idFromBytes = Identity.load(bytesOfDump, identity.getPasswd());
+ assertEquals(ByteUtils.toHexString(identity.getPrikey().getBytes()), ByteUtils.toHexString(idFromBytes.getPrikey().getBytes()));
+ assertEquals(ByteUtils.toHexString(identity.getPubkey().getBytes()), ByteUtils.toHexString(idFromBytes.getPubkey().getBytes()));
+ // test dump and load without passwd
+ bytesOfDump = identity.dump(null);
+ idFromBytes = Identity.load(bytesOfDump, null);
+ assertEquals(ByteUtils.toHexString(identity.getPrikey().getBytes()), ByteUtils.toHexString(idFromBytes.getPrikey().getBytes()));
+ assertEquals(ByteUtils.toHexString(identity.getPubkey().getBytes()), ByteUtils.toHexString(idFromBytes.getPubkey().getBytes()));
+
+ logger.debug(identity.getPrikey().getBytes().length + " " + identity.getPubkey().getBytes().length);
+ }
+
+
+}
diff --git a/src/test/java/minsecurity/identity/TestPersist.java b/src/test/java/minsecurity/identity/TestPersist.java
new file mode 100644
index 0000000..8578ba6
--- /dev/null
+++ b/src/test/java/minsecurity/identity/TestPersist.java
@@ -0,0 +1,68 @@
+package minsecurity.identity;
+
+
+import minsecurity.Common;
+import minsecurity.certificate.cert.CertUtils;
+import minsecurity.certificate.cert.Certificate;
+import minsecurity.crypto.sm2.SM2Base;
+import minsecurity.crypto.sm2.SM2PrivateKey;
+import minsecurity.crypto.sm2.SM2PublicKey;
+import minsecurity.identity.persist.IdentitySerializer;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.junit.Test;
+import org.mapdb.BTreeMap;
+import org.mapdb.DB;
+import org.mapdb.DBMaker;
+import org.mapdb.Serializer;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ConcurrentMap;
+
+/*
+ * @Author: hongyu guo
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 17:35 2021/03/09
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class TestPersist {
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestIdentity.class);
+
+ @Test
+ public void testMapDB() throws Exception {
+
+
+ AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
+ ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
+ ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
+ byte[] d = priKey.getD().toByteArray();
+ // d = Arrays.copyOf(d,32);
+ byte[] x = pubKey.getQ().getAffineXCoord().getEncoded();
+ byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
+ // BigInteger bigInteger = priKey.getD();
+ SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
+ SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
+ KeyParam keyParam = new KeyParam(Common.SM2, Common.SM3withSM2);
+ Identity identity = new Identity("root",keyParam,sm2PrivateKey,null,sm2PublicKey, "123456", null, false);
+ Certificate certificate = new Certificate(1, 1, sm2PublicKey, null,
+ Common.SM3withSM2, Common.SM2, "root", "root",
+ System.currentTimeMillis() - 1000, System.currentTimeMillis() + 5000,
+ Common.CertSign, true, System.currentTimeMillis());
+ CertUtils.signCert(certificate, sm2PrivateKey);
+ identity.setCert(certificate);
+ DB db = DBMaker.fileDB("./target/test.db").closeOnJvmShutdown().transactionEnable().make();
+ Serializer customSerializer = new IdentitySerializer();
+ ConcurrentMap map = db.hashMap("identity")
+ .keySerializer(Serializer.STRING)
+ .valueSerializer(customSerializer)
+ .createOrOpen();
+ // map.put("/min/test05", new Identity());
+ map.put("/min/test06", identity);
+ db.commit();
+ logger.debug(identity.toString());
+ Identity id = map.get("/min/test06");
+ logger.debug(id.toString());
+ }
+}
diff --git a/src/test/java/others/Animal.java b/src/test/java/others/Animal.java
new file mode 100644
index 0000000..528dbce
--- /dev/null
+++ b/src/test/java/others/Animal.java
@@ -0,0 +1,15 @@
+package others;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 9:15 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+interface Animal {
+// private String name="灵长类动物";
+
+
+ public void sayHi();
+}
diff --git a/src/test/java/others/God.java b/src/test/java/others/God.java
new file mode 100644
index 0000000..3db3f9b
--- /dev/null
+++ b/src/test/java/others/God.java
@@ -0,0 +1,13 @@
+package others;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 9:15 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+interface God {
+
+ public void makeWorld();
+}
diff --git a/src/test/java/others/HumanImpl.java b/src/test/java/others/HumanImpl.java
new file mode 100644
index 0000000..4385ccb
--- /dev/null
+++ b/src/test/java/others/HumanImpl.java
@@ -0,0 +1,26 @@
+package others;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 10:10 2021/3/9
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class HumanImpl implements God,Animal {
+ @Override
+ public void sayHi() {
+ System.out.println("hi");
+ }
+
+ @Override
+ public void makeWorld() {
+ System.out.println("world");
+ }
+
+ public static void main(String[] args){
+ HumanImpl h=new HumanImpl();
+ h.sayHi();
+ h.makeWorld();
+ }
+}