当前位置:   article > 正文

【Java加解密系列】- SM2加解密_sm2engine

sm2engine

上一篇博客介绍了SM2算法生成密钥的过程,详见-SM2生成密钥。这篇博客接着介绍SM2算法如何用上篇博客生成的密钥进行加解密操作。

因为密钥都是byte数组,在进行加解密前,我们需要将密钥转换成BC库的CipherParameters。代码如下:

  1. /**
  2. * 私钥转换为 {@link ECPrivateKeyParameters}
  3. * @param key key
  4. * @return
  5. * @throws InvalidKeyException
  6. */
  7. public static ECPrivateKeyParameters privateKeyToParams(String algorithm, byte[] key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException {
  8. Preconditions.checkNotNull(key, "key must be not null !");
  9. PrivateKey privateKey = generatePrivateKey(algorithm, key);
  10. return (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey);
  11. }
  12. /**
  13. * 生成私钥
  14. * @param algorithm 算法
  15. * @param key key
  16. * @return
  17. */
  18. public static PrivateKey generatePrivateKey(String algorithm, byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
  19. Preconditions.checkNotNull(algorithm, "algorithm must be not null !");
  20. Preconditions.checkNotNull(key, "key must be not null !");
  21. KeySpec keySpec = new PKCS8EncodedKeySpec(key);
  22. algorithm = getAlgorithmAfterWith(algorithm);
  23. return getKeyFactory(algorithm).generatePrivate(keySpec);
  24. }
  25. /**
  26. * 公钥转换为 {@link ECPublicKeyParameters}
  27. * @param key key
  28. * @return
  29. * @throws InvalidKeyException
  30. */
  31. public static ECPublicKeyParameters publicKeyToParams(String algorithm, byte[] key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException {
  32. Preconditions.checkNotNull(key, "key must be not null !");
  33. PublicKey publicKey = generatePublicKey(algorithm, key);
  34. return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
  35. }
  36. /**
  37. * 生成公钥
  38. * @param algorithm 算法
  39. * @param key key
  40. * @return
  41. */
  42. public static PublicKey generatePublicKey(String algorithm, byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
  43. Preconditions.checkNotNull(algorithm, "algorithm must be not null !");
  44. Preconditions.checkNotNull(key, "key must be not null !");
  45. KeySpec keySpec = new X509EncodedKeySpec(key);
  46. algorithm = getAlgorithmAfterWith(algorithm);
  47. return getKeyFactory(algorithm).generatePublic(keySpec);
  48. }
  49. /**
  50. * 获取用于密钥生成的算法<br>
  51. * 获取XXXwithXXX算法的后半部分算法,如果为ECDSA或SM2,返回算法为EC
  52. * @param algorithm XXXwithXXX算法
  53. * @return 算法
  54. */
  55. private static String getAlgorithmAfterWith(String algorithm) {
  56. Preconditions.checkNotNull(algorithm, "algorithm must be not null !");
  57. int indexOfWith = StringUtils.lastIndexOfIgnoreCase(algorithm, "with");
  58. if (indexOfWith > 0) {
  59. algorithm = StringUtils.substring(algorithm, indexOfWith + "with".length());
  60. }
  61. if ("ECDSA".equalsIgnoreCase(algorithm) || "SM2".equalsIgnoreCase(algorithm)) {
  62. algorithm = "EC";
  63. }
  64. return algorithm;
  65. }
  66. /**
  67. * 获取{@link KeyFactory}
  68. * @param algorithm 非对称加密算法
  69. * @return {@link KeyFactory}
  70. */
  71. private static KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException {
  72. final Provider provider = new BouncyCastleProvider();
  73. return KeyFactory.getInstance(algorithm, provider);
  74. }

SM2操作主要有四类:加密、解密、签名和验签。代码如下:

  1. /**
  2. * 加密
  3. * @param data 数据
  4. * @param publicKey 公钥
  5. * @return 加密之后的数据
  6. */
  7. public static byte[] encrypt(byte[] data, byte[] publicKey) throws Exception {
  8. CipherParameters pubKeyParameters = new ParametersWithRandom(publicKeyToParams("SM2", publicKey));
  9. SM2Engine engine = new SM2Engine(DIGEST);
  10. engine.init(true, pubKeyParameters);
  11. return engine.processBlock(data, 0, data.length);
  12. }
  13. /**
  14. * 解密
  15. * @param data 数据
  16. * @param privateKey 私钥
  17. * @return 解密之后的数据
  18. */
  19. public static byte[] decrypt(byte[] data, byte[] privateKey) throws Exception {
  20. CipherParameters privateKeyParameters = privateKeyToParams("SM2", privateKey);
  21. SM2Engine engine = new SM2Engine(DIGEST);
  22. engine.init(false, privateKeyParameters);
  23. byte[] byteDate = engine.processBlock(data, 0, data.length);
  24. return byteDate;
  25. }
  26. /**
  27. * 签名
  28. * @param data 数据
  29. * @return 签名
  30. */
  31. public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {
  32. SM2Signer signer = new SM2Signer();
  33. CipherParameters param = new ParametersWithRandom(privateKeyToParams("SM2", privateKey));
  34. signer.init(true, param);
  35. signer.update(data, 0, data.length);
  36. return signer.generateSignature();
  37. }
  38. /**
  39. * 用公钥检验数字签名的合法性
  40. * @param data 数据
  41. * @param sign 签名
  42. * @param publicKey 公钥
  43. * @return 是否验证通过
  44. */
  45. public static boolean verify(byte[] data, byte[] sign, byte[] publicKey) throws Exception {
  46. SM2Signer signer = new SM2Signer();
  47. CipherParameters param = publicKeyToParams("SM2", publicKey);
  48. signer.init(false, param);
  49. signer.update(data, 0, data.length);
  50. return signer.verifySignature(sign);
  51. }

跑个测试用例试下:

  1. public static void main(String[] args) throws Exception {
  2. KeyPair keyPair = generateSm2KeyPair();
  3. //明文
  4. String plaintext = "test";
  5. //加密
  6. String ciphertext = Base64Utils.encode(encrypt(plaintext.getBytes("utf-8"), keyPair.getPublic().getEncoded()));
  7. //生成签名
  8. String signature = Base64Utils.encode(sign(plaintext.getBytes("utf-8"),keyPair.getPrivate().getEncoded()));
  9. System.out.println("ciphertext: " + ciphertext);
  10. System.out.println("signature: " + signature);
  11. //解密
  12. plaintext = new String(decrypt(Base64Utils.decode(ciphertext),keyPair.getPrivate().getEncoded()),"utf-8");
  13. //验签
  14. boolean result = verify(plaintext.getBytes("utf-8"),Base64Utils.decode(signature),keyPair.getPublic().getEncoded());
  15. System.out.println("plaintext: " + plaintext);
  16. System.out.println("verify result: " + result);
  17. }

输出结果如下:

  1. ciphertext: BFH0SXC1bX7OL1i5I4GO/Ck8Lak6gfzrsEzhrk4GY2cKZOug73ThLBYSjbtnpC5z30CJuKmaAf/W+jlviRr9PT1dcBWyrO599UUC4XWW8as4XHej8nE/Rlr9TP5+wP+4AWaub6o=
  2. signature: MEYCIQC7OldJ7B8JvP51zw8P2DfieG5iAj5rWEybqZ3bPG8D5wIhAIVXlOmMxk0t4cNm0oQ0HYIzJZ5JShGIWuVwZLZ/t9mQ
  3. plaintext: test
  4. verify result: true

从结果可以看出,可以进行正常的加解密、生成签名以及验签操作。

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

闽ICP备14008679号