数据安全验证签名问题.RSA 与PKCS8的坑

举报
西魏陶渊明 发表于 2022/09/25 04:53:04 2022/09/25
【摘要】 在做支付的涉及安全的时候,经常会 遇到很多情况,就是合作方在生成公钥和私钥的情况下都喜欢是RSA格式,对方要求未经过PKCS#8编码的私钥文件,这中格式对于js代码很容易实现,但是对于Java来就不是很容易,要多很多代码,笔者在此总结: 笔者在这里提供两种解决办法: 一、RSA转换PKSC8 1.源头解决 生成p...

在做支付的涉及安全的时候,经常会
遇到很多情况,就是合作方在生成公钥和私钥的情况下都喜欢是RSA格式,对方要求未经过PKCS#8编码的私钥文件,这中格式对于js代码很容易实现,但是对于Java来就不是很容易,要多很多代码,笔者在此总结:

171693766.jpg

笔者在这里提供两种解决办法:

一、RSA转换PKSC8

  • 1.源头解决

  
  1. 生成pem格式的私钥:
  2. openssl genrsa -out private_key.pem 1024
  3. 生成公钥:
  4. openssl rsa -in private_key.pem -pubout -out public_key.pem

使用下面的方式进行转换

openssl pkcs8 -topk8 -inform PEM -in private_key.pem -outform PEM -nocrypt -out private_key_pkcs8.pem

 
  • 2.将已经生成的私钥进行转换

RSA转换PKCS8

以上两种方法,均可以使用下面解决


  
  1. /**
  2. * 工具类:
  3. * 私钥:openssl genrsa -out /Users/mac/Desktop/private_key.pem 1024
  4. * 公钥:openssl rsa -in /Users/mac/Desktop/private_key.pem -out /Users/mac/Desktop/rsa_public_key.pem -pubout
  5. *
  6. * 异常:
  7. * algid parse error, not a sequence
  8. *
  9. * 解决办法:
  10. * 将rsa转换为pkcs8
  11. * http://tool.chacuo.net/cryptrsapkcs1pkcs8
  12. * @Auther lx
  13. */
  14. public class SignUtil {
  15. public static String text = "war";
  16. public static RSAPublicKey rsaPublicKey;
  17. public static RSAPrivateKey rsaPrivateKey;
  18. public static void main(String[] args) throws Exception {
  19. String rsaprivateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMhvuLsBi0FWmuwF\n" +
  20. "x2XHZWOBNkzviihv9r0CD2qc0D4rnQW/DO9muIu2zsWLD88Iujk19WE28X85I/pU\n" +
  21. "3QMR2NKQ57iNZzX+/vy1LsrF/vZMzJRnN0Xa4OqYYF0KP2ZiXSIqFOyUx2rqgWa8\n" +
  22. "YFmfhJGfsmMCpOvHCPV/pokXHDy1AgMBAAECgYB7mREkGD6kCuC7nJCp/XxTENHI\n" +
  23. "PYpHh0tyn/ubtZlgTQqmCXrTgddZKGB3Rlp4Q5x6PQDUcsoWtsitzHkBNJcroVR8\n" +
  24. "yhD9JaaFWLuJXJoYaTvAFtUzqaSVhuaZfflL57i9FnVhkDeh9rVwp5f9EfO3OrM0\n" +
  25. "ez4Q0Q0MnMOEJyCp4QJBAPQI2HNPi4fwgWc6fvrFkf6FDDTRcpn0W5kLNtmmImw+\n" +
  26. "IVK1MQgOKT1FXTwsz3pNkhwbbxg5ZskItYg4tYs6NkkCQQDSQ6Bad0xD/TnqzlHP\n" +
  27. "krqBPx4dMataXLsDb8b/CcTGeXtEzrVQCxeP6LwhPD7Yrn4lctASXMwqvjn843xT\n" +
  28. "36MNAkEA3K0jDyNfig5y9mZvbVY8L20hHKJKf+345uy9LRSPDFMizygKrr4fjMit\n" +
  29. "Bz1+YZrEBabJT56Y1DKL9iNSCBUcAQJARObsUTjuwQjmRc++d2r5uwjX8XEpWb8x\n" +
  30. "eXrTlxe4Z+G/R1kFiWlZG0uE+s8nORJVPChXjuzh6s/TaM+TGlkasQJAODVjJ2IE\n" +
  31. "fXurgMxfsAed8D4ZoDnNPEUIjfJnc9P5Wx5WZHe/CfPgEPbzkl70eI+hvG9Zl/IN\n" +
  32. "VKzUByVSsbajcQ==";
  33. loadPrivateKey(rsaprivateKey);
  34. //TODO 使用SHA256加密解密
  35. Signature signature = Signature.getInstance("SHA256withRSA");
  36. signature.initSign(rsaPrivateKey);
  37. signature.update(text.getBytes());
  38. byte[] result = signature.sign();
  39. System.out.println("SHA256withRSA加密:" + Base64Utils.encodeToString(result));
  40. String rsapublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIb7i7AYtBVprsBcdlx2VjgTZM\n" +
  41. "74oob/a9Ag9qnNA+K50FvwzvZriLts7Fiw/PCLo5NfVhNvF/OSP6VN0DEdjSkOe4\n" +
  42. "jWc1/v78tS7Kxf72TMyUZzdF2uDqmGBdCj9mYl0iKhTslMdq6oFmvGBZn4SRn7Jj\n" +
  43. "AqTrxwj1f6aJFxw8tQIDAQAB";
  44. loadPublicKey(rsapublicKey);
  45. signature.initVerify(rsaPublicKey);
  46. signature.update("war".getBytes());
  47. boolean flag = signature.verify(result);
  48. System.out.println("SHA256withRSA解密:" + flag);
  49. }
  50. /**
  51. * 从字符串中加载公钥
  52. *
  53. * @param publicKeyStr 公钥数据字符串
  54. * @throws Exception 加载公钥时产生的异常
  55. */
  56. public static void loadPublicKey(String publicKeyStr) throws Exception {
  57. try {
  58. BASE64Decoder base64Decoder = new BASE64Decoder();
  59. byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
  60. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  61. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
  62. rsaPublicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
  63. } catch (NoSuchAlgorithmException e) {
  64. throw new Exception("无此算法");
  65. } catch (InvalidKeySpecException e) {
  66. e.printStackTrace();
  67. } catch (IOException e) {
  68. throw new Exception("公钥数据内容读取错误");
  69. } catch (NullPointerException e) {
  70. throw new Exception("公钥数据为空");
  71. }
  72. }
  73. public static void loadPrivateKey(String privateKeyStr) throws Exception {
  74. try {
  75. BASE64Decoder base64Decoder = new BASE64Decoder();
  76. byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr);
  77. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
  78. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  79. rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
  80. } catch (NoSuchAlgorithmException e) {
  81. e.printStackTrace();
  82. } catch (InvalidKeySpecException e) {
  83. e.printStackTrace();
  84. } catch (IOException e) {
  85. throw new Exception("私钥数据内容读取错误");
  86. } catch (NullPointerException e) {
  87. throw new Exception("私钥数据为空");
  88. }
  89. }
  90. }

二、直接使用RSA验证签名,多写两行实现

Oracle参考文献


  
  1. 去掉---开头----
  2. byte [] asn1PrivateKeyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(b64encoded.getBytes("US-ASCII"));
  3. RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(asn1PrivateKeyBytes));
  4. RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent());
  5. KeyFactory kf = KeyFactory.getInstance("RSA");
  6. RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(rsaPrivKeySpec);
  7. System.out.println(privKey.getPrivateExponent());

  
  1. String rsaprivateKey = "MIICXAIBAAKBgQDIb7i7AYtBVprsBcdlx2VjgTZM74oob/a9Ag9qnNA+K50Fvwzv\n" +
  2. "ZriLts7Fiw/PCLo5NfVhNvF/OSP6VN0DEdjSkOe4jWc1/v78tS7Kxf72TMyUZzdF\n" +
  3. "2uDqmGBdCj9mYl0iKhTslMdq6oFmvGBZn4SRn7JjAqTrxwj1f6aJFxw8tQIDAQAB\n" +
  4. "AoGAe5kRJBg+pArgu5yQqf18UxDRyD2KR4dLcp/7m7WZYE0Kpgl604HXWShgd0Za\n" +
  5. "eEOcej0A1HLKFrbIrcx5ATSXK6FUfMoQ/SWmhVi7iVyaGGk7wBbVM6mklYbmmX35\n" +
  6. "S+e4vRZ1YZA3ofa1cKeX/RHztzqzNHs+ENENDJzDhCcgqeECQQD0CNhzT4uH8IFn\n" +
  7. "On76xZH+hQw00XKZ9FuZCzbZpiJsPiFStTEIDik9RV08LM96TZIcG28YOWbJCLWI\n" +
  8. "OLWLOjZJAkEA0kOgWndMQ/056s5Rz5K6gT8eHTGrWly7A2/G/wnExnl7RM61UAsX\n" +
  9. "j+i8ITw+2K5+JXLQElzMKr45/ON8U9+jDQJBANytIw8jX4oOcvZmb21WPC9tIRyi\n" +
  10. "Sn/t+ObsvS0UjwxTIs8oCq6+H4zIrQc9fmGaxAWmyU+emNQyi/YjUggVHAECQETm\n" +
  11. "7FE47sEI5kXPvndq+bsI1/FxKVm/MXl605cXuGfhv0dZBYlpWRtLhPrPJzkSVTwo\n" +
  12. "V47s4erP02jPkxpZGrECQDg1YydiBH17q4DMX7AHnfA+GaA5zTxFCI3yZ3PT+Vse\n" +
  13. "VmR3vwnz4BD285Je9HiPobxvWZfyDVSs1AclUrG2o3E=";
  14. byte [] asn1PrivateKeyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(rsaprivateKey.getBytes("US-ASCII"));
  15. RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence)
  16. ASN1Sequence.fromByteArray(asn1PrivateKeyBytes));
  17. RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(),
  18. asn1PrivKey.getPrivateExponent());
  19. KeyFactory keyFactory= KeyFactory.getInstance("RSA");
  20. PrivateKey priKey= keyFactory.generatePrivate(rsaPrivKeySpec);
  21. //TODO 使用SHA256加密解密
  22. Signature signature = Signature.getInstance("SHA256withRSA");
  23. signature.initSign(priKey);
  24. signature.update(text.getBytes());
  25. byte[] result = signature.sign();
  26. System.out.println("SHA256withRSA加密:" + Base64Utils.encodeToString(result));
  27. String rsapublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIb7i7AYtBVprsBcdlx2VjgTZM\n" +
  28. "74oob/a9Ag9qnNA+K50FvwzvZriLts7Fiw/PCLo5NfVhNvF/OSP6VN0DEdjSkOe4\n" +
  29. "jWc1/v78tS7Kxf72TMyUZzdF2uDqmGBdCj9mYl0iKhTslMdq6oFmvGBZn4SRn7Jj\n" +
  30. "AqTrxwj1f6aJFxw8tQIDAQAB";
  31. loadPublicKey(rsapublicKey);
  32. signature.initVerify(rsaPublicKey);
  33. signature.update("test".getBytes());
  34. boolean flag = signature.verify(result);
  35. System.out.println("SHA256withRSA解密:" + flag);

附录

上面的RSA其实就是PKCS1

PKCS

The Public-Key Cryptography Standards (PKCS)是由美国RSA数据安全公司及其合作伙伴制定的一组公钥密码学标准,其中包括证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名数字信封的格式等方面的一系列相关协议。

PKCS已经公布了以下标准:

PKCS#1:定义RSA公开密钥算法加密和签名机制,主要用于组织PKCS#7中所描述的数字签名数字信封[22]。
PKCS#3:定义Diffie-Hellman密钥交换协议[23]。
PKCS#5:描述一种利用从口令派生出来的安全密钥加密字符串的方法。使用MD2或MD5 从口令中派生密钥,并采用DES-CBC模式加密。主要用于加密从一个计算机传送到另一个计算机的私人密钥,不能用于加密消息[24]。
PKCS#6:描述了公钥证书的标准语法,主要描述X.509证书的扩展格式[25]。
PKCS#7:定义一种通用的消息语法,包括数字签名和加密等用于增强的加密机制,PKCS#7与PEM兼容,所以不需其他密码操作,就可以将加密的消息转换成PEM消息[26]。
PKCS#8:描述私有密钥信息格式,该信息包括公开密钥算法的私有密钥以及可选的属性集等[27]。
PKCS#9:定义一些用于PKCS#6证书扩展、PKCS#7数字签名和PKCS#8私钥加密信息的属性类型[28]。
PKCS#10:描述证书请求语法[29]。
PKCS#11:称为Cyptoki,定义了一套独立于技术的程序设计接口,用于智能卡和PCMCIA卡之类的加密设备[30]。
PKCS#12:描述个人信息交换语法标准。描述了将用户公钥私钥、证书和其他相关信息打包的语法[31]。
PKCS#13:椭圆曲线密码体制标准[32]。
PKCS#14:伪随机数生成标准。
PKCS#15:密码令牌信息格式标准[33]。

RSA

4279695-65d76c8ef12fa9b1.jpg

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的"非对称加密算法"。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。
这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。

文章来源: springlearn.blog.csdn.net,作者:西魏陶渊明,版权归原作者所有,如需转载,请联系作者。

原文链接:springlearn.blog.csdn.net/article/details/102425292

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。