【转】Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式

代码中实现了电码本ECB模式和密文分组连接CBC模式,SM3.java和SM4.java为算法实现类,utils的都是根据实现类写的工具,可以根据需要调用杂凑算法SM3的杂凑功能获得杂凑值。

SM4.java中

sm4_crypt_ecb(SM4_Context ctx, byte[] input)      ECB模式加解密方法,根据密钥判断加解密功能

sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input)      CBC模式加解密方法,根据密钥判断加解密功能

加密解密通过如下方法:

sm4_setkey_enc(SM4_Context ctx, byte[] key)  设置加密密钥调用上述方法,实现加密

sm4_setkey_dec(SM4_Context ctx, byte[] key)  设置解密密钥调用上述方法,实现解密

 

需要导入的包为bcprov-jdk16  我用的版本是bcprov-jdk16-1.46

maven中配置依赖:

 
  1. <dependency>

  2. <groupId>org.bouncycastle</groupId>

  3. <artifactId></artifactId>

  4. <version>1.46</version>

  5. </dependency>

 

package中class目录如下:

 

chiper.java

 
  1. import java.math.BigInteger;

  2. import org.bouncycastle.crypto.AsymmetricCipherKeyPair;

  3. import org.bouncycastle.crypto.params.ECPrivateKeyParameters;

  4. import org.bouncycastle.crypto.params.ECPublicKeyParameters;

  5. import org.bouncycastle.math.ec.ECPoint;

  6.  
  7. public class Cipher {

  8. private int ct;

  9. private ECPoint p2;

  10. private SM3Digest sm3keybase;

  11. private SM3Digest sm3c3;

  12. private byte key[];

  13. private byte keyOff;

  14.  
  15. public Cipher()

  16. {

  17. this.ct = 1;

  18. this.key = new byte[32];

  19. this.keyOff = 0;

  20. }

  21.  
  22. private void Reset()

  23. {

  24. this.sm3keybase = new SM3Digest();

  25. this.sm3c3 = new SM3Digest();

  26.  
  27. byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger());

  28. this.sm3keybase.update(p, 0, p.length);

  29. this.sm3c3.update(p, 0, p.length);

  30.  
  31. p = Util.byteConvert32Bytes(p2.getY().toBigInteger());

  32. this.sm3keybase.update(p, 0, p.length);

  33. this.ct = 1;

  34. NextKey();

  35. }

  36.  
  37. private void NextKey()

  38. {

  39. SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);

  40. sm3keycur.update((byte) (ct >> 24 & 0xff));

  41. sm3keycur.update((byte) (ct >> 16 & 0xff));

  42. sm3keycur.update((byte) (ct >> 8 & 0xff));

  43. sm3keycur.update((byte) (ct & 0xff));

  44. sm3keycur.doFinal(key, 0);

  45. this.keyOff = 0;

  46. this.ct++;

  47. }

  48.  
  49. public ECPoint Init_enc(SM2 sm2, ECPoint userKey)

  50. {

  51. AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();

  52. ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();

  53. ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();

  54. BigInteger k = ecpriv.getD();

  55. ECPoint c1 = ecpub.getQ();

  56. this.p2 = userKey.multiply(k);

  57. Reset();

  58. return c1;

  59. }

  60.  
  61. public void Encrypt(byte data[])

  62. {

  63. this.sm3c3.update(data, 0, data.length);

  64. for (int i = 0; i < data.length; i++)

  65. {

  66. if (keyOff == key.length)

  67. {

  68. NextKey();

  69. }

  70. data[i] ^= key[keyOff++];

  71. }

  72. }

  73.  
  74. public void Init_dec(BigInteger userD, ECPoint c1)

  75. {

  76. this.p2 = c1.multiply(userD);

  77. Reset();

  78. }

  79.  
  80. public void Decrypt(byte data[])

  81. {

  82. for (int i = 0; i < data.length; i++)

  83. {

  84. if (keyOff == key.length)

  85. {

  86. NextKey();

  87. }

  88. data[i] ^= key[keyOff++];

  89. }

  90.  
  91. this.sm3c3.update(data, 0, data.length);

  92. }

  93.  
  94. public void Dofinal(byte c3[])

  95. {

  96. byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger());

  97. this.sm3c3.update(p, 0, p.length);

  98. this.sm3c3.doFinal(c3, 0);

  99. Reset();

  100. }

  101. }

SM2.java

 
  1. import java.math.BigInteger;

  2. import java.security.SecureRandom;

  3.  
  4. import org.bouncycastle.crypto.generators.ECKeyPairGenerator;

  5. import org.bouncycastle.crypto.params.ECDomainParameters;

  6. import org.bouncycastle.crypto.params.ECKeyGenerationParameters;

  7. import org.bouncycastle.math.ec.ECCurve;

  8. import org.bouncycastle.math.ec.ECFieldElement;

  9. import org.bouncycastle.math.ec.ECPoint;

  10. import org.bouncycastle.math.ec.ECFieldElement.Fp;

  11.  
  12. public class SM2 {

  13. //测试参数

  14. // public static final String[] ecc_param = {

  15. // "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",

  16. // "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",

  17. // "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",

  18. // "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",

  19. // "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",

  20. // "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"

  21. // };

  22.  
  23. //正式参数

  24. public static String[] ecc_param = {

  25. "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",

  26. "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",

  27. "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",

  28. "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",

  29. "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",

  30. "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"

  31. };

  32.  
  33. public static SM2 Instance()

  34. {

  35. return new SM2();

  36. }

  37.  
  38. public final BigInteger ecc_p;

  39. public final BigInteger ecc_a;

  40. public final BigInteger ecc_b;

  41. public final BigInteger ecc_n;

  42. public final BigInteger ecc_gx;

  43. public final BigInteger ecc_gy;

  44. public final ECCurve ecc_curve;

  45. public final ECPoint ecc_point_g;

  46. public final ECDomainParameters ecc_bc_spec;

  47. public final ECKeyPairGenerator ecc_key_pair_generator;

  48. public final ECFieldElement ecc_gx_fieldelement;

  49. public final ECFieldElement ecc_gy_fieldelement;

  50.  
  51. public SM2()

  52. {

  53. this.ecc_p = new BigInteger(ecc_param[0], 16);

  54. this.ecc_a = new BigInteger(ecc_param[1], 16);

  55. this.ecc_b = new BigInteger(ecc_param[2], 16);

  56. this.ecc_n = new BigInteger(ecc_param[3], 16);

  57. this.ecc_gx = new BigInteger(ecc_param[4], 16);

  58. this.ecc_gy = new BigInteger(ecc_param[5], 16);

  59.  
  60. this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);

  61. this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);

  62.  
  63. this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);

  64. this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);

  65.  
  66. this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);

  67.  
  68. ECKeyGenerationParameters ecc_ecgenparam;

  69. ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());

  70.  
  71. this.ecc_key_pair_generator = new ECKeyPairGenerator();

  72. this.ecc_key_pair_generator.init(ecc_ecgenparam);

  73. }

  74. }

SM2Utils.java

 
  1. import java.io.IOException;

  2. import java.math.BigInteger;

  3. import org.bouncycastle.crypto.AsymmetricCipherKeyPair;

  4. import org.bouncycastle.crypto.params.ECPrivateKeyParameters;

  5. import org.bouncycastle.crypto.params.ECPublicKeyParameters;

  6. import org.bouncycastle.math.ec.ECPoint;

  7.  
  8. public class SM2Utils {

  9. //生成随机秘钥对

  10. public static void generateKeyPair(){

  11. SM2 sm2 = SM2.Instance();

  12. AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();

  13. ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();

  14. ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();

  15. BigInteger privateKey = ecpriv.getD();

  16. ECPoint publicKey = ecpub.getQ();

  17.  
  18. System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded()));

  19. System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray()));

  20. }

  21.  
  22. //数据加密

  23. public static String encrypt(byte[] publicKey, byte[] data) throws IOException

  24. {

  25. if (publicKey == null || publicKey.length == 0)

  26. {

  27. return null;

  28. }

  29.  
  30. if (data == null || data.length == 0)

  31. {

  32. return null;

  33. }

  34.  
  35. byte[] source = new byte[data.length];

  36. System.arraycopy(data, 0, source, 0, data.length);

  37.  
  38. Cipher cipher = new Cipher();

  39. SM2 sm2 = SM2.Instance();

  40. ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

  41.  
  42. ECPoint c1 = cipher.Init_enc(sm2, userKey);

  43. cipher.Encrypt(source);

  44. byte[] c3 = new byte[32];

  45. cipher.Dofinal(c3);

  46.  
  47. // System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));

  48. // System.out.println("C2 " + Util.byteToHex(source));

  49. // System.out.println("C3 " + Util.byteToHex(c3));

  50. //C1 C2 C3拼装成加密字串

  51. return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);

  52.  
  53. }

  54.  
  55. //数据解密

  56. public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException

  57. {

  58. if (privateKey == null || privateKey.length == 0)

  59. {

  60. return null;

  61. }

  62.  
  63. if (encryptedData == null || encryptedData.length == 0)

  64. {

  65. return null;

  66. }

  67. //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2

  68. String data = Util.byteToHex(encryptedData);

  69. /***分解加密字串

  70. * (C1 = C1标志位2位 + C1实体部分128位 = 130)

  71. * (C3 = C3实体部分64位 = 64)

  72. * (C2 = encryptedData.length * 2 - C1长度 - C2长度)

  73. */

  74. byte[] c1Bytes = Util.hexToByte(data.substring(0,130));

  75. int c2Len = encryptedData.length - 97;

  76. byte[] c2 = Util.hexToByte(data.substring(130,130 + 2 * c2Len));

  77. byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));

  78.  
  79. SM2 sm2 = SM2.Instance();

  80. BigInteger userD = new BigInteger(1, privateKey);

  81.  
  82. //通过C1实体字节来生成ECPoint

  83. ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);

  84. Cipher cipher = new Cipher();

  85. cipher.Init_dec(userD, c1);

  86. cipher.Decrypt(c2);

  87. cipher.Dofinal(c3);

  88.  
  89. //返回解密结果

  90. return c2;

  91. }

  92.  
  93. public static void main(String[] args) throws Exception

  94. {

  95. //生成密钥对

  96. generateKeyPair();

  97.  
  98. String plainText = "ererfeiisgod";

  99. byte[] sourceData = plainText.getBytes();

  100.  
  101. //下面的秘钥可以使用generateKeyPair()生成的秘钥内容

  102. // 国密规范正式私钥

  103. String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";

  104. // 国密规范正式公钥

  105. String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A";

  106.  
  107. System.out.println("加密: ");

  108. String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);

  109. System.out.println(cipherText);

  110. System.out.println("解密: ");

  111. plainText = new String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte(cipherText)));

  112. System.out.println(plainText);

  113.  
  114. }

  115. }

SM3.java

 
  1. public class SM3 {

  2. public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,

  3. 0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,

  4. (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,

  5. (byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,

  6. (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,

  7. 0x4e };

  8.  
  9. public static int[] Tj = new int[64];

  10.  
  11. static

  12. {

  13. for (int i = 0; i < 16; i++)

  14. {

  15. Tj[i] = 0x79cc4519;

  16. }

  17.  
  18. for (int i = 16; i < 64; i++)

  19. {

  20. Tj[i] = 0x7a879d8a;

  21. }

  22. }

  23.  
  24. public static byte[] CF(byte[] V, byte[] B)

  25. {

  26. int[] v, b;

  27. v = convert(V);

  28. b = convert(B);

  29. return convert(CF(v, b));

  30. }

  31.  
  32. private static int[] convert(byte[] arr)

  33. {

  34. int[] out = new int[arr.length / 4];

  35. byte[] tmp = new byte[4];

  36. for (int i = 0; i < arr.length; i += 4)

  37. {

  38. System.arraycopy(arr, i, tmp, 0, 4);

  39. out[i / 4] = bigEndianByteToInt(tmp);

  40. }

  41. return out;

  42. }

  43.  
  44. private static byte[] convert(int[] arr)

  45. {

  46. byte[] out = new byte[arr.length * 4];

  47. byte[] tmp = null;

  48. for (int i = 0; i < arr.length; i++

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值