SignatureUtils.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package com.dk.mdm.infrastructure.util;
  2. import org.springframework.stereotype.Component;
  3. import java.security.*;
  4. import java.security.spec.InvalidKeySpecException;
  5. import java.security.spec.PKCS8EncodedKeySpec;
  6. import java.security.spec.X509EncodedKeySpec;
  7. import java.util.Base64;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. import java.util.Objects;
  11. import java.util.stream.Collectors;
  12. import java.util.stream.Stream;
  13. /**
  14. * 签名工具类
  15. */
  16. @Component
  17. public class SignatureUtils {
  18. /**
  19. * 签名
  20. */
  21. public static final String HEADER_PARAM_API_VERIFY_SIGN = "apiVerifySign";
  22. /**
  23. * 随机字符串
  24. */
  25. public static final String HEADER_PARAM_API_VERIFY_NONCE = "apiVerifyNonce";
  26. /**
  27. * 时间戳
  28. */
  29. public static final String HEADER_PARAM_API_VERIFY_TS = "apiVerifyTS";
  30. /**
  31. * 应用标识
  32. */
  33. public static final String HEADER_PARAM_ACCESS_KEY = "accessKey";
  34. /**
  35. * 签名算法
  36. */
  37. private static final String RSA = "RSA";
  38. /**
  39. * 加密算法
  40. */
  41. private static final String SHA512_WITH_RSA = "SHA512withRSA";
  42. private SignatureUtils() {
  43. }
  44. /**
  45. * 执行签名
  46. *
  47. * @param rsaPrivateKey 私钥
  48. * @param toSignStr 参数内容
  49. * @return 签名后的内容,base64后的字符串
  50. */
  51. public static String executeSignature(String rsaPrivateKey, String toSignStr) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
  52. // base64解码私钥
  53. byte[] decodePrivateKey = Base64.getDecoder().decode(rsaPrivateKey.replace("\r\n", ""));
  54. PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decodePrivateKey);
  55. KeyFactory keyFactory = KeyFactory.getInstance(RSA);
  56. PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
  57. Signature signature = Signature.getInstance(SHA512_WITH_RSA);
  58. signature.initSign(privateKey);
  59. signature.update(toSignStr.getBytes());
  60. // 生成签名
  61. byte[] result = signature.sign();
  62. // base64编码签名为字符串
  63. return Base64.getEncoder().encodeToString(result);
  64. }
  65. /**
  66. * 验证签名
  67. *
  68. * @param rsaPublicKey 公钥
  69. * @param sign 签名
  70. * @param src 参数内容
  71. * @return 验证结果
  72. */
  73. public static boolean verifySignature(String rsaPublicKey, String sign, String src) throws IllegalArgumentException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
  74. // base64解码公钥
  75. byte[] decodePublicKey = Base64.getDecoder().decode(rsaPublicKey.replace("\r\n", ""));
  76. X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decodePublicKey);
  77. KeyFactory keyFactory = KeyFactory.getInstance(RSA);
  78. PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
  79. Signature signature = Signature.getInstance(SHA512_WITH_RSA);
  80. signature.initVerify(publicKey);
  81. signature.update(src.getBytes());
  82. // base64解码签名为字节数组
  83. byte[] decodeSign = Base64.getDecoder().decode(sign);
  84. // 验证签名
  85. return signature.verify(decodeSign);
  86. }
  87. /**
  88. * 构建加签参数字符串
  89. *
  90. * @param urlParamsStr url参数(格式如:”a=1&b=2“)
  91. * @param bodyStr body参数
  92. * @param accessKey 应用标识
  93. * @param apiVerifyTS 时间戳
  94. * @param apiVerifyNonce 随机字符串
  95. * @return 签名字符串
  96. */
  97. public static String buildToSignatureStr(String urlParamsStr, String bodyStr, String accessKey, long apiVerifyTS, String apiVerifyNonce) {
  98. Map<String, Object> urlParams = null;
  99. if (null != urlParamsStr && !urlParamsStr.isEmpty()) {
  100. // 将url参数解析为Map
  101. urlParams = Stream.of(urlParamsStr.split("&"))
  102. .filter(Objects::nonNull)
  103. .map(String::trim)
  104. .filter(param -> !param.isEmpty())
  105. .map(param -> param.split("="))
  106. .filter(paramSplitArr -> paramSplitArr.length >= 2)
  107. .collect(Collectors.toMap(paramSplitArr -> paramSplitArr[0].trim(), paramSplitArr -> paramSplitArr[1].trim()));
  108. }
  109. return buildToSignatureStr(urlParams, bodyStr, accessKey, apiVerifyTS, apiVerifyNonce);
  110. }
  111. /**
  112. * 构建加签参数字符串
  113. *
  114. * @param urlParams url参数
  115. * @param bodyStr body参数
  116. * @param accessKey 应用标识
  117. * @param apiVerifyTS 时间戳
  118. * @param apiVerifyNonce 随机字符串
  119. * @return 签名字符串
  120. */
  121. public static String buildToSignatureStr(Map<String, Object> urlParams, String bodyStr, String accessKey, long apiVerifyTS, String apiVerifyNonce) {
  122. Map<String, Object> parameterMap = new HashMap<>();
  123. // 拼接时间戳与随机字符串
  124. parameterMap.put(HEADER_PARAM_ACCESS_KEY, accessKey);
  125. parameterMap.put(HEADER_PARAM_API_VERIFY_TS, apiVerifyTS);
  126. parameterMap.put(HEADER_PARAM_API_VERIFY_NONCE, apiVerifyNonce);
  127. // 拼接请求参数
  128. if (urlParams != null && !urlParams.isEmpty()) {
  129. parameterMap.putAll(urlParams);
  130. }
  131. StringBuilder sb = new StringBuilder();
  132. // 字典序排序拼接
  133. parameterMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry ->
  134. sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&")
  135. );
  136. String substring = sb.substring(0, sb.length() - 1);
  137. return null == bodyStr || bodyStr.isEmpty() ? substring : substring + ";" + bodyStr;
  138. }
  139. }