当前位置:   article > 正文

国密算法SM2/3/4简单比较,以及基于Java的SM4(ECB模式,CBC模式)对称加解密实现_国密算法sm2 sm3

国密算法sm2 sm3

常用的国密算法包含SM2,SM3,SM4。以下针对每个算法使用场景进行说明以比较其差异

  • SM2:非对称加密算法,可以替代RSA
    • 数字签名,SM2为非对称加密,加解密使用一对私钥和公钥,只有签名发行者拥有私钥,可用于加密,其他需要验证解密或验签者使用公钥进行。如果使用公钥可以成功解密,则可以确定数据、文档或其他数字资产的拥有者。
    • 因性能问题,根据实际需要常用于小体积数据加密,例如对密钥或SM3生成的hash进行加密。针对SM3生成的hash值进行加密也是一种常用的签名方式,一般先对需要签名的数据、文档或数字资产使用SM3生成hash再用SM2进行签名。

             注:

             如果用于加密,那么加密是用公钥进行的,解密是用私钥进行的。

             如果用于数字签名,那么签名是用私钥进行的,验证签名则使用公钥。

  • SM3:散列哈希算法
    • 数据库中用户密码的保存,获取用户输入明文密码后,进行SM3生成hash值,再与数据库中保存的已经过SM3计算后的密码值进行比对。
    • 数据完整性验证,针对数据、文件或数据资产进行SM3生成hash并保存,在需要验证数据是否被修改时重新生成hash并与之前保存的hash值进行比对,一旦文件有被修改则会生成不同的hash值。例如可以针对数据库中关键数据字段进行hash,并保存。然后可以通过遍历定期验证hash是否一致,来发现被篡改的数据。
  • SM4:对称加密算法,性能比SM2好
    • 可以用于一般数据的加密与解密,例如可以在需要网络传输的数据发送前进行加密,对方收到数据后使用相同密钥进行解密获得明文。

基于Java的SM4(ECB模式,CBC模式)对称加解密实现

简单说明:加密算法依赖了groupId:org.bouncycastle中的bcprov-jdk15to18,Bouncy Castle (bcprov-jdk15to18)提供了JDK 1.5 to 1.8可使用的大量标准加密算法实现,其中包含了SM2,SM3,SM4。在这个类库基础上实现了一个SM4Util加解密工具类。注意: 此版本我在JDK1.8环境下,不同版本JDK需要找到匹配的依赖版本1.8及以上可以使用bcprov-jdk18on。Bouncy Castle同时也提供了bcutil-jdk15to18可以实现SM4加解密。

方式一:依赖bcprov-jdk15to18(以ECB模式为例) 注如果用jdk1.8的话使用bcprov-jdk18on比bcprov-jdk15to18的加密性能要好。

  1. <dependency>
  2. <groupId>org.bouncycastle</groupId>
  3. <artifactId>bcprov-jdk15to18</artifactId>
  4. <version>1.77</version>
  5. </dependency>

字节数组处理工具类: 

  1. public class ByteUtils {
  2. private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
  3. 'f' };
  4. private ByteUtils() {
  5. // Utility class
  6. }
  7. public static byte[] fromHexString(String s) {
  8. int len = s.length();
  9. //
  10. // // Data length must be even
  11. // if (len % 2 != 0) {
  12. // throw new IllegalArgumentException("Hex string has an odd number of
  13. // characters");
  14. // }
  15. byte[] data = new byte[len / 2];
  16. for (int i = 0; i < len; i += 2) {
  17. data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
  18. }
  19. return data;
  20. }
  21. public static String toHexString(byte[] input) {
  22. StringBuilder sb = new StringBuilder();
  23. for (byte b : input) {
  24. sb.append(HEX_CHARS[(b >>> 4) & 0x0f]);
  25. sb.append(HEX_CHARS[b & 0x0f]);
  26. }
  27. return sb.toString();
  28. }
  29. public static String toHexString(byte[] input, String prefix, String separator) {
  30. StringBuilder sb = new StringBuilder(prefix);
  31. for (int i = 0; i < input.length; i++) {
  32. sb.append(HEX_CHARS[(input[i] >>> 4) & 0x0f]);
  33. sb.append(HEX_CHARS[input[i] & 0x0f]);
  34. if (i < input.length - 1) {
  35. sb.append(separator);
  36. }
  37. }
  38. return sb.toString();
  39. }
  40. }

 加解密工具类:

  1. import java.nio.charset.StandardCharsets;
  2. import java.security.Key;
  3. import java.security.MessageDigest;
  4. import java.security.SecureRandom;
  5. import java.security.Security;
  6. import java.util.Arrays;
  7. import javax.crypto.Cipher;
  8. import javax.crypto.KeyGenerator;
  9. import javax.crypto.spec.SecretKeySpec;
  10. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  11. public class Sm4Utils {
  12. static {
  13. Security.addProvider(new BouncyCastleProvider());
  14. }
  15. private static final String ENCODING = "UTF-8";
  16. public static final String ALGORIGTHM_NAME = "SM4";
  17. public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
  18. public static final int DEFAULT_KEY_SIZE = 128;
  19. private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
  20. Cipher cipher = Cipher.getInstance(algorithmName, "BC");
  21. Key sm4Key = new SecretKeySpec(key, ALGORIGTHM_NAME);
  22. cipher.init(mode, sm4Key);
  23. return cipher;
  24. }
  25. public static byte[] generateKey(String keyString) throws Exception {
  26. // Use SHA-256 to hash the string and then take first 128 bits (16 bytes)
  27. MessageDigest digest = MessageDigest.getInstance("SHA-256");
  28. byte[] hash = digest.digest(keyString.getBytes(StandardCharsets.UTF_8));
  29. byte[] key = new byte[16];
  30. System.arraycopy(hash, 0, key, 0, 16);
  31. return key;
  32. }
  33. public static String encryptEcb(String key, String paramStr, String charset) throws Exception {
  34. String cipherText = "";
  35. if (null != paramStr && !"".equals(paramStr)) {
  36. byte[] keyData = generateKey(key);
  37. charset = charset.trim();
  38. if (charset.length() <= 0) {
  39. charset = ENCODING;
  40. }
  41. byte[] srcData = paramStr.getBytes(charset);
  42. byte[] cipherArray = encryptEcbPadding(keyData, srcData);
  43. cipherText = ByteUtils.toHexString(cipherArray);
  44. }
  45. return cipherText;
  46. }
  47. public static byte[] encryptEcbPadding(byte[] key, byte[] data) throws Exception {
  48. Cipher cipher = generateEcbCipher("SM4/ECB/PKCS7Padding", Cipher.ENCRYPT_MODE, key);
  49. byte[] bs = cipher.doFinal(data);
  50. return bs;
  51. }
  52. public static String decryptEcb(String key, String cipherText, String charset) throws Exception {
  53. String decryptStr = "";
  54. byte[] keyData = generateKey(key);
  55. byte[] cipherData = ByteUtils.fromHexString(cipherText);
  56. byte[] srcData = decryptEcbPadding(keyData, cipherData);
  57. charset = charset.trim();
  58. if (charset.length() <= 0) {
  59. charset = ENCODING;
  60. }
  61. decryptStr = new String(srcData, charset);
  62. return decryptStr;
  63. }
  64. public static byte[] decryptEcbPadding(byte[] key, byte[] cipherText) throws Exception {
  65. Cipher cipher = generateEcbCipher("SM4/ECB/PKCS7Padding", Cipher.DECRYPT_MODE, key);
  66. return cipher.doFinal(cipherText);
  67. }
  68. public static void main(String[] args) {
  69. try {
  70. String json = "311111190001010001";
  71. String key = "test";
  72. String cipher = encryptEcb(key, json, ENCODING);
  73. System.out.println(cipher);
  74. System.out.println(decryptEcb(key, cipher, ENCODING));
  75. } catch (Exception var5) {
  76. var5.printStackTrace();
  77. }
  78. }
  79. }

方式二:依赖bcprov-jdk15to18(以CBC模式为例),代码根据GPT-4生成修改调试,可运行。

  1. <dependency>
  2. <groupId>org.bouncycastle</groupId>
  3. <artifactId>bcprov-jdk15to18</artifactId>
  4. <version>1.77</version>
  5. </dependency>
  1. import org.bouncycastle.crypto.CipherParameters;
  2. import org.bouncycastle.crypto.engines.SM4Engine;
  3. import org.bouncycastle.crypto.modes.CBCBlockCipher;
  4. import org.bouncycastle.crypto.modes.CBCModeCipher;
  5. import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
  6. import org.bouncycastle.crypto.params.KeyParameter;
  7. import org.bouncycastle.crypto.params.ParametersWithIV;
  8. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  9. import java.security.Security;
  10. import java.util.Arrays;
  11. public class SM4Example {
  12. static {
  13. Security.addProvider(new BouncyCastleProvider());
  14. }
  15. public static byte[] encrypt(byte[] key, byte[] iv, byte[] data) throws Exception {
  16. SM4Engine engine = new SM4Engine();
  17. CBCModeCipher cbcBlockCipher = CBCBlockCipher.newInstance(engine);
  18. PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(cbcBlockCipher);
  19. CipherParameters params = new ParametersWithIV(new KeyParameter(key), iv);
  20. cipher.init(true, params);
  21. byte[] temp = new byte[cipher.getOutputSize(data.length)];
  22. int len = cipher.processBytes(data, 0, data.length, temp, 0);
  23. len += cipher.doFinal(temp, len);
  24. byte[] out = new byte[len];
  25. System.arraycopy(temp, 0, out, 0, len);
  26. return out;
  27. }
  28. public static byte[] decrypt(byte[] key, byte[] iv, byte[] data) throws Exception {
  29. SM4Engine engine = new SM4Engine();
  30. CBCModeCipher cbcBlockCipher = CBCBlockCipher.newInstance(engine);
  31. PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(cbcBlockCipher);
  32. CipherParameters params = new ParametersWithIV(new KeyParameter(key), iv);
  33. cipher.init(false, params);
  34. byte[] temp = new byte[cipher.getOutputSize(data.length)];
  35. int len = cipher.processBytes(data, 0, data.length, temp, 0);
  36. len += cipher.doFinal(temp, len);
  37. byte[] out = new byte[len];
  38. System.arraycopy(temp, 0, out, 0, len);
  39. return out;
  40. }
  41. public static void main(String[] args) throws Exception {
  42. byte[] key = "0123456789abcdef".getBytes(); // 16-byte key for SM4
  43. byte[] iv = "abcdef9876543210".getBytes(); // 16-byte IV for CBC mode
  44. byte[] dataToEncrypt = "Hello, Bouncy Castle SM4!".getBytes();
  45. byte[] encryptedData = encrypt(key, iv, dataToEncrypt);
  46. System.out.println("Encrypted Data: " + java.util.Base64.getEncoder().encodeToString(encryptedData));
  47. byte[] decryptedData = decrypt(key, iv, encryptedData);
  48. System.out.println("Decrypted Data: " + new String(decryptedData));
  49. }
  50. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/494281
推荐阅读
相关标签
  

闽ICP备14008679号