From 431bd907759d09c5f7a198e50ff357c4ff673372 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Wed, 7 Aug 2024 11:30:19 +0800 Subject: [PATCH 01/20] sm2 jce develop --- .../java/org/gmssl/crypto/GmSSLProvider.java | 30 +++++++ src/main/java/org/gmssl/crypto/MainTest.java | 79 +++++++++++++++++ src/main/java/org/gmssl/crypto/SM2Cipher.java | 88 +++++++++++++++++++ src/main/java/org/gmssl/crypto/SM2Key.java | 31 +++++++ .../java/org/gmssl/crypto/SM2KeyFactory.java | 38 ++++++++ .../org/gmssl/crypto/SM2KeyPairGenerator.java | 39 ++++++++ .../java/org/gmssl/crypto/SM2PrivateKey.java | 55 ++++++++++++ .../java/org/gmssl/crypto/SM2PublicKey.java | 53 +++++++++++ .../java/org/gmssl/crypto/SM2Signature.java | 54 ++++++++++++ 9 files changed, 467 insertions(+) create mode 100644 src/main/java/org/gmssl/crypto/GmSSLProvider.java create mode 100644 src/main/java/org/gmssl/crypto/MainTest.java create mode 100644 src/main/java/org/gmssl/crypto/SM2Cipher.java create mode 100644 src/main/java/org/gmssl/crypto/SM2Key.java create mode 100644 src/main/java/org/gmssl/crypto/SM2KeyFactory.java create mode 100644 src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java create mode 100644 src/main/java/org/gmssl/crypto/SM2PrivateKey.java create mode 100644 src/main/java/org/gmssl/crypto/SM2PublicKey.java create mode 100644 src/main/java/org/gmssl/crypto/SM2Signature.java diff --git a/src/main/java/org/gmssl/crypto/GmSSLProvider.java b/src/main/java/org/gmssl/crypto/GmSSLProvider.java new file mode 100644 index 0000000..d250461 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/GmSSLProvider.java @@ -0,0 +1,30 @@ +package org.gmssl.crypto; + +import java.security.Provider; + +/** + * @author yongfeili + * @date 2024/8/2 + * @description + */ +public class GmSSLProvider extends Provider { + + protected GmSSLProvider() { + super("GmSSL", 1.0, "GmSSL Provider v1.0"); + + // 注册Cipher + put("Cipher.SM2", "org.gmssl.crypto.SM2Cipher"); + + // 注册KeyPairGenerator + put("KeyPairGenerator.SM2", "org.gmssl.crypto.SM2KeyPairGenerator"); + + // 注册KeyFactory + put("KeyFactory.SM2", "org.gmssl.crypto.SM2KeyFactory"); + + // 注册Signature + put("Signature.SM2", "org.gmssl.crypto.SM2Signature"); + + } + + +} diff --git a/src/main/java/org/gmssl/crypto/MainTest.java b/src/main/java/org/gmssl/crypto/MainTest.java new file mode 100644 index 0000000..8ebcc78 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/MainTest.java @@ -0,0 +1,79 @@ +package org.gmssl.crypto; + +import javax.crypto.Cipher; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; +import java.security.Signature; + +/** + * @author yongfeili + * @date 2024/8/2 + * @description + */ +public class MainTest { + + public static void main(String[] args) { + SM2Test(); + + + } + + public static void SM2Test() { + // 动态添加提供者 + Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); + + // 打印所有已注册的提供者 + for (java.security.Provider provider : Security.getProviders()) { + //System.out.println(provider.getName()); + } + + // 尝试获取Cipher实例 + try { + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM2", "GmSSL"); + keyPairGen.initialize(256); + KeyPair keyPair = keyPairGen.generateKeyPair(); + byte[] pub= keyPair.getPublic().getEncoded(); + System.out.println(byteToHex(pub)); + byte[] pri= keyPair.getPrivate().getEncoded(); + System.out.println(byteToHex(pri)); + + /*Cipher cipher = Cipher.getInstance("SM2", "GmSSLProvider"); + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); + + Signature signature = Signature.getInstance("SM2", "GmSSLProvider"); + signature.initSign(keyPair.getPrivate());*/ + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * convert byte array to hex string + * @param btArr + * @return String + */ + public static String byteToHex(byte[] btArr) { + BigInteger bigInteger = new BigInteger(1, btArr); + return bigInteger.toString(16); + } + + /** + * convert hex string to byte array + * @param hexString + * @return byte[] + */ + public static byte[] hexToByte(String hexString) { + byte[] byteArray = new BigInteger(hexString, 16) + .toByteArray(); + if (byteArray[0] == 0) { + byte[] output = new byte[byteArray.length - 1]; + System.arraycopy( + byteArray, 1, output, + 0, output.length); + return output; + } + return byteArray; + } +} diff --git a/src/main/java/org/gmssl/crypto/SM2Cipher.java b/src/main/java/org/gmssl/crypto/SM2Cipher.java new file mode 100644 index 0000000..ad6cb29 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/SM2Cipher.java @@ -0,0 +1,88 @@ +package org.gmssl.crypto; + +import javax.crypto.*; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/2 + * @description + */ +public class SM2Cipher extends CipherSpi { + + private Key key; + private int opmode; + + @Override + protected void engineSetMode(String s) throws NoSuchAlgorithmException { + // 实现加密模式设置,SM2不需要设置模式,可以留空 + } + + @Override + protected void engineSetPadding(String s) throws NoSuchPaddingException { + // 实现填充方式设置,SM2不需要填充,可以留空 + } + + @Override + protected int engineGetBlockSize() { + // SM2 是流加密,没有块大小 + return 0; + } + + @Override + protected int engineGetOutputSize(int i) { + // 根据输入长度计算输出长度 + // 这里只是示例,具体实现需要根据实际情况调整 + // 例如,假设增加一个固定长度的输出 + return i+32; + } + + @Override + protected byte[] engineGetIV() { + // SM2 不使用 IV,可以返回 null + return new byte[0]; + } + + @Override + protected AlgorithmParameters engineGetParameters() { + // SM2 不使用参数,可以返回 null + return null; + } + + @Override + protected void engineInit(int i, Key key, SecureRandom secureRandom) throws InvalidKeyException { + this.key = key; + this.opmode = i; + } + + @Override + protected void engineInit(int i, Key key, AlgorithmParameterSpec algorithmParameterSpec, SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException { + + } + + @Override + protected void engineInit(int i, Key key, AlgorithmParameters algorithmParameters, SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException { + + } + + @Override + protected byte[] engineUpdate(byte[] bytes, int i, int i1) { + return new byte[0]; + } + + @Override + protected int engineUpdate(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throws ShortBufferException { + return 0; + } + + @Override + protected byte[] engineDoFinal(byte[] bytes, int i, int i1) throws IllegalBlockSizeException, BadPaddingException { + return new byte[0]; + } + + @Override + protected int engineDoFinal(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + return 0; + } +} diff --git a/src/main/java/org/gmssl/crypto/SM2Key.java b/src/main/java/org/gmssl/crypto/SM2Key.java new file mode 100644 index 0000000..dfc123d --- /dev/null +++ b/src/main/java/org/gmssl/crypto/SM2Key.java @@ -0,0 +1,31 @@ +package org.gmssl.crypto; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import java.security.Key; + +/** + * @author yongfeili + * @date 2024/8/2 + * @description + */ +public abstract class SM2Key implements Key { + + protected long sm2_key = 0; + protected boolean has_private_key = false; + + public SM2Key() { + } + + public SM2Key(long sm2_key, boolean has_private_key) { + this.sm2_key = sm2_key; + this.has_private_key = has_private_key; + } + + @Override + public String getAlgorithm() { + return "SM2"; + } + +} diff --git a/src/main/java/org/gmssl/crypto/SM2KeyFactory.java b/src/main/java/org/gmssl/crypto/SM2KeyFactory.java new file mode 100644 index 0000000..11eb106 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/SM2KeyFactory.java @@ -0,0 +1,38 @@ +package org.gmssl.crypto; + +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +/** + * @author yongfeili + * @date 2024/8/2 + * @description + */ +public class SM2KeyFactory extends KeyFactorySpi { + + @Override + protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { + // 实现生成公钥 + + return null; + } + + @Override + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { + // 实现生成私钥 + return null; + } + + @Override + protected T engineGetKeySpec(Key key, Class keySpec) throws InvalidKeySpecException { + // 实现根据 Key 和 KeySpec 类型返回相应的 KeySpec + return null; + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + // 实现将 Key 转换为本地的 SM2Key + return null; + } +} diff --git a/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java b/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java new file mode 100644 index 0000000..bfb2af3 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java @@ -0,0 +1,39 @@ +package org.gmssl.crypto; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import java.security.*; + +/** + * @author yongfeili + * @date 2024/8/2 + * @description + */ +public class SM2KeyPairGenerator extends KeyPairGeneratorSpi { + + private long sm2_key = 0; + private boolean has_private_key = false; + + @Override + public void initialize(int keysize, SecureRandom random) { + generateKey(); + } + + @Override + public KeyPair generateKeyPair() { + PublicKey publicKey = new SM2PublicKey(sm2_key, has_private_key); + PrivateKey privateKey = new SM2PrivateKey(sm2_key, has_private_key); + return new KeyPair(publicKey, privateKey); + } + + private void generateKey() { + if (this.sm2_key != 0) { + GmSSLJNI.sm2_key_free(this.sm2_key); + } + if ((sm2_key = GmSSLJNI.sm2_key_generate()) == 0) { + throw new GmSSLException(""); + } + this.has_private_key = true; + } +} diff --git a/src/main/java/org/gmssl/crypto/SM2PrivateKey.java b/src/main/java/org/gmssl/crypto/SM2PrivateKey.java new file mode 100644 index 0000000..33a979b --- /dev/null +++ b/src/main/java/org/gmssl/crypto/SM2PrivateKey.java @@ -0,0 +1,55 @@ +package org.gmssl.crypto; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import java.security.PrivateKey; + +/** + * @author yongfeili + * @date 2024/8/7 + * @description + */ +public class SM2PrivateKey extends SM2Key implements PrivateKey{ + + public SM2PrivateKey() { + super(); + } + + public SM2PrivateKey(long sm2_key) { + super(sm2_key, true); + } + + public SM2PrivateKey(long sm2_key, boolean has_private_key) { + super(sm2_key,has_private_key); + } + + public String getAlgorithm() { + return "SM2"; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return exportPrivateKeyInfoDer(); + } + + private byte[] exportPrivateKeyInfoDer() { + if (this.sm2_key == 0) { + throw new GmSSLException(""); + } + if (this.has_private_key == false) { + throw new GmSSLException(""); + } + byte[] der; + if ((der = GmSSLJNI.sm2_private_key_info_to_der(this.sm2_key)) == null) { + throw new GmSSLException(""); + } + return der; + } + +} diff --git a/src/main/java/org/gmssl/crypto/SM2PublicKey.java b/src/main/java/org/gmssl/crypto/SM2PublicKey.java new file mode 100644 index 0000000..20581af --- /dev/null +++ b/src/main/java/org/gmssl/crypto/SM2PublicKey.java @@ -0,0 +1,53 @@ +package org.gmssl.crypto; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import java.security.PublicKey; + +/** + * @author yongfeili + * @date 2024/8/7 + * @description + */ +public class SM2PublicKey extends SM2Key implements PublicKey{ + + public SM2PublicKey() { + super(); + } + + public SM2PublicKey(long sm2_key) { + super(sm2_key, false); + } + + public SM2PublicKey(long sm2_key, boolean has_private_key) { + super(sm2_key,has_private_key); + } + + @Override + public String getAlgorithm() { + return "SM2"; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return exportPublicKeyInfoDer(); + } + + private byte[] exportPublicKeyInfoDer() { + if (this.sm2_key == 0) { + throw new GmSSLException(""); + } + byte[] der; + if ((der = GmSSLJNI.sm2_public_key_info_to_der(this.sm2_key)) == null) { + throw new GmSSLException(""); + } + return der; + } + +} diff --git a/src/main/java/org/gmssl/crypto/SM2Signature.java b/src/main/java/org/gmssl/crypto/SM2Signature.java new file mode 100644 index 0000000..c375d23 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/SM2Signature.java @@ -0,0 +1,54 @@ +package org.gmssl.crypto; + +import java.security.*; + +/** + * @author yongfeili + * @date 2024/8/2 + * @description + */ +public class SM2Signature extends SignatureSpi { + + @Override + protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { +// 实现初始化验证 + } + + @Override + protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + // 实现初始化签名 + } + + @Override + protected void engineUpdate(byte b) throws SignatureException { +// 实现更新方法 + } + + @Override + protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { +// 实现更新方法 + } + + @Override + protected byte[] engineSign() throws SignatureException { + // 实现签名生成 + return new byte[0]; + } + + @Override + protected boolean engineVerify(byte[] sigBytes) throws SignatureException { + // 实现签名验证 + return false; + } + + @Override + protected void engineSetParameter(String param, Object value) throws InvalidParameterException { +// 实现设置参数 + } + + @Override + protected Object engineGetParameter(String param) throws InvalidParameterException { + // 实现获取参数 + return null; + } +} From 9c0246845c71bc843a0503aff045ab7ab8c2a7fd Mon Sep 17 00:00:00 2001 From: liyongfei Date: Thu, 8 Aug 2024 17:47:46 +0800 Subject: [PATCH 02/20] sm2 jce develop --- .../java/org/gmssl/crypto/GmSSLProvider.java | 15 +-- src/main/java/org/gmssl/crypto/MainTest.java | 39 ++++-- src/main/java/org/gmssl/crypto/SM2Cipher.java | 115 +++++++++++++---- src/main/java/org/gmssl/crypto/SM2Key.java | 19 +++ .../java/org/gmssl/crypto/SM2Signature.java | 117 +++++++++++++++++- 5 files changed, 253 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/gmssl/crypto/GmSSLProvider.java b/src/main/java/org/gmssl/crypto/GmSSLProvider.java index d250461..980627e 100644 --- a/src/main/java/org/gmssl/crypto/GmSSLProvider.java +++ b/src/main/java/org/gmssl/crypto/GmSSLProvider.java @@ -1,5 +1,6 @@ package org.gmssl.crypto; +import java.security.PrivilegedAction; import java.security.Provider; /** @@ -9,21 +10,13 @@ */ public class GmSSLProvider extends Provider { - protected GmSSLProvider() { - super("GmSSL", 1.0, "GmSSL Provider v1.0"); + public GmSSLProvider() { + super("GmSSL", "3.1.1", "GmSSL Provider"); - // 注册Cipher put("Cipher.SM2", "org.gmssl.crypto.SM2Cipher"); - - // 注册KeyPairGenerator - put("KeyPairGenerator.SM2", "org.gmssl.crypto.SM2KeyPairGenerator"); - - // 注册KeyFactory put("KeyFactory.SM2", "org.gmssl.crypto.SM2KeyFactory"); - - // 注册Signature + put("KeyPairGenerator.SM2", "org.gmssl.crypto.SM2KeyPairGenerator"); put("Signature.SM2", "org.gmssl.crypto.SM2Signature"); - } diff --git a/src/main/java/org/gmssl/crypto/MainTest.java b/src/main/java/org/gmssl/crypto/MainTest.java index 8ebcc78..b939144 100644 --- a/src/main/java/org/gmssl/crypto/MainTest.java +++ b/src/main/java/org/gmssl/crypto/MainTest.java @@ -10,25 +10,21 @@ /** * @author yongfeili * @date 2024/8/2 - * @description + * @description you must need to use openjdk! + * https://jdk.java.net/archive/ + * https://stackoverflow.com/questions/1756801/how-to-sign-a-custom-jce-security-provider */ public class MainTest { public static void main(String[] args) { + // 动态添加提供者 + Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); SM2Test(); } public static void SM2Test() { - // 动态添加提供者 - Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); - - // 打印所有已注册的提供者 - for (java.security.Provider provider : Security.getProviders()) { - //System.out.println(provider.getName()); - } - // 尝试获取Cipher实例 try { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM2", "GmSSL"); @@ -39,11 +35,30 @@ public static void SM2Test() { byte[] pri= keyPair.getPrivate().getEncoded(); System.out.println(byteToHex(pri)); - /*Cipher cipher = Cipher.getInstance("SM2", "GmSSLProvider"); + Cipher cipher = Cipher.getInstance("SM2", "GmSSL"); + // 测试加密 cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); + byte[] plaintext = "Hello, GmSSL".getBytes(); + byte[] ciphertext = cipher.doFinal(plaintext); + System.out.println("Ciphertext: " + byteToHex(ciphertext)); + // 测试解密 + cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + byte[] decrypted = cipher.doFinal(ciphertext); + System.out.println("Decrypted: " + new String(decrypted)); + - Signature signature = Signature.getInstance("SM2", "GmSSLProvider"); - signature.initSign(keyPair.getPrivate());*/ + Signature signature = Signature.getInstance("SM2", "GmSSL"); + // 测试签名 + signature.initSign(keyPair.getPrivate()); + byte[] signatureText = "Hello, GmSSL".getBytes(); + signature.update(signatureText); + byte[] signatureByte = signature.sign(); + System.out.println("Signature:"+byteToHex(signatureByte)); + // 测试验签 + signature.initVerify(keyPair.getPublic()); + signature.update(signatureText); + boolean signatureResult = signature.verify(signatureByte); + System.out.println("SignatureResult:"+signatureResult); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/org/gmssl/crypto/SM2Cipher.java b/src/main/java/org/gmssl/crypto/SM2Cipher.java index ad6cb29..64d25ae 100644 --- a/src/main/java/org/gmssl/crypto/SM2Cipher.java +++ b/src/main/java/org/gmssl/crypto/SM2Cipher.java @@ -1,6 +1,10 @@ package org.gmssl.crypto; +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + import javax.crypto.*; +import java.nio.ByteBuffer; import java.security.*; import java.security.spec.AlgorithmParameterSpec; @@ -11,17 +15,25 @@ */ public class SM2Cipher extends CipherSpi { - private Key key; - private int opmode; + private int mode; + private SM2Key key; + private SecureRandom random; + private ByteBuffer buffer; @Override - protected void engineSetMode(String s) throws NoSuchAlgorithmException { - // 实现加密模式设置,SM2不需要设置模式,可以留空 + protected void engineSetMode(String mode) throws NoSuchAlgorithmException { + if (!mode.equalsIgnoreCase("ECB")) { + throw new NoSuchAlgorithmException("Unsupported mode: " + mode); + } + // SM2 只支持 ECB 模式 } @Override - protected void engineSetPadding(String s) throws NoSuchPaddingException { - // 实现填充方式设置,SM2不需要填充,可以留空 + protected void engineSetPadding(String padding) throws NoSuchPaddingException { + if (!padding.equalsIgnoreCase("NoPadding")) { + throw new NoSuchPaddingException("Unsupported padding: " + padding); + } + // SM2 不使用填充 } @Override @@ -31,58 +43,115 @@ protected int engineGetBlockSize() { } @Override - protected int engineGetOutputSize(int i) { + protected int engineGetOutputSize(int inputLen) { // 根据输入长度计算输出长度 // 这里只是示例,具体实现需要根据实际情况调整 // 例如,假设增加一个固定长度的输出 - return i+32; + return inputLen+32; } @Override protected byte[] engineGetIV() { - // SM2 不使用 IV,可以返回 null - return new byte[0]; + // // SM2 不使用 IV + return null; } @Override protected AlgorithmParameters engineGetParameters() { - // SM2 不使用参数,可以返回 null + // SM2 不使用参数 return null; } @Override - protected void engineInit(int i, Key key, SecureRandom secureRandom) throws InvalidKeyException { - this.key = key; - this.opmode = i; + protected void engineInit(int mode, Key key, SecureRandom secureRandom) throws InvalidKeyException { + if (!(key instanceof SM2Key)) { + throw new InvalidKeyException("Invalid key type"); + } + this.key = (SM2Key)key; + this.mode = mode; + this.random = (secureRandom != null) ? secureRandom : new SecureRandom(); + // 初始化缓冲区 + this.buffer = ByteBuffer.allocate(2048); } @Override - protected void engineInit(int i, Key key, AlgorithmParameterSpec algorithmParameterSpec, SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException { - + protected void engineInit(int mode, Key key, AlgorithmParameterSpec algorithmParameterSpec, SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException { + engineInit(mode, key, random); } @Override protected void engineInit(int i, Key key, AlgorithmParameters algorithmParameters, SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException { - + engineInit(mode, key, random); } @Override - protected byte[] engineUpdate(byte[] bytes, int i, int i1) { + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { + buffer.put(input, inputOffset, inputLen); + // 暂时不返回输出,等待 doFinal return new byte[0]; } @Override - protected int engineUpdate(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throws ShortBufferException { + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + buffer.put(input, inputOffset, inputLen); + // 暂时不返回输出,等待 doFinal return 0; } @Override - protected byte[] engineDoFinal(byte[] bytes, int i, int i1) throws IllegalBlockSizeException, BadPaddingException { - return new byte[0]; + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + buffer.put(input, inputOffset, inputLen); + byte[] data = new byte[buffer.position()]; + buffer.flip(); + buffer.get(data); + + if (mode == Cipher.ENCRYPT_MODE) { + return encrypt(data); + } else if (mode == Cipher.DECRYPT_MODE) { + return decrypt(data); + } else { + throw new GmSSLException("Cipher not initialized properly"); + } } @Override - protected int engineDoFinal(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - return 0; + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + byte[] result = engineDoFinal(input, inputOffset, inputLen); + System.arraycopy(result, 0, output, outputOffset, result.length); + return result.length; + } + + public byte[] encrypt(byte[] plaintext) { + if (this.key.sm2_key == 0) { + throw new GmSSLException(""); + } + if (plaintext == null + || plaintext.length > this.key.MAX_PLAINTEXT_SIZE) { + throw new GmSSLException(""); + } + + byte[] ciphertext; + if ((ciphertext = GmSSLJNI.sm2_encrypt(this.key.sm2_key, plaintext)) == null) { + throw new GmSSLException(""); + } + return ciphertext; + } + + public byte[] decrypt(byte[] ciphertext) { + if (this.key.sm2_key == 0) { + throw new GmSSLException(""); + } + if (this.key.has_private_key == false) { + throw new GmSSLException(""); + } + if (ciphertext == null) { + throw new GmSSLException(""); + } + + byte[] plaintext; + if ((plaintext = GmSSLJNI.sm2_decrypt(this.key.sm2_key, ciphertext)) == null) { + throw new GmSSLException(""); + } + return plaintext; } } diff --git a/src/main/java/org/gmssl/crypto/SM2Key.java b/src/main/java/org/gmssl/crypto/SM2Key.java index dfc123d..71bd3cd 100644 --- a/src/main/java/org/gmssl/crypto/SM2Key.java +++ b/src/main/java/org/gmssl/crypto/SM2Key.java @@ -12,6 +12,8 @@ */ public abstract class SM2Key implements Key { + public final static int MAX_PLAINTEXT_SIZE = GmSSLJNI.SM2_MAX_PLAINTEXT_SIZE; + protected long sm2_key = 0; protected boolean has_private_key = false; @@ -28,4 +30,21 @@ public String getAlgorithm() { return "SM2"; } + long getPrivateKey() { + if (this.sm2_key == 0) { + throw new GmSSLException(""); + } + if (this.has_private_key == false) { + throw new GmSSLException(""); + } + return this.sm2_key; + } + + long getPublicKey() { + if (this.sm2_key == 0) { + throw new GmSSLException(""); + } + return this.sm2_key; + } + } diff --git a/src/main/java/org/gmssl/crypto/SM2Signature.java b/src/main/java/org/gmssl/crypto/SM2Signature.java index c375d23..b3139ef 100644 --- a/src/main/java/org/gmssl/crypto/SM2Signature.java +++ b/src/main/java/org/gmssl/crypto/SM2Signature.java @@ -1,6 +1,10 @@ package org.gmssl.crypto; +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + import java.security.*; +import java.util.Arrays; /** * @author yongfeili @@ -9,41 +13,66 @@ */ public class SM2Signature extends SignatureSpi { + public final static String DEFAULT_ID = GmSSLJNI.SM2_DEFAULT_ID; + + private long sm2_sign_ctx = 0; + private boolean inited = false; + + private boolean do_sign = true; + + public SM2Signature() { + super(); + init(); + } + @Override protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { -// 实现初始化验证 + // 实现初始化验证 + if (!(publicKey instanceof SM2PublicKey)) { + throw new GmSSLException("Invalid publicKey type"); + } + initVerify((SM2PublicKey) publicKey,DEFAULT_ID); } @Override protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { // 实现初始化签名 + if (!(privateKey instanceof SM2PrivateKey)) { + throw new GmSSLException("Invalid privateKey type"); + } + initSign((SM2PrivateKey) privateKey,DEFAULT_ID); } @Override protected void engineUpdate(byte b) throws SignatureException { -// 实现更新方法 + // 实现更新方法 + byte[] data= new byte[]{b}; + update(data, 0, data.length); } @Override protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { -// 实现更新方法 + // 实现更新方法 + update(b, off, len); } @Override protected byte[] engineSign() throws SignatureException { // 实现签名生成 - return new byte[0]; + byte[] data = sign(); + return data; } @Override protected boolean engineVerify(byte[] sigBytes) throws SignatureException { // 实现签名验证 - return false; + boolean verifyResult= verify(sigBytes); + return verifyResult; } @Override protected void engineSetParameter(String param, Object value) throws InvalidParameterException { -// 实现设置参数 + // 实现设置参数 } @Override @@ -51,4 +80,80 @@ protected Object engineGetParameter(String param) throws InvalidParameterExcepti // 实现获取参数 return null; } + + private void init(){ + if ((this.sm2_sign_ctx = GmSSLJNI.sm2_sign_ctx_new()) == 0) { + throw new GmSSLException(""); + } + this.inited = true; + } + + private void initSign(SM2PrivateKey privateKey,String id){ + if (GmSSLJNI.sm2_sign_init(this.sm2_sign_ctx, privateKey.getPrivateKey(), id) != 1) { + throw new GmSSLException(""); + } + this.do_sign = true; + } + + private void initVerify(SM2PublicKey publicKey,String id){ + if (GmSSLJNI.sm2_verify_init(sm2_sign_ctx, publicKey.getPublicKey(), id) != 1) { + throw new GmSSLException(""); + } + this.do_sign = false; + } + + private void update(byte[] data, int offset, int len) { + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (data == null + || offset < 0 + || len < 0 + || offset + len <= 0 + || data.length < offset + len) { + throw new GmSSLException(""); + } + + if (this.do_sign == true) { + if (GmSSLJNI.sm2_sign_update(this.sm2_sign_ctx, data, offset, len) != 1) { + throw new GmSSLException(""); + } + } else { + if (GmSSLJNI.sm2_verify_update(this.sm2_sign_ctx, data, offset, len) != 1) { + throw new GmSSLException(""); + } + } + } + + private byte[] sign() { + if (this.inited == false) { + throw new GmSSLException(""); + } + if (this.do_sign == false) { + throw new GmSSLException(""); + } + + byte[] sig; + if ((sig = GmSSLJNI.sm2_sign_finish(this.sm2_sign_ctx)) == null) { + throw new GmSSLException(""); + } + return sig; + } + + private boolean verify(byte[] signature) { + if (this.sm2_sign_ctx == 0) { + throw new GmSSLException(""); + } + if (this.do_sign == true) { + throw new GmSSLException(""); + } + + int ret; + if ((ret = GmSSLJNI.sm2_verify_finish(sm2_sign_ctx, signature)) != 1) { + return false; + } + return true; + } + } From dee3a55dbac166a23611e13456bd0f01003ae4fd Mon Sep 17 00:00:00 2001 From: liyongfei Date: Fri, 9 Aug 2024 17:48:34 +0800 Subject: [PATCH 03/20] sm2 jce develop --- .../java/org/gmssl/crypto/GmSSLProvider.java | 1 - src/main/java/org/gmssl/crypto/MainTest.java | 20 ++++++++- .../org/gmssl/crypto/SM2KeyPairGenerator.java | 2 + .../java/org/gmssl/crypto/SM2PrivateKey.java | 43 ++++++++++++++++++- .../java/org/gmssl/crypto/SM2PublicKey.java | 40 ++++++++++++++++- 5 files changed, 100 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/gmssl/crypto/GmSSLProvider.java b/src/main/java/org/gmssl/crypto/GmSSLProvider.java index 980627e..948cd7b 100644 --- a/src/main/java/org/gmssl/crypto/GmSSLProvider.java +++ b/src/main/java/org/gmssl/crypto/GmSSLProvider.java @@ -1,6 +1,5 @@ package org.gmssl.crypto; -import java.security.PrivilegedAction; import java.security.Provider; /** diff --git a/src/main/java/org/gmssl/crypto/MainTest.java b/src/main/java/org/gmssl/crypto/MainTest.java index b939144..bef4c11 100644 --- a/src/main/java/org/gmssl/crypto/MainTest.java +++ b/src/main/java/org/gmssl/crypto/MainTest.java @@ -1,6 +1,7 @@ package org.gmssl.crypto; import javax.crypto.Cipher; +import javax.crypto.spec.PBEParameterSpec; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -46,7 +47,7 @@ public static void SM2Test() { byte[] decrypted = cipher.doFinal(ciphertext); System.out.println("Decrypted: " + new String(decrypted)); - + // 测试签名验签 Signature signature = Signature.getInstance("SM2", "GmSSL"); // 测试签名 signature.initSign(keyPair.getPrivate()); @@ -59,6 +60,23 @@ public static void SM2Test() { signature.update(signatureText); boolean signatureResult = signature.verify(signatureByte); System.out.println("SignatureResult:"+signatureResult); + + //测试导入私钥公钥签名验签 + Signature signatureImport = Signature.getInstance("SM2", "GmSSL"); + // 测试导入私钥 + String privateKeyInfoHex="308193020100301306072a8648ce3d020106082a811ccf5501822d0479307702010104207fef3e258348873c47117c15093266e9dad99e131f1778e53d362b2b70649f85a00a06082a811ccf5501822da14403420004f94c0abb6cd00c6f0918cb9c54162213501d5cc278f5d3fcf63886f4e1dc6322b1b110e33a25216f258c4cce5fd52ab320d3b086ee5390f7387218c92578c3ab"; + byte[] privateKeyInfo = hexToByte(privateKeyInfoHex); + signatureImport.initSign(new SM2PrivateKey(privateKeyInfo)); + signatureImport.update(signatureText); + byte[] signatureByteImport = signatureImport.sign(); + System.out.println("Signature:"+byteToHex(signatureByteImport)); + // 测试导入公钥 + String publicKeyInfoHex = "3059301306072a8648ce3d020106082a811ccf5501822d03420004f94c0abb6cd00c6f0918cb9c54162213501d5cc278f5d3fcf63886f4e1dc6322b1b110e33a25216f258c4cce5fd52ab320d3b086ee5390f7387218c92578c3ab"; + byte[] publicKeyInfo = hexToByte(publicKeyInfoHex); + signatureImport.initVerify(new SM2PublicKey(publicKeyInfo)); + signatureImport.update(signatureText); + boolean signatureResultImport = signatureImport.verify(signatureByteImport); + System.out.println("SignatureResult:"+signatureResultImport); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java b/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java index bfb2af3..4ed7625 100644 --- a/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java +++ b/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java @@ -4,6 +4,7 @@ import org.gmssl.GmSSLJNI; import java.security.*; +import java.security.spec.AlgorithmParameterSpec; /** * @author yongfeili @@ -36,4 +37,5 @@ private void generateKey() { } this.has_private_key = true; } + } diff --git a/src/main/java/org/gmssl/crypto/SM2PrivateKey.java b/src/main/java/org/gmssl/crypto/SM2PrivateKey.java index 33a979b..186eb03 100644 --- a/src/main/java/org/gmssl/crypto/SM2PrivateKey.java +++ b/src/main/java/org/gmssl/crypto/SM2PrivateKey.java @@ -16,8 +16,12 @@ public SM2PrivateKey() { super(); } - public SM2PrivateKey(long sm2_key) { - super(sm2_key, true); + public SM2PrivateKey(byte[] der) { + importPrivateKeyInfoDer(der); + } + + public SM2PrivateKey(String password, String file) { + importEncryptedPrivateKeyInfoPem(password, file); } public SM2PrivateKey(long sm2_key, boolean has_private_key) { @@ -38,6 +42,19 @@ public byte[] getEncoded() { return exportPrivateKeyInfoDer(); } + private void importPrivateKeyInfoDer(byte[] der) { + if (der == null) { + throw new GmSSLException(""); + } + if (this.sm2_key != 0) { + GmSSLJNI.sm2_key_free(this.sm2_key); + } + if ((this.sm2_key = GmSSLJNI.sm2_private_key_info_from_der(der)) == 0) { + throw new GmSSLException(""); + } + this.has_private_key = true; + } + private byte[] exportPrivateKeyInfoDer() { if (this.sm2_key == 0) { throw new GmSSLException(""); @@ -52,4 +69,26 @@ private byte[] exportPrivateKeyInfoDer() { return der; } + private void importEncryptedPrivateKeyInfoPem(String pass, String file) { + if (this.sm2_key != 0) { + GmSSLJNI.sm2_key_free(this.sm2_key); + } + if ((sm2_key = GmSSLJNI.sm2_private_key_info_decrypt_from_pem(pass, file)) == 0) { + throw new GmSSLException(""); + } + this.has_private_key = true; + } + + public void exportEncryptedPrivateKeyInfoPem(String pass, String file) { + if (this.sm2_key == 0) { + throw new GmSSLException(""); + } + if (this.has_private_key == false) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm2_private_key_info_encrypt_to_pem(this.sm2_key, pass, file) != 1) { + throw new GmSSLException(""); + } + } + } diff --git a/src/main/java/org/gmssl/crypto/SM2PublicKey.java b/src/main/java/org/gmssl/crypto/SM2PublicKey.java index 20581af..4937009 100644 --- a/src/main/java/org/gmssl/crypto/SM2PublicKey.java +++ b/src/main/java/org/gmssl/crypto/SM2PublicKey.java @@ -16,8 +16,12 @@ public SM2PublicKey() { super(); } - public SM2PublicKey(long sm2_key) { - super(sm2_key, false); + public SM2PublicKey(byte[] der) { + importPublicKeyInfoDer(der); + } + + public SM2PublicKey(String file) { + importPublicKeyInfoPem(file); } public SM2PublicKey(long sm2_key, boolean has_private_key) { @@ -39,6 +43,19 @@ public byte[] getEncoded() { return exportPublicKeyInfoDer(); } + private void importPublicKeyInfoDer(byte[] der) { + if (der == null) { + throw new GmSSLException(""); + } + if (this.sm2_key != 0) { + GmSSLJNI.sm2_key_free(this.sm2_key); + } + if ((this.sm2_key = GmSSLJNI.sm2_public_key_info_from_der(der)) == 0) { + throw new GmSSLException(""); + } + this.has_private_key = false; + } + private byte[] exportPublicKeyInfoDer() { if (this.sm2_key == 0) { throw new GmSSLException(""); @@ -50,4 +67,23 @@ private byte[] exportPublicKeyInfoDer() { return der; } + private void importPublicKeyInfoPem(String file) { + if (this.sm2_key != 0) { + GmSSLJNI.sm2_key_free(this.sm2_key); + } + if ((this.sm2_key = GmSSLJNI.sm2_public_key_info_from_pem(file)) == 0) { + throw new GmSSLException(""); + } + this.has_private_key = false; + } + + public void exportPublicKeyInfoPem(String file) { + if (this.sm2_key == 0) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm2_public_key_info_to_pem(this.sm2_key, file) != 1) { + throw new GmSSLException(""); + } + } + } From 43496765c70c5c70291f20872c4181300497921b Mon Sep 17 00:00:00 2001 From: liyongfei Date: Mon, 12 Aug 2024 09:49:32 +0800 Subject: [PATCH 04/20] sm2 jce develop --- .gitignore | 10 ++++++---- src/main/java/org/gmssl/crypto/SM2Key.java | 10 ++++++---- .../java/org/gmssl/crypto/SM2KeyPairGenerator.java | 2 -- src/main/java/org/gmssl/crypto/SM2PrivateKey.java | 10 +++++----- src/main/java/org/gmssl/crypto/SM2PublicKey.java | 10 +++++----- .../MainTest.java => test/java/org/gmssl/JceTest.java} | 8 +++++--- 6 files changed, 27 insertions(+), 23 deletions(-) rename src/{main/java/org/gmssl/crypto/MainTest.java => test/java/org/gmssl/JceTest.java} (97%) diff --git a/.gitignore b/.gitignore index 19f99f1..0187e2f 100644 --- a/.gitignore +++ b/.gitignore @@ -90,7 +90,9 @@ lint/tmp/ -/.idea/compiler.xml -/.idea/encodings.xml -/.idea/jarRepositories.xml -/.idea/misc.xml +/.idea/ +/target/ +/sm9enc.mpk +/sm9EncryptData.txt +/sm9sign.mpk +/sm9SignData.txt diff --git a/src/main/java/org/gmssl/crypto/SM2Key.java b/src/main/java/org/gmssl/crypto/SM2Key.java index 71bd3cd..c4728bb 100644 --- a/src/main/java/org/gmssl/crypto/SM2Key.java +++ b/src/main/java/org/gmssl/crypto/SM2Key.java @@ -14,13 +14,15 @@ public abstract class SM2Key implements Key { public final static int MAX_PLAINTEXT_SIZE = GmSSLJNI.SM2_MAX_PLAINTEXT_SIZE; - protected long sm2_key = 0; - protected boolean has_private_key = false; + protected long sm2_key; + protected boolean has_private_key; - public SM2Key() { + protected SM2Key() { + this.sm2_key = 0; + this.has_private_key = false; } - public SM2Key(long sm2_key, boolean has_private_key) { + protected SM2Key(long sm2_key, boolean has_private_key) { this.sm2_key = sm2_key; this.has_private_key = has_private_key; } diff --git a/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java b/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java index 4ed7625..c415f55 100644 --- a/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java +++ b/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java @@ -4,8 +4,6 @@ import org.gmssl.GmSSLJNI; import java.security.*; -import java.security.spec.AlgorithmParameterSpec; - /** * @author yongfeili * @date 2024/8/2 diff --git a/src/main/java/org/gmssl/crypto/SM2PrivateKey.java b/src/main/java/org/gmssl/crypto/SM2PrivateKey.java index 186eb03..6970a79 100644 --- a/src/main/java/org/gmssl/crypto/SM2PrivateKey.java +++ b/src/main/java/org/gmssl/crypto/SM2PrivateKey.java @@ -12,7 +12,7 @@ */ public class SM2PrivateKey extends SM2Key implements PrivateKey{ - public SM2PrivateKey() { + protected SM2PrivateKey() { super(); } @@ -24,7 +24,7 @@ public SM2PrivateKey(String password, String file) { importEncryptedPrivateKeyInfoPem(password, file); } - public SM2PrivateKey(long sm2_key, boolean has_private_key) { + protected SM2PrivateKey(long sm2_key, boolean has_private_key) { super(sm2_key,has_private_key); } @@ -42,7 +42,7 @@ public byte[] getEncoded() { return exportPrivateKeyInfoDer(); } - private void importPrivateKeyInfoDer(byte[] der) { + public void importPrivateKeyInfoDer(byte[] der) { if (der == null) { throw new GmSSLException(""); } @@ -55,7 +55,7 @@ private void importPrivateKeyInfoDer(byte[] der) { this.has_private_key = true; } - private byte[] exportPrivateKeyInfoDer() { + public byte[] exportPrivateKeyInfoDer() { if (this.sm2_key == 0) { throw new GmSSLException(""); } @@ -69,7 +69,7 @@ private byte[] exportPrivateKeyInfoDer() { return der; } - private void importEncryptedPrivateKeyInfoPem(String pass, String file) { + public void importEncryptedPrivateKeyInfoPem(String pass, String file) { if (this.sm2_key != 0) { GmSSLJNI.sm2_key_free(this.sm2_key); } diff --git a/src/main/java/org/gmssl/crypto/SM2PublicKey.java b/src/main/java/org/gmssl/crypto/SM2PublicKey.java index 4937009..5e992f4 100644 --- a/src/main/java/org/gmssl/crypto/SM2PublicKey.java +++ b/src/main/java/org/gmssl/crypto/SM2PublicKey.java @@ -12,7 +12,7 @@ */ public class SM2PublicKey extends SM2Key implements PublicKey{ - public SM2PublicKey() { + protected SM2PublicKey() { super(); } @@ -24,7 +24,7 @@ public SM2PublicKey(String file) { importPublicKeyInfoPem(file); } - public SM2PublicKey(long sm2_key, boolean has_private_key) { + protected SM2PublicKey(long sm2_key, boolean has_private_key) { super(sm2_key,has_private_key); } @@ -43,7 +43,7 @@ public byte[] getEncoded() { return exportPublicKeyInfoDer(); } - private void importPublicKeyInfoDer(byte[] der) { + public void importPublicKeyInfoDer(byte[] der) { if (der == null) { throw new GmSSLException(""); } @@ -56,7 +56,7 @@ private void importPublicKeyInfoDer(byte[] der) { this.has_private_key = false; } - private byte[] exportPublicKeyInfoDer() { + public byte[] exportPublicKeyInfoDer() { if (this.sm2_key == 0) { throw new GmSSLException(""); } @@ -67,7 +67,7 @@ private byte[] exportPublicKeyInfoDer() { return der; } - private void importPublicKeyInfoPem(String file) { + public void importPublicKeyInfoPem(String file) { if (this.sm2_key != 0) { GmSSLJNI.sm2_key_free(this.sm2_key); } diff --git a/src/main/java/org/gmssl/crypto/MainTest.java b/src/test/java/org/gmssl/JceTest.java similarity index 97% rename from src/main/java/org/gmssl/crypto/MainTest.java rename to src/test/java/org/gmssl/JceTest.java index bef4c11..6b5a840 100644 --- a/src/main/java/org/gmssl/crypto/MainTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -1,4 +1,7 @@ -package org.gmssl.crypto; +package org.gmssl; + +import org.gmssl.crypto.SM2PrivateKey; +import org.gmssl.crypto.SM2PublicKey; import javax.crypto.Cipher; import javax.crypto.spec.PBEParameterSpec; @@ -15,14 +18,13 @@ * https://jdk.java.net/archive/ * https://stackoverflow.com/questions/1756801/how-to-sign-a-custom-jce-security-provider */ -public class MainTest { +public class JceTest { public static void main(String[] args) { // 动态添加提供者 Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); SM2Test(); - } public static void SM2Test() { From 98d7ae6fe4e500d19c79b6830c88992d2933aa41 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Mon, 12 Aug 2024 10:09:32 +0800 Subject: [PATCH 05/20] sm2 jce develop --- src/main/java/org/gmssl/crypto/SM2PublicKey.java | 12 ++++++++++++ src/test/java/org/gmssl/JceTest.java | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/org/gmssl/crypto/SM2PublicKey.java b/src/main/java/org/gmssl/crypto/SM2PublicKey.java index 5e992f4..174c6f0 100644 --- a/src/main/java/org/gmssl/crypto/SM2PublicKey.java +++ b/src/main/java/org/gmssl/crypto/SM2PublicKey.java @@ -2,6 +2,7 @@ import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; +import org.gmssl.Sm3; import java.security.PublicKey; @@ -86,4 +87,15 @@ public void exportPublicKeyInfoPem(String file) { } } + public byte[] computeZ(String id) { + if (this.sm2_key == 0) { + throw new GmSSLException(""); + } + byte[] z = new byte[Sm3.DIGEST_SIZE]; + if (GmSSLJNI.sm2_compute_z(this.sm2_key, id, z) != 1) { + throw new GmSSLException(""); + } + return z; + } + } diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index 6b5a840..844133b 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -38,6 +38,11 @@ public static void SM2Test() { byte[] pri= keyPair.getPrivate().getEncoded(); System.out.println(byteToHex(pri)); + //测试“Z值”哈希值 + SM2PublicKey sm2PublicKey = new SM2PublicKey(pub); + byte[] zHash = sm2PublicKey.computeZ("Hello, GmSSL"); + System.out.println("zHash:"+byteToHex(zHash)); + Cipher cipher = Cipher.getInstance("SM2", "GmSSL"); // 测试加密 cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); From e03a279aec340874a555791f3cf5e974f285e413 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Mon, 12 Aug 2024 19:33:40 +0800 Subject: [PATCH 06/20] sm4 jce develop --- src/main/java/org/gmssl/Sm4.java | 1 - .../java/org/gmssl/crypto/GmSSLProvider.java | 14 +- src/main/java/org/gmssl/crypto/Mode.java | 27 +++ src/main/java/org/gmssl/crypto/Padding.java | 13 ++ src/main/java/org/gmssl/crypto/Random.java | 54 ++++++ .../crypto/{ => asymmetric}/SM2Cipher.java | 4 +- .../gmssl/crypto/{ => asymmetric}/SM2Key.java | 2 +- .../{ => asymmetric}/SM2KeyFactory.java | 2 +- .../{ => asymmetric}/SM2KeyPairGenerator.java | 2 +- .../{ => asymmetric}/SM2PrivateKey.java | 2 +- .../crypto/{ => asymmetric}/SM2PublicKey.java | 2 +- .../crypto/{ => asymmetric}/SM2Signature.java | 3 +- .../org/gmssl/crypto/digest/SM3Digest.java | 83 ++++++++++ .../java/org/gmssl/crypto/digest/SM3Hmac.java | 125 ++++++++++++++ .../org/gmssl/crypto/digest/SM3Pbkdf2.java | 76 +++++++++ .../org/gmssl/crypto/symmetric/SM4Cbc.java | 43 +++++ .../org/gmssl/crypto/symmetric/SM4Cipher.java | 155 ++++++++++++++++++ src/test/java/org/gmssl/JceTest.java | 71 +++++++- 18 files changed, 656 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/gmssl/crypto/Mode.java create mode 100644 src/main/java/org/gmssl/crypto/Padding.java create mode 100644 src/main/java/org/gmssl/crypto/Random.java rename src/main/java/org/gmssl/crypto/{ => asymmetric}/SM2Cipher.java (98%) rename src/main/java/org/gmssl/crypto/{ => asymmetric}/SM2Key.java (96%) rename src/main/java/org/gmssl/crypto/{ => asymmetric}/SM2KeyFactory.java (96%) rename src/main/java/org/gmssl/crypto/{ => asymmetric}/SM2KeyPairGenerator.java (96%) rename src/main/java/org/gmssl/crypto/{ => asymmetric}/SM2PrivateKey.java (98%) rename src/main/java/org/gmssl/crypto/{ => asymmetric}/SM2PublicKey.java (98%) rename src/main/java/org/gmssl/crypto/{ => asymmetric}/SM2Signature.java (98%) create mode 100644 src/main/java/org/gmssl/crypto/digest/SM3Digest.java create mode 100644 src/main/java/org/gmssl/crypto/digest/SM3Hmac.java create mode 100644 src/main/java/org/gmssl/crypto/digest/SM3Pbkdf2.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4Cbc.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java diff --git a/src/main/java/org/gmssl/Sm4.java b/src/main/java/org/gmssl/Sm4.java index d1b593c..bf9de4f 100644 --- a/src/main/java/org/gmssl/Sm4.java +++ b/src/main/java/org/gmssl/Sm4.java @@ -41,7 +41,6 @@ public Sm4(byte[] key, boolean do_encrypt) { } public void encrypt(byte[] in, int in_offset, byte[] out, int out_offset) { - if (in == null || in_offset < 0 || in_offset + this.BLOCK_SIZE <= 0 diff --git a/src/main/java/org/gmssl/crypto/GmSSLProvider.java b/src/main/java/org/gmssl/crypto/GmSSLProvider.java index 948cd7b..54e8ac9 100644 --- a/src/main/java/org/gmssl/crypto/GmSSLProvider.java +++ b/src/main/java/org/gmssl/crypto/GmSSLProvider.java @@ -12,10 +12,16 @@ public class GmSSLProvider extends Provider { public GmSSLProvider() { super("GmSSL", "3.1.1", "GmSSL Provider"); - put("Cipher.SM2", "org.gmssl.crypto.SM2Cipher"); - put("KeyFactory.SM2", "org.gmssl.crypto.SM2KeyFactory"); - put("KeyPairGenerator.SM2", "org.gmssl.crypto.SM2KeyPairGenerator"); - put("Signature.SM2", "org.gmssl.crypto.SM2Signature"); + put("SecureRandom.Random", "org.gmssl.crypto.Random"); + put("Cipher.SM2", "org.gmssl.crypto.asymmetric.SM2Cipher"); + put("KeyPairGenerator.SM2", "org.gmssl.crypto.asymmetric.SM2KeyPairGenerator"); + put("Signature.SM2", "org.gmssl.crypto.asymmetric.SM2Signature"); + //put("KeyFactory.SM2", "org.gmssl.crypto.asymmetric.SM2KeyFactory"); + put("MessageDigest.SM3", "org.gmssl.crypto.digest.SM3Digest"); + put("Mac.SM3Hmac", "org.gmssl.crypto.digest.SM3Hmac"); + put("SecretKeyFactory.SM3Pbkdf2", "org.gmssl.crypto.digest.SM3Pbkdf2"); + put("Cipher.SM4", "org.gmssl.crypto.symmetric.SM4Cipher"); + put("Cipher.SM4Cbc", "org.gmssl.crypto.symmetric.SM4Cbc"); } diff --git a/src/main/java/org/gmssl/crypto/Mode.java b/src/main/java/org/gmssl/crypto/Mode.java new file mode 100644 index 0000000..c3391b0 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/Mode.java @@ -0,0 +1,27 @@ +package org.gmssl.crypto; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public enum Mode { + NONE, + /** + * Cipher Block Chaining + */ + CBC, + /** + * Grinding Cycle Monitor + */ + GCM, + /** + * + */ + CTR, + /** + * + */ + ECB; + +} diff --git a/src/main/java/org/gmssl/crypto/Padding.java b/src/main/java/org/gmssl/crypto/Padding.java new file mode 100644 index 0000000..9e9378e --- /dev/null +++ b/src/main/java/org/gmssl/crypto/Padding.java @@ -0,0 +1,13 @@ +package org.gmssl.crypto; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public enum Padding { + + NoPadding, + ZeroPadding, + PKCS5Padding; +} diff --git a/src/main/java/org/gmssl/crypto/Random.java b/src/main/java/org/gmssl/crypto/Random.java new file mode 100644 index 0000000..e8b0478 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/Random.java @@ -0,0 +1,54 @@ +package org.gmssl.crypto; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import java.security.SecureRandomSpi; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public class Random extends SecureRandomSpi { + + public Random() { + super(); + } + + @Override + protected void engineSetSeed(byte[] seed) { + + } + + @Override + protected void engineNextBytes(byte[] bytes) { + randBytes(bytes,0, bytes.length); + } + + @Override + protected byte[] engineGenerateSeed(int numBytes) { + return randBytes(numBytes); + } + + public byte[] randBytes(int len) { + byte[] out = new byte[len]; + if (GmSSLJNI.rand_bytes(out, 0, len) != 1) { + throw new GmSSLException(""); + } + return out; + } + + public void randBytes(byte[] out, int offset, int len) { + if (out == null + || offset < 0 + || len < 0 + || offset + len <= 0 + || out.length < offset + len) { + throw new GmSSLException(""); + } + if (GmSSLJNI.rand_bytes(out, offset, len) != 1) { + throw new GmSSLException(""); + } + } +} diff --git a/src/main/java/org/gmssl/crypto/SM2Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java similarity index 98% rename from src/main/java/org/gmssl/crypto/SM2Cipher.java rename to src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java index 64d25ae..680487d 100644 --- a/src/main/java/org/gmssl/crypto/SM2Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java @@ -1,4 +1,4 @@ -package org.gmssl.crypto; +package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; @@ -88,7 +88,7 @@ protected void engineInit(int i, Key key, AlgorithmParameters algorithmParameter protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { buffer.put(input, inputOffset, inputLen); // 暂时不返回输出,等待 doFinal - return new byte[0]; + return buffer.array(); } @Override diff --git a/src/main/java/org/gmssl/crypto/SM2Key.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Key.java similarity index 96% rename from src/main/java/org/gmssl/crypto/SM2Key.java rename to src/main/java/org/gmssl/crypto/asymmetric/SM2Key.java index c4728bb..dd16294 100644 --- a/src/main/java/org/gmssl/crypto/SM2Key.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Key.java @@ -1,4 +1,4 @@ -package org.gmssl.crypto; +package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; diff --git a/src/main/java/org/gmssl/crypto/SM2KeyFactory.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyFactory.java similarity index 96% rename from src/main/java/org/gmssl/crypto/SM2KeyFactory.java rename to src/main/java/org/gmssl/crypto/asymmetric/SM2KeyFactory.java index 11eb106..5bbcd30 100644 --- a/src/main/java/org/gmssl/crypto/SM2KeyFactory.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyFactory.java @@ -1,4 +1,4 @@ -package org.gmssl.crypto; +package org.gmssl.crypto.asymmetric; import java.security.*; import java.security.spec.InvalidKeySpecException; diff --git a/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyPairGenerator.java similarity index 96% rename from src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java rename to src/main/java/org/gmssl/crypto/asymmetric/SM2KeyPairGenerator.java index c415f55..db3c9eb 100644 --- a/src/main/java/org/gmssl/crypto/SM2KeyPairGenerator.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyPairGenerator.java @@ -1,4 +1,4 @@ -package org.gmssl.crypto; +package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; diff --git a/src/main/java/org/gmssl/crypto/SM2PrivateKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2PrivateKey.java similarity index 98% rename from src/main/java/org/gmssl/crypto/SM2PrivateKey.java rename to src/main/java/org/gmssl/crypto/asymmetric/SM2PrivateKey.java index 6970a79..98730a3 100644 --- a/src/main/java/org/gmssl/crypto/SM2PrivateKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2PrivateKey.java @@ -1,4 +1,4 @@ -package org.gmssl.crypto; +package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; diff --git a/src/main/java/org/gmssl/crypto/SM2PublicKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2PublicKey.java similarity index 98% rename from src/main/java/org/gmssl/crypto/SM2PublicKey.java rename to src/main/java/org/gmssl/crypto/asymmetric/SM2PublicKey.java index 174c6f0..dfec541 100644 --- a/src/main/java/org/gmssl/crypto/SM2PublicKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2PublicKey.java @@ -1,4 +1,4 @@ -package org.gmssl.crypto; +package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; diff --git a/src/main/java/org/gmssl/crypto/SM2Signature.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java similarity index 98% rename from src/main/java/org/gmssl/crypto/SM2Signature.java rename to src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java index b3139ef..0d4bc93 100644 --- a/src/main/java/org/gmssl/crypto/SM2Signature.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java @@ -1,10 +1,9 @@ -package org.gmssl.crypto; +package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; import java.security.*; -import java.util.Arrays; /** * @author yongfeili diff --git a/src/main/java/org/gmssl/crypto/digest/SM3Digest.java b/src/main/java/org/gmssl/crypto/digest/SM3Digest.java new file mode 100644 index 0000000..5ff14f9 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/digest/SM3Digest.java @@ -0,0 +1,83 @@ +package org.gmssl.crypto.digest; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import java.security.MessageDigestSpi; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public class SM3Digest extends MessageDigestSpi { + + private final static int DIGEST_SIZE = GmSSLJNI.SM3_DIGEST_SIZE; + + private long sm3_ctx = 0; + + public SM3Digest() { + init(); + } + + @Override + protected void engineUpdate(byte input) { + byte[] data = new byte[]{input}; + this.update(data, 0, data.length); + } + + @Override + protected void engineUpdate(byte[] input, int offset, int len) { + this.update(input, offset, len); + } + + @Override + protected byte[] engineDigest() { + return this.digest(); + } + + @Override + protected void engineReset() { + this.reset(); + } + + private void init(){ + if ((sm3_ctx = GmSSLJNI.sm3_ctx_new()) == 0) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm3_init(sm3_ctx) != 1) { + throw new GmSSLException(""); + } + } + + public void update(byte[] data, int offset, int len) { + if (data == null + || offset < 0 + || len < 0 + || offset + len <= 0 + || data.length < offset + len) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm3_update(sm3_ctx, data, offset, len) != 1) { + throw new GmSSLException(""); + } + } + + public byte[] digest() { + byte[] dgst = new byte[DIGEST_SIZE]; + if (GmSSLJNI.sm3_finish(sm3_ctx, dgst) != 1) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm3_init(sm3_ctx) != 1) { + throw new GmSSLException(""); + } + return dgst; + } + + public void reset() { + if (GmSSLJNI.sm3_init(sm3_ctx) != 1) { + throw new GmSSLException(""); + } + } + +} diff --git a/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java b/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java new file mode 100644 index 0000000..ed9f45f --- /dev/null +++ b/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java @@ -0,0 +1,125 @@ +package org.gmssl.crypto.digest; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.MacSpi; +import javax.crypto.SecretKey; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public class SM3Hmac extends MacSpi { + + private final static int MAC_SIZE = GmSSLJNI.SM3_HMAC_SIZE; + + private Key key; + + private long sm3_hmac_ctx = 0; + + public SM3Hmac() { + super(); + ctx(); + } + + public SM3Hmac(Key key){ + this.key = key; + ctx(); + init(); + } + + @Override + protected int engineGetMacLength() { + return MAC_SIZE; + } + + @Override + protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { + if (!(key instanceof SecretKey)) { + throw new GmSSLException("Invalid key for HMAC-SM3"); + } + this.key = key; + init(); + } + + @Override + protected void engineUpdate(byte input) { + byte[] data = new byte[]{input}; + this.update(data, 0, data.length); + } + + @Override + protected void engineUpdate(byte[] input, int offset, int len) { + this.update(input, 0, len); + } + + @Override + protected byte[] engineDoFinal() { + return generateMac(); + } + + @Override + protected void engineReset() { + this.reset(this.key); + } + + public void engineReset(Key key) { + this.reset(key); + } + + private void ctx(){ + if ((this.sm3_hmac_ctx = GmSSLJNI.sm3_hmac_ctx_new()) == 0) { + throw new GmSSLException(""); + } + } + + private void init() { + if (GmSSLJNI.sm3_hmac_init(this.sm3_hmac_ctx, key.getEncoded()) != 1) { + throw new GmSSLException(""); + } + } + + public void update(byte[] data, int offset, int len) { + if (data == null + || offset < 0 + || len < 0 + || offset + len <= 0 + || data.length < offset + len) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm3_hmac_update(this.sm3_hmac_ctx, data, offset, len) != 1) { + throw new GmSSLException(""); + } + } + + public void update(byte[] data) { + this.update(data, 0, data.length); + } + + public byte[] generateMac() { + byte[] mac = new byte[this.MAC_SIZE]; + if (GmSSLJNI.sm3_hmac_finish(this.sm3_hmac_ctx, mac) != 1) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm3_hmac_init(this.sm3_hmac_ctx, this.key.getEncoded()) != 1) { + throw new GmSSLException(""); + } + return mac; + } + + public void reset(Key key) { + if (key == null) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm3_hmac_init(this.sm3_hmac_ctx, key.getEncoded()) != 1) { + throw new GmSSLException(""); + } + this.key = key; + } +} diff --git a/src/main/java/org/gmssl/crypto/digest/SM3Pbkdf2.java b/src/main/java/org/gmssl/crypto/digest/SM3Pbkdf2.java new file mode 100644 index 0000000..03c8fbc --- /dev/null +++ b/src/main/java/org/gmssl/crypto/digest/SM3Pbkdf2.java @@ -0,0 +1,76 @@ +package org.gmssl.crypto.digest; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public class SM3Pbkdf2 extends SecretKeyFactorySpi { + + public final static int MAX_SALT_SIZE = GmSSLJNI.SM3_PBKDF2_MAX_SALT_SIZE; + public final static int DEFAULT_SALT_SIZE = GmSSLJNI.SM3_PBKDF2_DEFAULT_SALT_SIZE; + public final static int MIN_ITER = GmSSLJNI.SM3_PBKDF2_MIN_ITER; + public final static int MAX_ITER = GmSSLJNI.SM3_PBKDF2_MAX_ITER; + public final static int MAX_KEY_SIZE = GmSSLJNI.SM3_PBKDF2_MAX_KEY_SIZE; + + public final static String ALGORITHM = "SM3Pbkdf2"; + + public SM3Pbkdf2() { + super(); + } + + @Override + protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException { + if (!(keySpec instanceof PBEKeySpec)) { + throw new GmSSLException("Invalid KeySpec"); + } + PBEKeySpec pbeKeySpec = (PBEKeySpec) keySpec; + char[] password = pbeKeySpec.getPassword(); + byte[] salt = pbeKeySpec.getSalt(); + int iterations = pbeKeySpec.getIterationCount(); + int derivedKeyLength = pbeKeySpec.getKeyLength(); + byte[] key = deriveKey(new String(password), salt, iterations, derivedKeyLength); + return new SecretKeySpec(key, ALGORITHM); + } + + @Override + protected KeySpec engineGetKeySpec(SecretKey key, Class keySpec) throws InvalidKeySpecException { + throw new GmSSLException("Not supported"); + } + + @Override + protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException { + throw new GmSSLException("Not supported"); + } + + public byte[] deriveKey(String pass, byte[] salt, int iter, int keylen) { + if (pass == null) { + throw new GmSSLException(""); + } + if (salt == null || salt.length > MAX_SALT_SIZE) { + throw new GmSSLException(""); + } + if (iter < MIN_ITER || iter > MAX_ITER) { + throw new GmSSLException(""); + } + if (keylen < 0 || keylen > MAX_KEY_SIZE) { + throw new GmSSLException(""); + } + byte[] key = GmSSLJNI.sm3_pbkdf2(pass, salt, iter, keylen); + if (key == null) { + throw new GmSSLException(""); + } + return key; + } +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Cbc.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Cbc.java new file mode 100644 index 0000000..42c8cdb --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Cbc.java @@ -0,0 +1,43 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.spec.IvParameterSpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public class SM4Cbc extends SM4Cipher{ + + public final static int IV_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + + private long sm4_cbc_ctx = 0; + + private byte[] iv; + + public SM4Cbc() { + super(); + } + + @Override + protected byte[] engineGetIV() { + return iv; + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + if (!(params instanceof IvParameterSpec)) { + throw new GmSSLException("need the IvParameterSpec parameter"); + } + this.iv = ((IvParameterSpec) params).getIV(); + + } +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java new file mode 100644 index 0000000..81587ed --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java @@ -0,0 +1,155 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import java.nio.ByteBuffer; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public class SM4Cipher extends CipherSpi { + + public final static int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; + public final static int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + + private long sm4_key = 0; + + private Key key; + + private boolean do_encrypt = false; + + /** + * 加密模式 CBC、CTR、GCM、ECB + */ + private String mode; + /** + * 填充模式 PKCS5Padding、NoPadding等 + */ + private String padding; + + private ByteBuffer buffer; + + public SM4Cipher() { + super(); + } + + @Override + protected void engineSetMode(String mode) throws NoSuchAlgorithmException { + // 设置加密模式 + this.mode = mode; + } + + @Override + protected void engineSetPadding(String padding) throws NoSuchPaddingException { + // 设置填充方式,可以选择支持PKCS5Padding,NoPadding等 + this.padding = padding; + } + + @Override + protected int engineGetBlockSize() { + // SM4块大小为16字节 + return KEY_SIZE; + } + + @Override + protected int engineGetOutputSize(int inputLen) { + // 输出大小根据模式和填充计算 + return 0; + } + + @Override + protected byte[] engineGetIV() { + // ECB模式不使用IV + return null; + } + + @Override + protected AlgorithmParameters engineGetParameters() { + // 无需额外的参数 + return null; + } + + @Override + protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { + if (!(key instanceof SecretKey)) { + throw new GmSSLException("Invalid KeySpec"); + } + this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); + this.key = key; + init(); + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + + } + + @Override + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { + return new byte[0]; + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + return 0; + } + + @Override + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + return new byte[0]; + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + encrypt(input,inputOffset,output,outputOffset); + return output.length; + } + + private void init(){ + if ((sm4_key = GmSSLJNI.sm4_key_new()) == 0) { + throw new GmSSLException(""); + } + + if (do_encrypt == true) { + if (GmSSLJNI.sm4_set_encrypt_key(sm4_key, key.getEncoded()) != 1) { + throw new GmSSLException(""); + } + } else { + if (GmSSLJNI.sm4_set_decrypt_key(sm4_key, key.getEncoded()) != 1) { + throw new GmSSLException(""); + } + } + } + + + public void encrypt(byte[] in, int in_offset, byte[] out, int out_offset) { + if (in == null + || in_offset < 0 + || in_offset + this.BLOCK_SIZE <= 0 + || in_offset + this.BLOCK_SIZE > in.length) { + throw new GmSSLException(""); + } + if (out == null + || out_offset < 0 + || out_offset + this.BLOCK_SIZE <= 0 + || out_offset + this.BLOCK_SIZE > in.length) { + throw new GmSSLException(""); + } + + if (GmSSLJNI.sm4_encrypt(sm4_key, in, in_offset, out, out_offset) != 1) { + throw new GmSSLException(""); + } + } +} diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index 844133b..4487b07 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -1,15 +1,17 @@ package org.gmssl; -import org.gmssl.crypto.SM2PrivateKey; -import org.gmssl.crypto.SM2PublicKey; +import org.gmssl.crypto.asymmetric.SM2PrivateKey; +import org.gmssl.crypto.asymmetric.SM2PublicKey; +import org.gmssl.crypto.digest.SM3Pbkdf2; import javax.crypto.Cipher; -import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.Security; -import java.security.Signature; +import java.security.*; /** * @author yongfeili @@ -23,8 +25,9 @@ public class JceTest { public static void main(String[] args) { // 动态添加提供者 Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); - SM2Test(); - + //SM2Test(); + //SM3Test(); + SM4Test(); } public static void SM2Test() { @@ -89,6 +92,56 @@ public static void SM2Test() { } } + public static void SM3Test() { + try { + String text="Hello, GmSSL"; + //测试SM3哈希 + MessageDigest sm3Digest = MessageDigest.getInstance("SM3","GmSSL"); + sm3Digest.update("abc".getBytes()); + byte[] digest = sm3Digest.digest(); + sm3Digest.reset(); + sm3Digest.update(text.getBytes()); + System.out.println("digest:"+byteToHex(digest)); + + //基于SM3的HMAC消息认证码算法 + Mac hmac = Mac.getInstance("SM3Hmac", "GmSSL"); + hmac.init(new SecretKeySpec(new Random().randBytes(Sm3Hmac.MAC_SIZE), "SM3Hmac")); + hmac.update(text.getBytes()); + byte[] hmacFinal = hmac.doFinal(); + System.out.println("hmac:"+byteToHex(hmacFinal)); + + //基于口令的密钥导出函数PBKDF2 + char[] password = "P@ssw0rd".toCharArray(); + byte[] salt = new Random().randBytes(SM3Pbkdf2.DEFAULT_SALT_SIZE); + int iterations = SM3Pbkdf2.MIN_ITER * 2; + int keyLength = SM3Pbkdf2.MAX_KEY_SIZE; + PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength); + SecretKeyFactory skf = SecretKeyFactory.getInstance("SM3Pbkdf2"); + SecretKey key = skf.generateSecret(spec); + byte[] keyBytes = key.getEncoded(); + System.out.println("DerivedKey: " + byteToHex(keyBytes)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void SM4Test() { + try { + SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); + byte[] randomBytes = new byte[32]; + secureRandom.nextBytes(randomBytes); + System.out.println("Generated Random Bytes: " + byteToHex(randomBytes)); + + Cipher sm4Cipher = Cipher.getInstance("SM4/CBC/PKCS5Padding", "GmSSL"); + + + } catch (Exception e) { + e.printStackTrace(); + } + + + } + /** * convert byte array to hex string * @param btArr From 8f5eecd430af80fa650d3a405f84335aef06c125 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Thu, 22 Aug 2024 11:33:28 +0800 Subject: [PATCH 07/20] sm4 sm9 jce develop --- .../crypto/{Mode.java => CipherModeEnum.java} | 2 +- .../{Padding.java => CipherPaddingEnum.java} | 2 +- src/main/java/org/gmssl/crypto/Decryptor.java | 9 + .../java/org/gmssl/crypto/GmSSLProvider.java | 8 +- .../org/gmssl/crypto/NoPaddingScheme.java | 9 + .../org/gmssl/crypto/PKCS5PaddingScheme.java | 9 + .../java/org/gmssl/crypto/PaddingScheme.java | 15 ++ .../gmssl/crypto/asymmetric/SM2Cipher.java | 3 +- .../crypto/asymmetric/SM2KeyFactory.java | 38 ---- .../gmssl/crypto/asymmetric/SM2Signature.java | 8 +- .../gmssl/crypto/asymmetric/SM9Cipher.java | 136 +++++++++++++++ .../crypto/asymmetric/SM9EncMasterKey.java | 129 ++++++++++++++ .../SM9EncMasterKeyGenParameterSpec.java | 32 ++++ .../crypto/asymmetric/SM9EncUserKey.java | 56 ++++++ .../asymmetric/SM9KeyPairGeneratorSpi.java | 46 +++++ .../gmssl/crypto/asymmetric/SM9MasterKey.java | 27 +++ .../crypto/asymmetric/SM9PrivateKey.java | 41 +++++ .../gmssl/crypto/asymmetric/SM9PublicKey.java | 42 +++++ .../crypto/asymmetric/SM9SignMasterKey.java | 120 +++++++++++++ .../SM9SignMasterKeyGenParameterSpec.java | 29 ++++ .../crypto/asymmetric/SM9SignUserKey.java | 52 ++++++ .../gmssl/crypto/asymmetric/SM9Signature.java | 150 ++++++++++++++++ .../gmssl/crypto/asymmetric/SM9UserKey.java | 26 +++ .../symmetric/AadAlgorithmParameters.java | 32 ++++ .../java/org/gmssl/crypto/symmetric/SM4.java | 115 ++++++++++++ .../org/gmssl/crypto/symmetric/SM4CBC.java | 160 +++++++++++++++++ .../org/gmssl/crypto/symmetric/SM4CTR.java | 131 ++++++++++++++ .../org/gmssl/crypto/symmetric/SM4Cbc.java | 43 ----- .../org/gmssl/crypto/symmetric/SM4Cipher.java | 99 +++-------- .../crypto/symmetric/SM4CipherFactory.java | 37 ++++ .../org/gmssl/crypto/symmetric/SM4ECB.java | 35 ++++ .../org/gmssl/crypto/symmetric/SM4Engine.java | 34 ++++ .../org/gmssl/crypto/symmetric/SM4GCM.java | 164 ++++++++++++++++++ src/test/java/org/gmssl/JceTest.java | 148 ++++++++++++++-- 34 files changed, 1813 insertions(+), 174 deletions(-) rename src/main/java/org/gmssl/crypto/{Mode.java => CipherModeEnum.java} (90%) rename src/main/java/org/gmssl/crypto/{Padding.java => CipherPaddingEnum.java} (81%) create mode 100644 src/main/java/org/gmssl/crypto/Decryptor.java create mode 100644 src/main/java/org/gmssl/crypto/NoPaddingScheme.java create mode 100644 src/main/java/org/gmssl/crypto/PKCS5PaddingScheme.java create mode 100644 src/main/java/org/gmssl/crypto/PaddingScheme.java delete mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM2KeyFactory.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKeyGenParameterSpec.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9KeyPairGeneratorSpi.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9PublicKey.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKeyGenParameterSpec.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9Signature.java create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/AadAlgorithmParameters.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java delete mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4Cbc.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java diff --git a/src/main/java/org/gmssl/crypto/Mode.java b/src/main/java/org/gmssl/crypto/CipherModeEnum.java similarity index 90% rename from src/main/java/org/gmssl/crypto/Mode.java rename to src/main/java/org/gmssl/crypto/CipherModeEnum.java index c3391b0..dabad61 100644 --- a/src/main/java/org/gmssl/crypto/Mode.java +++ b/src/main/java/org/gmssl/crypto/CipherModeEnum.java @@ -5,7 +5,7 @@ * @date 2024/8/12 * @description */ -public enum Mode { +public enum CipherModeEnum { NONE, /** * Cipher Block Chaining diff --git a/src/main/java/org/gmssl/crypto/Padding.java b/src/main/java/org/gmssl/crypto/CipherPaddingEnum.java similarity index 81% rename from src/main/java/org/gmssl/crypto/Padding.java rename to src/main/java/org/gmssl/crypto/CipherPaddingEnum.java index 9e9378e..a61ca1d 100644 --- a/src/main/java/org/gmssl/crypto/Padding.java +++ b/src/main/java/org/gmssl/crypto/CipherPaddingEnum.java @@ -5,7 +5,7 @@ * @date 2024/8/12 * @description */ -public enum Padding { +public enum CipherPaddingEnum { NoPadding, ZeroPadding, diff --git a/src/main/java/org/gmssl/crypto/Decryptor.java b/src/main/java/org/gmssl/crypto/Decryptor.java new file mode 100644 index 0000000..bcde33f --- /dev/null +++ b/src/main/java/org/gmssl/crypto/Decryptor.java @@ -0,0 +1,9 @@ +package org.gmssl.crypto; + +/** + * @author yongfeili + * @date 2024/8/22 + * @description + */ +public interface Decryptor { +} diff --git a/src/main/java/org/gmssl/crypto/GmSSLProvider.java b/src/main/java/org/gmssl/crypto/GmSSLProvider.java index 54e8ac9..c1957dc 100644 --- a/src/main/java/org/gmssl/crypto/GmSSLProvider.java +++ b/src/main/java/org/gmssl/crypto/GmSSLProvider.java @@ -16,12 +16,16 @@ public GmSSLProvider() { put("Cipher.SM2", "org.gmssl.crypto.asymmetric.SM2Cipher"); put("KeyPairGenerator.SM2", "org.gmssl.crypto.asymmetric.SM2KeyPairGenerator"); put("Signature.SM2", "org.gmssl.crypto.asymmetric.SM2Signature"); - //put("KeyFactory.SM2", "org.gmssl.crypto.asymmetric.SM2KeyFactory"); + put("MessageDigest.SM3", "org.gmssl.crypto.digest.SM3Digest"); put("Mac.SM3Hmac", "org.gmssl.crypto.digest.SM3Hmac"); put("SecretKeyFactory.SM3Pbkdf2", "org.gmssl.crypto.digest.SM3Pbkdf2"); + put("Cipher.SM4", "org.gmssl.crypto.symmetric.SM4Cipher"); - put("Cipher.SM4Cbc", "org.gmssl.crypto.symmetric.SM4Cbc"); + + put("Cipher.SM9", "org.gmssl.crypto.asymmetric.SM9Cipher"); + put("Signature.SM9", "org.gmssl.crypto.asymmetric.SM9Signature"); + put("KeyPairGenerator.SM9", "org.gmssl.crypto.asymmetric.SM9KeyPairGeneratorSpi"); } diff --git a/src/main/java/org/gmssl/crypto/NoPaddingScheme.java b/src/main/java/org/gmssl/crypto/NoPaddingScheme.java new file mode 100644 index 0000000..e29e4bd --- /dev/null +++ b/src/main/java/org/gmssl/crypto/NoPaddingScheme.java @@ -0,0 +1,9 @@ +package org.gmssl.crypto; + +/** + * @author yongfeili + * @date 2024/8/13 + * @description + */ +public class NoPaddingScheme { +} diff --git a/src/main/java/org/gmssl/crypto/PKCS5PaddingScheme.java b/src/main/java/org/gmssl/crypto/PKCS5PaddingScheme.java new file mode 100644 index 0000000..5aac9f6 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/PKCS5PaddingScheme.java @@ -0,0 +1,9 @@ +package org.gmssl.crypto; + +/** + * @author yongfeili + * @date 2024/8/13 + * @description + */ +public class PKCS5PaddingScheme { +} diff --git a/src/main/java/org/gmssl/crypto/PaddingScheme.java b/src/main/java/org/gmssl/crypto/PaddingScheme.java new file mode 100644 index 0000000..8ab5579 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/PaddingScheme.java @@ -0,0 +1,15 @@ +package org.gmssl.crypto; + +/** + * @author yongfeili + * @date 2024/8/13 + * @description + */ +public interface PaddingScheme { + + String getPaddingName(); + + int addPadding(byte[] in, int inOff); + + int padCount(byte[] in); +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java index 680487d..efc469a 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java @@ -95,7 +95,7 @@ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { buffer.put(input, inputOffset, inputLen); // 暂时不返回输出,等待 doFinal - return 0; + return output.length; } @Override @@ -104,6 +104,7 @@ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) thro byte[] data = new byte[buffer.position()]; buffer.flip(); buffer.get(data); + buffer.clear(); if (mode == Cipher.ENCRYPT_MODE) { return encrypt(data); diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyFactory.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyFactory.java deleted file mode 100644 index 5bbcd30..0000000 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.gmssl.crypto.asymmetric; - -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; - -/** - * @author yongfeili - * @date 2024/8/2 - * @description - */ -public class SM2KeyFactory extends KeyFactorySpi { - - @Override - protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { - // 实现生成公钥 - - return null; - } - - @Override - protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { - // 实现生成私钥 - return null; - } - - @Override - protected T engineGetKeySpec(Key key, Class keySpec) throws InvalidKeySpecException { - // 实现根据 Key 和 KeySpec 类型返回相应的 KeySpec - return null; - } - - @Override - protected Key engineTranslateKey(Key key) throws InvalidKeyException { - // 实现将 Key 转换为本地的 SM2Key - return null; - } -} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java index 0d4bc93..61f0667 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java @@ -21,7 +21,6 @@ public class SM2Signature extends SignatureSpi { public SM2Signature() { super(); - init(); } @Override @@ -30,6 +29,7 @@ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException if (!(publicKey instanceof SM2PublicKey)) { throw new GmSSLException("Invalid publicKey type"); } + init(); initVerify((SM2PublicKey) publicKey,DEFAULT_ID); } @@ -39,19 +39,18 @@ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException if (!(privateKey instanceof SM2PrivateKey)) { throw new GmSSLException("Invalid privateKey type"); } + init(); initSign((SM2PrivateKey) privateKey,DEFAULT_ID); } @Override protected void engineUpdate(byte b) throws SignatureException { - // 实现更新方法 byte[] data= new byte[]{b}; update(data, 0, data.length); } @Override protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { - // 实现更新方法 update(b, off, len); } @@ -137,6 +136,7 @@ private byte[] sign() { if ((sig = GmSSLJNI.sm2_sign_finish(this.sm2_sign_ctx)) == null) { throw new GmSSLException(""); } + this.inited = false; return sig; } @@ -147,7 +147,7 @@ private boolean verify(byte[] signature) { if (this.do_sign == true) { throw new GmSSLException(""); } - + this.inited = false; int ret; if ((ret = GmSSLJNI.sm2_verify_finish(sm2_sign_ctx, signature)) != 1) { return false; diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java new file mode 100644 index 0000000..05a380f --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java @@ -0,0 +1,136 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.Sm9EncMasterKey; + +import javax.crypto.*; +import java.nio.ByteBuffer; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/21 + * @description + */ +public class SM9Cipher extends CipherSpi { + + private int opmode; + + private Key key; + + private ByteBuffer buffer; + + private String id; + + @Override + protected void engineSetMode(String mode) throws NoSuchAlgorithmException { + + } + + @Override + protected void engineSetPadding(String padding) throws NoSuchPaddingException { + + } + + @Override + protected int engineGetBlockSize() { + return 0; + } + + @Override + protected int engineGetOutputSize(int inputLen) { + return 0; + } + + @Override + protected byte[] engineGetIV() { + return new byte[0]; + } + + @Override + protected AlgorithmParameters engineGetParameters() { + return null; + } + + @Override + protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { + /*if (!(key instanceof SM9PublicKey) || !(key instanceof SM9PrivateKey)) { + throw new GmSSLException("Invalid key type"); + }*/ + this.opmode = opmode; + this.key = key; + SM9PrivateKey privateKey = (SM9PrivateKey)key; + SM9UserKey userKey = (SM9UserKey)privateKey.getOuterKey(); + this.id = userKey.getId(); + // 初始化缓冲区 + this.buffer = ByteBuffer.allocate(2048); + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + /*if (!(key instanceof SM9PublicKey) || !(key instanceof SM9PrivateKey)) { + throw new GmSSLException("Invalid key type"); + }*/ + this.opmode = opmode; + this.key = key; + this.id = ((SM9EncMasterKeyGenParameterSpec)params).getId(); + // 初始化缓冲区 + this.buffer = ByteBuffer.allocate(2048); + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + throw new GmSSLException("params should not be null!"); + } + + @Override + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { + buffer.put(input, inputOffset, inputLen); + // 暂时不返回输出,等待 doFinal + return buffer.array(); + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + buffer.put(input, inputOffset, inputLen); + // 暂时不返回输出,等待 doFinal + return output.length; + } + + @Override + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + buffer.put(input, inputOffset, inputLen); + byte[] data = new byte[buffer.position()]; + buffer.flip(); + buffer.get(data); + buffer.clear(); + + if (opmode == Cipher.ENCRYPT_MODE) { + return encrypt(data); + } else if (opmode == Cipher.DECRYPT_MODE) { + return decrypt(data); + } else { + throw new GmSSLException("Cipher not initialized properly"); + } + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + byte[] result = engineDoFinal(input, inputOffset, inputLen); + System.arraycopy(result, 0, output, outputOffset, result.length); + return result.length; + } + + private byte[] encrypt(byte[] plaintext) { + SM9PublicKey encMasterKey = (SM9PublicKey) key; + byte[] ciphertext = encMasterKey.encrypt(plaintext,id); + return ciphertext; + } + + private byte[] decrypt(byte[] ciphertext) { + SM9PrivateKey privateKey = (SM9PrivateKey)key; + byte[] plaintext = privateKey.decrypt(ciphertext); + return plaintext; + } +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java new file mode 100644 index 0000000..58d314e --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java @@ -0,0 +1,129 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +/** + * @author yongfeili + * @date 2024/8/20 + * @description + */ +public class SM9EncMasterKey extends SM9MasterKey{ + + public final static int MAX_PLAINTEXT_SIZE = GmSSLJNI.SM9_MAX_PLAINTEXT_SIZE; + + public SM9EncMasterKey(){ + publicKey = new SM9EncPublicKey(); + privateKey = new SM9EncPrivateKey(); + } + + class SM9EncPublicKey extends SM9PublicKey { + + public long getPublicKey() { + if (master_key == 0) { + throw new GmSSLException(""); + } + return master_key; + } + + public void importPublicKeyPem(String file) { + if (master_key != 0) { + GmSSLJNI.sm9_enc_master_key_free(master_key); + } + if ((master_key = GmSSLJNI.sm9_enc_master_public_key_from_pem(file)) == 0) { + throw new GmSSLException(""); + } + has_private_key = false; + } + + public void exportPublicKeyPem(String file) { + if (master_key == 0) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm9_enc_master_public_key_to_pem(master_key, file) != 1) { + throw new GmSSLException(""); + } + } + + public byte[] encrypt(byte[] plaintext, String id) { + if (master_key == 0) { + throw new GmSSLException(""); + } + if (plaintext == null + || plaintext.length > MAX_PLAINTEXT_SIZE) { + throw new GmSSLException(""); + } + + byte[] ciphertext; + if ((ciphertext = GmSSLJNI.sm9_encrypt(master_key, id, plaintext)) == null) { + throw new GmSSLException(""); + } + return ciphertext; + } + + } + + class SM9EncPrivateKey extends SM9PrivateKey{ + public void importEncryptedPrivateKeyInfoPem(String pass, String file) { + if (master_key != 0) { + GmSSLJNI.sm9_enc_master_key_free(master_key); + } + if ((master_key = GmSSLJNI.sm9_enc_master_key_info_decrypt_from_pem(pass, file)) == 0) { + throw new GmSSLException(""); + } + has_private_key = true; + } + + public void exportEncryptedPrivateKeyInfoPem(String pass, String file) { + if (master_key == 0) { + throw new GmSSLException(""); + } + if (has_private_key == false) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm9_enc_master_key_info_encrypt_to_pem(master_key, pass, file) != 1) { + throw new GmSSLException(""); + } + } + + public SM9EncMasterKey getOuterKey() { + return SM9EncMasterKey.this; + } + + } + + public void generateMasterKey() { + if (master_key != 0) { + GmSSLJNI.sm9_enc_master_key_free(master_key); + } + if ((master_key = GmSSLJNI.sm9_enc_master_key_generate()) == 0) { + throw new GmSSLException(""); + } + has_private_key = true; + } + + public long getOuterKey() { + if (master_key == 0) { + throw new GmSSLException(""); + } + if (has_private_key == false) { + throw new GmSSLException(""); + } + return master_key; + } + + public SM9UserKey extractKey(String id) { + if (this.master_key == 0) { + throw new GmSSLException(""); + } + if (this.has_private_key == false) { + throw new GmSSLException(""); + } + long key; + if ((key = GmSSLJNI.sm9_enc_master_key_extract_key(this.master_key, id)) == 0) { + throw new GmSSLException(""); + } + return new SM9EncUserKey(key, id); + } + +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKeyGenParameterSpec.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKeyGenParameterSpec.java new file mode 100644 index 0000000..a1a4465 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKeyGenParameterSpec.java @@ -0,0 +1,32 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.GmSSLJNI; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/21 + * @description + */ +public class SM9EncMasterKeyGenParameterSpec implements AlgorithmParameterSpec { + + private String id; + + protected SM9EncMasterKeyGenParameterSpec() { + + } + + public SM9EncMasterKeyGenParameterSpec(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} + diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java new file mode 100644 index 0000000..c40df08 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java @@ -0,0 +1,56 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; +import org.gmssl.Sm9SignKey; + +/** + * @author yongfeili + * @date 2024/8/21 + * @description + */ +public class SM9EncUserKey extends SM9UserKey{ + protected SM9EncUserKey(long sm9_key, String id) { + super(sm9_key, id); + this.privateKey = new SM9EncPrivateKey(); + } + + class SM9EncPrivateKey extends SM9PrivateKey { + public void importEncryptedPrivateKeyInfoPem(String pass, String file) { + if (sm9_key != 0) { + GmSSLJNI.sm9_enc_key_free(sm9_key); + } + if ((sm9_key = GmSSLJNI.sm9_enc_key_info_decrypt_from_pem(pass, file)) == 0) { + throw new GmSSLException(""); + } + } + + public void exportEncryptedPrivateKeyInfoPem(String pass, String file) { + if (sm9_key == 0) { + throw new GmSSLException("Key not initialized"); + } + if (GmSSLJNI.sm9_enc_key_info_encrypt_to_pem(sm9_key, pass, file) != 1) { + throw new GmSSLException(""); + } + } + + public byte[] decrypt(byte[] ciphertext) { + if (sm9_key == 0) { + throw new GmSSLException(""); + } + if (ciphertext == null) { + throw new GmSSLException(""); + } + + byte[] plaintext; + if ((plaintext = GmSSLJNI.sm9_decrypt(sm9_key, id, ciphertext)) == null) { + throw new GmSSLException(""); + } + return plaintext; + } + public SM9EncUserKey getOuterKey() { + return SM9EncUserKey.this; + } + } + +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9KeyPairGeneratorSpi.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9KeyPairGeneratorSpi.java new file mode 100644 index 0000000..48d5500 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9KeyPairGeneratorSpi.java @@ -0,0 +1,46 @@ +package org.gmssl.crypto.asymmetric; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGeneratorSpi; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.KeySpec; + +/** + * @author yongfeili + * @date 2024/8/20 + * @description + */ +public class SM9KeyPairGeneratorSpi extends KeyPairGeneratorSpi { + + private SM9MasterKey masterKey; + + @Override + public void initialize(int keysize, SecureRandom random) { + + } + + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { + if (params == null) { + throw new InvalidAlgorithmParameterException("The parameter must not be null"); + } + if (params instanceof SM9SignMasterKeyGenParameterSpec) { + SM9SignMasterKeyGenParameterSpec spec = (SM9SignMasterKeyGenParameterSpec) params; + this.masterKey = new SM9SignMasterKey(); + } else if (params instanceof SM9EncMasterKeyGenParameterSpec) { + SM9EncMasterKeyGenParameterSpec spec = (SM9EncMasterKeyGenParameterSpec) params; + this.masterKey = new SM9EncMasterKey(); + } else { + throw new InvalidAlgorithmParameterException(""); + } + masterKey.generateMasterKey(); + } + + @Override + public KeyPair generateKeyPair() { + return new KeyPair(masterKey.publicKey, masterKey.privateKey); + } + +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java new file mode 100644 index 0000000..d208733 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java @@ -0,0 +1,27 @@ +package org.gmssl.crypto.asymmetric; + +import java.security.Key; +import java.security.spec.KeySpec; + +/** + * @author yongfeili + * @date 2024/8/20 + * @description + */ +public abstract class SM9MasterKey implements KeySpec { + + protected long master_key; + + protected boolean has_private_key; + + public SM9PublicKey publicKey; + + public SM9PrivateKey privateKey; + + public abstract void generateMasterKey(); + + public abstract long getOuterKey(); + + public abstract SM9UserKey extractKey(String id); + +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java new file mode 100644 index 0000000..a4491ff --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java @@ -0,0 +1,41 @@ +package org.gmssl.crypto.asymmetric; + +import java.security.PrivateKey; +import java.security.spec.KeySpec; + +/** + * @author yongfeili + * @date 2024/8/20 + * @description + */ +public abstract class SM9PrivateKey implements PrivateKey { + + @Override + public String getAlgorithm() { + return null; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return new byte[0]; + } + + public abstract KeySpec getOuterKey(); + + public abstract void importEncryptedPrivateKeyInfoPem(String pass, String file); + + public abstract void exportEncryptedPrivateKeyInfoPem(String pass, String file); + + public byte[] decrypt(byte[] ciphertext) { + return null; + } + + public byte[] sign(long sign_ctx) { + return null; + } +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9PublicKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9PublicKey.java new file mode 100644 index 0000000..68758ba --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9PublicKey.java @@ -0,0 +1,42 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.Sm9SignMasterKey; + +import java.security.PublicKey; + +/** + * @author yongfeili + * @date 2024/8/20 + * @description + */ +public abstract class SM9PublicKey implements PublicKey { + + @Override + public String getAlgorithm() { + return null; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return new byte[0]; + } + + public abstract long getPublicKey(); + + public abstract void importPublicKeyPem(String file); + + public abstract void exportPublicKeyPem(String file); + + public byte[] encrypt(byte[] plaintext, String id){ + return null; + }; + + public Boolean verify(byte[] signature, String id,long sign_ctx){ + return null; + } +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java new file mode 100644 index 0000000..16773b5 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java @@ -0,0 +1,120 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; +import org.gmssl.Sm9SignMasterKey; + +/** + * @author yongfeili + * @date 2024/8/20 + * @description + */ +public class SM9SignMasterKey extends SM9MasterKey{ + + public SM9SignMasterKey(){ + publicKey = new SM9SignPublicKey(); + privateKey = new SM9SignPrivateKey(); + } + + class SM9SignPublicKey extends SM9PublicKey { + public long getPublicKey() { + if (master_key == 0) { + throw new GmSSLException(""); + } + return master_key; + } + + public void importPublicKeyPem(String file) { + if (master_key != 0) { + GmSSLJNI.sm9_sign_master_key_free(master_key); + } + if ((master_key = GmSSLJNI.sm9_sign_master_public_key_from_pem(file)) == 0) { + throw new GmSSLException(""); + } + has_private_key = false; + } + + public void exportPublicKeyPem(String file) { + if (master_key == 0) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm9_sign_master_public_key_to_pem(master_key, file) != 1) { + throw new GmSSLException(""); + } + } + + public Boolean verify(byte[] signature, String id,long sm9_sign_ctx) { + int ret; + ret = GmSSLJNI.sm9_verify_finish(sm9_sign_ctx, signature, master_key, id); + if (ret == 1) { + return true; + } else { + return false; + } + } + + } + + class SM9SignPrivateKey extends SM9PrivateKey{ + public void importEncryptedPrivateKeyInfoPem(String pass, String file) { + if (master_key != 0) { + GmSSLJNI.sm9_sign_master_key_free(master_key); + } + if ((master_key = GmSSLJNI.sm9_sign_master_key_info_decrypt_from_pem(pass, file)) == 0) { + throw new GmSSLException(""); + } + has_private_key = true; + } + + public void exportEncryptedPrivateKeyInfoPem(String pass, String file) { + if (master_key == 0) { + throw new GmSSLException(""); + } + if (has_private_key == false) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm9_sign_master_key_info_encrypt_to_pem(master_key, pass, file) != 1) { + throw new GmSSLException(""); + } + } + + public SM9SignMasterKey getOuterKey() { + return SM9SignMasterKey.this; + } + + } + public void generateMasterKey() { + if (this.master_key != 0) { + GmSSLJNI.sm9_sign_master_key_free(this.master_key); + } + if ((this.master_key = GmSSLJNI.sm9_sign_master_key_generate()) == 0) { + throw new GmSSLException(""); + } + this.has_private_key = true; + } + + public long getOuterKey() { + if (this.master_key == 0) { + throw new GmSSLException(""); + } + if (this.has_private_key == false) { + throw new GmSSLException(""); + } + return this.master_key; + } + + public SM9UserKey extractKey(String id) { + if (this.master_key == 0) { + throw new GmSSLException(""); + } + if (this.has_private_key == false) { + throw new GmSSLException(""); + } + long key; + if ((key = GmSSLJNI.sm9_sign_master_key_extract_key(this.master_key, id)) == 0) { + throw new GmSSLException(""); + } + return new SM9SignUserKey(key, id); + } + +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKeyGenParameterSpec.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKeyGenParameterSpec.java new file mode 100644 index 0000000..51a40e2 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKeyGenParameterSpec.java @@ -0,0 +1,29 @@ +package org.gmssl.crypto.asymmetric; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/21 + * @description + */ +public class SM9SignMasterKeyGenParameterSpec implements AlgorithmParameterSpec { + + private String id; + + protected SM9SignMasterKeyGenParameterSpec() { + + } + + public SM9SignMasterKeyGenParameterSpec(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java new file mode 100644 index 0000000..6fb95ea --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java @@ -0,0 +1,52 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; +import org.gmssl.Sm9SignKey; + +/** + * @author yongfeili + * @date 2024/8/21 + * @description + */ +public class SM9SignUserKey extends SM9UserKey{ + protected SM9SignUserKey(long sm9_key, String id) { + super(sm9_key, id); + this.privateKey = new SM9SignPrivateKey(); + } + + class SM9SignPrivateKey extends SM9PrivateKey { + + public void exportEncryptedPrivateKeyInfoPem(String pass, String file) { + if (sm9_key == 0) { + throw new GmSSLException("Key not initialized"); + } + if (GmSSLJNI.sm9_sign_key_info_encrypt_to_pem(sm9_key, pass, file) != 1) { + throw new GmSSLException(""); + } + } + + public void importEncryptedPrivateKeyInfoPem(String pass, String file) { + if (sm9_key != 0) { + GmSSLJNI.sm9_sign_key_free(sm9_key); + } + if ((sm9_key = GmSSLJNI.sm9_sign_key_info_decrypt_from_pem(pass, file)) == 0) { + throw new GmSSLException("Import key failure"); + } + } + + public byte[] sign(long sm9_sign_ctx) { + byte[] signature; + if ((signature = GmSSLJNI.sm9_sign_finish(sm9_sign_ctx, sm9_key)) == null) { + throw new GmSSLException(""); + } + return signature; + } + + public SM9SignUserKey getOuterKey() { + return SM9SignUserKey.this; + } + + } + +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9Signature.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9Signature.java new file mode 100644 index 0000000..c23c827 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9Signature.java @@ -0,0 +1,150 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/21 + * @description + */ +public class SM9Signature extends SignatureSpi { + + private long sm9_sign_ctx; + + private boolean inited; + + private boolean do_sign; + + private Key key; + + private String id; + + public SM9Signature() { + super(); + } + + @Override + protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { + if (!(publicKey instanceof SM9PublicKey)) { + throw new GmSSLException("Invalid publicKey type"); + } + this.key = publicKey; + init(); + initVerify(); + } + + @Override + protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + if (!(privateKey instanceof SM9PrivateKey)) { + throw new GmSSLException("Invalid privateKey type"); + } + this.key = privateKey; + init(); + initSign(); + } + + @Override + protected void engineUpdate(byte b) throws SignatureException { + byte[] data= new byte[]{b}; + update(data, 0, data.length); + } + + @Override + protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { + update(b, off, len); + } + + @Override + protected byte[] engineSign() { + SM9PrivateKey sm9_private_key = (SM9PrivateKey)key; + byte[] signature = sm9_private_key.sign(sm9_sign_ctx); + this.inited = false; + return signature; + } + + @Override + protected boolean engineVerify(byte[] sigBytes) { + SM9PublicKey sm9_public_key = (SM9PublicKey)key; + boolean verify = sm9_public_key.verify(sigBytes,id,sm9_sign_ctx); + this.inited = false; + return verify; + } + + @Deprecated + @Override + protected void engineSetParameter(String param, Object value) throws InvalidParameterException { + + } + + @Deprecated + @Override + protected Object engineGetParameter(String param) throws InvalidParameterException { + return null; + } + + @Override + protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { + this.id = ((SM9SignMasterKeyGenParameterSpec)params).getId(); + } + + private void init(){ + if ((this.sm9_sign_ctx = GmSSLJNI.sm9_sign_ctx_new()) == 0) { + throw new GmSSLException(""); + } + this.inited = true; + } + + private void initSign() { + if (GmSSLJNI.sm9_sign_init(this.sm9_sign_ctx) != 1) { + throw new GmSSLException(""); + } + this.do_sign = true; + } + + private void initVerify() { + if (GmSSLJNI.sm9_verify_init(this.sm9_sign_ctx) != 1) { + throw new GmSSLException(""); + } + this.do_sign = false; + } + + public void reset(boolean do_sign) { + if (do_sign == true) { + if (GmSSLJNI.sm9_sign_init(this.sm9_sign_ctx) != 1) { + throw new GmSSLException(""); + } + } else { + if (GmSSLJNI.sm9_verify_init(this.sm9_sign_ctx) != 1) { + throw new GmSSLException(""); + } + } + this.inited = true; + this.do_sign = do_sign; + } + + public void update(byte[] data, int offset, int len) { + if (this.inited == false) { + throw new GmSSLException(""); + } + if (data == null + || offset < 0 + || len < 0 + || offset + len <= 0 + || data.length < offset + len) { + throw new GmSSLException(""); + } + if (this.do_sign == true) { + if (GmSSLJNI.sm9_sign_update(this.sm9_sign_ctx, data, offset, len) != 1) { + throw new GmSSLException(""); + } + } else { + if (GmSSLJNI.sm9_verify_update(this.sm9_sign_ctx, data, offset, len) != 1) { + throw new GmSSLException(""); + } + } + } +} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java new file mode 100644 index 0000000..831f859 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java @@ -0,0 +1,26 @@ +package org.gmssl.crypto.asymmetric; + +import java.security.spec.KeySpec; + +/** + * @author yongfeili + * @date 2024/8/20 + * @description + */ +public abstract class SM9UserKey implements KeySpec { + + protected long sm9_key; + + protected String id; + + public SM9PrivateKey privateKey; + + protected SM9UserKey(long key, String id) { + this.sm9_key = key; + this.id = id; + } + + public String getId() { + return this.id; + } +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/AadAlgorithmParameters.java b/src/main/java/org/gmssl/crypto/symmetric/AadAlgorithmParameters.java new file mode 100644 index 0000000..04bb2fe --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/AadAlgorithmParameters.java @@ -0,0 +1,32 @@ +package org.gmssl.crypto.symmetric; + +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/14 + * @description + */ + +public class AadAlgorithmParameters extends GCMParameterSpec { + + protected byte[] aad; + + public AadAlgorithmParameters(int tLen, byte[] iv) { + super(tLen, iv); + } + + public AadAlgorithmParameters(int tLen, byte[] iv,byte[] aad) { + super(tLen, iv); + this.aad = aad; + } + + public byte[] getAad() { + return aad; + } + + public void setAad(byte[] aad) { + this.aad = aad; + } +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4.java b/src/main/java/org/gmssl/crypto/symmetric/SM4.java new file mode 100644 index 0000000..3a2bbcb --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4.java @@ -0,0 +1,115 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.*; +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; + +/** + * @author yongfeili + * @date 2024/8/13 + * @description + */ +public class SM4 extends SM4Cipher { + + public final static int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; + public final static int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + + private Key key; + private long sm4_key = 0; + + private boolean do_encrypt = false; + + private ByteBuffer buffer; + + @Override + protected int engineGetBlockSize() { + // SM4块大小为16字节 + return BLOCK_SIZE; + } + + @Override + protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { + if (!(key instanceof SecretKey)) { + throw new GmSSLException("Invalid KeySpec"); + } + this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); + this.key = key; + // 初始化缓冲区 + this.buffer = ByteBuffer.allocate(2048); + init(); + } + + @Override + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { + buffer.put(input, inputOffset, inputLen); + // 暂时不返回输出,等待 doFinal + return buffer.array(); + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + buffer.put(input, inputOffset, inputLen); + // 暂时不返回输出,等待 doFinal + return output.length; + } + + @Override + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + buffer.put(input, inputOffset, inputLen); + byte[] data = new byte[buffer.position()]; + buffer.flip(); + buffer.get(data); + + byte[] output = new byte[buffer.position()]; + encrypt(data,0,output,0); + buffer.clear(); + return output; + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + encrypt(input,inputOffset,output,outputOffset); + //计算返回实际长度 + return output.length; + } + + private void init(){ + if ((sm4_key = GmSSLJNI.sm4_key_new()) == 0) { + throw new GmSSLException(""); + } + + if (do_encrypt == true) { + if (GmSSLJNI.sm4_set_encrypt_key(sm4_key, key.getEncoded()) != 1) { + throw new GmSSLException(""); + } + } else { + if (GmSSLJNI.sm4_set_decrypt_key(sm4_key, key.getEncoded()) != 1) { + throw new GmSSLException(""); + } + } + } + + public void encrypt(byte[] in, int in_offset, byte[] out, int out_offset) { + if (in == null + || in_offset < 0 + || in_offset + this.BLOCK_SIZE <= 0 + || in_offset + this.BLOCK_SIZE > in.length) { + throw new GmSSLException(""); + } + if (out == null + || out_offset < 0 + || out_offset + this.BLOCK_SIZE <= 0 + || out_offset + this.BLOCK_SIZE > in.length) { + throw new GmSSLException(""); + } + + if (GmSSLJNI.sm4_encrypt(sm4_key, in, in_offset, out, out_offset) != 1) { + throw new GmSSLException(""); + } + } +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java new file mode 100644 index 0000000..a3aa981 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java @@ -0,0 +1,160 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/12 + * @description + */ +public class SM4CBC extends SM4Engine { + + public final static int IV_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + + private long sm4_cbc_ctx = 0; + + private byte[] iv; + + private boolean do_encrypt = true; + + private boolean inited = false; + + private int offset = 0; + + public SM4CBC() { + super(); + ctx(); + } + + + @Override + protected byte[] engineGetIV() { + return iv; + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random){ + if (!(params instanceof IvParameterSpec)) { + throw new GmSSLException("need the IvParameterSpec parameter"); + } + this.iv = ((IvParameterSpec) params).getIV(); + this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); + init(key.getEncoded(), iv, do_encrypt); + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + int outLen = update(input, inputOffset, inputLen, output, outputOffset); + this.offset+=outLen; + return outLen; + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + this.engineUpdate(input, inputOffset, inputLen, output, outputOffset); + int outLen = doFinal(output, this.offset); + outLen = outLen + this.offset; + this.offset = 0; + return outLen; + } + + private void ctx() { + if ((this.sm4_cbc_ctx = GmSSLJNI.sm4_cbc_ctx_new()) == 0) { + throw new GmSSLException(""); + } + this.inited = false; + } + + private void init(byte[] key, byte[] iv, boolean do_encrypt) { + if (key == null + || key.length != this.KEY_SIZE + || iv == null + || iv.length != this.IV_SIZE) { + throw new GmSSLException(""); + } + + if (do_encrypt == true) { + if (GmSSLJNI.sm4_cbc_encrypt_init(this.sm4_cbc_ctx, key, iv) != 1) { + throw new GmSSLException(""); + } + } else { + if (GmSSLJNI.sm4_cbc_decrypt_init(this.sm4_cbc_ctx, key, iv) != 1) { + throw new GmSSLException(""); + } + } + + this.do_encrypt = do_encrypt; + this.inited = true; + } + + private int update(byte[] in, int in_offset, int inlen, byte[] out, int out_offset) { + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (in == null + || in_offset < 0 + || inlen < 0 + || in_offset + inlen <= 0 + || in.length < in_offset + inlen) { + throw new GmSSLException(""); + } + if (out == null + || out_offset < 0 + || out.length < out_offset) { + throw new GmSSLException(""); + } + + int outlen; + if (this.do_encrypt) { + if ((outlen = GmSSLJNI.sm4_cbc_encrypt_update(this.sm4_cbc_ctx, in, in_offset, inlen, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + } else { + if ((outlen = GmSSLJNI.sm4_cbc_decrypt_update(this.sm4_cbc_ctx, in, in_offset, inlen, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + } + + return outlen; + } + + private int doFinal(byte[] out, int out_offset) { + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (out == null + || out_offset < 0 + || out.length < out_offset) { + throw new GmSSLException(""); + } + + int outlen; + if (this.do_encrypt) { + if ((outlen = GmSSLJNI.sm4_cbc_encrypt_finish(this.sm4_cbc_ctx, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + } else { + if ((outlen = GmSSLJNI.sm4_cbc_decrypt_finish(this.sm4_cbc_ctx, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + } + + this.inited = false; + return outlen; + } + +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java new file mode 100644 index 0000000..62a5312 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java @@ -0,0 +1,131 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/13 + * @description + */ +public class SM4CTR extends SM4Engine { + + public final static int IV_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + + private byte[] iv; + + private long sm4_ctr_ctx = 0; + private boolean inited = false; + + private int offset; + + public SM4CTR() { + super(); + ctx(); + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { + if (!(params instanceof IvParameterSpec)) { + throw new GmSSLException("need the IvParameterSpec parameter"); + } + this.iv = ((IvParameterSpec) params).getIV(); + init(key.getEncoded(), iv); + } + + @Override + protected byte[] engineGetIV() { + return iv; + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + int outLen = update(input, inputOffset, inputLen, output, outputOffset); + this.offset += outLen; + return outLen; + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + engineUpdate(input, inputOffset, inputLen, output, outputOffset); + int outLen = doFinal(output, this.offset); + outLen = outLen + this.offset; + this.offset = 0; + return outLen; + } + + + public void ctx(){ + if ((this.sm4_ctr_ctx = GmSSLJNI.sm4_ctr_ctx_new()) == 0) { + throw new GmSSLException(""); + } + this.inited = false; + } + + public void init(byte[] key, byte[] iv) { + if (key == null + || key.length != this.KEY_SIZE + || iv == null + || iv.length != this.IV_SIZE) { + throw new GmSSLException(""); + } + + if (GmSSLJNI.sm4_ctr_encrypt_init(this.sm4_ctr_ctx, key, iv) != 1) { + throw new GmSSLException(""); + } + + this.inited = true; + } + + public int update(byte[] in, int in_offset, int inlen, byte[] out, int out_offset) { + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (in == null + || in_offset < 0 + || inlen < 0 + || in_offset + inlen <= 0 + || in.length < in_offset + inlen) { + throw new GmSSLException(""); + } + if (out == null + || out_offset < 0 + || out.length < out_offset) { + throw new GmSSLException(""); + } + + int outlen; + if ((outlen = GmSSLJNI.sm4_ctr_encrypt_update(this.sm4_ctr_ctx, in, in_offset, inlen, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + return outlen; + } + + public int doFinal(byte[] out, int out_offset){ + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (out == null + || out_offset < 0 + || out.length < out_offset) { + throw new GmSSLException(""); + } + + int outlen; + if ((outlen = GmSSLJNI.sm4_ctr_encrypt_finish(this.sm4_ctr_ctx, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + this.inited = false; + return outlen; + } +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Cbc.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Cbc.java deleted file mode 100644 index 42c8cdb..0000000 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Cbc.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.gmssl.crypto.symmetric; - -import org.gmssl.GmSSLException; -import org.gmssl.GmSSLJNI; - -import javax.crypto.spec.IvParameterSpec; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -/** - * @author yongfeili - * @date 2024/8/12 - * @description - */ -public class SM4Cbc extends SM4Cipher{ - - public final static int IV_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; - - private long sm4_cbc_ctx = 0; - - private byte[] iv; - - public SM4Cbc() { - super(); - } - - @Override - protected byte[] engineGetIV() { - return iv; - } - - @Override - protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - if (!(params instanceof IvParameterSpec)) { - throw new GmSSLException("need the IvParameterSpec parameter"); - } - this.iv = ((IvParameterSpec) params).getIV(); - - } -} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java index 81587ed..41bec9a 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java @@ -1,10 +1,6 @@ package org.gmssl.crypto.symmetric; -import org.gmssl.GmSSLException; -import org.gmssl.GmSSLJNI; - import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; import java.nio.ByteBuffer; import java.security.*; import java.security.spec.AlgorithmParameterSpec; @@ -16,25 +12,7 @@ */ public class SM4Cipher extends CipherSpi { - public final static int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; - public final static int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; - - private long sm4_key = 0; - - private Key key; - - private boolean do_encrypt = false; - - /** - * 加密模式 CBC、CTR、GCM、ECB - */ - private String mode; - /** - * 填充模式 PKCS5Padding、NoPadding等 - */ - private String padding; - - private ByteBuffer buffer; + private SM4Engine sm4Engine; public SM4Cipher() { super(); @@ -43,19 +21,19 @@ public SM4Cipher() { @Override protected void engineSetMode(String mode) throws NoSuchAlgorithmException { // 设置加密模式 - this.mode = mode; + this.sm4Engine = SM4CipherFactory.createCipher(mode); } @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { // 设置填充方式,可以选择支持PKCS5Padding,NoPadding等 - this.padding = padding; + System.out.println("padding2:" + padding); } @Override protected int engineGetBlockSize() { // SM4块大小为16字节 - return KEY_SIZE; + return SM4Engine.BLOCK_SIZE; } @Override @@ -67,7 +45,7 @@ protected int engineGetOutputSize(int inputLen) { @Override protected byte[] engineGetIV() { // ECB模式不使用IV - return null; + return sm4Engine.engineGetIV(); } @Override @@ -78,16 +56,12 @@ protected AlgorithmParameters engineGetParameters() { @Override protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - if (!(key instanceof SecretKey)) { - throw new GmSSLException("Invalid KeySpec"); - } - this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); - this.key = key; - init(); + } @Override protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + sm4Engine.engineInit(opmode, key, params, random); } @@ -98,58 +72,35 @@ protected void engineInit(int opmode, Key key, AlgorithmParameters params, Secur @Override protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { - return new byte[0]; + + return null; } @Override protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { - return 0; + int outLen = sm4Engine.engineUpdate(input, inputOffset, inputLen, output, outputOffset); + return outLen; } @Override protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { - return new byte[0]; + + return null; } @Override protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - encrypt(input,inputOffset,output,outputOffset); - return output.length; - } - - private void init(){ - if ((sm4_key = GmSSLJNI.sm4_key_new()) == 0) { - throw new GmSSLException(""); - } - - if (do_encrypt == true) { - if (GmSSLJNI.sm4_set_encrypt_key(sm4_key, key.getEncoded()) != 1) { - throw new GmSSLException(""); - } - } else { - if (GmSSLJNI.sm4_set_decrypt_key(sm4_key, key.getEncoded()) != 1) { - throw new GmSSLException(""); - } - } - } - - - public void encrypt(byte[] in, int in_offset, byte[] out, int out_offset) { - if (in == null - || in_offset < 0 - || in_offset + this.BLOCK_SIZE <= 0 - || in_offset + this.BLOCK_SIZE > in.length) { - throw new GmSSLException(""); - } - if (out == null - || out_offset < 0 - || out_offset + this.BLOCK_SIZE <= 0 - || out_offset + this.BLOCK_SIZE > in.length) { - throw new GmSSLException(""); - } - - if (GmSSLJNI.sm4_encrypt(sm4_key, in, in_offset, out, out_offset) != 1) { - throw new GmSSLException(""); - } + int outLen = sm4Engine.engineDoFinal(input, inputOffset, inputLen, output, outputOffset); + return outLen; + } + + @Override + protected void engineUpdateAAD(byte[] src, int offset, int len) { + super.engineUpdateAAD(src, offset, len); + } + + @Override + protected void engineUpdateAAD(ByteBuffer src) { + super.engineUpdateAAD(src); } } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java new file mode 100644 index 0000000..f47e917 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java @@ -0,0 +1,37 @@ +package org.gmssl.crypto.symmetric; + +import java.security.NoSuchAlgorithmException; + +/** + * @author yongfeili + * @date 2024/8/13 + * @description + */ +public class SM4CipherFactory { + + public static SM4Engine createCipher(String mode){ + SM4Engine cipher; + try { + switch (mode.toUpperCase()) { + case "ECB": + cipher = new SM4ECB(); + break; + case "CBC": + cipher = new SM4CBC(); + break; + case "CTR": + cipher = new SM4CTR(); + break; + case "GCM": + cipher = new SM4GCM(); + break; + default: + throw new NoSuchAlgorithmException("Unsupported mode: " + mode); + } + }catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + return cipher; + } + +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java b/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java new file mode 100644 index 0000000..7a500b3 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java @@ -0,0 +1,35 @@ +package org.gmssl.crypto.symmetric; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.ShortBufferException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/13 + * @description + */ +public class SM4ECB extends SM4Engine { + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { + + } + + @Override + protected byte[] engineGetIV() { + return new byte[0]; + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + return 0; + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + return 0; + } +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java new file mode 100644 index 0000000..a31a859 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java @@ -0,0 +1,34 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLJNI; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.ShortBufferException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/14 + * @description + */ +public abstract class SM4Engine { + + public static final int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; + + public static final int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + + protected abstract void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random); + + protected abstract byte[] engineGetIV(); + + protected abstract int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException; + + protected abstract int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException; + + //String getAlgorithmName(); + + //int getBlockSize(); +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java new file mode 100644 index 0000000..65a2175 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java @@ -0,0 +1,164 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.ShortBufferException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/13 + * @description + */ +public class SM4GCM extends SM4Engine { + + public final static int MIN_IV_SIZE = GmSSLJNI.SM4_GCM_MIN_IV_SIZE; + public final static int MAX_IV_SIZE = GmSSLJNI.SM4_GCM_MAX_IV_SIZE; + public final static int DEFAULT_IV_SIZE = GmSSLJNI.SM4_GCM_DEFAULT_IV_SIZE; + public final static int MIN_TAG_SIZE = 8; + public final static int MAX_TAG_SIZE = GmSSLJNI.SM4_GCM_MAX_TAG_SIZE; + + private long sm4_gcm_ctx = 0; + private boolean do_encrypt = true; + private boolean inited = false; + + private byte[] iv; + + private int offset; + + public SM4GCM(){ + super(); + ctx(); + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { + if (!(params instanceof AadAlgorithmParameters)){ + throw new GmSSLException("need the AadAlgorithmParameters parameter"); + } + this.iv = ((AadAlgorithmParameters) params).getIV(); + int tLen = ((AadAlgorithmParameters) params).getTLen(); + byte[] aad = ((AadAlgorithmParameters) params).getAad(); + + this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); + init(key.getEncoded(), iv,aad, tLen, do_encrypt); + } + + @Override + protected byte[] engineGetIV() { + return iv; + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + int outLen = update(input, inputOffset, inputLen, output, outputOffset); + this.offset+=outLen; + return outLen; + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + engineUpdate(input, inputOffset, inputLen, output, outputOffset); + int outLen = doFinal(output, this.offset); + outLen = outLen + this.offset; + this.offset = 0; + return outLen; + } + + private void ctx(){ + if ((this.sm4_gcm_ctx = GmSSLJNI.sm4_gcm_ctx_new()) == 0) { + throw new GmSSLException(""); + } + this.inited = false; + } + + private void init(byte[] key, byte[] iv, byte[] aad, int taglen, boolean do_encrypt){ + if (key == null + || key.length != this.KEY_SIZE + || iv == null + || iv.length < this.MIN_IV_SIZE + || iv.length > this.MAX_IV_SIZE + || taglen < this.MIN_TAG_SIZE + || taglen > this.MAX_TAG_SIZE) { + throw new GmSSLException(""); + } + + if (do_encrypt == true) { + if (GmSSLJNI.sm4_gcm_encrypt_init(this.sm4_gcm_ctx, key, iv, aad, taglen) != 1) { + throw new GmSSLException(""); + } + } else { + if (GmSSLJNI.sm4_gcm_decrypt_init(this.sm4_gcm_ctx, key, iv, aad, taglen) != 1) { + throw new GmSSLException(""); + } + } + + this.do_encrypt = do_encrypt; + this.inited = true; + } + + private int update(byte[] in, int in_offset, int inlen, byte[] out, int out_offset){ + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (in == null + || in_offset < 0 + || inlen < 0 + || in_offset + inlen <= 0 + || in.length < in_offset + inlen) { + throw new GmSSLException(""); + } + if (out == null + || out_offset < 0 + || out.length < out_offset) { + throw new GmSSLException(""); + } + + int outlen; + if (this.do_encrypt) { + if ((outlen = GmSSLJNI.sm4_gcm_encrypt_update(this.sm4_gcm_ctx, in, in_offset, inlen, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + } else { + if ((outlen = GmSSLJNI.sm4_gcm_decrypt_update(this.sm4_gcm_ctx, in, in_offset, inlen, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + } + + return outlen; + } + + private int doFinal(byte[] out, int out_offset) { + + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (out == null + || out_offset < 0 + || out.length < out_offset) { + throw new GmSSLException(""); + } + + int outlen; + if (this.do_encrypt) { + if ((outlen = GmSSLJNI.sm4_gcm_encrypt_finish(this.sm4_gcm_ctx, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + } else { + if ((outlen = GmSSLJNI.sm4_gcm_decrypt_finish(this.sm4_gcm_ctx, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + } + + this.inited = false; + return outlen; + } +} diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index 4487b07..83a3cc8 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -1,17 +1,18 @@ package org.gmssl; -import org.gmssl.crypto.asymmetric.SM2PrivateKey; -import org.gmssl.crypto.asymmetric.SM2PublicKey; +import org.gmssl.crypto.asymmetric.*; import org.gmssl.crypto.digest.SM3Pbkdf2; +import org.gmssl.crypto.symmetric.*; +import org.junit.Before; +import org.junit.Test; -import javax.crypto.Cipher; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger; import java.security.*; +import java.util.Arrays; /** * @author yongfeili @@ -22,12 +23,17 @@ */ public class JceTest { - public static void main(String[] args) { + @Before + public void beforeTest(){ + Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); + } + + public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException { // 动态添加提供者 Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); - //SM2Test(); + SM2Test(); //SM3Test(); - SM4Test(); + //SM4Test(); } public static void SM2Test() { @@ -127,14 +133,43 @@ public static void SM3Test() { public static void SM4Test() { try { + String text="Hello, GmSSL"; SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); byte[] randomBytes = new byte[32]; secureRandom.nextBytes(randomBytes); System.out.println("Generated Random Bytes: " + byteToHex(randomBytes)); - Cipher sm4Cipher = Cipher.getInstance("SM4/CBC/PKCS5Padding", "GmSSL"); + /*// 测试SM4加密,固定16个长度 + Cipher sm4Cipher = Cipher.getInstance("SM4", "GmSSL"); + SecretKeySpec sm4Key = new SecretKeySpec(secureRandom.generateSeed(SM4.KEY_SIZE), "SM4"); + sm4Cipher.init(Cipher.ENCRYPT_MODE, sm4Key); + sm4Cipher.update("87654321".getBytes(),0, 8); + byte[] ciphertext = sm4Cipher.doFinal("12345678".getBytes(), 0, 8); + System.out.println("Ciphertext: " + byteToHex(ciphertext)); + // 测试SM4解密 + sm4Cipher.init(Cipher.DECRYPT_MODE, sm4Key); + byte[] plaintext = sm4Cipher.doFinal(ciphertext, 0, 16); + System.out.println("plaintext: " + new String(plaintext));*/ + Cipher sm4cbcCipher = Cipher.getInstance("SM4/CBC/PKCS5Padding", "GmSSL"); + byte[] key = secureRandom.generateSeed(SM4CBC.KEY_SIZE); + byte[] iv = secureRandom.generateSeed(SM4CBC.IV_SIZE); + sm4cbcCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); + byte[] plaintext = ("text:"+text).getBytes(); + int inputOffset = "text:".getBytes().length; + int inputLen = plaintext.length - inputOffset; + byte[] ciphertext = new byte[inputLen+SM4CBC.BLOCK_SIZE]; + //int test= sm4cbcCipher.update("abc".getBytes(), 0, 3, ciphertext, 0); + int cipherlen = sm4cbcCipher.doFinal(plaintext, inputOffset, inputLen,ciphertext, 0); + byte[] ciphertext1 = Arrays.copyOfRange(ciphertext,0,cipherlen); + System.out.println("Ciphertext: " + byteToHex(ciphertext1)); + sm4cbcCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); + byte[] plaintext1 = new byte[ciphertext1.length + SM4CBC.BLOCK_SIZE]; + int decryptedLen = sm4cbcCipher.doFinal(ciphertext1, 0,ciphertext1.length, plaintext1,0); + byte[] plaintext2 =Arrays.copyOfRange(plaintext1,0,decryptedLen); + String plaintextStr=new String(plaintext2); + System.out.println("plaintext: " + plaintextStr); } catch (Exception e) { e.printStackTrace(); } @@ -142,6 +177,99 @@ public static void SM4Test() { } + @Test + public void SM4_CTR_test() throws Exception{ + SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); + Cipher sm4Cipher = Cipher.getInstance("SM4/CTR/NoPadding", "GmSSL"); + byte[] key = secureRandom.generateSeed(SM4CTR.KEY_SIZE); + byte[] iv = secureRandom.generateSeed(SM4CTR.IV_SIZE); + sm4Cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); + byte[] ciphertext = new byte[64]; + sm4Cipher.update("abc".getBytes(), 0, "abc".length(), ciphertext, 0); + sm4Cipher.update("12345678".getBytes(), 0, "12345678".length(), ciphertext, 0); + sm4Cipher.update("xxyyyzzz".getBytes(), 0, "xxyyyzzz".length(), ciphertext, 0); + int cipherlen = sm4Cipher.doFinal("gmssl".getBytes(), 0, "gmssl".length(), ciphertext, 0); + byte[] ciphertext1 = Arrays.copyOfRange(ciphertext,0,cipherlen); + System.out.println("Ciphertext: " + byteToHex(ciphertext1)); + + byte[] plaintext = new byte[64]; + sm4Cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); + int plainlen = sm4Cipher.doFinal(ciphertext, 0, cipherlen, plaintext, 0); + byte[] plaintext1 = Arrays.copyOfRange(plaintext,0,plainlen); + System.out.println("plaintext: " + new String(plaintext1)); + } + + @Test + public void SM4_GCM_test() throws Exception { + SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); + Cipher sm4Cipher = Cipher.getInstance("SM4/GCM/ZeroPadding", "GmSSL"); + byte[] key = secureRandom.generateSeed(SM4CTR.KEY_SIZE); + byte[] iv = secureRandom.generateSeed(SM4CTR.IV_SIZE); + byte[] aad = "Hello: ".getBytes(); + sm4Cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new AadAlgorithmParameters(SM4GCM.MAX_TAG_SIZE,iv,aad)); + sm4Cipher.updateAAD(aad); + //TODO fix aad不需要专门建立参数 + byte[] ciphertext = new byte[64]; + int cipherlen = sm4Cipher.doFinal("abc".getBytes(), 0, 3, ciphertext, 0); + System.out.println("Ciphertext: " + byteToHex(ciphertext)); + + byte[] plaintext = new byte[64]; + sm4Cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new AadAlgorithmParameters(SM4GCM.MAX_TAG_SIZE,iv,aad)); + int plainlen =sm4Cipher.doFinal(ciphertext, 0, cipherlen, plaintext, 0); + byte[] plaintext1 = Arrays.copyOfRange(plaintext,0,plainlen); + System.out.println("plaintext: " + new String(plaintext1)); + } + + @Test + public void SM9_cipher_test() throws Exception{ + String text="Hello, GmSSL"; + SM9EncMasterKeyGenParameterSpec sm9EncMasterKeyGenParameterSpec = new SM9EncMasterKeyGenParameterSpec("bob"); + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM9", "GmSSL"); + keyPairGen.initialize(sm9EncMasterKeyGenParameterSpec); + keyPairGen.generateKeyPair(); + + PublicKey publicKey = keyPairGen.genKeyPair().getPublic(); + Cipher sm9Cipher = Cipher.getInstance("SM9", "GmSSL"); + sm9Cipher.init(Cipher.ENCRYPT_MODE, publicKey,sm9EncMasterKeyGenParameterSpec); + byte[] ciphertext = sm9Cipher.doFinal(text.getBytes()); + System.out.println("Ciphertext: " + byteToHex(ciphertext)); + + SM9PrivateKey privateKey= (SM9PrivateKey) keyPairGen.genKeyPair().getPrivate(); + SM9MasterKey masterKey = (SM9MasterKey)privateKey.getOuterKey(); + SM9UserKey userKey= masterKey.extractKey(sm9EncMasterKeyGenParameterSpec.getId()); + sm9Cipher.init(Cipher.DECRYPT_MODE, userKey.privateKey); + byte[] plaintext = sm9Cipher.doFinal(ciphertext); + System.out.println("plaintext: " + new String(plaintext)); + } + + @Test + public void SM9_sign_test() throws Exception{ + String text="Hello, GmSSL"; + SM9SignMasterKeyGenParameterSpec sm9SignMasterKeyGenParameterSpec = new SM9SignMasterKeyGenParameterSpec("alice"); + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM9", "GmSSL"); + keyPairGen.initialize(sm9SignMasterKeyGenParameterSpec); + keyPairGen.generateKeyPair(); + + Signature signature = Signature.getInstance("SM9", "GmSSL"); + // 测试签名 + SM9PrivateKey privateKey= (SM9PrivateKey) keyPairGen.genKeyPair().getPrivate(); + SM9MasterKey masterKey = (SM9MasterKey)privateKey.getOuterKey(); + SM9UserKey userKey= masterKey.extractKey(sm9SignMasterKeyGenParameterSpec.getId()); + signature.initSign(userKey.privateKey); + byte[] signatureText = text.getBytes(); + signature.update(signatureText); + byte[] signatureByte = signature.sign(); + System.out.println("Signature:"+byteToHex(signatureByte)); + // 测试验签 + signature.setParameter(sm9SignMasterKeyGenParameterSpec); + PublicKey publicKey= keyPairGen.genKeyPair().getPublic(); + signature.initVerify(publicKey); + signature.update(signatureText); + boolean signatureResult = signature.verify(signatureByte); + System.out.println("SignatureResult:"+signatureResult); + } + + /** * convert byte array to hex string * @param btArr From db790590f582eeeb7450b20de984f54980ded1d4 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Thu, 22 Aug 2024 12:06:03 +0800 Subject: [PATCH 08/20] sm4 sm9 jce develop --- src/main/java/org/gmssl/crypto/Decryptor.java | 9 --------- .../java/org/gmssl/crypto/asymmetric/SM9Cipher.java | 2 +- .../gmssl/crypto/asymmetric/SM9EncMasterKey.java | 4 ++-- .../org/gmssl/crypto/asymmetric/SM9EncUserKey.java | 2 +- .../org/gmssl/crypto/asymmetric/SM9MasterKey.java | 13 ++++++++++--- .../org/gmssl/crypto/asymmetric/SM9PrivateKey.java | 2 +- .../gmssl/crypto/asymmetric/SM9SignMasterKey.java | 4 ++-- .../org/gmssl/crypto/asymmetric/SM9SignUserKey.java | 2 +- .../org/gmssl/crypto/asymmetric/SM9UserKey.java | 6 +++++- src/test/java/org/gmssl/JceTest.java | 8 ++++---- 10 files changed, 27 insertions(+), 25 deletions(-) delete mode 100644 src/main/java/org/gmssl/crypto/Decryptor.java diff --git a/src/main/java/org/gmssl/crypto/Decryptor.java b/src/main/java/org/gmssl/crypto/Decryptor.java deleted file mode 100644 index bcde33f..0000000 --- a/src/main/java/org/gmssl/crypto/Decryptor.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.gmssl.crypto; - -/** - * @author yongfeili - * @date 2024/8/22 - * @description - */ -public interface Decryptor { -} diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java index 05a380f..d8daf05 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java @@ -61,7 +61,7 @@ protected void engineInit(int opmode, Key key, SecureRandom random) throws Inval this.opmode = opmode; this.key = key; SM9PrivateKey privateKey = (SM9PrivateKey)key; - SM9UserKey userKey = (SM9UserKey)privateKey.getOuterKey(); + SM9UserKey userKey = (SM9UserKey)privateKey.getSecretKey(); this.id = userKey.getId(); // 初始化缓冲区 this.buffer = ByteBuffer.allocate(2048); diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java index 58d314e..382a060 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java @@ -86,7 +86,7 @@ public void exportEncryptedPrivateKeyInfoPem(String pass, String file) { } } - public SM9EncMasterKey getOuterKey() { + public SM9EncMasterKey getSecretKey() { return SM9EncMasterKey.this; } @@ -102,7 +102,7 @@ public void generateMasterKey() { has_private_key = true; } - public long getOuterKey() { + public long getSecretKey() { if (master_key == 0) { throw new GmSSLException(""); } diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java index c40df08..d74d46c 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java @@ -48,7 +48,7 @@ public byte[] decrypt(byte[] ciphertext) { } return plaintext; } - public SM9EncUserKey getOuterKey() { + public SM9EncUserKey getSecretKey() { return SM9EncUserKey.this; } } diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java index d208733..7fe3d8f 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java @@ -14,14 +14,21 @@ public abstract class SM9MasterKey implements KeySpec { protected boolean has_private_key; - public SM9PublicKey publicKey; + protected SM9PublicKey publicKey; - public SM9PrivateKey privateKey; + protected SM9PrivateKey privateKey; public abstract void generateMasterKey(); - public abstract long getOuterKey(); + public abstract long getSecretKey(); public abstract SM9UserKey extractKey(String id); + public SM9PublicKey getPublicKey() { + return this.publicKey; + } + + public SM9PrivateKey getPrivateKey() { + return this.privateKey; + } } diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java index a4491ff..14c47c8 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java @@ -25,7 +25,7 @@ public byte[] getEncoded() { return new byte[0]; } - public abstract KeySpec getOuterKey(); + public abstract KeySpec getSecretKey(); public abstract void importEncryptedPrivateKeyInfoPem(String pass, String file); diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java index 16773b5..03b7c5f 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java @@ -78,7 +78,7 @@ public void exportEncryptedPrivateKeyInfoPem(String pass, String file) { } } - public SM9SignMasterKey getOuterKey() { + public SM9SignMasterKey getSecretKey() { return SM9SignMasterKey.this; } @@ -93,7 +93,7 @@ public void generateMasterKey() { this.has_private_key = true; } - public long getOuterKey() { + public long getSecretKey() { if (this.master_key == 0) { throw new GmSSLException(""); } diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java index 6fb95ea..efd02cc 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java @@ -43,7 +43,7 @@ public byte[] sign(long sm9_sign_ctx) { return signature; } - public SM9SignUserKey getOuterKey() { + public SM9SignUserKey getSecretKey() { return SM9SignUserKey.this; } diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java index 831f859..bb98d84 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java @@ -13,7 +13,7 @@ public abstract class SM9UserKey implements KeySpec { protected String id; - public SM9PrivateKey privateKey; + protected SM9PrivateKey privateKey; protected SM9UserKey(long key, String id) { this.sm9_key = key; @@ -23,4 +23,8 @@ protected SM9UserKey(long key, String id) { public String getId() { return this.id; } + + public SM9PrivateKey getPrivateKey() { + return this.privateKey; + } } diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index 83a3cc8..aad0399 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -235,9 +235,9 @@ public void SM9_cipher_test() throws Exception{ System.out.println("Ciphertext: " + byteToHex(ciphertext)); SM9PrivateKey privateKey= (SM9PrivateKey) keyPairGen.genKeyPair().getPrivate(); - SM9MasterKey masterKey = (SM9MasterKey)privateKey.getOuterKey(); + SM9MasterKey masterKey = (SM9MasterKey)privateKey.getSecretKey(); SM9UserKey userKey= masterKey.extractKey(sm9EncMasterKeyGenParameterSpec.getId()); - sm9Cipher.init(Cipher.DECRYPT_MODE, userKey.privateKey); + sm9Cipher.init(Cipher.DECRYPT_MODE, userKey.getPrivateKey()); byte[] plaintext = sm9Cipher.doFinal(ciphertext); System.out.println("plaintext: " + new String(plaintext)); } @@ -253,9 +253,9 @@ public void SM9_sign_test() throws Exception{ Signature signature = Signature.getInstance("SM9", "GmSSL"); // 测试签名 SM9PrivateKey privateKey= (SM9PrivateKey) keyPairGen.genKeyPair().getPrivate(); - SM9MasterKey masterKey = (SM9MasterKey)privateKey.getOuterKey(); + SM9MasterKey masterKey = (SM9MasterKey)privateKey.getSecretKey(); SM9UserKey userKey= masterKey.extractKey(sm9SignMasterKeyGenParameterSpec.getId()); - signature.initSign(userKey.privateKey); + signature.initSign(userKey.getPrivateKey()); byte[] signatureText = text.getBytes(); signature.update(signatureText); byte[] signatureByte = signature.sign(); From e77f7d711eb2e3845e2262306d6c44c7a7786339 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Fri, 23 Aug 2024 16:57:55 +0800 Subject: [PATCH 09/20] sm4 sm9 jce develop --- .../symmetric/AadAlgorithmParameters.java | 32 ------------------- .../java/org/gmssl/crypto/symmetric/SM4.java | 2 ++ .../org/gmssl/crypto/symmetric/SM4CBC.java | 5 +++ .../org/gmssl/crypto/symmetric/SM4CTR.java | 5 +++ .../org/gmssl/crypto/symmetric/SM4Cipher.java | 6 +--- .../org/gmssl/crypto/symmetric/SM4ECB.java | 5 +++ .../org/gmssl/crypto/symmetric/SM4Engine.java | 3 ++ .../org/gmssl/crypto/symmetric/SM4GCM.java | 29 +++++++++++++---- src/test/java/org/gmssl/JceTest.java | 23 ++++++------- 9 files changed, 53 insertions(+), 57 deletions(-) delete mode 100644 src/main/java/org/gmssl/crypto/symmetric/AadAlgorithmParameters.java diff --git a/src/main/java/org/gmssl/crypto/symmetric/AadAlgorithmParameters.java b/src/main/java/org/gmssl/crypto/symmetric/AadAlgorithmParameters.java deleted file mode 100644 index 04bb2fe..0000000 --- a/src/main/java/org/gmssl/crypto/symmetric/AadAlgorithmParameters.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.gmssl.crypto.symmetric; - -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.IvParameterSpec; - -/** - * @author yongfeili - * @date 2024/8/14 - * @description - */ - -public class AadAlgorithmParameters extends GCMParameterSpec { - - protected byte[] aad; - - public AadAlgorithmParameters(int tLen, byte[] iv) { - super(tLen, iv); - } - - public AadAlgorithmParameters(int tLen, byte[] iv,byte[] aad) { - super(tLen, iv); - this.aad = aad; - } - - public byte[] getAad() { - return aad; - } - - public void setAad(byte[] aad) { - this.aad = aad; - } -} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4.java b/src/main/java/org/gmssl/crypto/symmetric/SM4.java index 3a2bbcb..f856678 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4.java @@ -78,6 +78,8 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] return output.length; } + + private void init(){ if ((sm4_key = GmSSLJNI.sm4_key_new()) == 0) { throw new GmSSLException(""); diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java index a3aa981..76a7a27 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java @@ -70,6 +70,11 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] return outLen; } + @Override + protected void engineUpdateAAD(byte[] src, int offset, int len) { + + } + private void ctx() { if ((this.sm4_cbc_ctx = GmSSLJNI.sm4_cbc_ctx_new()) == 0) { throw new GmSSLException(""); diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java index 62a5312..dd18b03 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java @@ -62,6 +62,11 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] return outLen; } + @Override + protected void engineUpdateAAD(byte[] src, int offset, int len) { + + } + public void ctx(){ if ((this.sm4_ctr_ctx = GmSSLJNI.sm4_ctr_ctx_new()) == 0) { diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java index 41bec9a..55a7ab1 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java @@ -96,11 +96,7 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] @Override protected void engineUpdateAAD(byte[] src, int offset, int len) { - super.engineUpdateAAD(src, offset, len); + sm4Engine.engineUpdateAAD(src, offset, len); } - @Override - protected void engineUpdateAAD(ByteBuffer src) { - super.engineUpdateAAD(src); - } } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java b/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java index 7a500b3..ba368c1 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java @@ -32,4 +32,9 @@ protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] o protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { return 0; } + + @Override + protected void engineUpdateAAD(byte[] src, int offset, int len) { + + } } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java index a31a859..d7797ff 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java @@ -5,6 +5,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.ShortBufferException; +import java.nio.ByteBuffer; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; @@ -28,6 +29,8 @@ public abstract class SM4Engine { protected abstract int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException; + protected abstract void engineUpdateAAD(byte[] src, int offset, int len); + //String getAlgorithmName(); //int getBlockSize(); diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java index 65a2175..de0e1ba 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java @@ -7,6 +7,9 @@ import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.ShortBufferException; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import java.nio.ByteBuffer; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; @@ -30,6 +33,12 @@ public class SM4GCM extends SM4Engine { private byte[] iv; + private byte[] aad; + + private Key key; + + private int tLen; + private int offset; public SM4GCM(){ @@ -39,15 +48,13 @@ public SM4GCM(){ @Override protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { - if (!(params instanceof AadAlgorithmParameters)){ - throw new GmSSLException("need the AadAlgorithmParameters parameter"); + if (!(params instanceof GCMParameterSpec)) { + throw new GmSSLException("need the GCMParameterSpec parameter"); } - this.iv = ((AadAlgorithmParameters) params).getIV(); - int tLen = ((AadAlgorithmParameters) params).getTLen(); - byte[] aad = ((AadAlgorithmParameters) params).getAad(); - + this.key = key; + this.iv = ((GCMParameterSpec) params).getIV(); + this.tLen = ((GCMParameterSpec) params).getTLen(); this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); - init(key.getEncoded(), iv,aad, tLen, do_encrypt); } @Override @@ -71,6 +78,14 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] return outLen; } + @Override + protected void engineUpdateAAD(byte[] src, int offset, int len) { + this.aad = new byte[len]; + System.arraycopy(src, offset, this.aad, 0, len); + + init(key.getEncoded(), iv,aad,tLen, do_encrypt); + } + private void ctx(){ if ((this.sm4_gcm_ctx = GmSSLJNI.sm4_gcm_ctx_new()) == 0) { throw new GmSSLException(""); diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index aad0399..fa4ec4d 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import javax.crypto.*; +import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; @@ -131,8 +132,8 @@ public static void SM3Test() { } } - public static void SM4Test() { - try { + @Test + public void SM4_CBC_test() throws Exception{ String text="Hello, GmSSL"; SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); byte[] randomBytes = new byte[32]; @@ -170,11 +171,6 @@ public static void SM4Test() { byte[] plaintext2 =Arrays.copyOfRange(plaintext1,0,decryptedLen); String plaintextStr=new String(plaintext2); System.out.println("plaintext: " + plaintextStr); - } catch (Exception e) { - e.printStackTrace(); - } - - } @Test @@ -201,20 +197,21 @@ public void SM4_CTR_test() throws Exception{ @Test public void SM4_GCM_test() throws Exception { + String text="Hello, GmSSL"; SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); Cipher sm4Cipher = Cipher.getInstance("SM4/GCM/ZeroPadding", "GmSSL"); - byte[] key = secureRandom.generateSeed(SM4CTR.KEY_SIZE); - byte[] iv = secureRandom.generateSeed(SM4CTR.IV_SIZE); + byte[] key = secureRandom.generateSeed(SM4GCM.KEY_SIZE); + byte[] iv = secureRandom.generateSeed(SM4GCM.DEFAULT_IV_SIZE); byte[] aad = "Hello: ".getBytes(); - sm4Cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new AadAlgorithmParameters(SM4GCM.MAX_TAG_SIZE,iv,aad)); + sm4Cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new GCMParameterSpec(SM4GCM.MAX_TAG_SIZE,iv)); sm4Cipher.updateAAD(aad); - //TODO fix aad不需要专门建立参数 byte[] ciphertext = new byte[64]; - int cipherlen = sm4Cipher.doFinal("abc".getBytes(), 0, 3, ciphertext, 0); + int cipherlen = sm4Cipher.doFinal(text.getBytes(), 0, text.getBytes().length, ciphertext, 0); System.out.println("Ciphertext: " + byteToHex(ciphertext)); byte[] plaintext = new byte[64]; - sm4Cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new AadAlgorithmParameters(SM4GCM.MAX_TAG_SIZE,iv,aad)); + sm4Cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new GCMParameterSpec(SM4GCM.MAX_TAG_SIZE,iv)); + sm4Cipher.updateAAD(aad); int plainlen =sm4Cipher.doFinal(ciphertext, 0, cipherlen, plaintext, 0); byte[] plaintext1 = Arrays.copyOfRange(plaintext,0,plainlen); System.out.println("plaintext: " + new String(plaintext1)); From fa1f5bcc2e53b53d3e35cc5336031773c1f89cd4 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Fri, 23 Aug 2024 17:02:40 +0800 Subject: [PATCH 10/20] sm4 sm9 jce develop --- src/test/java/org/gmssl/JceTest.java | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index fa4ec4d..c041ad5 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -29,17 +29,8 @@ public void beforeTest(){ Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); } - public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException { - // 动态添加提供者 - Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); - SM2Test(); - //SM3Test(); - //SM4Test(); - } - - public static void SM2Test() { - // 尝试获取Cipher实例 - try { + @Test + public void SM2Test() throws Exception{ KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM2", "GmSSL"); keyPairGen.initialize(256); KeyPair keyPair = keyPairGen.generateKeyPair(); @@ -94,13 +85,10 @@ public static void SM2Test() { signatureImport.update(signatureText); boolean signatureResultImport = signatureImport.verify(signatureByteImport); System.out.println("SignatureResult:"+signatureResultImport); - } catch (Exception e) { - e.printStackTrace(); - } } - public static void SM3Test() { - try { + @Test + public void SM3Test() throws Exception{ String text="Hello, GmSSL"; //测试SM3哈希 MessageDigest sm3Digest = MessageDigest.getInstance("SM3","GmSSL"); @@ -127,9 +115,6 @@ public static void SM3Test() { SecretKey key = skf.generateSecret(spec); byte[] keyBytes = key.getEncoded(); System.out.println("DerivedKey: " + byteToHex(keyBytes)); - } catch (Exception e) { - e.printStackTrace(); - } } @Test From ab25d00a919c9e2e1eb650ac917c1f4cd1f5b957 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Mon, 26 Aug 2024 20:15:55 +0800 Subject: [PATCH 11/20] zuc jce develop --- .../java/org/gmssl/crypto/GmSSLProvider.java | 2 + .../org/gmssl/crypto/symmetric/ZucCipher.java | 183 ++++++++++++++++++ .../org/gmssl/crypto/symmetric/ZucKey.java | 36 ++++ src/test/java/org/gmssl/JceTest.java | 21 ++ 4 files changed, 242 insertions(+) create mode 100644 src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java create mode 100644 src/main/java/org/gmssl/crypto/symmetric/ZucKey.java diff --git a/src/main/java/org/gmssl/crypto/GmSSLProvider.java b/src/main/java/org/gmssl/crypto/GmSSLProvider.java index c1957dc..192b7ad 100644 --- a/src/main/java/org/gmssl/crypto/GmSSLProvider.java +++ b/src/main/java/org/gmssl/crypto/GmSSLProvider.java @@ -26,6 +26,8 @@ public GmSSLProvider() { put("Cipher.SM9", "org.gmssl.crypto.asymmetric.SM9Cipher"); put("Signature.SM9", "org.gmssl.crypto.asymmetric.SM9Signature"); put("KeyPairGenerator.SM9", "org.gmssl.crypto.asymmetric.SM9KeyPairGeneratorSpi"); + + put("Cipher.ZUC", "org.gmssl.crypto.symmetric.ZucCipher"); } diff --git a/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java b/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java new file mode 100644 index 0000000..195b058 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java @@ -0,0 +1,183 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author yongfeili + * @date 2024/8/26 + * @description + */ +public class ZucCipher extends CipherSpi { + + public final static int IV_SIZE = GmSSLJNI.ZUC_IV_SIZE; + public final static int BLOCK_SIZE = 4; + + private long zuc_ctx; + private boolean inited; + + private byte[] iv; + + private int offset; + + public ZucCipher(){ + ctx(); + } + + @Override + protected void engineSetMode(String mode){ + // ZUC 是流密码算法,不支持 ECB、CBC 等模式 + } + + @Override + protected void engineSetPadding(String padding){ + // ZUC 是流密码算法,不需要填充 + if (!"NoPadding".equalsIgnoreCase(padding)) { + throw new GmSSLException("Unsupported padding: " + padding); + } + } + + @Override + protected int engineGetBlockSize() { + // ZUC 是流密码算法,没有固定的块大小 + return 0; + } + + @Override + protected int engineGetOutputSize(int inputLen) { + // 输出大小与输入大小相同 + return inputLen; + } + + @Override + protected byte[] engineGetIV() { + return iv; + } + + @Override + protected AlgorithmParameters engineGetParameters() { + return null; + } + + @Override + protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { + + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + if (params instanceof IvParameterSpec) { + IvParameterSpec ivSpec = (IvParameterSpec) params; + this.iv = ivSpec.getIV(); + } else { + throw new InvalidAlgorithmParameterException("Unsupported parameters"); + } + init(key.getEncoded(), iv); + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + + } + + @Override + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { + return new byte[0]; + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + int outLen = update(input, inputOffset, inputLen, output, outputOffset); + this.offset+=outLen; + return outLen; + } + + @Override + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + return new byte[0]; + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + this.engineUpdate(input, inputOffset, inputLen, output, outputOffset); + int outLen = doFinal(output, this.offset); + outLen = outLen + this.offset; + this.offset = 0; + return outLen; + } + + private void ctx(){ + if ((this.zuc_ctx = GmSSLJNI.zuc_ctx_new()) == 0) { + throw new GmSSLException(""); + } + this.inited = false; + } + + private void init(byte[] key, byte[] iv){ + if (key == null + || key.length != ZucKey.KEY_SIZE + || iv == null + || iv.length != this.IV_SIZE) { + throw new GmSSLException(""); + } + + if (GmSSLJNI.zuc_encrypt_init(this.zuc_ctx, key, iv) != 1) { + throw new GmSSLException(""); + } + + this.inited = true; + } + + private int update(byte[] in, int in_offset, int inlen, byte[] out, int out_offset) { + + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (in == null + || in_offset < 0 + || inlen < 0 + || in_offset + inlen <= 0 + || in.length < in_offset + inlen) { + throw new GmSSLException(""); + } + if (out == null + || out_offset < 0 + || out.length < out_offset) { + throw new GmSSLException(""); + } + + int outlen; + if ((outlen = GmSSLJNI.zuc_encrypt_update(this.zuc_ctx, in, in_offset, inlen, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + + return outlen; + } + + private int doFinal(byte[] out, int out_offset) { + + if (this.inited == false) { + throw new GmSSLException(""); + } + + if (out == null + || out_offset < 0 + || out.length < out_offset) { + throw new GmSSLException(""); + } + + int outlen; + if ((outlen = GmSSLJNI.zuc_encrypt_finish(this.zuc_ctx, out, out_offset)) < 0) { + throw new GmSSLException(""); + } + + this.inited = false; + return outlen; + } +} diff --git a/src/main/java/org/gmssl/crypto/symmetric/ZucKey.java b/src/main/java/org/gmssl/crypto/symmetric/ZucKey.java new file mode 100644 index 0000000..92c9a50 --- /dev/null +++ b/src/main/java/org/gmssl/crypto/symmetric/ZucKey.java @@ -0,0 +1,36 @@ +package org.gmssl.crypto.symmetric; + +import org.gmssl.GmSSLJNI; + +import javax.crypto.SecretKey; + +/** + * @author yongfeili + * @date 2024/8/26 + * @description + */ +public class ZucKey implements SecretKey { + + public final static int KEY_SIZE = GmSSLJNI.ZUC_KEY_SIZE; + + private byte[] key; + + public ZucKey(byte[] key){ + this.key = key; + } + + @Override + public String getAlgorithm() { + return "ZUC"; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return key; + } +} diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index c041ad5..48635f4 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -117,6 +117,7 @@ public void SM3Test() throws Exception{ System.out.println("DerivedKey: " + byteToHex(keyBytes)); } + //SM4 C代码是否已进行了填充处理?填充后的密文与填充前明文长度是否一致,密文如何知道长度反向出明文?填充模式和算法模式是否是绑定的,比如GCM只能zeroPadding? @Test public void SM4_CBC_test() throws Exception{ String text="Hello, GmSSL"; @@ -251,6 +252,26 @@ public void SM9_sign_test() throws Exception{ System.out.println("SignatureResult:"+signatureResult); } + @Test + public void zuc_test() throws Exception{ + String text="Hello, GmSSL"; + SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); + Cipher cipher = Cipher.getInstance("ZUC","GmSSL"); + SecretKey key = new ZucKey(secureRandom.generateSeed(ZucKey.KEY_SIZE)); + IvParameterSpec ivParameterSpec = new IvParameterSpec(secureRandom.generateSeed(ZucCipher.IV_SIZE)); + cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec); + byte[] ciphertext = new byte[32]; + int cipherlen = cipher.doFinal(text.getBytes(), 0, text.getBytes().length, ciphertext, 0); + byte[] ciphertext1 = Arrays.copyOfRange(ciphertext,0,cipherlen); + System.out.println("Ciphertext: " + byteToHex(ciphertext1)); + + cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec); + byte[] plaintext = new byte[32]; + int plainlen = cipher.doFinal(ciphertext1, 0, cipherlen, plaintext, 0); + byte[] plaintext1 = Arrays.copyOfRange(plaintext,0,plainlen); + System.out.println("plaintext: " + new String(plaintext1)); + + } /** * convert byte array to hex string From b6c273dd8dde821c9f04353c0801bb1aaf8795db Mon Sep 17 00:00:00 2001 From: liyongfei Date: Thu, 5 Sep 2024 18:47:31 +0800 Subject: [PATCH 12/20] sm2Certificate jce develop --- .../crypto/asymmetric/SM2Certificate.java | 114 ++++++++++++++++++ src/test/java/org/gmssl/JceTest.java | 29 +++++ 2 files changed, 143 insertions(+) create mode 100644 src/main/java/org/gmssl/crypto/asymmetric/SM2Certificate.java diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Certificate.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Certificate.java new file mode 100644 index 0000000..29fdd9d --- /dev/null +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Certificate.java @@ -0,0 +1,114 @@ +package org.gmssl.crypto.asymmetric; + +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import java.security.*; +import java.security.cert.*; + +/** + * @author yongfeili + * @date 2024/8/27 + * @description + */ +public class SM2Certificate{ + + private byte[] cert; + + public byte[] getEncoded() throws CertificateEncodingException { + if (this.cert == null) { + throw new GmSSLException(""); + } + return this.cert; + } + + public String toString() { + return null; + } + + public PublicKey getPublicKey() { + if (this.cert == null) { + throw new GmSSLException(""); + } + long pub_key; + if ((pub_key = GmSSLJNI.cert_get_subject_public_key(this.cert)) == 0) { + throw new GmSSLException(""); + } + boolean has_private_key = false; + return new SM2PublicKey(pub_key, has_private_key); + } + + public void importPem(String file) { + if ((this.cert = GmSSLJNI.cert_from_pem(file)) == null) { + throw new GmSSLException(""); + } + } + + public void exportPem(String file) { + if (this.cert == null) { + throw new GmSSLException(""); + } + if (GmSSLJNI.cert_to_pem(this.cert, file) != 1) { + throw new GmSSLException(""); + } + } + + public boolean verifyByCaCertificate(SM2Certificate caCert, String sm2Id) throws CertificateEncodingException { + if (this.cert == null) { + throw new GmSSLException(""); + } + int ret = GmSSLJNI.cert_verify_by_ca_cert(this.cert, caCert.getEncoded(), sm2Id); + if (ret == 1) { + return true; + } else { + return false; + } + } + + public byte[] getSerialNumber() { + if (this.cert == null) { + throw new GmSSLException(""); + } + byte[] serial; + if ((serial = GmSSLJNI.cert_get_serial_number(this.cert)) == null) { + throw new GmSSLException(""); + } + return serial; + } + + public java.util.Date getNotBefore() { + if (this.cert == null) { + throw new GmSSLException(""); + } + return new java.util.Date(GmSSLJNI.cert_get_not_before(this.cert)); + } + + public java.util.Date getNotAfter() { + if (this.cert == null) { + throw new GmSSLException(""); + } + return new java.util.Date(GmSSLJNI.cert_get_not_after(this.cert)); + } + + public String[] getIssuer() { + if (this.cert == null) { + throw new GmSSLException(""); + } + String[] issuer; + if ((issuer = GmSSLJNI.cert_get_issuer(this.cert)) == null) { + throw new GmSSLException(""); + } + return issuer; + } + + public String[] getSubject() { + if (this.cert == null) { + throw new GmSSLException(""); + } + String[] subject; + if ((subject = GmSSLJNI.cert_get_subject(this.cert)) == null) { + throw new GmSSLException(""); + } + return subject; + } +} diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index 48635f4..073cc5e 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -13,6 +13,8 @@ import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger; import java.security.*; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.util.Arrays; /** @@ -87,6 +89,33 @@ public void SM2Test() throws Exception{ System.out.println("SignatureResult:"+signatureResultImport); } + @Test + public void sm2_certificate_test() throws Exception{ + SM2Certificate sm2Cert = new SM2Certificate(); + sm2Cert.importPem("D:\\cert.pem"); + System.out.println("NotAfter:"+sm2Cert.getNotAfter()); + + //TODO SM2Certificate继承Certificate,获取tbsCertificate解析cert实现verify方法。创建SM2CertificateFactory用以生成SM2Certificate + CertificateFactory certFactory = CertificateFactory.getInstance("SM2", "GmSSL"); + X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new java.io.ByteArrayInputStream(sm2Cert.getEncoded())); + // 提取证书的所有字段 + System.out.println("版本号: " + cert.getVersion()); + System.out.println("序列号: " + cert.getSerialNumber()); + System.out.println("签名算法: " + cert.getSigAlgName()); + System.out.println("颁发者: " + cert.getIssuerX500Principal().getName()); + System.out.println("主体: " + cert.getSubjectX500Principal().getName()); + System.out.println("有效期开始: " + cert.getNotBefore()); + System.out.println("有效期结束: " + cert.getNotAfter()); + System.out.println("公钥算法: " + cert.getPublicKey().getAlgorithm()); + System.out.println("公钥格式: " + cert.getPublicKey().getFormat()); + System.out.println("公钥: " + cert.getPublicKey()); + System.out.println("签名值: " + byteToHex(cert.getSignature())); + // 可选字段 + System.out.println("扩展字段是否存在: " + cert.getCriticalExtensionOIDs()); + } + + + @Test public void SM3Test() throws Exception{ String text="Hello, GmSSL"; From 6cf554a9d977c3850d22dbaf22264afac6e1ca29 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Thu, 5 Sep 2024 18:48:43 +0800 Subject: [PATCH 13/20] sm2Certificate jce develop --- src/test/java/org/gmssl/JceTest.java | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index 073cc5e..3b444ba 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -94,28 +94,8 @@ public void sm2_certificate_test() throws Exception{ SM2Certificate sm2Cert = new SM2Certificate(); sm2Cert.importPem("D:\\cert.pem"); System.out.println("NotAfter:"+sm2Cert.getNotAfter()); - - //TODO SM2Certificate继承Certificate,获取tbsCertificate解析cert实现verify方法。创建SM2CertificateFactory用以生成SM2Certificate - CertificateFactory certFactory = CertificateFactory.getInstance("SM2", "GmSSL"); - X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new java.io.ByteArrayInputStream(sm2Cert.getEncoded())); - // 提取证书的所有字段 - System.out.println("版本号: " + cert.getVersion()); - System.out.println("序列号: " + cert.getSerialNumber()); - System.out.println("签名算法: " + cert.getSigAlgName()); - System.out.println("颁发者: " + cert.getIssuerX500Principal().getName()); - System.out.println("主体: " + cert.getSubjectX500Principal().getName()); - System.out.println("有效期开始: " + cert.getNotBefore()); - System.out.println("有效期结束: " + cert.getNotAfter()); - System.out.println("公钥算法: " + cert.getPublicKey().getAlgorithm()); - System.out.println("公钥格式: " + cert.getPublicKey().getFormat()); - System.out.println("公钥: " + cert.getPublicKey()); - System.out.println("签名值: " + byteToHex(cert.getSignature())); - // 可选字段 - System.out.println("扩展字段是否存在: " + cert.getCriticalExtensionOIDs()); } - - @Test public void SM3Test() throws Exception{ String text="Hello, GmSSL"; From 67d73042356bbb09ac462abd071779b1587cf53f Mon Sep 17 00:00:00 2001 From: liyongfei Date: Sat, 14 Sep 2024 17:25:57 +0800 Subject: [PATCH 14/20] jce develop --- .../java/org/gmssl/crypto/CipherModeEnum.java | 27 --- .../org/gmssl/crypto/CipherPaddingEnum.java | 16 +- .../java/org/gmssl/crypto/GmSSLProvider.java | 14 +- .../org/gmssl/crypto/NoPaddingScheme.java | 9 - .../org/gmssl/crypto/PKCS5PaddingScheme.java | 9 - .../org/gmssl/crypto/PKCS7PaddingScheme.java | 33 +++ .../java/org/gmssl/crypto/PaddingScheme.java | 12 +- src/main/java/org/gmssl/crypto/Random.java | 12 +- .../crypto/asymmetric/SM2Certificate.java | 15 +- .../gmssl/crypto/asymmetric/SM2Cipher.java | 79 +++++-- .../org/gmssl/crypto/asymmetric/SM2Key.java | 14 +- .../asymmetric/SM2KeyPairGenerator.java | 12 +- .../crypto/asymmetric/SM2PrivateKey.java | 12 +- .../gmssl/crypto/asymmetric/SM2PublicKey.java | 12 +- .../gmssl/crypto/asymmetric/SM2Signature.java | 20 +- .../gmssl/crypto/asymmetric/SM9Cipher.java | 75 ++++-- .../crypto/asymmetric/SM9EncMasterKey.java | 12 +- .../SM9EncMasterKeyGenParameterSpec.java | 12 +- .../crypto/asymmetric/SM9EncUserKey.java | 12 +- .../asymmetric/SM9KeyPairGeneratorSpi.java | 13 +- .../gmssl/crypto/asymmetric/SM9MasterKey.java | 13 +- .../crypto/asymmetric/SM9PrivateKey.java | 12 +- .../gmssl/crypto/asymmetric/SM9PublicKey.java | 14 +- .../crypto/asymmetric/SM9SignMasterKey.java | 13 +- .../SM9SignMasterKeyGenParameterSpec.java | 12 +- .../crypto/asymmetric/SM9SignUserKey.java | 12 +- .../gmssl/crypto/asymmetric/SM9Signature.java | 12 +- .../gmssl/crypto/asymmetric/SM9UserKey.java | 12 +- .../org/gmssl/crypto/digest/SM3Digest.java | 26 ++- .../java/org/gmssl/crypto/digest/SM3Hmac.java | 51 ++-- .../org/gmssl/crypto/digest/SM3Pbkdf2.java | 25 +- .../java/org/gmssl/crypto/symmetric/SM4.java | 14 +- .../org/gmssl/crypto/symmetric/SM4CBC.java | 34 ++- .../org/gmssl/crypto/symmetric/SM4CTR.java | 35 ++- .../org/gmssl/crypto/symmetric/SM4Cipher.java | 44 ++-- .../crypto/symmetric/SM4CipherFactory.java | 12 +- .../org/gmssl/crypto/symmetric/SM4ECB.java | 115 ++++++++- .../org/gmssl/crypto/symmetric/SM4Engine.java | 29 ++- .../org/gmssl/crypto/symmetric/SM4GCM.java | 40 +++- .../org/gmssl/crypto/symmetric/ZucCipher.java | 12 +- .../org/gmssl/crypto/symmetric/ZucKey.java | 12 +- src/test/java/org/gmssl/JceTest.java | 219 ++++++++++-------- src/test/java/org/gmssl/Sm4EcbTest.java | 44 ++-- 43 files changed, 907 insertions(+), 325 deletions(-) delete mode 100644 src/main/java/org/gmssl/crypto/CipherModeEnum.java delete mode 100644 src/main/java/org/gmssl/crypto/NoPaddingScheme.java delete mode 100644 src/main/java/org/gmssl/crypto/PKCS5PaddingScheme.java create mode 100644 src/main/java/org/gmssl/crypto/PKCS7PaddingScheme.java diff --git a/src/main/java/org/gmssl/crypto/CipherModeEnum.java b/src/main/java/org/gmssl/crypto/CipherModeEnum.java deleted file mode 100644 index dabad61..0000000 --- a/src/main/java/org/gmssl/crypto/CipherModeEnum.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.gmssl.crypto; - -/** - * @author yongfeili - * @date 2024/8/12 - * @description - */ -public enum CipherModeEnum { - NONE, - /** - * Cipher Block Chaining - */ - CBC, - /** - * Grinding Cycle Monitor - */ - GCM, - /** - * - */ - CTR, - /** - * - */ - ECB; - -} diff --git a/src/main/java/org/gmssl/crypto/CipherPaddingEnum.java b/src/main/java/org/gmssl/crypto/CipherPaddingEnum.java index a61ca1d..a11b709 100644 --- a/src/main/java/org/gmssl/crypto/CipherPaddingEnum.java +++ b/src/main/java/org/gmssl/crypto/CipherPaddingEnum.java @@ -1,13 +1,23 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto; /** * @author yongfeili - * @date 2024/8/12 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public enum CipherPaddingEnum { - NoPadding, ZeroPadding, - PKCS5Padding; + PKCS5Padding, + PKCS7Padding; } diff --git a/src/main/java/org/gmssl/crypto/GmSSLProvider.java b/src/main/java/org/gmssl/crypto/GmSSLProvider.java index 192b7ad..f8b6f2f 100644 --- a/src/main/java/org/gmssl/crypto/GmSSLProvider.java +++ b/src/main/java/org/gmssl/crypto/GmSSLProvider.java @@ -1,11 +1,21 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto; import java.security.Provider; /** * @author yongfeili - * @date 2024/8/2 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class GmSSLProvider extends Provider { @@ -18,7 +28,7 @@ public GmSSLProvider() { put("Signature.SM2", "org.gmssl.crypto.asymmetric.SM2Signature"); put("MessageDigest.SM3", "org.gmssl.crypto.digest.SM3Digest"); - put("Mac.SM3Hmac", "org.gmssl.crypto.digest.SM3Hmac"); + put("Mac.SM3", "org.gmssl.crypto.digest.SM3Hmac"); put("SecretKeyFactory.SM3Pbkdf2", "org.gmssl.crypto.digest.SM3Pbkdf2"); put("Cipher.SM4", "org.gmssl.crypto.symmetric.SM4Cipher"); diff --git a/src/main/java/org/gmssl/crypto/NoPaddingScheme.java b/src/main/java/org/gmssl/crypto/NoPaddingScheme.java deleted file mode 100644 index e29e4bd..0000000 --- a/src/main/java/org/gmssl/crypto/NoPaddingScheme.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.gmssl.crypto; - -/** - * @author yongfeili - * @date 2024/8/13 - * @description - */ -public class NoPaddingScheme { -} diff --git a/src/main/java/org/gmssl/crypto/PKCS5PaddingScheme.java b/src/main/java/org/gmssl/crypto/PKCS5PaddingScheme.java deleted file mode 100644 index 5aac9f6..0000000 --- a/src/main/java/org/gmssl/crypto/PKCS5PaddingScheme.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.gmssl.crypto; - -/** - * @author yongfeili - * @date 2024/8/13 - * @description - */ -public class PKCS5PaddingScheme { -} diff --git a/src/main/java/org/gmssl/crypto/PKCS7PaddingScheme.java b/src/main/java/org/gmssl/crypto/PKCS7PaddingScheme.java new file mode 100644 index 0000000..006445e --- /dev/null +++ b/src/main/java/org/gmssl/crypto/PKCS7PaddingScheme.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.gmssl.crypto; + +/** + * @author yongfeili + * @email 290836576@qq.com + * @date 2024/07/27 + * @description + * + */ +public class PKCS7PaddingScheme implements PaddingScheme{ + @Override + public String getPaddingName() { + return null; + } + + @Override + public int addPadding(byte[] in, int inOff) { + return 0; + } + + @Override + public int padCount(byte[] in) { + return 0; + } +} diff --git a/src/main/java/org/gmssl/crypto/PaddingScheme.java b/src/main/java/org/gmssl/crypto/PaddingScheme.java index 8ab5579..9aa2079 100644 --- a/src/main/java/org/gmssl/crypto/PaddingScheme.java +++ b/src/main/java/org/gmssl/crypto/PaddingScheme.java @@ -1,9 +1,19 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto; /** * @author yongfeili - * @date 2024/8/13 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public interface PaddingScheme { diff --git a/src/main/java/org/gmssl/crypto/Random.java b/src/main/java/org/gmssl/crypto/Random.java index e8b0478..fa40637 100644 --- a/src/main/java/org/gmssl/crypto/Random.java +++ b/src/main/java/org/gmssl/crypto/Random.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto; import org.gmssl.GmSSLException; @@ -7,8 +15,10 @@ /** * @author yongfeili - * @date 2024/8/12 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class Random extends SecureRandomSpi { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Certificate.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Certificate.java index 29fdd9d..a4cab9f 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2Certificate.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Certificate.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -8,8 +16,13 @@ /** * @author yongfeili - * @date 2024/8/27 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * The certificate format is the standard X.509v3 certificate. Currently, only the SM2 signature algorithm is supported. + * This includes functions for parsing and verifying SM2 certificates. However, issuing and generating SM2 certificates are not supported. + * If the application needs to implement certificate request (i.e., generating CSR files) or self-built CA certificate issuance, + * these functionalities can be achieved using the GmSSL library or the gmssl command-line tool. */ public class SM2Certificate{ diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java index efc469a..33f21df 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -10,8 +18,11 @@ /** * @author yongfeili - * @date 2024/8/2 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * The SM2Cipher class implements encryption and decryption methods. When calling the encrypt method, ensure that the length of the plaintext input does not exceed the MAX_PLAINTEXT_SIZE limit. + * If you need to encrypt a message at the reference layer, first generate a symmetric key, encrypt the message using SM4-GCM, and then encrypt the symmetric key using SM2. */ public class SM2Cipher extends CipherSpi { @@ -20,45 +31,52 @@ public class SM2Cipher extends CipherSpi { private SecureRandom random; private ByteBuffer buffer; + /** + * SM2 uses the C1C2C3 encryption mode. + * @param mode the cipher mode + * + * @throws NoSuchAlgorithmException + */ @Override protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - if (!mode.equalsIgnoreCase("ECB")) { - throw new NoSuchAlgorithmException("Unsupported mode: " + mode); - } - // SM2 只支持 ECB 模式 + } + /** + * SM2 has adopted the corresponding padding rule and does not involve specific padding modes. + * @param padding the padding mechanism + * + * @throws NoSuchPaddingException + */ @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { - if (!padding.equalsIgnoreCase("NoPadding")) { - throw new NoSuchPaddingException("Unsupported padding: " + padding); - } - // SM2 不使用填充 + } + /** + * SM2 does not have a fixed block size. + * @return + */ @Override protected int engineGetBlockSize() { - // SM2 是流加密,没有块大小 return 0; } @Override protected int engineGetOutputSize(int inputLen) { - // 根据输入长度计算输出长度 - // 这里只是示例,具体实现需要根据实际情况调整 - // 例如,假设增加一个固定长度的输出 - return inputLen+32; + // TODO 计算输出长度。加密模式和解密模式输出长度随机,在+-3范围内跳动 + //cipherLen=65+plainTextLen+32 cipherLen=C1_size+plainTextLen+C3_size + //plainTextLen=cipherLen−C1_size−C3_size plainTextLen=cipherLen−65−32 + return 0; } @Override protected byte[] engineGetIV() { - // // SM2 不使用 IV return null; } @Override protected AlgorithmParameters engineGetParameters() { - // SM2 不使用参数 return null; } @@ -70,8 +88,7 @@ protected void engineInit(int mode, Key key, SecureRandom secureRandom) throws I this.key = (SM2Key)key; this.mode = mode; this.random = (secureRandom != null) ? secureRandom : new SecureRandom(); - // 初始化缓冲区 - this.buffer = ByteBuffer.allocate(2048); + this.buffer = ByteBuffer.allocate(1024); } @Override @@ -84,23 +101,39 @@ protected void engineInit(int i, Key key, AlgorithmParameters algorithmParameter engineInit(mode, key, random); } + /** + * + * @param input the input buffer + * @param inputOffset the offset in input where the input + * starts + * @param inputLen the input length + * + * @return null + * The SM2 algorithm typically does not return any data during the engineUpdate phase. + */ @Override protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { + if (input == null || inputOffset < 0 || inputLen < 0 || inputOffset + inputLen > input.length) { + throw new IllegalArgumentException("Invalid input parameters"); + } buffer.put(input, inputOffset, inputLen); - // 暂时不返回输出,等待 doFinal - return buffer.array(); + return null; } @Override protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + if (input == null || inputOffset < 0 || inputLen < 0 || inputOffset + inputLen > input.length) { + throw new IllegalArgumentException("Invalid input parameters"); + } buffer.put(input, inputOffset, inputLen); - // 暂时不返回输出,等待 doFinal - return output.length; + return 0; } @Override protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { - buffer.put(input, inputOffset, inputLen); + if(null != input){ + buffer.put(input, inputOffset, inputLen); + } byte[] data = new byte[buffer.position()]; buffer.flip(); buffer.get(data); diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Key.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Key.java index dd16294..ac006e2 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2Key.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Key.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -7,8 +15,10 @@ /** * @author yongfeili - * @date 2024/8/2 - * @description + * @email 290836576@qq.com + * @date 2024/08/11 + * @description SM2Key + * */ public abstract class SM2Key implements Key { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyPairGenerator.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyPairGenerator.java index db3c9eb..3fe591e 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyPairGenerator.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2KeyPairGenerator.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -6,8 +14,10 @@ import java.security.*; /** * @author yongfeili - * @date 2024/8/2 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM2KeyPairGenerator extends KeyPairGeneratorSpi { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2PrivateKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2PrivateKey.java index 98730a3..bd5ac98 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2PrivateKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2PrivateKey.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -7,8 +15,10 @@ /** * @author yongfeili - * @date 2024/8/7 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM2PrivateKey extends SM2Key implements PrivateKey{ diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2PublicKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2PublicKey.java index dfec541..5d301f8 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2PublicKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2PublicKey.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -8,8 +16,10 @@ /** * @author yongfeili - * @date 2024/8/7 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM2PublicKey extends SM2Key implements PublicKey{ diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java index 61f0667..3d6bd8b 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Signature.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -7,8 +15,10 @@ /** * @author yongfeili - * @date 2024/8/2 - * @description + * @email 290836576@qq.com + * @date 2024/08/11 + * @description SM2Signature + * It provides signing and verification functionality for messages of arbitrary length. */ public class SM2Signature extends SignatureSpi { @@ -25,7 +35,6 @@ public SM2Signature() { @Override protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { - // 实现初始化验证 if (!(publicKey instanceof SM2PublicKey)) { throw new GmSSLException("Invalid publicKey type"); } @@ -35,7 +44,6 @@ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException @Override protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { - // 实现初始化签名 if (!(privateKey instanceof SM2PrivateKey)) { throw new GmSSLException("Invalid privateKey type"); } @@ -56,26 +64,22 @@ protected void engineUpdate(byte[] b, int off, int len) throws SignatureExceptio @Override protected byte[] engineSign() throws SignatureException { - // 实现签名生成 byte[] data = sign(); return data; } @Override protected boolean engineVerify(byte[] sigBytes) throws SignatureException { - // 实现签名验证 boolean verifyResult= verify(sigBytes); return verifyResult; } @Override protected void engineSetParameter(String param, Object value) throws InvalidParameterException { - // 实现设置参数 } @Override protected Object engineGetParameter(String param) throws InvalidParameterException { - // 实现获取参数 return null; } diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java index d8daf05..a1c2dc6 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java @@ -1,7 +1,14 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; -import org.gmssl.Sm9EncMasterKey; import javax.crypto.*; import java.nio.ByteBuffer; @@ -10,8 +17,12 @@ /** * @author yongfeili - * @date 2024/8/21 - * @description + * @email 290836576@qq.com + * @date 2024/08/11 + * @description SM9Cipher + * The SM9 algorithm belongs to an identity-based encryption (IBE) system. + * Since IBE does not require a Certificate Authority (CA) or a digital certificate infrastructure, + * if the application operates in a closed internal environment where all participating users are within the system, adopting the SM9 solution is a better choice. */ public class SM9Cipher extends CipherSpi { @@ -23,16 +34,32 @@ public class SM9Cipher extends CipherSpi { private String id; + /** + * + * @param mode the cipher mode + * @throws NoSuchAlgorithmException + * @description + * SM9 is an identity-based encryption and signature algorithm that does not support traditional block cipher modes. + */ @Override protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - } + /** + * + * @param padding the padding mechanism + * @throws NoSuchPaddingException + * @description + * SM9 is an identity-based encryption and signature algorithm that does not support common padding modes. + */ @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { - } + /** + * SM9 is a public key encryption algorithm that does not have a fixed block size and does not use blocks. + * @return + */ @Override protected int engineGetBlockSize() { return 0; @@ -40,6 +67,9 @@ protected int engineGetBlockSize() { @Override protected int engineGetOutputSize(int inputLen) { + //TODO 输出长度具有随机性,输入与输出长度偏差值在119-120范围内浮动 + //32 + inputLen + 32 encrypt + //inputLen - 64 decrypt return 0; } @@ -55,47 +85,52 @@ protected AlgorithmParameters engineGetParameters() { @Override protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - /*if (!(key instanceof SM9PublicKey) || !(key instanceof SM9PrivateKey)) { - throw new GmSSLException("Invalid key type"); - }*/ + if (!(key instanceof SM9PrivateKey)) { + throw new GmSSLException("Invalid privateKey type"); + } this.opmode = opmode; this.key = key; SM9PrivateKey privateKey = (SM9PrivateKey)key; SM9UserKey userKey = (SM9UserKey)privateKey.getSecretKey(); this.id = userKey.getId(); - // 初始化缓冲区 - this.buffer = ByteBuffer.allocate(2048); + this.buffer = ByteBuffer.allocate(1024); } @Override protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - /*if (!(key instanceof SM9PublicKey) || !(key instanceof SM9PrivateKey)) { - throw new GmSSLException("Invalid key type"); - }*/ + if (!(key instanceof SM9PublicKey)) { + throw new GmSSLException("Invalid publicKey type"); + } this.opmode = opmode; this.key = key; this.id = ((SM9EncMasterKeyGenParameterSpec)params).getId(); - // 初始化缓冲区 - this.buffer = ByteBuffer.allocate(2048); + this.buffer = ByteBuffer.allocate(1024); } @Override protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - throw new GmSSLException("params should not be null!"); } + /** + * + * @param input the input buffer + * @param inputOffset the offset in input where the input + * starts + * @param inputLen the input length + * @description + * SM9 encryption and decryption are completed during the engineDoFinal phase. During the update phase, data is only cached, and no partial encryption or decryption results are returned. + * @return + */ @Override protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { buffer.put(input, inputOffset, inputLen); - // 暂时不返回输出,等待 doFinal - return buffer.array(); + return null; } @Override protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { buffer.put(input, inputOffset, inputLen); - // 暂时不返回输出,等待 doFinal - return output.length; + return 0; } @Override diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java index 382a060..f549cda 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKey.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -5,8 +13,10 @@ /** * @author yongfeili - * @date 2024/8/20 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM9EncMasterKey extends SM9MasterKey{ diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKeyGenParameterSpec.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKeyGenParameterSpec.java index a1a4465..da982ad 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKeyGenParameterSpec.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncMasterKeyGenParameterSpec.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLJNI; @@ -6,8 +14,10 @@ /** * @author yongfeili - * @date 2024/8/21 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM9EncMasterKeyGenParameterSpec implements AlgorithmParameterSpec { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java index d74d46c..4a417da 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9EncUserKey.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -6,8 +14,10 @@ /** * @author yongfeili - * @date 2024/8/21 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM9EncUserKey extends SM9UserKey{ protected SM9EncUserKey(long sm9_key, String id) { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9KeyPairGeneratorSpi.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9KeyPairGeneratorSpi.java index 48d5500..a3962cc 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9KeyPairGeneratorSpi.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9KeyPairGeneratorSpi.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import java.security.InvalidAlgorithmParameterException; @@ -5,12 +13,13 @@ import java.security.KeyPairGeneratorSpi; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.KeySpec; /** * @author yongfeili - * @date 2024/8/20 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM9KeyPairGeneratorSpi extends KeyPairGeneratorSpi { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java index 7fe3d8f..3ad7fe3 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9MasterKey.java @@ -1,12 +1,21 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; -import java.security.Key; import java.security.spec.KeySpec; /** * @author yongfeili - * @date 2024/8/20 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public abstract class SM9MasterKey implements KeySpec { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java index 14c47c8..d34c9de 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9PrivateKey.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import java.security.PrivateKey; @@ -5,8 +13,10 @@ /** * @author yongfeili - * @date 2024/8/20 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public abstract class SM9PrivateKey implements PrivateKey { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9PublicKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9PublicKey.java index 68758ba..474776c 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9PublicKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9PublicKey.java @@ -1,13 +1,21 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; -import org.gmssl.Sm9SignMasterKey; - import java.security.PublicKey; /** * @author yongfeili - * @date 2024/8/20 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public abstract class SM9PublicKey implements PublicKey { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java index 03b7c5f..6b4dbe7 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKey.java @@ -1,13 +1,22 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; -import org.gmssl.Sm9SignMasterKey; /** * @author yongfeili - * @date 2024/8/20 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM9SignMasterKey extends SM9MasterKey{ diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKeyGenParameterSpec.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKeyGenParameterSpec.java index 51a40e2..51749c8 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKeyGenParameterSpec.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignMasterKeyGenParameterSpec.java @@ -1,11 +1,21 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import java.security.spec.AlgorithmParameterSpec; /** * @author yongfeili - * @date 2024/8/21 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM9SignMasterKeyGenParameterSpec implements AlgorithmParameterSpec { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java index efd02cc..815d338 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9SignUserKey.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -6,8 +14,10 @@ /** * @author yongfeili - * @date 2024/8/21 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM9SignUserKey extends SM9UserKey{ protected SM9SignUserKey(long sm9_key, String id) { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9Signature.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9Signature.java index c23c827..704328e 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9Signature.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9Signature.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import org.gmssl.GmSSLException; @@ -8,8 +16,10 @@ /** * @author yongfeili - * @date 2024/8/21 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public class SM9Signature extends SignatureSpi { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java index bb98d84..7e219b5 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9UserKey.java @@ -1,11 +1,21 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.asymmetric; import java.security.spec.KeySpec; /** * @author yongfeili - * @date 2024/8/20 + * @email 290836576@qq.com + * @date 2024/08/11 * @description + * */ public abstract class SM9UserKey implements KeySpec { diff --git a/src/main/java/org/gmssl/crypto/digest/SM3Digest.java b/src/main/java/org/gmssl/crypto/digest/SM3Digest.java index 5ff14f9..15273e4 100644 --- a/src/main/java/org/gmssl/crypto/digest/SM3Digest.java +++ b/src/main/java/org/gmssl/crypto/digest/SM3Digest.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.digest; import org.gmssl.GmSSLException; @@ -7,8 +15,10 @@ /** * @author yongfeili - * @date 2024/8/12 + * @email 290836576@qq.com + * @date 2024/09/07 * @description + * The SM3 cryptographic hash function can compute input data of arbitrary length into a fixed hash value of 32 bytes. */ public class SM3Digest extends MessageDigestSpi { @@ -20,6 +30,10 @@ public SM3Digest() { init(); } + /** + * You can call the update method multiple times. After all the data has been input, finally call the digest method to obtain the SM3 hash value of the entire data. + * @param input the input byte to be processed. + */ @Override protected void engineUpdate(byte input) { byte[] data = new byte[]{input}; @@ -36,6 +50,10 @@ protected byte[] engineDigest() { return this.digest(); } + /** + * If you need to calculate different SM3 hash values for multiple sets of data, you can use the reset method to reset, + * and then call the update and digest methods again to compute the hash value of a new set of data. + */ @Override protected void engineReset() { this.reset(); @@ -50,7 +68,7 @@ private void init(){ } } - public void update(byte[] data, int offset, int len) { + private void update(byte[] data, int offset, int len) { if (data == null || offset < 0 || len < 0 @@ -63,7 +81,7 @@ public void update(byte[] data, int offset, int len) { } } - public byte[] digest() { + private byte[] digest() { byte[] dgst = new byte[DIGEST_SIZE]; if (GmSSLJNI.sm3_finish(sm3_ctx, dgst) != 1) { throw new GmSSLException(""); @@ -74,7 +92,7 @@ public byte[] digest() { return dgst; } - public void reset() { + private void reset() { if (GmSSLJNI.sm3_init(sm3_ctx) != 1) { throw new GmSSLException(""); } diff --git a/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java b/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java index ed9f45f..fc89f13 100644 --- a/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java +++ b/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.digest; import org.gmssl.GmSSLException; @@ -12,12 +20,19 @@ /** * @author yongfeili - * @date 2024/8/12 + * @email 290836576@qq.com + * @date 2024/09/07 * @description + * HMAC-SM3 is a Message Authentication Code (MAC) algorithm based on the SM3 cryptographic hash algorithm. + * A MAC algorithm can be viewed as a keyed hash function, primarily used to protect messages from tampering. + * Both communicating parties need to agree on a key in advance, such as a 32-byte random byte sequence. + * The data sender uses this key to compute the MAC value of the message and appends the MAC value to the message. + * Upon receiving the message, the recipient uses the same key to compute the MAC value of the message and compares it with the MAC value attached to the sent message. + * If they match, it indicates that the message has not been tampered with; if they do not match, it indicates that the message has been altered. */ public class SM3Hmac extends MacSpi { - private final static int MAC_SIZE = GmSSLJNI.SM3_HMAC_SIZE; + public final static int MAC_SIZE = GmSSLJNI.SM3_HMAC_SIZE; private Key key; @@ -28,17 +43,21 @@ public SM3Hmac() { ctx(); } - public SM3Hmac(Key key){ - this.key = key; - ctx(); - init(); - } - @Override protected int engineGetMacLength() { return MAC_SIZE; } + /** + * The HMAC-SM3 algorithm can be seen as the SM3 algorithm with a key, so when creating an Sm3Hmac object, a key must be passed as an input parameter. + * Although HMAC-SM3 does not have any restrictions on key length in terms of the algorithm and implementation, for considerations of security and efficiency, the key length for the HMAC-SM3 algorithm is recommended to be 32 bytes (equivalent to the length of the SM3 hash value) and should not be less than 16 bytes. + * Using a key length longer than 32 bytes would increase computational overhead without enhancing security. + * @param key the (secret) key. + * @param params the algorithm parameters. + * + * @throws InvalidKeyException + * @throws InvalidAlgorithmParameterException + */ @Override protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { if (!(key instanceof SecretKey)) { @@ -48,6 +67,10 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) throws Invalid init(); } + /** + * You can call update multiple times and ultimately execute doFinal. The HMAC-SM3 output is a fixed 32 bytes, which is a binary message authentication code of length MAC_SIZE. + * @param input the input byte to be processed. + */ @Override protected void engineUpdate(byte input) { byte[] data = new byte[]{input}; @@ -69,10 +92,6 @@ protected void engineReset() { this.reset(this.key); } - public void engineReset(Key key) { - this.reset(key); - } - private void ctx(){ if ((this.sm3_hmac_ctx = GmSSLJNI.sm3_hmac_ctx_new()) == 0) { throw new GmSSLException(""); @@ -85,7 +104,7 @@ private void init() { } } - public void update(byte[] data, int offset, int len) { + private void update(byte[] data, int offset, int len) { if (data == null || offset < 0 || len < 0 @@ -98,11 +117,11 @@ public void update(byte[] data, int offset, int len) { } } - public void update(byte[] data) { + private void update(byte[] data) { this.update(data, 0, data.length); } - public byte[] generateMac() { + private byte[] generateMac() { byte[] mac = new byte[this.MAC_SIZE]; if (GmSSLJNI.sm3_hmac_finish(this.sm3_hmac_ctx, mac) != 1) { throw new GmSSLException(""); @@ -113,7 +132,7 @@ public byte[] generateMac() { return mac; } - public void reset(Key key) { + private void reset(Key key) { if (key == null) { throw new GmSSLException(""); } diff --git a/src/main/java/org/gmssl/crypto/digest/SM3Pbkdf2.java b/src/main/java/org/gmssl/crypto/digest/SM3Pbkdf2.java index 03c8fbc..1e29f1a 100644 --- a/src/main/java/org/gmssl/crypto/digest/SM3Pbkdf2.java +++ b/src/main/java/org/gmssl/crypto/digest/SM3Pbkdf2.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.digest; import org.gmssl.GmSSLException; @@ -13,8 +21,11 @@ /** * @author yongfeili - * @date 2024/8/12 + * @email 290836576@qq.com + * @date 2024/09/07 * @description + * PBKDF2 is one of the secure and widely used PBKDF algorithm standards. The algorithm uses a hash function as the primary component to map passwords to keys. + * It employs a random and public salt value (Salt) to resist precomputation attacks, increases the difficulty of online cracking by adding multiple rounds of iterative computation, and supports variable derived key lengths. */ public class SM3Pbkdf2 extends SecretKeyFactorySpi { @@ -30,6 +41,16 @@ public SM3Pbkdf2() { super(); } + /** + * + * @param keySpec PBEKeySpec the specification (key material) of the secret key + * pass is the user password used for deriving the key. + * salt is the value used to resist precomputation attacks. This value should be randomly generated (for example, using the Random class) and should have a certain length. + * The iter parameter represents the number of times the SM3 algorithm is called iteratively when deriving the key. A larger iter value increases the difficulty of brute-force attacks but also increases the computational overhead for users calling this function. + * The keylen parameter indicates the desired length of the derived key, which must not exceed the constant MAX_KEY_SIZE. + * @return + * @throws InvalidKeySpecException + */ @Override protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException { if (!(keySpec instanceof PBEKeySpec)) { @@ -54,7 +75,7 @@ protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException throw new GmSSLException("Not supported"); } - public byte[] deriveKey(String pass, byte[] salt, int iter, int keylen) { + private byte[] deriveKey(String pass, byte[] salt, int iter, int keylen) { if (pass == null) { throw new GmSSLException(""); } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4.java b/src/main/java/org/gmssl/crypto/symmetric/SM4.java index f856678..3fb92aa 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; import org.gmssl.GmSSLException; @@ -11,8 +19,10 @@ /** * @author yongfeili - * @date 2024/8/13 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class SM4 extends SM4Cipher { @@ -78,8 +88,6 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] return output.length; } - - private void init(){ if ((sm4_key = GmSSLJNI.sm4_key_new()) == 0) { throw new GmSSLException(""); diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java index 76a7a27..710f87d 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; import org.gmssl.GmSSLException; @@ -16,8 +24,10 @@ /** * @author yongfeili - * @date 2024/8/12 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class SM4CBC extends SM4Engine { @@ -45,7 +55,17 @@ protected byte[] engineGetIV() { } @Override - protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random){ + protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { + return new byte[0]; + } + + @Override + protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { + + } + + @Override + protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random){ if (!(params instanceof IvParameterSpec)) { throw new GmSSLException("need the IvParameterSpec parameter"); } @@ -55,15 +75,15 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, Se } @Override - protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset+=outLen; return outLen; } @Override - protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - this.engineUpdate(input, inputOffset, inputLen, output, outputOffset); + protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + this.processUpdate(input, inputOffset, inputLen, output, outputOffset); int outLen = doFinal(output, this.offset); outLen = outLen + this.offset; this.offset = 0; @@ -71,8 +91,8 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] } @Override - protected void engineUpdateAAD(byte[] src, int offset, int len) { - + protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + return new byte[0]; } private void ctx() { diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java index dd18b03..b5c71d9 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; import org.gmssl.GmSSLException; @@ -7,14 +15,17 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.ShortBufferException; import javax.crypto.spec.IvParameterSpec; +import java.security.InvalidKeyException; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; /** * @author yongfeili - * @date 2024/8/13 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class SM4CTR extends SM4Engine { @@ -33,7 +44,12 @@ public SM4CTR() { } @Override - protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { + protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { + + } + + @Override + protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { if (!(params instanceof IvParameterSpec)) { throw new GmSSLException("need the IvParameterSpec parameter"); } @@ -47,15 +63,20 @@ protected byte[] engineGetIV() { } @Override - protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { + return new byte[0]; + } + + @Override + protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset += outLen; return outLen; } @Override - protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - engineUpdate(input, inputOffset, inputLen, output, outputOffset); + protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + processUpdate(input, inputOffset, inputLen, output, outputOffset); int outLen = doFinal(output, this.offset); outLen = outLen + this.offset; this.offset = 0; @@ -63,8 +84,8 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] } @Override - protected void engineUpdateAAD(byte[] src, int offset, int len) { - + protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + return new byte[0]; } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java index 55a7ab1..a635cb6 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java @@ -1,14 +1,26 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; +import org.gmssl.crypto.CipherPaddingEnum; +import org.gmssl.crypto.PKCS7PaddingScheme; + import javax.crypto.*; -import java.nio.ByteBuffer; import java.security.*; import java.security.spec.AlgorithmParameterSpec; /** * @author yongfeili - * @date 2024/8/12 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class SM4Cipher extends CipherSpi { @@ -20,19 +32,18 @@ public SM4Cipher() { @Override protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - // 设置加密模式 this.sm4Engine = SM4CipherFactory.createCipher(mode); } @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { - // 设置填充方式,可以选择支持PKCS5Padding,NoPadding等 - System.out.println("padding2:" + padding); + if(CipherPaddingEnum.PKCS7Padding.name().equals(padding)){ + this.sm4Engine.paddingScheme=new PKCS7PaddingScheme(); + } } @Override protected int engineGetBlockSize() { - // SM4块大小为16字节 return SM4Engine.BLOCK_SIZE; } @@ -44,25 +55,22 @@ protected int engineGetOutputSize(int inputLen) { @Override protected byte[] engineGetIV() { - // ECB模式不使用IV return sm4Engine.engineGetIV(); } @Override protected AlgorithmParameters engineGetParameters() { - // 无需额外的参数 return null; } @Override protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - + sm4Engine.init(opmode,key,random); } @Override protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - sm4Engine.engineInit(opmode, key, params, random); - + sm4Engine.init(opmode, key, params, random); } @Override @@ -72,31 +80,31 @@ protected void engineInit(int opmode, Key key, AlgorithmParameters params, Secur @Override protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { - - return null; + byte[] result = sm4Engine.processUpdate(input,inputOffset,inputLen); + return result; } @Override protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { - int outLen = sm4Engine.engineUpdate(input, inputOffset, inputLen, output, outputOffset); + int outLen = sm4Engine.processUpdate(input, inputOffset, inputLen, output, outputOffset); return outLen; } @Override protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { - - return null; + byte[] result = sm4Engine.processBlock(input, inputOffset, inputLen); + return result; } @Override protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - int outLen = sm4Engine.engineDoFinal(input, inputOffset, inputLen, output, outputOffset); + int outLen = sm4Engine.processBlock(input, inputOffset, inputLen, output, outputOffset); return outLen; } @Override protected void engineUpdateAAD(byte[] src, int offset, int len) { - sm4Engine.engineUpdateAAD(src, offset, len); + sm4Engine.processUpdateAAD(src, offset, len); } } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java index f47e917..1093312 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java @@ -1,11 +1,21 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; import java.security.NoSuchAlgorithmException; /** * @author yongfeili - * @date 2024/8/13 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class SM4CipherFactory { diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java b/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java index ba368c1..719f9b9 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java @@ -1,40 +1,137 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.ShortBufferException; +import org.gmssl.GmSSLException; +import org.gmssl.GmSSLJNI; + +import javax.crypto.*; +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; /** * @author yongfeili - * @date 2024/8/13 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class SM4ECB extends SM4Engine { + + public final static int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; + public final static int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + + private Key key; + private long sm4_key = 0; + + private boolean do_encrypt = false; + + private ByteBuffer buffer; + @Override - protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { + protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { + if (!(key instanceof SecretKey)) { + throw new GmSSLException("Invalid KeySpec"); + } + this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); + this.key = key; + // 初始化缓冲区 + this.buffer = ByteBuffer.allocate(2048); + init(); + } + + @Override + protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { } @Override protected byte[] engineGetIV() { - return new byte[0]; + return null; + } + + @Override + protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { + putBytes(input, inputOffset, inputLen); + return null; } @Override - protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + putBytes(input, inputOffset, inputLen); return 0; } @Override - protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + return 0; } @Override - protected void engineUpdateAAD(byte[] src, int offset, int len) { + protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + putBytes(input, inputOffset, inputLen); + byte[] data = new byte[buffer.position()]; + buffer.flip(); + buffer.get(data); + + byte[] output = new byte[buffer.position()]; + encrypt(data,0,output,0); + buffer.clear(); + return output; + } + + private void putBytes(byte[] input, int inputOffset, int inputLen){ + if(buffer.remaining() in.length) { + throw new GmSSLException(""); + } + if (out == null + || out_offset < 0 + || out_offset + this.BLOCK_SIZE <= 0 + || out_offset + this.BLOCK_SIZE > in.length) { + throw new GmSSLException(""); + } + if (GmSSLJNI.sm4_encrypt(sm4_key, in, in_offset, out, out_offset) != 1) { + throw new GmSSLException(""); + } } } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java index d7797ff..5bd2b69 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java @@ -1,35 +1,54 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; import org.gmssl.GmSSLJNI; +import org.gmssl.crypto.PaddingScheme; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.ShortBufferException; import java.nio.ByteBuffer; +import java.security.InvalidKeyException; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; /** * @author yongfeili - * @date 2024/8/14 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public abstract class SM4Engine { + protected PaddingScheme paddingScheme; + public static final int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; public static final int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; - protected abstract void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random); + protected abstract void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException; + + protected abstract void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random); protected abstract byte[] engineGetIV(); - protected abstract int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException; + protected abstract byte[] processUpdate(byte[] input, int inputOffset, int inputLen); + + protected abstract int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException; - protected abstract int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException; + protected abstract int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException; - protected abstract void engineUpdateAAD(byte[] src, int offset, int len); + protected abstract byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException; + protected void processUpdateAAD(byte[] src, int offset, int len){}; //String getAlgorithmName(); diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java index de0e1ba..0aecef4 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; import org.gmssl.GmSSLException; @@ -8,16 +16,17 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.ShortBufferException; import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.IvParameterSpec; -import java.nio.ByteBuffer; +import java.security.InvalidKeyException; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; /** * @author yongfeili - * @date 2024/8/13 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class SM4GCM extends SM4Engine { @@ -47,7 +56,12 @@ public SM4GCM(){ } @Override - protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { + protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { + + } + + @Override + protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { if (!(params instanceof GCMParameterSpec)) { throw new GmSSLException("need the GCMParameterSpec parameter"); } @@ -63,15 +77,20 @@ protected byte[] engineGetIV() { } @Override - protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { + return new byte[0]; + } + + @Override + protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset+=outLen; return outLen; } @Override - protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - engineUpdate(input, inputOffset, inputLen, output, outputOffset); + protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + processUpdate(input, inputOffset, inputLen, output, outputOffset); int outLen = doFinal(output, this.offset); outLen = outLen + this.offset; this.offset = 0; @@ -79,7 +98,12 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] } @Override - protected void engineUpdateAAD(byte[] src, int offset, int len) { + protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + return new byte[0]; + } + + @Override + protected void processUpdateAAD(byte[] src, int offset, int len) { this.aad = new byte[len]; System.arraycopy(src, offset, this.aad, 0, len); diff --git a/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java b/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java index 195b058..d142fae 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java +++ b/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; import org.gmssl.GmSSLException; @@ -10,8 +18,10 @@ /** * @author yongfeili - * @date 2024/8/26 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class ZucCipher extends CipherSpi { diff --git a/src/main/java/org/gmssl/crypto/symmetric/ZucKey.java b/src/main/java/org/gmssl/crypto/symmetric/ZucKey.java index 92c9a50..f305f91 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/ZucKey.java +++ b/src/main/java/org/gmssl/crypto/symmetric/ZucKey.java @@ -1,3 +1,11 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ package org.gmssl.crypto.symmetric; import org.gmssl.GmSSLJNI; @@ -6,8 +14,10 @@ /** * @author yongfeili - * @date 2024/8/26 + * @email 290836576@qq.com + * @date 2024/07/27 * @description + * */ public class ZucKey implements SecretKey { diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index 3b444ba..e11d0c8 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -1,6 +1,7 @@ package org.gmssl; import org.gmssl.crypto.asymmetric.*; +import org.gmssl.crypto.digest.SM3Hmac; import org.gmssl.crypto.digest.SM3Pbkdf2; import org.gmssl.crypto.symmetric.*; import org.junit.Before; @@ -13,8 +14,6 @@ import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger; import java.security.*; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; import java.util.Arrays; /** @@ -31,62 +30,87 @@ public void beforeTest(){ Security.addProvider(new org.gmssl.crypto.GmSSLProvider()); } + @Test + public void test() throws Exception{ + String text="Hello, GmSSL"; + SM9EncMasterKeyGenParameterSpec sm9EncMasterKeyGenParameterSpec = new SM9EncMasterKeyGenParameterSpec("bob"); + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM9", "GmSSL"); + keyPairGen.initialize(sm9EncMasterKeyGenParameterSpec); + keyPairGen.generateKeyPair(); + + PublicKey publicKey = keyPairGen.genKeyPair().getPublic(); + Cipher sm9Cipher = Cipher.getInstance("SM9", "GmSSL"); + sm9Cipher.init(Cipher.ENCRYPT_MODE, publicKey,sm9EncMasterKeyGenParameterSpec); + System.out.println("len1: " + text.getBytes().length); + byte[] ciphertext = sm9Cipher.doFinal(text.getBytes()); + System.out.println("len2: " + ciphertext.length); + System.out.println("Ciphertext: " + byteToHex(ciphertext)); + + SM9PrivateKey privateKey= (SM9PrivateKey) keyPairGen.genKeyPair().getPrivate(); + SM9MasterKey masterKey = (SM9MasterKey)privateKey.getSecretKey(); + SM9UserKey userKey= masterKey.extractKey(sm9EncMasterKeyGenParameterSpec.getId()); + sm9Cipher.init(Cipher.DECRYPT_MODE, userKey.getPrivateKey()); + byte[] plaintext = sm9Cipher.doFinal(ciphertext); + System.out.println("plaintext: " + new String(plaintext)); + + } + @Test public void SM2Test() throws Exception{ - KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM2", "GmSSL"); - keyPairGen.initialize(256); - KeyPair keyPair = keyPairGen.generateKeyPair(); - byte[] pub= keyPair.getPublic().getEncoded(); - System.out.println(byteToHex(pub)); - byte[] pri= keyPair.getPrivate().getEncoded(); - System.out.println(byteToHex(pri)); - - //测试“Z值”哈希值 - SM2PublicKey sm2PublicKey = new SM2PublicKey(pub); - byte[] zHash = sm2PublicKey.computeZ("Hello, GmSSL"); - System.out.println("zHash:"+byteToHex(zHash)); - - Cipher cipher = Cipher.getInstance("SM2", "GmSSL"); - // 测试加密 - cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); - byte[] plaintext = "Hello, GmSSL".getBytes(); - byte[] ciphertext = cipher.doFinal(plaintext); - System.out.println("Ciphertext: " + byteToHex(ciphertext)); - // 测试解密 - cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); - byte[] decrypted = cipher.doFinal(ciphertext); - System.out.println("Decrypted: " + new String(decrypted)); - - // 测试签名验签 - Signature signature = Signature.getInstance("SM2", "GmSSL"); - // 测试签名 - signature.initSign(keyPair.getPrivate()); - byte[] signatureText = "Hello, GmSSL".getBytes(); - signature.update(signatureText); - byte[] signatureByte = signature.sign(); - System.out.println("Signature:"+byteToHex(signatureByte)); - // 测试验签 - signature.initVerify(keyPair.getPublic()); - signature.update(signatureText); - boolean signatureResult = signature.verify(signatureByte); - System.out.println("SignatureResult:"+signatureResult); - - //测试导入私钥公钥签名验签 - Signature signatureImport = Signature.getInstance("SM2", "GmSSL"); - // 测试导入私钥 - String privateKeyInfoHex="308193020100301306072a8648ce3d020106082a811ccf5501822d0479307702010104207fef3e258348873c47117c15093266e9dad99e131f1778e53d362b2b70649f85a00a06082a811ccf5501822da14403420004f94c0abb6cd00c6f0918cb9c54162213501d5cc278f5d3fcf63886f4e1dc6322b1b110e33a25216f258c4cce5fd52ab320d3b086ee5390f7387218c92578c3ab"; - byte[] privateKeyInfo = hexToByte(privateKeyInfoHex); - signatureImport.initSign(new SM2PrivateKey(privateKeyInfo)); - signatureImport.update(signatureText); - byte[] signatureByteImport = signatureImport.sign(); - System.out.println("Signature:"+byteToHex(signatureByteImport)); - // 测试导入公钥 - String publicKeyInfoHex = "3059301306072a8648ce3d020106082a811ccf5501822d03420004f94c0abb6cd00c6f0918cb9c54162213501d5cc278f5d3fcf63886f4e1dc6322b1b110e33a25216f258c4cce5fd52ab320d3b086ee5390f7387218c92578c3ab"; - byte[] publicKeyInfo = hexToByte(publicKeyInfoHex); - signatureImport.initVerify(new SM2PublicKey(publicKeyInfo)); - signatureImport.update(signatureText); - boolean signatureResultImport = signatureImport.verify(signatureByteImport); - System.out.println("SignatureResult:"+signatureResultImport); + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM2", "GmSSL"); + keyPairGen.initialize(256); + KeyPair keyPair = keyPairGen.generateKeyPair(); + byte[] pub= keyPair.getPublic().getEncoded(); + System.out.println(byteToHex(pub)); + byte[] pri= keyPair.getPrivate().getEncoded(); + System.out.println(byteToHex(pri)); + + //测试“Z值”哈希值 + SM2PublicKey sm2PublicKey = new SM2PublicKey(pub); + byte[] zHash = sm2PublicKey.computeZ("Hello, GmSSL"); + System.out.println("zHash:"+byteToHex(zHash)); + + Cipher cipher = Cipher.getInstance("SM2", "GmSSL"); + // 测试加密 + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); + byte[] plaintext = "Hello, GmSSL".getBytes(); + byte[] ciphertext = cipher.doFinal(plaintext); + System.out.println("Ciphertext: " + byteToHex(ciphertext)); + // 测试解密 + cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + byte[] decrypted = cipher.doFinal(ciphertext); + System.out.println("Decrypted: " + new String(decrypted)); + + // 测试签名验签 + Signature signature = Signature.getInstance("SM2", "GmSSL"); + // 测试签名 + signature.initSign(keyPair.getPrivate()); + byte[] signatureText = "Hello, GmSSL".getBytes(); + signature.update(signatureText); + byte[] signatureByte = signature.sign(); + System.out.println("Signature:"+byteToHex(signatureByte)); + // 测试验签 + signature.initVerify(keyPair.getPublic()); + signature.update(signatureText); + boolean signatureResult = signature.verify(signatureByte); + System.out.println("SignatureResult:"+signatureResult); + + //测试导入私钥公钥签名验签 + Signature signatureImport = Signature.getInstance("SM2", "GmSSL"); + // 测试导入私钥 + String privateKeyInfoHex="308193020100301306072a8648ce3d020106082a811ccf5501822d0479307702010104207fef3e258348873c47117c15093266e9dad99e131f1778e53d362b2b70649f85a00a06082a811ccf5501822da14403420004f94c0abb6cd00c6f0918cb9c54162213501d5cc278f5d3fcf63886f4e1dc6322b1b110e33a25216f258c4cce5fd52ab320d3b086ee5390f7387218c92578c3ab"; + byte[] privateKeyInfo = hexToByte(privateKeyInfoHex); + signatureImport.initSign(new SM2PrivateKey(privateKeyInfo)); + signatureImport.update(signatureText); + byte[] signatureByteImport = signatureImport.sign(); + System.out.println("Signature:"+byteToHex(signatureByteImport)); + // 测试导入公钥 + String publicKeyInfoHex = "3059301306072a8648ce3d020106082a811ccf5501822d03420004f94c0abb6cd00c6f0918cb9c54162213501d5cc278f5d3fcf63886f4e1dc6322b1b110e33a25216f258c4cce5fd52ab320d3b086ee5390f7387218c92578c3ab"; + byte[] publicKeyInfo = hexToByte(publicKeyInfoHex); + signatureImport.initVerify(new SM2PublicKey(publicKeyInfo)); + signatureImport.update(signatureText); + boolean signatureResultImport = signatureImport.verify(signatureByteImport); + System.out.println("SignatureResult:"+signatureResultImport); } @Test @@ -98,32 +122,48 @@ public void sm2_certificate_test() throws Exception{ @Test public void SM3Test() throws Exception{ - String text="Hello, GmSSL"; - //测试SM3哈希 - MessageDigest sm3Digest = MessageDigest.getInstance("SM3","GmSSL"); - sm3Digest.update("abc".getBytes()); - byte[] digest = sm3Digest.digest(); - sm3Digest.reset(); - sm3Digest.update(text.getBytes()); - System.out.println("digest:"+byteToHex(digest)); - - //基于SM3的HMAC消息认证码算法 - Mac hmac = Mac.getInstance("SM3Hmac", "GmSSL"); - hmac.init(new SecretKeySpec(new Random().randBytes(Sm3Hmac.MAC_SIZE), "SM3Hmac")); - hmac.update(text.getBytes()); - byte[] hmacFinal = hmac.doFinal(); - System.out.println("hmac:"+byteToHex(hmacFinal)); - - //基于口令的密钥导出函数PBKDF2 - char[] password = "P@ssw0rd".toCharArray(); - byte[] salt = new Random().randBytes(SM3Pbkdf2.DEFAULT_SALT_SIZE); - int iterations = SM3Pbkdf2.MIN_ITER * 2; - int keyLength = SM3Pbkdf2.MAX_KEY_SIZE; - PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength); - SecretKeyFactory skf = SecretKeyFactory.getInstance("SM3Pbkdf2"); - SecretKey key = skf.generateSecret(spec); - byte[] keyBytes = key.getEncoded(); - System.out.println("DerivedKey: " + byteToHex(keyBytes)); + String text="Hello, GmSSL"; + //测试SM3哈希 + MessageDigest sm3Digest = MessageDigest.getInstance("SM3","GmSSL"); + sm3Digest.update("abc".getBytes()); + sm3Digest.reset(); + sm3Digest.update(text.getBytes()); + byte[] digest = sm3Digest.digest(); + System.out.println("digest:"+byteToHex(digest)); + + //基于SM3的HMAC消息认证码算法 + Mac hmac = Mac.getInstance("SM3", "GmSSL"); + hmac.init(new SecretKeySpec(new Random().randBytes(SM3Hmac.MAC_SIZE), "SM3")); + hmac.update(text.getBytes()); + byte[] hmacFinal = hmac.doFinal(); + System.out.println("hmac:"+byteToHex(hmacFinal)); + + //基于口令的密钥导出函数PBKDF2 + char[] password = "P@ssw0rd".toCharArray(); + byte[] salt = new Random().randBytes(SM3Pbkdf2.DEFAULT_SALT_SIZE); + int iterations = SM3Pbkdf2.MIN_ITER * 2; + int keyLength = SM3Pbkdf2.MAX_KEY_SIZE; + PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength); + SecretKeyFactory skf = SecretKeyFactory.getInstance("SM3Pbkdf2"); + SecretKey key = skf.generateSecret(spec); + byte[] keyBytes = key.getEncoded(); + System.out.println("DerivedKey: " + byteToHex(keyBytes)); + } + + @Test + public void SM4_ECB_test() throws Exception{ + SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); + // 测试SM4加密,固定16个长度 + Cipher sm4Cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", "GmSSL"); + SecretKeySpec sm4Key = new SecretKeySpec(secureRandom.generateSeed(SM4.KEY_SIZE), "SM4"); + sm4Cipher.init(Cipher.ENCRYPT_MODE, sm4Key); + sm4Cipher.update("87654321".getBytes(),0, 8); + byte[] ciphertext = sm4Cipher.doFinal("12345678".getBytes(), 0, 8); + System.out.println("Ciphertext: " + byteToHex(ciphertext)); + // 测试SM4解密 + sm4Cipher.init(Cipher.DECRYPT_MODE, sm4Key); + byte[] plaintext = sm4Cipher.doFinal(ciphertext, 0, 16); + System.out.println("plaintext: " + new String(plaintext)); } //SM4 C代码是否已进行了填充处理?填充后的密文与填充前明文长度是否一致,密文如何知道长度反向出明文?填充模式和算法模式是否是绑定的,比如GCM只能zeroPadding? @@ -135,18 +175,6 @@ public void SM4_CBC_test() throws Exception{ secureRandom.nextBytes(randomBytes); System.out.println("Generated Random Bytes: " + byteToHex(randomBytes)); - /*// 测试SM4加密,固定16个长度 - Cipher sm4Cipher = Cipher.getInstance("SM4", "GmSSL"); - SecretKeySpec sm4Key = new SecretKeySpec(secureRandom.generateSeed(SM4.KEY_SIZE), "SM4"); - sm4Cipher.init(Cipher.ENCRYPT_MODE, sm4Key); - sm4Cipher.update("87654321".getBytes(),0, 8); - byte[] ciphertext = sm4Cipher.doFinal("12345678".getBytes(), 0, 8); - System.out.println("Ciphertext: " + byteToHex(ciphertext)); - // 测试SM4解密 - sm4Cipher.init(Cipher.DECRYPT_MODE, sm4Key); - byte[] plaintext = sm4Cipher.doFinal(ciphertext, 0, 16); - System.out.println("plaintext: " + new String(plaintext));*/ - Cipher sm4cbcCipher = Cipher.getInstance("SM4/CBC/PKCS5Padding", "GmSSL"); byte[] key = secureRandom.generateSeed(SM4CBC.KEY_SIZE); byte[] iv = secureRandom.generateSeed(SM4CBC.IV_SIZE); @@ -156,6 +184,7 @@ public void SM4_CBC_test() throws Exception{ int inputLen = plaintext.length - inputOffset; byte[] ciphertext = new byte[inputLen+SM4CBC.BLOCK_SIZE]; //int test= sm4cbcCipher.update("abc".getBytes(), 0, 3, ciphertext, 0); + //System.out.println(ciphertext); int cipherlen = sm4cbcCipher.doFinal(plaintext, inputOffset, inputLen,ciphertext, 0); byte[] ciphertext1 = Arrays.copyOfRange(ciphertext,0,cipherlen); System.out.println("Ciphertext: " + byteToHex(ciphertext1)); @@ -194,7 +223,7 @@ public void SM4_CTR_test() throws Exception{ public void SM4_GCM_test() throws Exception { String text="Hello, GmSSL"; SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); - Cipher sm4Cipher = Cipher.getInstance("SM4/GCM/ZeroPadding", "GmSSL"); + Cipher sm4Cipher = Cipher.getInstance("SM4/GCM/NoPadding", "GmSSL"); byte[] key = secureRandom.generateSeed(SM4GCM.KEY_SIZE); byte[] iv = secureRandom.generateSeed(SM4GCM.DEFAULT_IV_SIZE); byte[] aad = "Hello: ".getBytes(); diff --git a/src/test/java/org/gmssl/Sm4EcbTest.java b/src/test/java/org/gmssl/Sm4EcbTest.java index b218c09..91fe1a1 100644 --- a/src/test/java/org/gmssl/Sm4EcbTest.java +++ b/src/test/java/org/gmssl/Sm4EcbTest.java @@ -32,7 +32,7 @@ public void beforeTest(){ @Test public void encryptTest(){ String test_plaintext="gmssl"; - byte[] paddingPlaintext=pkcs5padding(test_plaintext.getBytes(),Sm4.BLOCK_SIZE); + byte[] paddingPlaintext=pkcs7padding(test_plaintext.getBytes(),Sm4.BLOCK_SIZE); byte[] encrypted = encrypt(paddingPlaintext,key); //System.out.println("encrypted data:"+HexUtil.byteToHex(encrypted)); Assert.assertNotNull("data is empty exception!",encrypted); @@ -44,7 +44,7 @@ public void decryptTest(){ String test_plaintext="gmssl"; byte[] encrypted =HexUtil.hexToByte(test_hex_chipertext); byte[] plaintextArray = decrypt(encrypted,key); - byte[] unpaddingPlaintextArray = pkcs5Unpadding(plaintextArray); + byte[] unpaddingPlaintextArray = pkcs7UnPadding(plaintextArray); String plaintext=new String(unpaddingPlaintextArray); //System.out.println("chipertext:"+plaintext); Assert.assertEquals("original value is not equal to the expected value after decryption!",plaintext,test_plaintext); @@ -52,40 +52,40 @@ public void decryptTest(){ /** - * The purpose of PKCS5Padding is to pad the data to the block size required by the encryption algorithm, ensuring that the data length meets the requirements of the encryption algorithm. - * In special cases where the data length is already a multiple of the block size, according to the PKCS5 rule, padding is still added at the end. + * The purpose of PKCS7Padding is to pad the data to the block size required by the encryption algorithm, ensuring that the data length meets the requirements of the encryption algorithm. + * In special cases where the data length is already a multiple of the block size, according to the PKCS7 rule, padding is still added at the end. * This is done to ensure consistent handling of padding during encryption and decryption processes. - * @param ciphertextArray + * @param byteArray * @param blockSize - * @return byte[] ciphertext + * @return byte[] padding array */ - private static byte[] pkcs5padding(byte[] ciphertextArray, int blockSize) { - int paddingLength = blockSize - (ciphertextArray.length % blockSize); + private static byte[] pkcs7padding(byte[] byteArray, int blockSize) { + int paddingLength = blockSize - (byteArray.length % blockSize); byte[] padding = new byte[paddingLength]; Arrays.fill(padding, (byte) paddingLength); - byte[] result = new byte[ciphertextArray.length + padding.length]; - System.arraycopy(ciphertextArray, 0, result, 0, ciphertextArray.length); - System.arraycopy(padding, 0, result, ciphertextArray.length, padding.length); + byte[] result = new byte[byteArray.length + padding.length]; + System.arraycopy(byteArray, 0, result, 0, byteArray.length); + System.arraycopy(padding, 0, result, byteArray.length, padding.length); return result; } /** - * unpadding the plaintext - * @param plaintextArray - * @return byte[] plaintext + * unPadding the byteArray + * @param byteArray + * @return byte[] unPadding byteArray * @throws IllegalArgumentException */ - private static byte[] pkcs5Unpadding(byte[] plaintextArray) throws IllegalArgumentException { - int paddingSize = plaintextArray[plaintextArray.length - 1]; - if (paddingSize <= 0 || paddingSize > plaintextArray.length) { - throw new IllegalArgumentException("Invalid pkcs#5 padding!"); + private static byte[] pkcs7UnPadding(byte[] byteArray) throws IllegalArgumentException { + int paddingSize = byteArray[byteArray.length - 1]; + if (paddingSize <= 0 || paddingSize > byteArray.length) { + throw new IllegalArgumentException("Invalid pkcs#7 padding!"); } - for (int i = plaintextArray.length - paddingSize; i < plaintextArray.length; i++) { - if (plaintextArray[i] != paddingSize) { - throw new IllegalArgumentException("Invalid pkcs#5 padding!"); + for (int i = byteArray.length - paddingSize; i < byteArray.length; i++) { + if (byteArray[i] != paddingSize) { + throw new IllegalArgumentException("Invalid pkcs#7 padding!"); } } - return Arrays.copyOfRange(plaintextArray, 0, plaintextArray.length - paddingSize); + return Arrays.copyOfRange(byteArray, 0, byteArray.length - paddingSize); } From 8dbf393293960bd3c06b493c10a29df79fce2da3 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Thu, 19 Sep 2024 17:40:46 +0800 Subject: [PATCH 15/20] jce develop --- .../java/org/gmssl/crypto/GmSSLProvider.java | 8 +- .../org/gmssl/crypto/PKCS7PaddingScheme.java | 30 +- .../java/org/gmssl/crypto/PaddingScheme.java | 19 +- .../gmssl/crypto/asymmetric/SM2Cipher.java | 3 - .../gmssl/crypto/asymmetric/SM9Cipher.java | 3 - .../java/org/gmssl/crypto/symmetric/SM4.java | 125 --------- .../org/gmssl/crypto/symmetric/SM4CBC.java | 62 +++-- .../org/gmssl/crypto/symmetric/SM4CTR.java | 42 ++- .../org/gmssl/crypto/symmetric/SM4Cipher.java | 5 + .../org/gmssl/crypto/symmetric/SM4ECB.java | 86 ++++-- .../org/gmssl/crypto/symmetric/SM4Engine.java | 9 +- .../org/gmssl/crypto/symmetric/SM4GCM.java | 56 +++- .../org/gmssl/crypto/symmetric/ZucCipher.java | 64 +++-- src/test/java/org/gmssl/JceTest.java | 257 +++++++++++------- src/test/java/org/gmssl/Sm4EcbTest.java | 2 +- 15 files changed, 424 insertions(+), 347 deletions(-) delete mode 100644 src/main/java/org/gmssl/crypto/symmetric/SM4.java diff --git a/src/main/java/org/gmssl/crypto/GmSSLProvider.java b/src/main/java/org/gmssl/crypto/GmSSLProvider.java index f8b6f2f..60d1e31 100644 --- a/src/main/java/org/gmssl/crypto/GmSSLProvider.java +++ b/src/main/java/org/gmssl/crypto/GmSSLProvider.java @@ -15,7 +15,9 @@ * @email 290836576@qq.com * @date 2024/07/27 * @description - * + * GmSSL-Java currently provides functionality for random number generation, SM3 hash, SM3 message authentication code (HMAC-SM3), + * SM4 encryption (including block encryption and CBC/CTR/GCM encryption modes), ZUC encryption, SM2 encryption/signature, SM9 encryption/signature, and SM2 certificate parsing. + * These features cover the main application development scenarios for the current Chinese cryptographic algorithms. */ public class GmSSLProvider extends Provider { @@ -26,17 +28,13 @@ public GmSSLProvider() { put("Cipher.SM2", "org.gmssl.crypto.asymmetric.SM2Cipher"); put("KeyPairGenerator.SM2", "org.gmssl.crypto.asymmetric.SM2KeyPairGenerator"); put("Signature.SM2", "org.gmssl.crypto.asymmetric.SM2Signature"); - put("MessageDigest.SM3", "org.gmssl.crypto.digest.SM3Digest"); put("Mac.SM3", "org.gmssl.crypto.digest.SM3Hmac"); put("SecretKeyFactory.SM3Pbkdf2", "org.gmssl.crypto.digest.SM3Pbkdf2"); - put("Cipher.SM4", "org.gmssl.crypto.symmetric.SM4Cipher"); - put("Cipher.SM9", "org.gmssl.crypto.asymmetric.SM9Cipher"); put("Signature.SM9", "org.gmssl.crypto.asymmetric.SM9Signature"); put("KeyPairGenerator.SM9", "org.gmssl.crypto.asymmetric.SM9KeyPairGeneratorSpi"); - put("Cipher.ZUC", "org.gmssl.crypto.symmetric.ZucCipher"); } diff --git a/src/main/java/org/gmssl/crypto/PKCS7PaddingScheme.java b/src/main/java/org/gmssl/crypto/PKCS7PaddingScheme.java index 006445e..79e01a5 100644 --- a/src/main/java/org/gmssl/crypto/PKCS7PaddingScheme.java +++ b/src/main/java/org/gmssl/crypto/PKCS7PaddingScheme.java @@ -8,26 +8,44 @@ */ package org.gmssl.crypto; +import java.util.Arrays; + /** * @author yongfeili * @email 290836576@qq.com * @date 2024/07/27 - * @description + * @description PKCS#7 * */ public class PKCS7PaddingScheme implements PaddingScheme{ @Override public String getPaddingName() { - return null; + return "PKCS#7"; } @Override - public int addPadding(byte[] in, int inOff) { - return 0; + public byte[] pad(byte[] input, int blockSize) { + int paddingLength = blockSize - (input.length % blockSize); + byte[] padding = new byte[paddingLength]; + Arrays.fill(padding, (byte) paddingLength); + byte[] result = new byte[input.length + padding.length]; + System.arraycopy(input, 0, result, 0, input.length); + System.arraycopy(padding, 0, result, input.length, padding.length); + return result; } @Override - public int padCount(byte[] in) { - return 0; + public byte[] unpad(byte[] input) { + int paddingSize = input[input.length - 1]; + if (paddingSize <= 0 || paddingSize > input.length) { + throw new IllegalArgumentException("Invalid pkcs#7 padding!"); + } + for (int i = input.length - paddingSize; i < input.length; i++) { + if (input[i] != paddingSize) { + throw new IllegalArgumentException("Invalid pkcs#7 padding!"); + } + } + return Arrays.copyOfRange(input, 0, input.length - paddingSize); } + } diff --git a/src/main/java/org/gmssl/crypto/PaddingScheme.java b/src/main/java/org/gmssl/crypto/PaddingScheme.java index 9aa2079..1c18535 100644 --- a/src/main/java/org/gmssl/crypto/PaddingScheme.java +++ b/src/main/java/org/gmssl/crypto/PaddingScheme.java @@ -17,9 +17,24 @@ */ public interface PaddingScheme { + /** + * get padding name + * @return paddingName + */ String getPaddingName(); - int addPadding(byte[] in, int inOff); + /** + * Pad according to fixed block size + * @param input Data to be padded + * @param blockSize block size + * @return padded data + */ + byte[] pad(byte[] input, int blockSize); - int padCount(byte[] in); + /** + * Unpad according to fixed block size + * @param input Data to be unpadded + * @return unpadded data + */ + byte[] unpad(byte[] input); } diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java index 33f21df..c6905a3 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java @@ -64,9 +64,6 @@ protected int engineGetBlockSize() { @Override protected int engineGetOutputSize(int inputLen) { - // TODO 计算输出长度。加密模式和解密模式输出长度随机,在+-3范围内跳动 - //cipherLen=65+plainTextLen+32 cipherLen=C1_size+plainTextLen+C3_size - //plainTextLen=cipherLen−C1_size−C3_size plainTextLen=cipherLen−65−32 return 0; } diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java index a1c2dc6..ae2a5e3 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java @@ -67,9 +67,6 @@ protected int engineGetBlockSize() { @Override protected int engineGetOutputSize(int inputLen) { - //TODO 输出长度具有随机性,输入与输出长度偏差值在119-120范围内浮动 - //32 + inputLen + 32 encrypt - //inputLen - 64 decrypt return 0; } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4.java b/src/main/java/org/gmssl/crypto/symmetric/SM4.java deleted file mode 100644 index 3fb92aa..0000000 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package org.gmssl.crypto.symmetric; - -import org.gmssl.GmSSLException; -import org.gmssl.GmSSLJNI; - -import javax.crypto.*; -import java.nio.ByteBuffer; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.SecureRandom; - -/** - * @author yongfeili - * @email 290836576@qq.com - * @date 2024/07/27 - * @description - * - */ -public class SM4 extends SM4Cipher { - - public final static int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; - public final static int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; - - private Key key; - private long sm4_key = 0; - - private boolean do_encrypt = false; - - private ByteBuffer buffer; - - @Override - protected int engineGetBlockSize() { - // SM4块大小为16字节 - return BLOCK_SIZE; - } - - @Override - protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - if (!(key instanceof SecretKey)) { - throw new GmSSLException("Invalid KeySpec"); - } - this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); - this.key = key; - // 初始化缓冲区 - this.buffer = ByteBuffer.allocate(2048); - init(); - } - - @Override - protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { - buffer.put(input, inputOffset, inputLen); - // 暂时不返回输出,等待 doFinal - return buffer.array(); - } - - @Override - protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { - buffer.put(input, inputOffset, inputLen); - // 暂时不返回输出,等待 doFinal - return output.length; - } - - @Override - protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { - buffer.put(input, inputOffset, inputLen); - byte[] data = new byte[buffer.position()]; - buffer.flip(); - buffer.get(data); - - byte[] output = new byte[buffer.position()]; - encrypt(data,0,output,0); - buffer.clear(); - return output; - } - - @Override - protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - encrypt(input,inputOffset,output,outputOffset); - //计算返回实际长度 - return output.length; - } - - private void init(){ - if ((sm4_key = GmSSLJNI.sm4_key_new()) == 0) { - throw new GmSSLException(""); - } - - if (do_encrypt == true) { - if (GmSSLJNI.sm4_set_encrypt_key(sm4_key, key.getEncoded()) != 1) { - throw new GmSSLException(""); - } - } else { - if (GmSSLJNI.sm4_set_decrypt_key(sm4_key, key.getEncoded()) != 1) { - throw new GmSSLException(""); - } - } - } - - public void encrypt(byte[] in, int in_offset, byte[] out, int out_offset) { - if (in == null - || in_offset < 0 - || in_offset + this.BLOCK_SIZE <= 0 - || in_offset + this.BLOCK_SIZE > in.length) { - throw new GmSSLException(""); - } - if (out == null - || out_offset < 0 - || out_offset + this.BLOCK_SIZE <= 0 - || out_offset + this.BLOCK_SIZE > in.length) { - throw new GmSSLException(""); - } - - if (GmSSLJNI.sm4_encrypt(sm4_key, in, in_offset, out, out_offset) != 1) { - throw new GmSSLException(""); - } - } -} diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java index 710f87d..a2215e4 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java @@ -11,16 +11,13 @@ import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; -import javax.crypto.BadPaddingException; import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.ShortBufferException; import javax.crypto.spec.IvParameterSpec; -import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; /** * @author yongfeili @@ -33,35 +30,31 @@ public class SM4CBC extends SM4Engine { public final static int IV_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; - private long sm4_cbc_ctx = 0; + private long sm4_cbc_ctx; private byte[] iv; private boolean do_encrypt = true; - private boolean inited = false; + private boolean inited; - private int offset = 0; + private int offset; - public SM4CBC() { + private byte[] outputByteArray; + + protected SM4CBC() { super(); ctx(); } - @Override protected byte[] engineGetIV() { return iv; } - @Override - protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { - return new byte[0]; - } - @Override protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - + throw new GmSSLException("Initialization method not supported!"); } @Override @@ -72,27 +65,48 @@ protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRa this.iv = ((IvParameterSpec) params).getIV(); this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); init(key.getEncoded(), iv, do_encrypt); + + outputByteArray = new byte[BLOCK_SIZE]; + } + + @Override + protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { + byte[] tempByteArray=new byte[outputByteArray.length+inputLen]; + System.arraycopy(outputByteArray,0,tempByteArray,0,outputByteArray.length); + outputByteArray=tempByteArray; + + int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); + return Arrays.copyOfRange(outputByteArray,0,outLen); } @Override - protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset){ int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset+=outLen; - return outLen; + return offset; } @Override - protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - this.processUpdate(input, inputOffset, inputLen, output, outputOffset); - int outLen = doFinal(output, this.offset); + protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) { + if(null!=input){ + processUpdate(input, inputOffset, inputLen); + } + int outLen = doFinal(outputByteArray, this.offset); outLen = outLen + this.offset; this.offset = 0; - return outLen; + outputByteArray = Arrays.copyOfRange(outputByteArray,0,outLen); + return outputByteArray; } @Override - protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { - return new byte[0]; + protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { + if(null!=input){ + this.processUpdate(input, inputOffset, inputLen, output, outputOffset); + } + int outLen = doFinal(output, this.offset); + outLen = outLen + this.offset; + this.offset = 0; + return outLen; } private void ctx() { @@ -110,7 +124,7 @@ private void init(byte[] key, byte[] iv, boolean do_encrypt) { throw new GmSSLException(""); } - if (do_encrypt == true) { + if (do_encrypt) { if (GmSSLJNI.sm4_cbc_encrypt_init(this.sm4_cbc_ctx, key, iv) != 1) { throw new GmSSLException(""); } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java index b5c71d9..fb9ec29 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java @@ -19,6 +19,7 @@ import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; /** * @author yongfeili @@ -38,14 +39,16 @@ public class SM4CTR extends SM4Engine { private int offset; - public SM4CTR() { + private byte[] outputByteArray; + + protected SM4CTR() { super(); ctx(); } @Override protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - + throw new GmSSLException("Initialization method not supported!"); } @Override @@ -55,6 +58,8 @@ protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRa } this.iv = ((IvParameterSpec) params).getIV(); init(key.getEncoded(), iv); + + outputByteArray = new byte[BLOCK_SIZE]; } @Override @@ -64,31 +69,44 @@ protected byte[] engineGetIV() { @Override protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { - return new byte[0]; + byte[] tempByteArray=new byte[outputByteArray.length+inputLen]; + System.arraycopy(outputByteArray,0,tempByteArray,0,outputByteArray.length); + outputByteArray=tempByteArray; + + int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); + return Arrays.copyOfRange(outputByteArray,0,outLen); } @Override - protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset += outLen; - return outLen; + return offset; } @Override - protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - processUpdate(input, inputOffset, inputLen, output, outputOffset); - int outLen = doFinal(output, this.offset); + protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + if(null!=input){ + processUpdate(input, inputOffset, inputLen); + } + int outLen = doFinal(outputByteArray, this.offset); outLen = outLen + this.offset; this.offset = 0; - return outLen; + outputByteArray = Arrays.copyOfRange(outputByteArray,0,outLen); + return outputByteArray; } @Override - protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { - return new byte[0]; + protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + if(null!=input) { + processUpdate(input, inputOffset, inputLen, output, outputOffset); + } + int outLen = doFinal(output, this.offset); + outLen = outLen + this.offset; + this.offset = 0; + return outLen; } - public void ctx(){ if ((this.sm4_ctr_ctx = GmSSLJNI.sm4_ctr_ctx_new()) == 0) { throw new GmSSLException(""); diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java index a635cb6..d4da510 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java @@ -8,6 +8,7 @@ */ package org.gmssl.crypto.symmetric; +import org.gmssl.GmSSLJNI; import org.gmssl.crypto.CipherPaddingEnum; import org.gmssl.crypto.PKCS7PaddingScheme; @@ -24,6 +25,10 @@ */ public class SM4Cipher extends CipherSpi { + public static final int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; + + public static final int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + private SM4Engine sm4Engine; public SM4Cipher() { diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java b/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java index 719f9b9..27352c5 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4ECB.java @@ -10,6 +10,7 @@ import org.gmssl.GmSSLException; import org.gmssl.GmSSLJNI; +import org.gmssl.Sm4; import javax.crypto.*; import java.nio.ByteBuffer; @@ -17,6 +18,7 @@ import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; /** * @author yongfeili @@ -27,13 +29,10 @@ */ public class SM4ECB extends SM4Engine { - public final static int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; - public final static int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; - private Key key; - private long sm4_key = 0; + private long sm4_key; - private boolean do_encrypt = false; + private boolean do_encrypt; private ByteBuffer buffer; @@ -51,7 +50,7 @@ protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyE @Override protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) { - + throw new GmSSLException("Initialization method not supported!"); } @Override @@ -59,6 +58,14 @@ protected byte[] engineGetIV() { return null; } + /** + * Mainly used for caching data; it will not immediately generate encryption or decryption results + * @param input + * @param inputOffset + * @param inputLen + * @return null + * Return a non-actual value; actual encryption or decryption operations are performed in processBlock + */ @Override protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { putBytes(input, inputOffset, inputLen); @@ -66,28 +73,65 @@ protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { } @Override - protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { - putBytes(input, inputOffset, inputLen); - return 0; - } + protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + if(null!=input){ + putBytes(input, inputOffset, inputLen); + } + byte[] data = new byte[buffer.position()]; + buffer.flip(); + buffer.get(data); - @Override - protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + byte[] outPutByteArray = new byte[buffer.position()]; + if(do_encrypt){ + data = this.paddingScheme.pad(data,this.BLOCK_SIZE); + outPutByteArray = new byte[data.length]; + for (int i = 0; i < data.length; i += this.BLOCK_SIZE) { + encrypt(data,i,outPutByteArray,i); + } + }else{ + for (int i = 0; i < data.length; i += this.BLOCK_SIZE) { + encrypt(data,i,outPutByteArray,i); + } + outPutByteArray=this.paddingScheme.unpad(outPutByteArray); + } - return 0; + buffer.clear(); + return outPutByteArray; } + /** + * Mainly used for caching data; it will not immediately generate encryption or decryption results + * @param input + * @param inputOffset + * @param inputLen + * @param output + * @param outputOffset + * @return 0 + * Return a non-actual value; actual encryption or decryption operations are performed in processBlock + */ @Override - protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { putBytes(input, inputOffset, inputLen); - byte[] data = new byte[buffer.position()]; - buffer.flip(); - buffer.get(data); + return 0; + } - byte[] output = new byte[buffer.position()]; - encrypt(data,0,output,0); - buffer.clear(); - return output; + /** + * + * @param input + * @param inputOffset + * @param inputLen + * @param output + * @param outputOffset + * @return actual encryption or decryption bytes length,not the whole length of the output data + * + * @throws IllegalBlockSizeException + * @throws BadPaddingException + */ + @Override + protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws IllegalBlockSizeException, BadPaddingException { + byte[] outPutByteArray = processBlock(input, inputOffset, inputLen); + System.arraycopy(outPutByteArray, 0,output, outputOffset, outPutByteArray.length); + return outPutByteArray.length; } private void putBytes(byte[] input, int inputOffset, int inputLen){ diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java index 5bd2b69..52bfe1c 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Engine.java @@ -29,11 +29,11 @@ */ public abstract class SM4Engine { - protected PaddingScheme paddingScheme; + public static final int KEY_SIZE = SM4Cipher.KEY_SIZE; - public static final int KEY_SIZE = GmSSLJNI.SM4_KEY_SIZE; + public static final int BLOCK_SIZE = SM4Cipher.BLOCK_SIZE; - public static final int BLOCK_SIZE = GmSSLJNI.SM4_BLOCK_SIZE; + protected PaddingScheme paddingScheme; protected abstract void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException; @@ -50,7 +50,4 @@ public abstract class SM4Engine { protected abstract byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException; protected void processUpdateAAD(byte[] src, int offset, int len){}; - //String getAlgorithmName(); - - //int getBlockSize(); } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java index 0aecef4..b7ee7df 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java @@ -16,10 +16,12 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.ShortBufferException; import javax.crypto.spec.GCMParameterSpec; +import java.nio.ByteBuffer; import java.security.InvalidKeyException; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; /** * @author yongfeili @@ -42,7 +44,7 @@ public class SM4GCM extends SM4Engine { private byte[] iv; - private byte[] aad; + private ByteBuffer aad; private Key key; @@ -50,14 +52,16 @@ public class SM4GCM extends SM4Engine { private int offset; - public SM4GCM(){ + private byte[] outputByteArray; + + protected SM4GCM(){ super(); ctx(); } @Override protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - + throw new GmSSLException("Initialization method not supported!"); } @Override @@ -69,6 +73,9 @@ protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRa this.iv = ((GCMParameterSpec) params).getIV(); this.tLen = ((GCMParameterSpec) params).getTLen(); this.do_encrypt = (opmode == Cipher.ENCRYPT_MODE); + + outputByteArray = new byte[BLOCK_SIZE+tLen]; + aad=ByteBuffer.allocate(BLOCK_SIZE+tLen); } @Override @@ -78,36 +85,55 @@ protected byte[] engineGetIV() { @Override protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { - return new byte[0]; + byte[] tempByteArray=new byte[outputByteArray.length+inputLen]; + System.arraycopy(outputByteArray,0,tempByteArray,0,outputByteArray.length); + outputByteArray=tempByteArray; + + int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); + return Arrays.copyOfRange(outputByteArray,0,outLen); } @Override - protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset+=outLen; - return outLen; + return offset; } @Override - protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - processUpdate(input, inputOffset, inputLen, output, outputOffset); - int outLen = doFinal(output, this.offset); + protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { + if(null!=input){ + processUpdate(input, inputOffset, inputLen); + } + int outLen = doFinal(outputByteArray, this.offset); outLen = outLen + this.offset; this.offset = 0; - return outLen; + outputByteArray = Arrays.copyOfRange(outputByteArray,0,outLen); + return outputByteArray; } @Override - protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { - return new byte[0]; + protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + if(null!=input) { + processUpdate(input, inputOffset, inputLen, output, outputOffset); + } + int outLen = doFinal(output, this.offset); + outLen = outLen + this.offset; + this.offset = 0; + return outLen; } @Override protected void processUpdateAAD(byte[] src, int offset, int len) { - this.aad = new byte[len]; - System.arraycopy(src, offset, this.aad, 0, len); + if(aad.remaining() Date: Fri, 20 Sep 2024 16:38:40 +0800 Subject: [PATCH 16/20] jce develop --- .gitignore | 7 +- README.md | 8 +- src/main/java/org/gmssl/crypto/Random.java | 14 +++- .../java/org/gmssl/crypto/digest/SM3Hmac.java | 2 +- .../org/gmssl/crypto/symmetric/SM4CBC.java | 18 ++-- .../org/gmssl/crypto/symmetric/SM4CTR.java | 20 +++-- .../org/gmssl/crypto/symmetric/SM4Cipher.java | 9 +- .../crypto/symmetric/SM4CipherFactory.java | 19 +++++ .../org/gmssl/crypto/symmetric/SM4GCM.java | 20 +++-- .../org/gmssl/crypto/symmetric/ZucCipher.java | 22 ++--- src/main/resources/lib/libgmssljni.dll | Bin 0 -> 204800 bytes src/test/java/org/gmssl/JceTest.java | 78 +++++++++++------- 12 files changed, 134 insertions(+), 83 deletions(-) create mode 100644 src/main/resources/lib/libgmssljni.dll diff --git a/.gitignore b/.gitignore index 0187e2f..5e84b93 100644 --- a/.gitignore +++ b/.gitignore @@ -92,7 +92,6 @@ lint/tmp/ /.idea/ /target/ -/sm9enc.mpk -/sm9EncryptData.txt -/sm9sign.mpk -/sm9SignData.txt +/*.mpk +/*.txt +/*.pem diff --git a/README.md b/README.md index 9df6b1c..31f5aad 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,9 @@ GmSSL-Java是采用JNI (Java Native Interface)方式实现的,也就是说所 GmSSL的项目组成主要包括C语言的本地代码、`src`目录下的Java类库代码、`examples`目录下面的例子代码。其中只有本地代码和`src`下面的Java类库代码会参与默认的编译,生成动态库和Jar包,而`examples`下的例子默认不编译也不进入Jar包。 -GmSSL-Java提供一个包`org.gmssl`,其中包含如下密码算法类 +GmSSL-Java提供两种实现,基于JCE的实现和基于java本身的基础实现。 +JCE实现内容在包`org.gmssl.crypto`,可按照JCE调用方式完成各种算法功能,JCE调用可参考项目test目录下的JceTest类。因cipher属于Oracle java的受限“服务”,因此JCE调用前提必须使用[openJDK](https://jdk.java.net/archive/)。 +基础实现内容在包`org.gmssl`,JDK来源不限制,其中包含如下密码算法类 * org.gmssl.Random * org.gmssl.Sm3 @@ -57,7 +59,7 @@ GmSSL-Java提供一个包`org.gmssl`,其中包含如下密码算法类 ## 编译和安装 ### 编译安装GmSSL -GmSSL-Java依赖GmSSL项目,在编译前需要先在系统上编译、安装并测试通过GmSSL库及工具。请在https://github.com/guanzhi/GmSSL 项目上下载最新发布的GmSSL代码,并完成编译、测试和安装。 +GmSSL-Java依赖GmSSL项目,在编译前需要先在系统上编译、安装并测试通过GmSSL库及工具。请在https://github.com/guanzhi/GmSSL 项目上下载同一版本的GmSSL代码,并完成编译、测试和安装。 ### 通过Maven编译安装GmSSL-java @@ -84,7 +86,7 @@ mvn clean install 最终会执行单元测试并在target目录下生成相应版本jar包。 ## 使用 -在其他项目中使用GmSSL-java,只需在pom.xml中添加如下依赖: +以上步骤操作完成后会在本地Maven仓库生成项目相应jar包,在其他项目中使用GmSSL-java,只需在pom.xml中添加如下依赖: ```xml com.gmssl diff --git a/src/main/java/org/gmssl/crypto/Random.java b/src/main/java/org/gmssl/crypto/Random.java index fa40637..a19079a 100644 --- a/src/main/java/org/gmssl/crypto/Random.java +++ b/src/main/java/org/gmssl/crypto/Random.java @@ -28,23 +28,33 @@ public Random() { @Override protected void engineSetSeed(byte[] seed) { - + if (seed == null || seed.length == 0) { + throw new IllegalArgumentException("Seed cannot be null or empty"); + } + //rand_seed + throw new GmSSLException("The current method is not supported."); } @Override protected void engineNextBytes(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException("Output buffer cannot be null"); + } randBytes(bytes,0, bytes.length); } @Override protected byte[] engineGenerateSeed(int numBytes) { + if (numBytes <= 0) { + throw new IllegalArgumentException("Number of bytes must be positive"); + } return randBytes(numBytes); } public byte[] randBytes(int len) { byte[] out = new byte[len]; if (GmSSLJNI.rand_bytes(out, 0, len) != 1) { - throw new GmSSLException(""); + throw new GmSSLException("Failed to generate seed"); } return out; } diff --git a/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java b/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java index fc89f13..11d6243 100644 --- a/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java +++ b/src/main/java/org/gmssl/crypto/digest/SM3Hmac.java @@ -79,7 +79,7 @@ protected void engineUpdate(byte input) { @Override protected void engineUpdate(byte[] input, int offset, int len) { - this.update(input, 0, len); + this.update(input, offset, len); } @Override diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java index a2215e4..5c5fab2 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java @@ -71,19 +71,21 @@ protected void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRa @Override protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { - byte[] tempByteArray=new byte[outputByteArray.length+inputLen]; - System.arraycopy(outputByteArray,0,tempByteArray,0,outputByteArray.length); - outputByteArray=tempByteArray; + int newOutputLength = BLOCK_SIZE + offset + inputLen; + if (outputByteArray.length < newOutputLength) { + int newSize = Math.max(outputByteArray.length * 3 / 2 + BLOCK_SIZE, newOutputLength); + outputByteArray = Arrays.copyOf(outputByteArray, newSize); + } int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); - return Arrays.copyOfRange(outputByteArray,0,outLen); + return Arrays.copyOfRange(outputByteArray,offset,offset + outLen); } @Override protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset){ int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset+=outLen; - return offset; + return outLen; } @Override @@ -100,11 +102,11 @@ protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) { @Override protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { + int outLen = 0; if(null!=input){ - this.processUpdate(input, inputOffset, inputLen, output, outputOffset); + outLen=this.processUpdate(input, inputOffset, inputLen, output, outputOffset); } - int outLen = doFinal(output, this.offset); - outLen = outLen + this.offset; + outLen += doFinal(output, this.offset); this.offset = 0; return outLen; } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java index fb9ec29..c9dadb8 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java @@ -69,19 +69,21 @@ protected byte[] engineGetIV() { @Override protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { - byte[] tempByteArray=new byte[outputByteArray.length+inputLen]; - System.arraycopy(outputByteArray,0,tempByteArray,0,outputByteArray.length); - outputByteArray=tempByteArray; + int newOutputLength = BLOCK_SIZE + offset + inputLen; + if (outputByteArray.length < newOutputLength) { + int newSize = Math.max(outputByteArray.length * 3 / 2 + BLOCK_SIZE, newOutputLength); + outputByteArray = Arrays.copyOf(outputByteArray, newSize); + } int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); - return Arrays.copyOfRange(outputByteArray,0,outLen); + return Arrays.copyOfRange(outputByteArray,offset,offset + outLen); } @Override protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset += outLen; - return offset; + return outLen; } @Override @@ -98,11 +100,11 @@ protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throw @Override protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - if(null!=input) { - processUpdate(input, inputOffset, inputLen, output, outputOffset); + int outLen = 0; + if(null!=input){ + outLen=this.processUpdate(input, inputOffset, inputLen, output, outputOffset); } - int outLen = doFinal(output, this.offset); - outLen = outLen + this.offset; + outLen += doFinal(output, this.offset); this.offset = 0; return outLen; } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java index d4da510..2902c4c 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4Cipher.java @@ -9,8 +9,6 @@ package org.gmssl.crypto.symmetric; import org.gmssl.GmSSLJNI; -import org.gmssl.crypto.CipherPaddingEnum; -import org.gmssl.crypto.PKCS7PaddingScheme; import javax.crypto.*; import java.security.*; @@ -21,7 +19,7 @@ * @email 290836576@qq.com * @date 2024/07/27 * @description - * + * CBC、CTR、ECB、GCM */ public class SM4Cipher extends CipherSpi { @@ -42,9 +40,7 @@ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { - if(CipherPaddingEnum.PKCS7Padding.name().equals(padding)){ - this.sm4Engine.paddingScheme=new PKCS7PaddingScheme(); - } + SM4CipherFactory.setPaddingScheme(sm4Engine, padding); } @Override @@ -54,7 +50,6 @@ protected int engineGetBlockSize() { @Override protected int engineGetOutputSize(int inputLen) { - // 输出大小根据模式和填充计算 return 0; } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java index 1093312..cde6769 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CipherFactory.java @@ -8,6 +8,9 @@ */ package org.gmssl.crypto.symmetric; +import org.gmssl.crypto.CipherPaddingEnum; +import org.gmssl.crypto.PKCS7PaddingScheme; + import java.security.NoSuchAlgorithmException; /** @@ -19,6 +22,11 @@ */ public class SM4CipherFactory { + /** + * Create an SM4 encryption and decryption engine that supports ECB, CBC, CTR, and GCM modes. + * @param mode + * @return + */ public static SM4Engine createCipher(String mode){ SM4Engine cipher; try { @@ -44,4 +52,15 @@ public static SM4Engine createCipher(String mode){ return cipher; } + /** + * Currently, only the PKCS7Padding padding mode for ECB algorithm mode is set. Other algorithms (SM4/CBC/PKCS5Padding, SM4/CTR/NoPadding, SM4/GCM/NoPadding) have their default padding implemented. + * @param engine + * @param padding + */ + public static void setPaddingScheme(SM4Engine engine, String padding) { + if(CipherPaddingEnum.PKCS7Padding.name().equals(padding)){ + engine.paddingScheme=new PKCS7PaddingScheme(); + } + } + } diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java index b7ee7df..1c32e38 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java @@ -85,19 +85,21 @@ protected byte[] engineGetIV() { @Override protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { - byte[] tempByteArray=new byte[outputByteArray.length+inputLen]; - System.arraycopy(outputByteArray,0,tempByteArray,0,outputByteArray.length); - outputByteArray=tempByteArray; + int newOutputLength = BLOCK_SIZE + offset + tLen + inputLen; + if (outputByteArray.length < newOutputLength) { + int newSize = Math.max(outputByteArray.length * 3 / 2 + BLOCK_SIZE + tLen, newOutputLength); + outputByteArray = Arrays.copyOf(outputByteArray, newSize); + } int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); - return Arrays.copyOfRange(outputByteArray,0,outLen); + return Arrays.copyOfRange(outputByteArray,offset,offset + outLen); } @Override protected int processUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset+=outLen; - return offset; + return outLen; } @Override @@ -114,11 +116,11 @@ protected byte[] processBlock(byte[] input, int inputOffset, int inputLen) throw @Override protected int processBlock(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - if(null!=input) { - processUpdate(input, inputOffset, inputLen, output, outputOffset); + int outLen = 0; + if(null!=input){ + outLen=this.processUpdate(input, inputOffset, inputLen, output, outputOffset); } - int outLen = doFinal(output, this.offset); - outLen = outLen + this.offset; + outLen += doFinal(output, this.offset); this.offset = 0; return outLen; } diff --git a/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java b/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java index 5a971a7..8b11fe7 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java +++ b/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java @@ -41,7 +41,7 @@ public class ZucCipher extends CipherSpi { private byte[] outputByteArray; - protected ZucCipher(){ + public ZucCipher(){ ctx(); } @@ -109,19 +109,21 @@ protected void engineInit(int opmode, Key key, AlgorithmParameters params, Secur @Override protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { - byte[] tempByteArray=new byte[outputByteArray.length+inputLen]; - System.arraycopy(outputByteArray,0,tempByteArray,0,outputByteArray.length); - outputByteArray=tempByteArray; + int newOutputLength = BLOCK_SIZE + offset + inputLen; + if (outputByteArray.length < newOutputLength) { + int newSize = Math.max(outputByteArray.length * 3 / 2 + BLOCK_SIZE, newOutputLength); + outputByteArray = Arrays.copyOf(outputByteArray, newSize); + } int outLen = engineUpdate(input, inputOffset, inputLen, outputByteArray, offset); - return Arrays.copyOfRange(outputByteArray,0,outLen); + return Arrays.copyOfRange(outputByteArray,offset,offset + outLen); } @Override protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset){ int outLen = update(input, inputOffset, inputLen, output, outputOffset); this.offset+=outLen; - return offset; + return outLen; } @Override @@ -138,11 +140,11 @@ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) thro @Override protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - if(null!=input) { - engineUpdate(input, inputOffset, inputLen, output, outputOffset); + int outLen = 0; + if(null!=input){ + outLen=this.engineUpdate(input, inputOffset, inputLen, output, outputOffset); } - int outLen = doFinal(output, this.offset); - outLen = outLen + this.offset; + outLen += doFinal(output, this.offset); this.offset = 0; return outLen; } diff --git a/src/main/resources/lib/libgmssljni.dll b/src/main/resources/lib/libgmssljni.dll new file mode 100644 index 0000000000000000000000000000000000000000..0d4e190bd56801c547f8adfa9cca29f2016f7d37 GIT binary patch literal 204800 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 JfsZl+{~un_ktzTH literal 0 HcmV?d00001 diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index c8a8614..1eac137 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -38,6 +38,9 @@ public void SM2_test() throws Exception{ byte[] pub= keyPair.getPublic().getEncoded(); System.out.println(byteToHex(pub)); byte[] pri= keyPair.getPrivate().getEncoded(); + // export private key + SM2PrivateKey SM2PrivateKey= (SM2PrivateKey)keyPair.getPrivate(); + SM2PrivateKey.exportEncryptedPrivateKeyInfoPem("123456", "D:\\private.key.pem"); System.out.println(byteToHex(pri)); //Test "Z-value" hash @@ -105,14 +108,14 @@ public void SM3_test() throws Exception{ byte[] digest = sm3Digest.digest(); System.out.println("digest:"+byteToHex(digest)); - //基于SM3的HMAC消息认证码算法 + //HMAC Message Authentication Code Algorithm Based on SM3 Mac hmac = Mac.getInstance("SM3", "GmSSL"); hmac.init(new SecretKeySpec(new Random().randBytes(SM3Hmac.MAC_SIZE), "SM3")); hmac.update(text.getBytes()); byte[] hmacFinal = hmac.doFinal(); System.out.println("hmac:"+byteToHex(hmacFinal)); - //基于口令的密钥导出函数PBKDF2 + //Password-Based Key Derivation Function PBKDF2 char[] password = "P@ssw0rd".toCharArray(); byte[] salt = new Random().randBytes(SM3Pbkdf2.DEFAULT_SALT_SIZE); int iterations = SM3Pbkdf2.MIN_ITER * 2; @@ -128,7 +131,7 @@ public void SM3_test() throws Exception{ public void SM4_ECB_test() throws Exception{ String text="Hello, GmSSL!"; SecureRandom secureRandom = SecureRandom.getInstance("Random", "GmSSL"); - // 测试SM4加密 + // encryption Cipher sm4Cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", "GmSSL"); SecretKeySpec sm4Key = new SecretKeySpec(secureRandom.generateSeed(SM4ECB.KEY_SIZE), "SM4"); sm4Cipher.init(Cipher.ENCRYPT_MODE, sm4Key); @@ -136,7 +139,7 @@ public void SM4_ECB_test() throws Exception{ sm4Cipher.update("cipher.".getBytes(),0, 6); byte[] ciphertext = sm4Cipher.doFinal(); System.out.println("Ciphertext: " + byteToHex(ciphertext)); - // 测试SM4解密 + // decryption sm4Cipher.init(Cipher.DECRYPT_MODE, sm4Key); byte[] plaintext = sm4Cipher.doFinal(ciphertext); System.out.println("plaintext: " + new String(plaintext)); @@ -149,7 +152,7 @@ public void SM4_CBC_test1() throws Exception{ byte[] randomBytes = new byte[32]; secureRandom.nextBytes(randomBytes); System.out.println("Generated Random Bytes: " + byteToHex(randomBytes)); - + // encryption Cipher sm4cbcCipher = Cipher.getInstance("SM4/CBC/PKCS5Padding", "GmSSL"); byte[] key = secureRandom.generateSeed(SM4CBC.KEY_SIZE); byte[] iv = secureRandom.generateSeed(SM4CBC.IV_SIZE); @@ -159,7 +162,7 @@ public void SM4_CBC_test1() throws Exception{ sm4cbcCipher.update(text.getBytes()); byte[] ciphertext = sm4cbcCipher.doFinal(); System.out.println("Ciphertext: " + byteToHex(ciphertext)); - + // decryption sm4cbcCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); sm4cbcCipher.update(ciphertext); byte[] plaintext2 = sm4cbcCipher.doFinal(); @@ -174,18 +177,19 @@ public void SM4_CBC_test2() throws Exception{ byte[] randomBytes = new byte[32]; secureRandom.nextBytes(randomBytes); System.out.println("Generated Random Bytes: " + byteToHex(randomBytes)); - + // encryption Cipher sm4cbcCipher = Cipher.getInstance("SM4/CBC/PKCS5Padding", "GmSSL"); byte[] key = secureRandom.generateSeed(SM4CBC.KEY_SIZE); byte[] iv = secureRandom.generateSeed(SM4CBC.IV_SIZE); sm4cbcCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); byte[] ciphertext = new byte[100]; - int cipherlen= sm4cbcCipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, 0); - cipherlen = sm4cbcCipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); - cipherlen = sm4cbcCipher.doFinal(text.getBytes(), 0, text.getBytes().length,ciphertext, cipherlen); + int cipherlen = sm4cbcCipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, 0); + cipherlen += sm4cbcCipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + cipherlen += sm4cbcCipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + cipherlen += sm4cbcCipher.doFinal(text.getBytes(), 0, text.getBytes().length,ciphertext, cipherlen); byte[] ciphertext1 = Arrays.copyOfRange(ciphertext,0,cipherlen); System.out.println("Ciphertext: " + byteToHex(ciphertext1)); - + // decryption byte[] plaintext = new byte[ciphertext1.length + SM4CBC.BLOCK_SIZE]; sm4cbcCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); int plainLen = sm4cbcCipher.doFinal(ciphertext1, 0,ciphertext1.length, plaintext,0); @@ -201,14 +205,15 @@ public void SM4_CTR_test1() throws Exception{ Cipher sm4Cipher = Cipher.getInstance("SM4/CTR/NoPadding", "GmSSL"); byte[] key = secureRandom.generateSeed(SM4CTR.KEY_SIZE); byte[] iv = secureRandom.generateSeed(SM4CTR.IV_SIZE); - + // encryption sm4Cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); - byte[] ciphertext = new byte[50]; - int cipherlen= sm4Cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, 0); - cipherlen = sm4Cipher.doFinal(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + byte[] ciphertext = new byte[100]; + int cipherlen = sm4Cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, 0); + cipherlen += sm4Cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + cipherlen += sm4Cipher.doFinal(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); byte[] ciphertext1 = Arrays.copyOfRange(ciphertext,0,cipherlen); System.out.println("Ciphertext: " + byteToHex(ciphertext1)); - + // decryption byte[] plaintext = new byte[ciphertext1.length+SM4CTR.BLOCK_SIZE]; sm4Cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); int plainLen = sm4Cipher.doFinal(ciphertext1, 0, ciphertext1.length, plaintext, 0); @@ -223,13 +228,14 @@ public void SM4_CTR_test2() throws Exception{ Cipher sm4Cipher = Cipher.getInstance("SM4/CTR/NoPadding", "GmSSL"); byte[] key = secureRandom.generateSeed(SM4CTR.KEY_SIZE); byte[] iv = secureRandom.generateSeed(SM4CTR.IV_SIZE); + // encryption sm4Cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); sm4Cipher.update(text.getBytes()); sm4Cipher.update(text.getBytes()); sm4Cipher.update(text.getBytes()); byte[] ciphertext = sm4Cipher.doFinal(); System.out.println("Ciphertext: " + byteToHex(ciphertext)); - + // decryption sm4Cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new IvParameterSpec(iv)); sm4Cipher.update(ciphertext); byte[] plaintext1=sm4Cipher.doFinal(); @@ -244,15 +250,17 @@ public void SM4_GCM_test1() throws Exception { byte[] key = secureRandom.generateSeed(SM4GCM.KEY_SIZE); byte[] iv = secureRandom.generateSeed(SM4GCM.DEFAULT_IV_SIZE); byte[] aad = "Hello: ".getBytes(); + // encryption sm4Cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new GCMParameterSpec(SM4GCM.MAX_TAG_SIZE,iv)); sm4Cipher.updateAAD(aad); byte[] ciphertext = new byte[100]; int cipherlen = sm4Cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, 0); - cipherlen = sm4Cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); - cipherlen = sm4Cipher.doFinal(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + cipherlen += sm4Cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + cipherlen += sm4Cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + cipherlen += sm4Cipher.doFinal(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); byte[] ciphertext1 = Arrays.copyOfRange(ciphertext,0,cipherlen); System.out.println("Ciphertext: " + byteToHex(ciphertext1)); - + // decryption byte[] plaintext = new byte[ciphertext1.length+SM4GCM.MAX_TAG_SIZE]; sm4Cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new GCMParameterSpec(SM4GCM.MAX_TAG_SIZE,iv)); sm4Cipher.updateAAD(aad); @@ -269,16 +277,16 @@ public void SM4_GCM_test2() throws Exception { byte[] key = secureRandom.generateSeed(SM4GCM.KEY_SIZE); byte[] iv = secureRandom.generateSeed(SM4GCM.DEFAULT_IV_SIZE); byte[] aad = "Hello: ".getBytes(); + // encryption sm4Cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), new GCMParameterSpec(SM4GCM.MAX_TAG_SIZE,iv)); sm4Cipher.updateAAD(aad); sm4Cipher.updateAAD(aad); sm4Cipher.update(text.getBytes()); sm4Cipher.update(text.getBytes()); sm4Cipher.update(text.getBytes()); - sm4Cipher.update(text.getBytes()); byte[] ciphertext = sm4Cipher.doFinal(); System.out.println("Ciphertext: " + byteToHex(ciphertext)); - + // decryption sm4Cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"), new GCMParameterSpec(SM4GCM.MAX_TAG_SIZE,iv)); sm4Cipher.updateAAD(aad); sm4Cipher.updateAAD(aad); @@ -294,14 +302,19 @@ public void SM9_cipher_test() throws Exception{ KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("SM9", "GmSSL"); keyPairGen.initialize(sm9EncMasterKeyGenParameterSpec); keyPairGen.generateKeyPair(); - + // encryption PublicKey publicKey = keyPairGen.genKeyPair().getPublic(); + // export public key + SM9PublicKey SM9PublicKey = (SM9PublicKey)publicKey; + SM9PublicKey.exportPublicKeyPem("SM9Public.enc.mpk"); Cipher sm9Cipher = Cipher.getInstance("SM9", "GmSSL"); sm9Cipher.init(Cipher.ENCRYPT_MODE, publicKey,sm9EncMasterKeyGenParameterSpec); byte[] ciphertext = sm9Cipher.doFinal(text.getBytes()); System.out.println("Ciphertext: " + byteToHex(ciphertext)); - + // decryption SM9PrivateKey privateKey= (SM9PrivateKey) keyPairGen.genKeyPair().getPrivate(); + // export private key + privateKey.exportEncryptedPrivateKeyInfoPem("123456", "SM9Private.enc.mpk"); SM9MasterKey masterKey = (SM9MasterKey)privateKey.getSecretKey(); SM9UserKey userKey= masterKey.extractKey(sm9EncMasterKeyGenParameterSpec.getId()); sm9Cipher.init(Cipher.DECRYPT_MODE, userKey.getPrivateKey()); @@ -318,8 +331,10 @@ public void SM9_sign_test() throws Exception{ keyPairGen.generateKeyPair(); Signature signature = Signature.getInstance("SM9", "GmSSL"); - // 测试签名 + // Signature SM9PrivateKey privateKey= (SM9PrivateKey) keyPairGen.genKeyPair().getPrivate(); + // export private key + privateKey.exportEncryptedPrivateKeyInfoPem("123456", "SM9Private.sign.mpk"); SM9MasterKey masterKey = (SM9MasterKey)privateKey.getSecretKey(); SM9UserKey userKey= masterKey.extractKey(sm9SignMasterKeyGenParameterSpec.getId()); signature.initSign(userKey.getPrivateKey()); @@ -327,9 +342,12 @@ public void SM9_sign_test() throws Exception{ signature.update(signatureText); byte[] signatureByte = signature.sign(); System.out.println("Signature:"+byteToHex(signatureByte)); - // 测试验签 + // Verify signature.setParameter(sm9SignMasterKeyGenParameterSpec); PublicKey publicKey= keyPairGen.genKeyPair().getPublic(); + // export public key + SM9PublicKey SM9PublicKey = (SM9PublicKey)publicKey; + SM9PublicKey.exportPublicKeyPem("SM9Public.sign.mpk"); signature.initVerify(publicKey); signature.update(signatureText); boolean signatureResult = signature.verify(signatureByte); @@ -343,19 +361,19 @@ public void ZUC_test() throws Exception{ Cipher cipher = Cipher.getInstance("ZUC","GmSSL"); SecretKey key = new ZucKey(secureRandom.generateSeed(ZucKey.KEY_SIZE)); IvParameterSpec ivParameterSpec = new IvParameterSpec(secureRandom.generateSeed(ZucCipher.IV_SIZE)); + // encryption cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec); byte[] ciphertext = new byte[100]; int cipherlen = cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, 0); - cipherlen = cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); - cipherlen = cipher.doFinal(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + cipherlen += cipher.update(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); + cipherlen += cipher.doFinal(text.getBytes(), 0, text.getBytes().length, ciphertext, cipherlen); byte[] ciphertext1 = Arrays.copyOfRange(ciphertext,0,cipherlen); System.out.println("Ciphertext: " + byteToHex(ciphertext1)); - + // decryption cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec); cipher.update(ciphertext1); byte[] plaintext1 = cipher.doFinal(); System.out.println("plaintext: " + new String(plaintext1)); - } /** From 228f05a6f2947b6892eff241bdb9a62f7c85aa81 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Mon, 23 Sep 2024 10:24:26 +0800 Subject: [PATCH 17/20] fix Adjusted the array copy offset calculation in the SM4, SM4CTR, SM4GCM, and ZucCipher classes to return data within the correct range. Commented out the SM2 certificate test code in JceTest to temporarily disable the test and avoid hard-coded path issues. --- src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java | 2 +- src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java | 2 +- src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java | 2 +- src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java | 2 +- src/test/java/org/gmssl/JceTest.java | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java index 5c5fab2..5f2a4b9 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CBC.java @@ -78,7 +78,7 @@ protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { } int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); - return Arrays.copyOfRange(outputByteArray,offset,offset + outLen); + return Arrays.copyOfRange(outputByteArray,offset-outLen,offset); } @Override diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java index c9dadb8..01732f3 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4CTR.java @@ -76,7 +76,7 @@ protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { } int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); - return Arrays.copyOfRange(outputByteArray,offset,offset + outLen); + return Arrays.copyOfRange(outputByteArray,offset-outLen,offset); } @Override diff --git a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java index 1c32e38..a10f8b4 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java +++ b/src/main/java/org/gmssl/crypto/symmetric/SM4GCM.java @@ -92,7 +92,7 @@ protected byte[] processUpdate(byte[] input, int inputOffset, int inputLen) { } int outLen = processUpdate(input, inputOffset, inputLen, outputByteArray, offset); - return Arrays.copyOfRange(outputByteArray,offset,offset + outLen); + return Arrays.copyOfRange(outputByteArray,offset-outLen,offset); } @Override diff --git a/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java b/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java index 8b11fe7..5f43828 100644 --- a/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java +++ b/src/main/java/org/gmssl/crypto/symmetric/ZucCipher.java @@ -116,7 +116,7 @@ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { } int outLen = engineUpdate(input, inputOffset, inputLen, outputByteArray, offset); - return Arrays.copyOfRange(outputByteArray,offset,offset + outLen); + return Arrays.copyOfRange(outputByteArray,offset-outLen,offset); } @Override diff --git a/src/test/java/org/gmssl/JceTest.java b/src/test/java/org/gmssl/JceTest.java index 1eac137..39f2f35 100644 --- a/src/test/java/org/gmssl/JceTest.java +++ b/src/test/java/org/gmssl/JceTest.java @@ -93,8 +93,8 @@ public void SM2_test() throws Exception{ @Test public void sm2_certificate_test() throws Exception{ SM2Certificate sm2Cert = new SM2Certificate(); - sm2Cert.importPem("D:\\cert.pem"); - System.out.println("NotAfter:"+sm2Cert.getNotAfter()); + //sm2Cert.importPem("D:\\cert.pem"); + //System.out.println("NotAfter:"+sm2Cert.getNotAfter()); } @Test From 2f1adfa01ab99f89c29acefd438d7b25623fb61e Mon Sep 17 00:00:00 2001 From: liyongfei Date: Mon, 23 Sep 2024 10:33:57 +0800 Subject: [PATCH 18/20] Documentation Update: Clarify SM2/SM9 Encryption and Decryption Processes --- .../org/gmssl/crypto/asymmetric/SM2Cipher.java | 13 +++++++++++++ .../org/gmssl/crypto/asymmetric/SM9Cipher.java | 18 +++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java index c6905a3..2abc8c0 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM2Cipher.java @@ -117,6 +117,19 @@ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { return null; } + /** + * The method does not perform any encryption or decryption; it only stores the input data. The returned result is meaningless, and the final result is output through `doFinal`. + * @param input the input buffer + * @param inputOffset the offset in input where the input + * starts + * @param inputLen the input length + * @param output the buffer for the result + * @param outputOffset the offset in output where the result + * is stored + * + * @return + * @throws ShortBufferException + */ @Override protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { if (input == null || inputOffset < 0 || inputLen < 0 || inputOffset + inputLen > input.length) { diff --git a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java index ae2a5e3..5f1564c 100644 --- a/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java +++ b/src/main/java/org/gmssl/crypto/asymmetric/SM9Cipher.java @@ -109,13 +109,12 @@ protected void engineInit(int opmode, Key key, AlgorithmParameters params, Secur } /** - * + * SM9 encryption and decryption are completed during the engineDoFinal phase. During the update phase, data is only cached, and no partial encryption or decryption results are returned. * @param input the input buffer * @param inputOffset the offset in input where the input * starts * @param inputLen the input length - * @description - * SM9 encryption and decryption are completed during the engineDoFinal phase. During the update phase, data is only cached, and no partial encryption or decryption results are returned. + * * @return */ @Override @@ -124,6 +123,19 @@ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { return null; } + /** + * SM9 encryption and decryption are completed during the engineDoFinal phase. During the update phase, data is only cached, and no partial encryption or decryption results are returned. + * @param input the input buffer + * @param inputOffset the offset in input where the input + * starts + * @param inputLen the input length + * @param output the buffer for the result + * @param outputOffset the offset in output where the result + * is stored + * + * @return + * @throws ShortBufferException + */ @Override protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { buffer.put(input, inputOffset, inputLen); From 1d27b02e10eda1e47df77862006dfff2dd077854 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Thu, 26 Sep 2024 14:37:38 +0800 Subject: [PATCH 19/20] fix:Optimize NativeLoader to Prevent Duplicate Loading and Handle Exceptions --- src/main/java/org/gmssl/NativeLoader.java | 120 +++++++++++++--------- 1 file changed, 71 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/gmssl/NativeLoader.java b/src/main/java/org/gmssl/NativeLoader.java index dc119b8..16e8a44 100644 --- a/src/main/java/org/gmssl/NativeLoader.java +++ b/src/main/java/org/gmssl/NativeLoader.java @@ -11,7 +11,10 @@ import java.io.*; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import java.util.Properties; @@ -26,7 +29,9 @@ public class NativeLoader { /* custom jni library prefix path relative to project resources */ private static final String RESOURCELIB_PREFIXPATH = "lib"; - static final String GMSSLJNILIB_NAME="libgmssljni"; + static final String GMSSLJNILIB_NAME = "libgmssljni"; + + private static final Map loadedLibraries = new HashMap<>(); private static final Properties PROPERTIES = new Properties(); @@ -44,64 +49,80 @@ public class NativeLoader { /** * load jni lib from resources path,the parameter does not contain the path and suffix. - * @param libaray libarayName * + * @param library libraryName */ - public synchronized static void load (String libaray){ - String resourceLibPath = RESOURCELIB_PREFIXPATH + "/" + libaray + "." + libExtension(); + public static void load(String library) { + if (loadedLibraries.containsKey(library)) { + return; + } + Path tempFile = null; + String resourceLibPath = Paths.get(RESOURCELIB_PREFIXPATH, library + "." + libExtension()).toString(); try (InputStream inputStream = NativeLoader.class.getClassLoader().getResourceAsStream(resourceLibPath)) { - if (null == inputStream) { - throw new GmSSLException("lib file not found in JAR: " + resourceLibPath); - } - Path tempFile = Files.createTempFile(libaray, "."+libExtension()); + tempFile = Files.createTempFile(library, "." + libExtension()); tempFile.toFile().deleteOnExit(); Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING); checkReferencedLib(); System.load(tempFile.toAbsolutePath().toString()); + loadedLibraries.put(library, tempFile); + }catch (IOException e){ + throw new GmSSLException("lib file not found:"+ e.getMessage()); + }catch (UnsatisfiedLinkError e){ + throw new GmSSLException("Failed to load native library:"+ e.getMessage()); } catch (Exception e) { - throw new GmSSLException("Unable to load lib from JAR"); + throw new GmSSLException("Unable to load lib!"); + }finally { + if (null != tempFile) { + tempFile.toFile().delete(); + } } } /** * Get the operating system type. + * * @return operating system name */ - static String osType(){ - String os="unknown"; - String osName = System.getProperty("os.name").toLowerCase(); - if(osName.startsWith("windows")){ - os="win"; - } - if(osName.startsWith("linux")){ - if ("dalvik".equalsIgnoreCase(System.getProperty("java.vm.name"))) { - os = "android"; - System.setProperty("jna.nounpack", "true"); - } else { - os="linux"; - } + static String osType() { + String os = "unknown"; + String vmName = System.getProperty("java.vm.name"); + if ("dalvik".equalsIgnoreCase(vmName) || "art".equalsIgnoreCase(vmName)) { + os = "android"; } - if(osName.startsWith("mac os x") || osName.startsWith("darwin")){ - os="osx"; + String osName = System.getProperty("os.name").toLowerCase(); + if (osName.startsWith("windows")) { + os = "win"; + } else if (osName.startsWith("linux")) { + os = "linux"; + } else if (osName.startsWith("mac os x") || osName.startsWith("darwin")) { + os = "osx"; + } else { + System.err.println("Unsupported OS: " + osName); } return os; } /** * Get the library extension name based on the operating system type. + * * @return extension name */ - static String libExtension(){ - String osType=osType(); - String libExtension=null; - if("win".equals(osType)){ - libExtension="dll"; - } - if("osx".equals(osType)){ - libExtension="dylib"; - } - if("linux".equals(osType)){ - libExtension="so"; + static String libExtension() { + String osType = osType(); + String libExtension = null; + switch (osType) { + case "win": + libExtension = "dll"; + break; + case "osx": + libExtension = "dylib"; + break; + case "linux": + case "android": + libExtension = "so"; + break; + default: + throw new IllegalArgumentException("Unsupported OS type!"); } return libExtension; } @@ -112,20 +133,21 @@ static String libExtension(){ * in order to correct the @rpath path issue. Alternatively, you can manually execute the command * "install_name_tool -change @rpath/libgmssl.3.dylib /usr/local/lib/libgmssl.3.dylib xxx/lib/libgmssljni.dylib" to fix the library reference path issue. * This has already been loaded and manual execution is unnecessary. - * */ - private static void checkReferencedLib(){ - if("osx".equals(osType())){ - String macReferencedLib=PROPERTIES.getProperty("macReferencedLib"); - Optional optionalStr = Optional.ofNullable(macReferencedLib); - if(optionalStr.isPresent() && !optionalStr.get().isEmpty()){ - File libFile = new File(macReferencedLib); - if(libFile.exists()){ - System.load(macReferencedLib); - } - } - - } - } + private static void checkReferencedLib() { + if ("osx".equals(osType())) { + String macReferencedLib = PROPERTIES.getProperty("macReferencedLib"); + if (null != macReferencedLib) { + System.load(macReferencedLib); + Optional optionalStr = Optional.ofNullable(macReferencedLib); + if (optionalStr.isPresent() && !optionalStr.get().isEmpty()) { + File libFile = new File(macReferencedLib); + if (libFile.exists()) { + System.load(macReferencedLib); + } + } + } + } + } } From 9c7bf2ad14f6dc923b9012878536e30d0bf89f58 Mon Sep 17 00:00:00 2001 From: liyongfei Date: Thu, 26 Sep 2024 14:55:13 +0800 Subject: [PATCH 20/20] fix:Fix Path Reading Errors When Called from External Projects --- src/main/java/org/gmssl/NativeLoader.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/gmssl/NativeLoader.java b/src/main/java/org/gmssl/NativeLoader.java index 16e8a44..8ac47ec 100644 --- a/src/main/java/org/gmssl/NativeLoader.java +++ b/src/main/java/org/gmssl/NativeLoader.java @@ -11,7 +11,6 @@ import java.io.*; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.HashMap; import java.util.Map; @@ -57,7 +56,7 @@ public static void load(String library) { return; } Path tempFile = null; - String resourceLibPath = Paths.get(RESOURCELIB_PREFIXPATH, library + "." + libExtension()).toString(); + String resourceLibPath = RESOURCELIB_PREFIXPATH + "/" + library + "." + libExtension(); try (InputStream inputStream = NativeLoader.class.getClassLoader().getResourceAsStream(resourceLibPath)) { tempFile = Files.createTempFile(library, "." + libExtension()); tempFile.toFile().deleteOnExit();