zoukankan      html  css  js  c++  java
  • RSA公钥验签

    1.业务场景,公司做理财业务,但是可能有第三方合作。与第三方合作获得更多客户流量。别人可以在第三方进行购买理财产品。那么怎么保证交易信息的安全性那,我们这里给出rsa加密实现原理。

    2.工具类rsa:

    公钥私钥的生成百度一下有在线生成的网站。

    1. import java.security.KeyFactory;
    2. import java.security.PrivateKey;
    3. import java.security.PublicKey;
    4. import java.security.Signature;
    5. import java.security.spec.PKCS8EncodedKeySpec;
    6. import java.security.spec.X509EncodedKeySpec;
    7. import org.apache.commons.codec.binary.Base64;
    8. import org.slf4j.Logger;
    9. import org.slf4j.LoggerFactory;
    10. import lombok.extern.slf4j.Slf4j;
    11. /**
    12. * 使用私钥将明文进行签名生成秘闻串与明文一起传输。对方收到数据后通过公钥对明文与明文进行验签。
    13. * 若验签通过就说明第一数据没有被修改过;第二这些数据一定是持有私钥的人发送的,因为私钥自己持有,
    14. * 这就起到了防止抵赖的作用。
    15. */
    16. @Slf4j
    17. public class RSAUtil {
    18. static Logger LOG = LoggerFactory.getLogger(RSAUtil.class);
    19. private static final String SIGNATURE_ALGORITHM = "SHA1withRSA"; //签名算法
    20. private static final String KEY_ALGORITHM = "RSA"; //加密算法RSA
    21. /**
    22. * 公钥验签
    23. *
    24. * @param text 原字符串
    25. * @param sign 签名结果
    26. * @param publicKey 公钥
    27. * @return 验签结果
    28. */
    29. public static boolean verify(String text, String sign, String publicKey) {
    30. try {
    31. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
    32. PublicKey key = KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(publicKey)));
    33. signature.initVerify(key);
    34. signature.update(text.getBytes());
    35. return signature.verify(Base64.decodeBase64(sign));
    36. } catch (Exception e) {
    37. LOG.error("验签失败:text={},sign={}", text, sign, e);
    38. }
    39. return false;
    40. }
    41. /**
    42. * 签名字符串
    43. *
    44. * @param text 需要签名的字符串
    45. * @param privateKey 私钥(BASE64编码)
    46. * @return 签名结果(BASE64编码)
    47. */
    48. public static String sign(String text, String privateKey) {
    49. byte[] keyBytes = Base64.decodeBase64(privateKey);
    50. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
    51. try {
    52. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    53. PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
    54. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
    55. signature.initSign(privateK);
    56. signature.update(text.getBytes());
    57. byte[] result = signature.sign();
    58. return Base64.encodeBase64String(result);
    59. } catch (Exception e) {
    60. LOG.error("签名失败,text={}", text, e);
    61. }
    62. return null;
    63. }
    64. private static final String publicKey = "aaaaaaaaa" ;
    65. private static final String privateKey = "bbbbbbbbb";
    66. public static void main(String[] args) {
    67. String text = "hello world";
    68. String sign = RSAUtil.sign(text, privateKey);
    69. log.info(sign);
    70. boolean verify = RSAUtil.verify(text, sign, publicKey);
    71. log.info("result: {}",verify);
    72. }
    73. }

    3.对数据进行加密之前,首先要保证数据的顺序一致性,顺序不一致可能会导致生成的密文不同。我们这里默认采用拼音排序。

    1. import com.fasterxml.jackson.annotation.JsonInclude;
    2. import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    3. import com.happylaishop.admin.util.JsonUtil;
    4. /**
    5. * 签名明文,字典即拼音进行排序
    6. */
    7. @JsonInclude(JsonInclude.Include.NON_NULL)
    8. @JsonPropertyOrder(alphabetic = true)
    9. public interface SignText {
    10. default String toText(){
    11. return JsonUtil.obj2String(this);
    12. }
    13. }

    4.采用AOP进行校验。请求方法中前三个参数是string, string SignText的我们进行拦截校验。

    authId表示认证对象id,双方约定好。

    sign 表示密文签名

    text 传输的数据

    1. import org.aspectj.lang.annotation.Aspect;
    2. import org.aspectj.lang.annotation.Before;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.stereotype.Component;
    5. import org.springframework.util.Assert;
    6. import xxx.util.RSAUtil;
    7. /**
    8. * 验签aop
    9. */
    10. @Component
    11. @Aspect
    12. public class SignAop {
    13. @Autowired
    14. private SignService signService;
    15. @Before(value = "execution(* com.happylaishop.admin.controller.*.*(..)) && args(authId,sign,text,..)")
    16. public void verify(String authId,String sign,SignText text){
    17. /**根据认证id获取对应的公钥*/
    18. String publicKey = signService.getPublicKey(authId);
    19. //拿到公钥之后验签,若验签通过,执行后续业务逻辑,否则报异常
    20. Assert.isTrue(RSAUtil.verify(text.toText(),sign,publicKey),"验签失败");
    21. }
    22. }
    1. import org.springframework.stereotype.Service;
    2. import java.util.HashMap;
    3. import java.util.Map;
    4. /**
    5. * 签名服务
    6. */
    7. @Service
    8. public class SignService {
    9. static Map<String,String> PUBLIC_KEYS = new HashMap<>();
    10. static {
    11. PUBLIC_KEYS.put("1000","aaaaaaaa");
    12. }
    13. /**
    14. * 根据授权编号获取公钥
    15. * @param authId
    16. * @return
    17. */
    18. public String getPublicKey(String authId){
    19. return PUBLIC_KEYS.get(authId);
    20. }
    21. }

    我们这里给出一个传输数据,订单对象;

    1. import java.math.BigDecimal;
    2. import java.util.Date;
    3. import com.fasterxml.jackson.annotation.JsonFormat;
    4. import lombok.Getter;
    5. import lombok.Setter;
    6. import lombok.ToString;
    7. import lombok.extern.slf4j.Slf4j;
    8. @Getter
    9. @Setter
    10. @ToString
    11. public class OrderParam implements SignText{
    12. private String chanId;
    13. private String chanUserId;
    14. private String productId;
    15. private BigDecimal amount;
    16. private String outerOrderId;
    17. private String memo;
    18. @JsonFormat(pattern = "YYYY-MM-DD HH:mm:ss")
    19. private Date createAt;
    20. public static void main(String[] args) {
    21. OrderParam order = new OrderParam();
    22. order.setAmount(new BigDecimal("100"));
    23. order.setChanId("1000");
    24. order.setChanUserId("1000");
    25. order.setProductId("1");
    26. SignText signText = order;
    27. String text = signText.toText();
    28. System.out.println(text);
    29. }
    30. }


  • 相关阅读:
    inux修改profile文件出错后所有命令不能用
    windows常用批处理脚本
    Namespace + functions versus static methods on a class 命名空间函数和类的静态方法对比
    vs2008(visual studio)使用cppcheck
    保存文件为UTF8格式(Writing UTF8 files in C++).
    C++ smtp发送邮件类(ssl/tls)转自codeproject。
    CString、TCHAR、WCHAR 字符串等转BSTR的几种方法。
    C/C++中全局变量的那些事儿
    [C++] 哪本书是对程序员最有影响、每个程序员都该阅读的书?读书排行。
    (转)修改VS2008(vc)中工程/解决方案/类的名字
  • 原文地址:https://www.cnblogs.com/jpfss/p/10076602.html
Copyright © 2011-2022 走看看