mirror of
https://gitee.com/willfree/min-dev-java.git
synced 2026-06-18 06:00:25 +08:00
302 lines
9.8 KiB
Java
302 lines
9.8 KiB
Java
package security;
|
|
|
|
import component.Signature;
|
|
import encoding.Block;
|
|
import encoding.SelfEncodingBase;
|
|
import minsecurity.identity.Identity;
|
|
import minsecurity.identity.IdentityException;
|
|
import packet.CPacket;
|
|
import packet.Data;
|
|
import packet.Interest;
|
|
import packet.MINPacket;
|
|
|
|
import javax.crypto.BadPaddingException;
|
|
import javax.crypto.IllegalBlockSizeException;
|
|
import javax.crypto.NoSuchPaddingException;
|
|
import java.lang.reflect.Array;
|
|
import java.security.InvalidKeyException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.NoSuchProviderException;
|
|
import java.util.IdentityHashMap;
|
|
|
|
/*
|
|
* @Author: hongyu guo
|
|
* @Description: 用于给网络包签名和验签
|
|
* @Version: 1.0.0
|
|
* @Date: 15:49 2021/03/11
|
|
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
|
|
*/
|
|
public class KeyChain {
|
|
private static final String defaultIdentifyName = "/localhost/operator";
|
|
public IdentifyManager getIdentifyManager() {
|
|
return identifyManager;
|
|
}
|
|
|
|
public void setIdentifyManager(IdentifyManager identifyManager) {
|
|
this.identifyManager = identifyManager;
|
|
}
|
|
|
|
public Identity getCurrentIdentity() {
|
|
return currentIdentity;
|
|
}
|
|
|
|
public void setCurrentIdentity(Identity currentIdentity) {
|
|
this.currentIdentity = currentIdentity;
|
|
}
|
|
|
|
private IdentifyManager identifyManager;
|
|
private Identity currentIdentity;
|
|
|
|
/**
|
|
* 指定当前使用默认的网络身份
|
|
* @param
|
|
* @return
|
|
* @author hongyu guo
|
|
* @date 2021/3/11
|
|
**/
|
|
public KeyChain() throws Exception{
|
|
identifyManager = new IdentifyManager();
|
|
currentIdentity = identifyManager.getDefaultIdentity();
|
|
// DONE: 考虑是否需要在没有默认身份的时候创建一个缺省的本地网络身份
|
|
if (currentIdentity == null){
|
|
Identity newId = this.identifyManager.createIdentityByName(defaultIdentifyName, "", true);
|
|
this.identifyManager.setDefaultIdentity(newId);
|
|
this.currentIdentity = newId;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置当前使用的网络身份,用 password 对目标网络身份进行解锁
|
|
* @param identity
|
|
* @param passwd 如果passwd不为null 且不为空字符串, 则使用该passwd对identity进行解密
|
|
* @return void
|
|
* @author hongyu guo
|
|
* @date 2021/3/11
|
|
**/
|
|
public void setCurrentIdentity(Identity identity, String passwd) {
|
|
try {
|
|
if(passwd != null && !passwd.equals("")){
|
|
identity.unLock(passwd, identifyManager.getPrivateKeyEncryptionAlgorithm());
|
|
currentIdentity = identity;
|
|
}
|
|
} catch (IdentityException e) {
|
|
e.printStackTrace();
|
|
} catch (NoSuchAlgorithmException e) {
|
|
e.printStackTrace();
|
|
} catch (InvalidKeyException e) {
|
|
e.printStackTrace();
|
|
} catch (NoSuchPaddingException e) {
|
|
e.printStackTrace();
|
|
} catch (BadPaddingException e) {
|
|
e.printStackTrace();
|
|
} catch (NoSuchProviderException e) {
|
|
e.printStackTrace();
|
|
} catch (IllegalBlockSizeException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 为一个网络身份申请证书
|
|
* @param identity
|
|
* @param force
|
|
* @return void
|
|
* @author hongyu guo
|
|
* @date 2021/3/11
|
|
**/
|
|
public void generateCertificationForIdentity(Identity identity, boolean force) {
|
|
// TODO: 这边应该发起网络通信,向 MIS 请求给这个网络身份签发一个证书,留待 MIR 完成后进行补充
|
|
}
|
|
|
|
/**
|
|
* 检查一个网络身份是否可用
|
|
*
|
|
* 1. 首先检查 identity 是否为空;
|
|
* 2. 接着检查 identity 是否包含私钥;
|
|
* 3. 接着检查 identify 是否被锁定
|
|
* @param identity
|
|
* @return void
|
|
* @author hongyu guo
|
|
* @date 2021/3/11
|
|
**/
|
|
public void checkIdentifyCanUseToSign(Identity identity) throws KeyChainException {
|
|
if(identity == null)
|
|
throw new KeyChainException("identity is null");
|
|
if(!identity.hasPrivateKey()){
|
|
throw new KeyChainException("Identify not have Private key, so can't use to sign!");
|
|
}
|
|
if(identity.isLocked()){
|
|
throw new KeyChainException("Identify is locked, so can't use to sign");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 从 MIN 网络包中提取出标识区和只读区的值,用于签名和验签
|
|
* @param packet MINPacket
|
|
* @return byte[]
|
|
* @throws Exception
|
|
*/
|
|
private byte[] getIdentifierAndReadOnlyValueFromPacket(MINPacket packet) throws Exception{
|
|
byte[] rawData = null;
|
|
byte[] iBlockValue = null;
|
|
byte[] rBlockValue = null;
|
|
int totalLength = 0;
|
|
// 1. 获取标识区数据
|
|
Block iBlock = new SelfEncodingBase().selfWireEncode(packet.identifierField);
|
|
if (iBlock != null){
|
|
iBlockValue = iBlock.getValue();
|
|
totalLength += iBlockValue.length;
|
|
}
|
|
// 2. 获取只读区数据
|
|
Block rBlock = new SelfEncodingBase().selfWireEncode(packet.readOnlyField);
|
|
if (rBlock != null){
|
|
rBlockValue = rBlock.getValue();
|
|
totalLength += rBlockValue.length;
|
|
}
|
|
// 3. 合并数据
|
|
if (totalLength == 0)
|
|
return rawData;
|
|
rawData = new byte[totalLength];
|
|
if (iBlock != null)
|
|
System.arraycopy(iBlockValue, 0, rawData, 0, iBlockValue.length);
|
|
if (rBlock != null)
|
|
System.arraycopy(rBlockValue, 0, rawData, iBlockValue.length, rBlockValue.length);
|
|
return rawData;
|
|
}
|
|
|
|
/**
|
|
* 给一个通用的网络包签名
|
|
* @param packet
|
|
* @throws Exception
|
|
*/
|
|
public void sign(MINPacket packet) throws Exception{
|
|
// 首先检查当前使用的身份是否可以用来签名
|
|
checkIdentifyCanUseToSign(this.currentIdentity);
|
|
|
|
// 1. 提取标识区和只读区的值,对其进行签名
|
|
byte[] rawData = getIdentifierAndReadOnlyValueFromPacket(packet);
|
|
|
|
// 2. 对标识区和只读区进行签名
|
|
byte[] signResult = this.currentIdentity.sign(rawData);
|
|
|
|
// 3. 往包签名区中添加签名
|
|
Signature signature = new Signature(this.currentIdentity, signResult);
|
|
packet.signatureField.addSignature(signature);
|
|
}
|
|
|
|
/**
|
|
* 对CPacket进行签名
|
|
* @param cPacket
|
|
* @throws Exception
|
|
*/
|
|
public void signCPacket(CPacket cPacket) throws Exception{
|
|
cPacket.fillDataToFields();
|
|
this.sign(cPacket.minPacket);
|
|
}
|
|
|
|
/**
|
|
* 对Interest进行签名
|
|
* @param interest
|
|
* @throws Exception
|
|
*/
|
|
public void signInterest(Interest interest) throws Exception{
|
|
interest.fillDataToFields();
|
|
this.sign(interest.minPacket);
|
|
}
|
|
|
|
/**
|
|
* 对Data进行签名
|
|
* @param data
|
|
* @throws Exception
|
|
*/
|
|
public void signData(Data data) throws Exception{
|
|
data.fillDataToFields();
|
|
this.sign(data.minPacket);
|
|
}
|
|
|
|
/**
|
|
* 验证一个MIN网络包中的签名是否有效
|
|
* @param minPacket
|
|
* @throws Exception
|
|
*/
|
|
public void verify(MINPacket minPacket) throws Exception{
|
|
// 提取签名区的第一个签名进行验证(认为签名区的第一个签名为包的签名,包含标识区和只读区签名)
|
|
Signature signature = minPacket.signatureField.getSignature(0);
|
|
|
|
String identityName = signature.getSigInfo().getKeyLocator().getIdentifier().toUri();
|
|
Identity identity = this.identifyManager.getIdentityByName(identityName);
|
|
|
|
if (identity == null){
|
|
throw new KeyChainException("Verify failed, could not find the identity");
|
|
}
|
|
|
|
byte[] rawData = getIdentifierAndReadOnlyValueFromPacket(minPacket);
|
|
identity.verify(rawData, signature.getSigValue().getValue());
|
|
}
|
|
|
|
/**
|
|
* 验证一个 CPacket 中的签名是否有效
|
|
* @param packet
|
|
* @throws Exception
|
|
*/
|
|
public void verifyCPacket(CPacket packet) throws Exception{
|
|
packet.fillDataToFields();
|
|
verify(packet.minPacket);
|
|
}
|
|
|
|
/**
|
|
* 验证一个 Interest 中的签名是否有效
|
|
* @param interest
|
|
* @throws Exception
|
|
*/
|
|
public void verifyInterest(Interest interest) throws Exception{
|
|
interest.fillDataToFields();
|
|
verify(interest.minPacket);
|
|
}
|
|
|
|
/**
|
|
* 验证一个 Data 中的签名是否有效
|
|
* @param data
|
|
* @throws Exception
|
|
*/
|
|
public void verifyData(Data data) throws Exception{
|
|
data.fillDataToFields();
|
|
verify(data.minPacket);
|
|
}
|
|
|
|
/**
|
|
* 将一个网络身份导出为一个 SafeBag 对象
|
|
* @param identity
|
|
* @param passwd
|
|
* @return SafeBag
|
|
* @throws Exception
|
|
*/
|
|
public SafeBag exportSafeBag(Identity identity, String passwd) throws Exception{
|
|
if (identity == null)
|
|
return null;
|
|
byte[] res = identity.dump(passwd);
|
|
SafeBag safeBag = new SafeBag(res);
|
|
return safeBag;
|
|
}
|
|
|
|
/**
|
|
* 从一个 SafeBag 中导入网络身份,保存到本地
|
|
* @param safeBag
|
|
* @param passwd
|
|
* @param force
|
|
* @throws Exception
|
|
*/
|
|
public void importSafeBag(SafeBag safeBag, String passwd, boolean force) throws Exception{
|
|
if (safeBag == null)
|
|
throw new KeyChainException(String.format("SafeBag is %s", safeBag));
|
|
Identity identity = Identity.load(safeBag.getValue(), passwd);
|
|
|
|
if (!this.identifyManager.existIdentity(identity.getName()) || force){
|
|
this.identifyManager.saveIdentity(identity, force, false);
|
|
}else {
|
|
throw new KeyChainException(String.format("Identify %s is already exists!", identity.getName()));
|
|
}
|
|
}
|
|
}
|