diff --git a/src/main/java/minsecurity/crypto/sm2/SM2Base.java b/src/main/java/minsecurity/crypto/sm2/SM2Base.java index b84049b..e134585 100644 --- a/src/main/java/minsecurity/crypto/sm2/SM2Base.java +++ b/src/main/java/minsecurity/crypto/sm2/SM2Base.java @@ -177,5 +177,43 @@ public class SM2Base { return SM2KeyPair.generateKeyPair(); } + /** + * SM2字节数组->16进制字节数组 辅助函数 + * @param bytes byte[] + * @return byte[] + * @throws + * @author zhengqi wu + * @date 2021/4/12 + **/ + public static byte[] byteArraytoHexByteArray(byte[] bytes){ + // 16进制表示法 + StringBuilder sb = new StringBuilder(); + for(int i=0;i < bytes.length;i++) { + sb.append(String.format("%02x", bytes[i])); + } + String hexStr = sb.toString(); + return hexStr.getBytes(); + } + /** + * 16进制字节数组->SM2字节数组 辅助函数 + * @param bytes byte[] + * @return byte[] + * @throws + * @author zhengqi wu + * @date 2021/4/12 + **/ + public static byte[] hexByteArrayToByteArray(byte[] bytes){ + String hex = new String(bytes); + if (hex.length() < 1) { + return null; + } else { + byte[] result = new byte[hex.length() / 2]; + int j = 0; + for(int i = 0; i < hex.length(); i+=2) { + result[j++] = (byte)Integer.parseInt(hex.substring(i,i+2), 16); + } + return result; + } + } } diff --git a/src/main/java/minsecurity/crypto/sm2/SM2PrivateKey.java b/src/main/java/minsecurity/crypto/sm2/SM2PrivateKey.java index 08bcecf..fd39cec 100644 --- a/src/main/java/minsecurity/crypto/sm2/SM2PrivateKey.java +++ b/src/main/java/minsecurity/crypto/sm2/SM2PrivateKey.java @@ -12,6 +12,7 @@ import org.bouncycastle.crypto.signers.SM2Signer; import java.math.BigInteger; import java.security.SecureRandom; +import java.util.Arrays; /* * @Author: hongyu guo @@ -54,7 +55,8 @@ public class SM2PrivateKey implements PrivateKeyInterface { @Override public byte[] getBytes() { - return privateKey.getD().toByteArray(); + byte[] bytes = privateKey.getD().toByteArray(); + return SM2Base.byteArraytoHexByteArray(bytes); } @Override @@ -71,11 +73,20 @@ public class SM2PrivateKey implements PrivateKeyInterface { * @params d {byte[]} * @return boolean */ + // TODO 实现不同 public boolean setBytes(byte[] d){ -// if (d.length != 64) -// return false; - String priStr = new String(d); - privateKey = new ECPrivateKeyParameters(new BigInteger(priStr, 16), SM2Base.DOMAIN_PARAMS); + if (d.length != 64 && d.length != 32 && d.length != 33) + return false; + switch (d.length){ + case 32: + case 33: + privateKey = new ECPrivateKeyParameters(new BigInteger(d), SM2Base.DOMAIN_PARAMS); + break; + case 64: + d = SM2Base.hexByteArrayToByteArray(d); + privateKey = new ECPrivateKeyParameters(new BigInteger(d), SM2Base.DOMAIN_PARAMS); + break; + } return true; } diff --git a/src/main/java/minsecurity/crypto/sm2/SM2PublicKey.java b/src/main/java/minsecurity/crypto/sm2/SM2PublicKey.java index be2e269..c2fe814 100644 --- a/src/main/java/minsecurity/crypto/sm2/SM2PublicKey.java +++ b/src/main/java/minsecurity/crypto/sm2/SM2PublicKey.java @@ -12,6 +12,7 @@ import org.bouncycastle.math.ec.ECCurve; import java.nio.ByteBuffer; import java.security.SecureRandom; +import java.util.Arrays; /* * @Author: hongyu guo @@ -47,15 +48,31 @@ public class SM2PublicKey implements PublicKeyInterface { @Override public byte[] getBytes() { - if(publicKey != null) - return publicKey.getQ().getEncoded(false); //不压缩 + if(publicKey != null){ + byte[] bytes = publicKey.getQ().getEncoded(false); //不压缩 + byte[] basic = SM2Base.byteArraytoHexByteArray(bytes); + return basic; + } return null; } @Override public boolean setBytes(byte[] bytes) { - if(bytes.length != 65) - return false; + switch (bytes.length){ + case 65: + createPub(bytes); + break; + case 130: + bytes = SM2Base.hexByteArrayToByteArray(bytes); // 16进制表示法转为十进制表示法 + createPub(bytes); + break; + default: + return false; + } + return true; + } + + private void createPub(byte[] bytes){ ByteBuffer encoded = ByteBuffer.wrap(bytes); byte[] x = new byte[32]; byte[] y = new byte[32]; @@ -63,7 +80,6 @@ public class SM2PublicKey implements PublicKeyInterface { encoded.get(x,0,32); encoded.get(y,0,32); publicKey = createPublicKey(x,y); - return true; } /** diff --git a/src/main/java/minsecurity/identity/Identity.java b/src/main/java/minsecurity/identity/Identity.java index 4bd3f05..a2061b7 100644 --- a/src/main/java/minsecurity/identity/Identity.java +++ b/src/main/java/minsecurity/identity/Identity.java @@ -140,7 +140,7 @@ public class Identity { } /** - * 使用identity的密钥对密文进行解密, 返回解密数据. + * 使用identity的私钥对密文进行解密, 返回解密数据. * identity中的私钥为空或密文有误时时将抛出异常 * @param cipher 密文 * @return byte[] @@ -155,7 +155,7 @@ public class Identity { return this.Prikey.decrypt(cipher); } /** - * 使用identity的密钥对密文进行加密, 返回加密数据. + * 使用identity的公钥对密文进行加密, 返回加密数据. * identity中的公钥为空或原文有误时时将抛出异常 * @param content 原文 * @return byte[] @@ -188,6 +188,7 @@ public class Identity { 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); @@ -227,13 +228,17 @@ public class Identity { return IdentityUtil.parseInnerToIdentity(innerIdentity); } // TODO: passwd ??? - public boolean lock(String passwd, int algo) throws IdentityException { + public boolean lock(String passwd, int algo) throws IdentityException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException, InvalidKeyException { switch (algo){ case Common.SM4ECB: - if (passwd.length() != 16){ + if (passwd.length() == 0){ throw new IdentityException("密码应为16位"); } - PrikeyRawByte = Prikey.getBytes(); + byte[] passHash = KeyUtils.get16bytePasswd(passwd.getBytes()); + byte[] by = Prikey.getBytes(); + // 加密后的私钥序列化数据 + byte[] encMsg = SM4.encrypt_ECB_Padding(passHash, Prikey.getBytes()); + PrikeyRawByte = encMsg; Prikey = null; return true; default: @@ -252,14 +257,10 @@ public class Identity { if(passwd == null || passwd.length() == 0) return false; - byte[] passHash = HashAlgo.sm3(passwd); - if (passHash.length == 32){ - for (int i = 0; i < 16; i++){ - passHash[i] += passHash[i+16]; - } - } - byte[] dec = SM4.encrypt_ECB_NoPadding(Arrays.copyOfRange(passHash, 0, 16), PrikeyRawByte); - PrivateKeyInterface privateKey = KeyUtils.unMarshalPrivateKey(Arrays.copyOfRange(dec, 0, 64), KeyParam.PublicKeyAlgorithm); + byte[] passHash = KeyUtils.get16bytePasswd(passwd.getBytes()); + // 解密后的私钥序列化数据 + byte[] dec = SM4.decrypt_ECB_Padding(passHash, PrikeyRawByte); + PrivateKeyInterface privateKey = KeyUtils.unMarshalPrivateKey(dec, KeyParam.PublicKeyAlgorithm); Prikey = privateKey; PrikeyRawByte = null; return true; diff --git a/src/main/java/minsecurity/identity/IdentityUtil.java b/src/main/java/minsecurity/identity/IdentityUtil.java index 4735725..73cdee6 100644 --- a/src/main/java/minsecurity/identity/IdentityUtil.java +++ b/src/main/java/minsecurity/identity/IdentityUtil.java @@ -50,7 +50,8 @@ public class IdentityUtil { innerIdentity.setPubkey(identity.getPubkey().getBytes()); innerIdentity.setPasswd(identity.getPasswd()); innerIdentity.setCert(CertUtils.toPem(identity.getCert(), identity.getPasswd().getBytes(), Common.SM4CBC)); - + // add + innerIdentity.setPrikeyRawByte(identity.getPrikeyRawByte()); return innerIdentity; } @@ -84,6 +85,7 @@ public class IdentityUtil { Certificate certificate = CertUtils.fromPem(innerIdentity.getCert(), innerIdentity.getPasswd().getBytes(), Common.SM4CBC); identity.setCert(certificate); + identity.setPrikeyRawByte(innerIdentity.getPrikeyRawByte()); return identity; } diff --git a/src/main/java/minsecurity/identity/InnerIdentity.java b/src/main/java/minsecurity/identity/InnerIdentity.java index a59dd38..b4afdff 100644 --- a/src/main/java/minsecurity/identity/InnerIdentity.java +++ b/src/main/java/minsecurity/identity/InnerIdentity.java @@ -1,5 +1,6 @@ package minsecurity.identity; +import com.fasterxml.jackson.annotation.JsonProperty; import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; /* @@ -10,20 +11,29 @@ import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 */ public class InnerIdentity { + @JsonProperty("Name") private String Name; + @JsonProperty("KeyParam") private KeyParam KeyParam; + @JsonProperty("Prikey") private byte[] Prikey; + @JsonProperty("Pubkey") private byte[] Pubkey; + @JsonProperty("Passwd") private String Passwd; + @JsonProperty("Cert") private String Cert; + @JsonProperty("PrikeyRawByte") + private byte[] PrikeyRawByte; - public InnerIdentity(String name, minsecurity.identity.KeyParam keyParam, byte[] prikey, byte[] pubkey, String passwd, String cert) { + public InnerIdentity(String name, minsecurity.identity.KeyParam keyParam, byte[] prikey, byte[] pubkey, String passwd, String cert, byte[] prikeyRawByte) { Name = name; KeyParam = keyParam; Prikey = prikey; Pubkey = pubkey; Passwd = passwd; Cert = cert; + PrikeyRawByte = prikeyRawByte; } public InnerIdentity() { @@ -87,8 +97,17 @@ public class InnerIdentity { ", Pubkey=" + (Pubkey == null ? "null" : ByteUtils.toHexString(Pubkey)) + ", Passwd='" + Passwd + '\'' + ", Cert='" + Cert + '\'' + + ", PrikeyRawByte='" + PrikeyRawByte + '\''+ '}'; } + + public byte[] getPrikeyRawByte() { + return PrikeyRawByte; + } + + public void setPrikeyRawByte(byte[] prikeyRawByte) { + PrikeyRawByte = prikeyRawByte; + } } diff --git a/src/main/java/minsecurity/identity/KeyParam.java b/src/main/java/minsecurity/identity/KeyParam.java index 7a3ef10..83a85e8 100644 --- a/src/main/java/minsecurity/identity/KeyParam.java +++ b/src/main/java/minsecurity/identity/KeyParam.java @@ -1,5 +1,7 @@ package minsecurity.identity; +import com.fasterxml.jackson.annotation.JsonProperty; + /* * @Author: hongyu guo * @Description: @@ -8,7 +10,9 @@ package minsecurity.identity; * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 */ public class KeyParam { + @JsonProperty("PublicKeyAlgorithm") public int PublicKeyAlgorithm; + @JsonProperty("SignatureAlgorithm") public int SignatureAlgorithm; public KeyParam(int publicKeyAlgorithm, int signatureAlgorithm) { diff --git a/src/main/java/minsecurity/identity/persist/IdentitySerializer.java b/src/main/java/minsecurity/identity/persist/IdentitySerializer.java index 1da24b9..d28f0e0 100644 --- a/src/main/java/minsecurity/identity/persist/IdentitySerializer.java +++ b/src/main/java/minsecurity/identity/persist/IdentitySerializer.java @@ -31,7 +31,7 @@ import java.security.NoSuchProviderException; * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 */ -// TODO: 加密版本的序列化 +// DONE: 加密版本的序列化可以不用实现 已经改用加密Sqlite public class IdentitySerializer implements Serializer { @Override diff --git a/src/test/java/minsecurity/crypto/TestSM2.java b/src/test/java/minsecurity/crypto/TestSM2.java index 274d45e..afe7f5b 100644 --- a/src/test/java/minsecurity/crypto/TestSM2.java +++ b/src/test/java/minsecurity/crypto/TestSM2.java @@ -47,8 +47,8 @@ public class TestSM2 { buffer.put(y); sm2PublicKey.setBytes(buffer.array()); - assertArrayEquals(d, sm2PrivateKey.getBytes()); - assertArrayEquals(buffer.array(), sm2PublicKey.getBytes()); + assertArrayEquals(d, SM2Base.hexByteArrayToByteArray(sm2PrivateKey.getBytes())); + assertArrayEquals(buffer.array(), SM2Base.hexByteArrayToByteArray(sm2PublicKey.getBytes())); String content = "hello world"; byte[] encBytes = sm2PublicKey.encrypt(content.getBytes()); diff --git a/src/test/java/minsecurity/identity/sqlite/db/DBTest.java b/src/test/java/minsecurity/identity/sqlite/db/DBTest.java index c71c389..5049aaa 100644 --- a/src/test/java/minsecurity/identity/sqlite/db/DBTest.java +++ b/src/test/java/minsecurity/identity/sqlite/db/DBTest.java @@ -30,42 +30,42 @@ class OperationThread extends Thread{ System.out.println(String.format("Operation %d starting", this.threadNo)); try{ // 测试PersistIdentity -// SM2KeyPair pair = SM2KeyPair.generateKeyPair(); -// Identity identity = new Identity(); -// identity.setName("wzq"+this.threadNo); -// KeyParam keyParam = new KeyParam(); -// keyParam.PublicKeyAlgorithm = 0; -// keyParam.SignatureAlgorithm = 0; -// identity.setKeyParam(keyParam); -// identity.setPrikey(pair.getSm2PrivateKey()); -// identity.setPubkey(pair.getSm2PublicKey()); -// identity.setPasswd("2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99"); -// identity.lock("0123456789abcdef", Common.SM4ECB); -// Certificate cert = new Certificate(); -// cert.setVersion(1); -// cert.setSerialNumber(1); -// cert.setPublicKey(pair.getSm2PublicKey()); -// cert.setSignatureAlgorithm(Common.SM3withSM2); // TODO 名字有误? SM2withSM3? -// cert.setPublicKeyAlgorithm(Common.SM2); -// cert.setIssueTo("root"); -// cert.setIssuer("root"); -// long timestamp = System.currentTimeMillis() / 1000; -// cert.setTimestamp(timestamp); // 10bit timestamp -// cert.setNotAfter(timestamp); // 10bit timestamp -// cert.setNotBefore(timestamp + 1000); // 10bit timestamp -// cert.setKeyUsage(Common.CertSign); -// cert.setCA(true); -// CertUtils.signCert(cert, pair.getSm2PrivateKey()); -// -// identity.setCert(cert); -// Db.persistIdentity(identity); + SM2KeyPair pair = SM2KeyPair.generateKeyPair(); + Identity identity = new Identity(); + identity.setName("wzq"+this.threadNo); + KeyParam keyParam = new KeyParam(); + keyParam.PublicKeyAlgorithm = 0; + keyParam.SignatureAlgorithm = 0; + identity.setKeyParam(keyParam); + identity.setPrikey(pair.getSm2PrivateKey()); + identity.setPubkey(pair.getSm2PublicKey()); + identity.setPasswd("2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99"); + identity.lock("0123456789abcdef", Common.SM4ECB); + Certificate cert = new Certificate(); + cert.setVersion(1); + cert.setSerialNumber(1); + cert.setPublicKey(pair.getSm2PublicKey()); + cert.setSignatureAlgorithm(Common.SM3withSM2); // TODO 名字有误? SM2withSM3? + cert.setPublicKeyAlgorithm(Common.SM2); + cert.setIssueTo("root"); + cert.setIssuer("root"); + long timestamp = System.currentTimeMillis() / 1000; + cert.setTimestamp(timestamp); // 10bit timestamp + cert.setNotAfter(timestamp); // 10bit timestamp + cert.setNotBefore(timestamp + 1000); // 10bit timestamp + cert.setKeyUsage(Common.CertSign); + cert.setCA(true); + CertUtils.signCert(cert, pair.getSm2PrivateKey()); -// Identity id = Db.getIdentityByNameFromStorage("wzq"+this.threadNo); -// -// System.out.println("插入身份:" + id.getName()); -// System.out.println(String.format("开始设置 wzq%d 为default 身份", this.threadNo)); -// -// Db.SetDefaultIdentityByNameInStorage("wzq"+this.threadNo); + identity.setCert(cert); + Db.persistIdentity(identity); + + Identity id = Db.getIdentityByNameFromStorage("wzq"+this.threadNo); + + System.out.println("插入身份:" + id.getName()); + System.out.println(String.format("开始设置 wzq%d 为default 身份", this.threadNo)); + + Db.SetDefaultIdentityByNameInStorage("wzq"+this.threadNo); Identity id2 = Db.getDefaultIdentityFromStorage(); System.out.println("当前default身份:" + id2.getName()); @@ -100,7 +100,8 @@ public class DBTest { System.out.println(identities.get(0).getPrikeyRawByte()); identities.get(0).unLock("0123456789abcdef", Common.SM4ECB); PrivateKeyInterface id = identities.get(0).getPrikey(); - System.out.println(identities.get(0).getPrikey().getBytes()); + byte[] bytes = id.getBytes(); + System.out.println(new String(id.getBytes())); }catch (Exception ex){ System.out.println(ex.getMessage()); }