0


前后端RSA互相加解密、加签验签、密钥对生成(Java)

目录

一、序言

最近有一些安全性要求比较高的场景,我们提供API给第三方商户用于收单,其中有几个功能是绑卡、ATM/POS密码变更。

出于合规和监管要求,第三方商户不能保存卡号、CVV、密码等敏感信息,所以相关的敏感操作必须在接口提供方H5页面中完成。为了最大程度保证安全性,我们决定对敏感信息进行加密传输,同时对请求参数进行加签处理。

由于前端并不需要解密操作,最终我们选择

RSA

非对称加密,前端这块主要采用

jsencrypt

进行加解密,

jsrsasign

用来生成密钥对、加签验签。


二、关于PKCS#1和PKCS#8格式密钥

由于Java非对称加解密、加验签都是采用

PKCS#8

格式的密钥,

PKCS#1

格式的密钥跑不通,这里先简单介绍一下两者的区别。

1、简介

PKCS#1

PKCS#8

是两个不同的数字证书标准。

  • PKCS#1是一个公钥加密标准,它定义了使用RSA算法进行加密和签名的格式。主要用于对数字签名、加密以及数字签名验证等应用。
  • PKCS#8则是一个私钥保护标准,它定义了私钥的存储格式。它主要用于在文件中对私钥进行保护,以防止意外泄露或不当使用。

总的来说,

PKCS#1

是针对公钥的标准,而

PKCS#8

是针对私钥的标准。

2、区别

两者的密钥格式不一样,下面以标准

.pem

格式为例,看下PKCS#1格式和PKCS#8格式密钥的区别:

  • PKCS#1格式私钥:
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC5BW6T9GVaaG/epGDjPpY3wN0DrBt+NojvxkEgpUdOAxgAepqe
...
TbzKH/LEqZN8WVau3bf41yAx2YoaOsIJJtOUTYcfh14=
-----END RSA PRIVATE KEY-----
  • PKCS#8格式私钥:
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALkFbpP0ZVpob96k
...
wgkm05RNhx+HXg==
-----END PRIVATE KEY-----
  • PKCS#1格式公钥:
-----BEGIN RSA PUBLIC KEY-----
MIICXAIBAAKBgQC5BW6T9GVaaG/epGDjPpY3wN0DrBt+NojvxkEgpUdOAxgAepqe
...
TbzKH/LEqZN8WVau3bf41yAx2YoaOsIJJtOUTYcfh14=
-----END RSA PUBLIC KEY-----
  • PKCS#8格式公钥:
-----BEGIN PUBLIC KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALkFbpP0ZVpob96k
...
wgkm05RNhx+HXg==
-----END PUBLIC KEY-----

二、关于JSEncrypt

JSEncrypt是前端RSA加解密、密钥生成的一个实现方案,API也比较简单,更多请参考:JSEncrypt官网。

官网有个线上的Demo,可以生成非对称密钥,还有加解密。
在这里插入图片描述

Home页有相关的使用示例,还是很简单的。

// Create the encryption object and set the key.var crypt =newJSEncrypt();
crypt.setKey(__YOUR_OPENSSL_PRIVATE_OR_PUBLIC_KEY__);//You can use also setPrivateKey and setPublicKey, they are both alias to setKey//Eventhough the methods are called setPublicKey and setPrivateKey, remember//that they are only alias to setKey, so you can pass them both a private or//a public openssl key, just remember that setting a public key allows you to only encrypt.var text ='test';// Encrypt the data with the public key.var enc = crypt.encrypt(text);// Now decrypt the crypted text with the private key.var dec = crypt.decrypt(enc);// Now a simple check to see if the round-trip worked.if(dec === text){alert('It works!!!');}else{alert('Something went wrong....');}

备注:Download页有

JSEncrypt

官网demo的源代码。


三、关于jsrsasign

jsrsasign

是一个开源的纯JavaScript加密库,支持RSA/RSAPSS/ECDSA/DSA签名和验签,PKCS#1/5/8公私钥生成等等。

在Github上有两篇文章,一篇是关于如何使用

Signature

类进行加签、验签的,一篇是关于

jsrsasign

和Java互用性的,里面有通过Java加签,通过

jsrsasign

验签的demo。

在这里插入图片描述

更多相关类和方法的使用和描述可以参考,jsrsasign API文档说明。


四、前端RSA加解密、加验签示例

1、相关依赖

// JSEncrypt
npm i jsencrypt

// jsrsasign
npm i jsrsasign

2、cryptoUtils工具类封装

import CryptoJS from"crypto-js";import JSEncrypt from"jsencrypt";import JsRsaSign from"jsrsasign";/**
 * RSA加密
 * @param publicKey 公钥
 * @param plainText 明文
 * @returns {*} 密文
 */exportfunctionencryptByRSA(publicKey, plainText){const encryptor =newJSEncrypt();
  encryptor.setPublicKey(publicKey);return encryptor.encrypt(plainText);}/**
 * RSA解密
 * @param privateKey 私钥
 * @param cipherText 密文
 * @returns {*} 明文
 */exportfunctiondecryptByRSA(privateKey, cipherText){const decrypter =newJSEncrypt();
  decrypter.setPrivateKey(privateKey);return decrypter.decrypt(cipherText);}/**
 * 生成RSA密钥对,填充模式为PKCS8。
 * 更多模式参考:<a href="https://kjur.github.io/jsrsasign/api/symbols/KEYUTIL.html">https://kjur.github.io/jsrsasign/api/symbols/KEYUTIL.html</a>
 * @returns {{privateKey: (string|string|*), publicKey: (string|string|*)}}
 */exportfunctiongenerateRsaKeyWithPKCS8(){const keyPair = JsRsaSign.KEYUTIL.generateKeypair("RSA",1024);const privateKey = JsRsaSign.KEYUTIL.getPEM(keyPair.prvKeyObj,"PKCS8PRV");const publicKey = JsRsaSign.KEYUTIL.getPEM(keyPair.pubKeyObj);return{ privateKey, publicKey };}/**
 * SHA256和RSA加签
 * @param privateKey 私钥
 * @param msg 加签内容
 * @returns {string} Base64编码签名内容
 */exportfunctionsignBySHA256WithRSA(privateKey, msg){const key = JsRsaSign.KEYUTIL.getKey(privateKey);const signature =newJsRsaSign.KJUR.crypto.Signature({alg:"SHA256withRSA",});
  signature.init(key);
  signature.updateString(msg);// 签名后的为16进制字符串,这里转换为16进制字符串return JsRsaSign.hextob64(signature.sign());}/**
 * SHA256和RSA验签
 * @param publicKey 公钥:必须为标准pem格式。如果是PKCS1格式,必须包含-----BEGIN RSA PRIVATE KEY-----,如果是PKCS8格式,必须包含-----BEGIN PRIVATE KEY-----
 * @param base64SignStr Base64编码签名字符串
 * @param msg 原内容
 * @returns {boolean} 是否验签通过
 */exportfunctionverifyBySHA256WithRSA(publicKey, base64SignStr, msg){const key = JsRsaSign.KEYUTIL.getKey(publicKey);const signature =newJsRsaSign.KJUR.crypto.Signature({alg:"SHA256withRSA",});
  signature.init(key);
  signature.updateString(msg);// 需要将Base64进制签名字符串转换成16进制字符串return signature.verify(JsRsaSign.b64tohex(base64SignStr));}

3、测试用例

先在前端测试下密钥对生成,RSA加解密、加验签,测试代码如下:

import * as CryptoUtils from '@/utils/cryptoUtils.js';

const {privateKey, publicKey}= CryptoUtils.generateRsaKeyWithPKCS8();
console.log(`生成的私钥为:\n${privateKey}`);
console.log(`生成的公钥为:\n${publicKey}`);

const cipherText = CryptoUtils.encryptByRSA(publicKey, "test");
console.log(`test加密后的内容为:\n${cipherText}`);

const plainText = CryptoUtils.decryptByRSA(privateKey, cipherText);
console.log(`解密后的内容为:\n${plainText}`);

const signature = CryptoUtils.signBySHA256WithRSA(privateKey, "test");
console.log(`生成的签名:\n${signature}`);

const isVerified = CryptoUtils.verifyBySHA256WithRSA(publicKey, signature, "test");
console.log(`是否验签通过:${isVerified}`);

控制台输出结果为:

生成的私钥为:
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMv1adNmKNw4rtr2
Dy92DZ3Nk1SCrGGetlq0sSgLY8bJsByAvP2ZOOiiWq2xDUVu8ZpQfM8v89tjegfr
sIUcN/ZVLc68Ric3BIto85oQc9jBz+aCk1rXeNMePkSVqNaC/n4kJ73Y41ZgKAe0
GvyqMyUNhk8VZd+QSNATSv+lGep3AgMBAAECgYBoKMvDry98z+HUZsb4iQSJK1xr
U1SvgftEtXSnq7Fn6sZquABMTry2aXt/qqTJadAu653hvW5/Av1mICKEyBV3aT4O
jQRGPMgp6WhXvQepUIuyi9qlfUVsJy/+J0zGKZeKsCFlwZ2e2j4Un7Bb//pgUfjJ
rbPtwC7U85oHjtJb6QJBAOdcm07ThSXFbicj2MuX9Gh7geMjncf6aqnrOwUFjO0d
5OxfYRAxrZD1GghygHyoJ4ZOHgJ0s6HVEYjg/u6DBdsCQQDhrb4IOVdSew2cW15f
t/5DAKUXRRQBfz0OxOs0Uv5k7zqI+YmysWVRGaZgj8oMZ7gYxN1eYNOKTwVjiuwb
uyaVAkEA0OGSMpPT1WsvbVT26bFyb1Z6yTihvif/XxPKgFknh/kCcsoWFwnS+1ne
vBusl181+BLVE0CL4aM9pogEghB3GwJAWJTVzmyTdfCO+xxyAqg5yRrrsiKPI7dJ
xA5PNA6PhBbSpwkrn1Q6LIcg4y4NZKkhfbdoHK9s2REDUHsrCgd/sQJAALEe+PCX
hcHWnwbm4kRFyJCO4dWkii7o28ohTRourlNsoEmiu1+7lt7PY1+C3D+6A4FFCY/H
pGM0i0lJue8rZA==
-----END PRIVATE KEY-----

生成的公钥为:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL9WnTZijcOK7a9g8vdg2dzZNU
gqxhnrZatLEoC2PGybAcgLz9mTjoolqtsQ1FbvGaUHzPL/PbY3oH67CFHDf2VS3O
vEYnNwSLaPOaEHPYwc/mgpNa13jTHj5ElajWgv5+JCe92ONWYCgHtBr8qjMlDYZP
FWXfkEjQE0r/pRnqdwIDAQAB
-----END PUBLIC KEY-----

test加密后的内容为:
KjcaDKLnBbvxRzuKMysqoz9MHRXCUNIH67+XDiFGTJbM8Rjw4Cei0CzjAPjk2jgAR37Kgh6lX2+Xg8AI9wEmzWr08bt8i2FFxVMrcfOCs5zI1y+2T7G9034f5b0gNx/Pc4dDz+1k453vo0AhCC0vrtb1OfbsRu5oOFns0TqoAMY=

解密后的内容为:test

生成的签名:
t0koTqhiWmq/wEvI/ieJq5kZj7Dc/limF7GNVtHNLReqLVBXZvAZrOIwdqda7LBHBSHcRZBISWtbuyDiOR9KFPObrOgOEUOdfACUMzjWKCtO8ZgcQ+U02FyGeeH2rT9rJEJAXDEM+Kn3+H4ZdbrUFPY3jQRl535wnK9CLpxqAG4=

是否验签通过:true

备注:为什么在前端生成PKCS#8格式密钥呢?
因为在Java中非对称加解密、加验签都是用的PKCS#8PKCS#1格式密钥需要转换成PKCS#8


五、Java后端RSA加解密、加验签

1、CryptoUtils工具类封装

importcom.universe.crypto.CryptoUtils.Algorithm.Encryption;importcom.universe.crypto.CryptoUtils.Algorithm.Signing;importlombok.AllArgsConstructor;importlombok.Data;importlombok.Getter;importlombok.NoArgsConstructor;importorg.apache.commons.lang3.StringUtils;importjavax.crypto.Cipher;importjavax.crypto.KeyGenerator;importjavax.crypto.NoSuchPaddingException;importjavax.crypto.SecretKey;importjavax.crypto.spec.IvParameterSpec;importjavax.crypto.spec.SecretKeySpec;importjava.nio.charset.Charset;importjava.nio.charset.StandardCharsets;importjava.security.Key;importjava.security.KeyFactory;importjava.security.KeyPair;importjava.security.KeyPairGenerator;importjava.security.NoSuchAlgorithmException;importjava.security.PrivateKey;importjava.security.PublicKey;importjava.security.Signature;importjava.security.spec.InvalidKeySpecException;importjava.security.spec.KeySpec;importjava.security.spec.PKCS8EncodedKeySpec;importjava.security.spec.X509EncodedKeySpec;importjava.util.Base64;importjava.util.Base64.Decoder;importjava.util.Base64.Encoder;importjava.util.HashMap;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/**
 * 支持AES、DES、RSA加密、数字签名以及生成对称密钥和非对称密钥对
 */publicclassCryptoUtils{privatestaticfinalCharsetDEFAULT_CHARSET=StandardCharsets.UTF_8;privatestaticfinalEncoderBASE64_ENCODER=Base64.getEncoder();privatestaticfinalDecoderBASE64_DECODER=Base64.getDecoder();privatestaticfinalMap<Algorithm,KeyFactory>KEY_FACTORY_CACHE=newConcurrentHashMap<>();privatestaticfinalMap<Algorithm,Cipher>CIPHER_CACHE=newHashMap<>();/**
     * 生成对称密钥,目前支持的算法有AES、DES
     * @param algorithm
     * @return
     * @throws NoSuchAlgorithmException
     */publicstaticStringgenerateSymmetricKey(Algorithm algorithm)throwsNoSuchAlgorithmException{KeyGenerator generator =KeyGenerator.getInstance(algorithm.getName());
        generator.init(algorithm.getKeySize());SecretKey secretKey = generator.generateKey();returnBASE64_ENCODER.encodeToString(secretKey.getEncoded());}/**
     * 生成非对称密钥对,目前支持的算法有RSA、DSA。备注:默认生成的密钥格式为PKCS8
     * @param algorithm
     * @return
     * @throws NoSuchAlgorithmException
     */publicstaticAsymmetricKeyPairgenerateAsymmetricKeyPair(Algorithm algorithm)throwsNoSuchAlgorithmException{KeyPairGenerator generator =KeyPairGenerator.getInstance(algorithm.getName());
        generator.initialize(algorithm.getKeySize());KeyPair keyPair = generator.generateKeyPair();String publicKey =BASE64_ENCODER.encodeToString(keyPair.getPublic().getEncoded());String privateKey =BASE64_ENCODER.encodeToString(keyPair.getPrivate().getEncoded());returnnewAsymmetricKeyPair(publicKey, privateKey);}publicstaticStringencryptByRSA(String publicKeyText,String plainText)throwsException{returnencryptAsymmetrically(publicKeyText, plainText,Encryption.RSA_ECB_PKCS1);}publicstaticStringdecryptByRSA(String privateKeyText,String ciphertext)throwsException{returndecryptAsymmetrically(privateKeyText, ciphertext,Encryption.RSA_ECB_PKCS1);}/**
     * SHA1签名算法和DSA加密算法结合使用生成数字签名
     * @param privateKeyText
     * @param msg
     * @return 数字签名
     * @throws Exception
     */publicstaticStringsignBySHA1WithDSA(String privateKeyText,String msg)throwsException{returndoSign(privateKeyText, msg,Encryption.DSA,Signing.SHA1WithDSA);}/**
     * SHA1签名算法和RSA加密算法结合使用生成数字签名
     * @param privateKeyText 私钥
     * @param msg 待加签内容
     * @return 数字签名
     * @throws Exception
     */publicstaticStringsignBySHA1WithRSA(String privateKeyText,String msg)throwsException{returndoSign(privateKeyText, msg,Encryption.RSA_ECB_PKCS1,Signing.SHA1WithRSA);}/**
     * SHA256签名算法和RSA加密算法结合使用生成数字签名
     * @param privateKeyText 私钥
     * @param msg 待加签内容
     * @return 数字签名
     * @throws Exception
     */publicstaticStringsignBySHA256WithRSA(String privateKeyText,String msg)throwsException{returndoSign(privateKeyText, msg,Encryption.RSA_ECB_PKCS1,Signing.SHA256WithRSA);}/**
     * SHA1签名算法和DSA加密算法检验数字签名
     * @param publicKeyText 公钥
     * @param msg 待验签内容
     * @param signatureText 数字
     * @return 检验是否成功
     * @throws Exception
     */publicstaticbooleanverifyBySHA1WithDSA(String publicKeyText,String msg,String signatureText)throwsException{returndoVerify(publicKeyText, msg, signatureText,Encryption.DSA,Signing.SHA1WithDSA);}/**
     * SHA1签名算法和RSA加密算法检验数字签名
     * @param publicKeyText 公钥
     * @param msg 待验签内容
     * @param signatureText 签名
     * @return 校验是否成功
     * @throws Exception
     */publicstaticbooleanverifyBySHA1WithRSA(String publicKeyText,String msg,String signatureText)throwsException{returndoVerify(publicKeyText, msg, signatureText,Encryption.RSA_ECB_PKCS1,Signing.SHA1WithRSA);}/**
     * SHA256签名算法和RSA加密算法检验数字签名
     * @param publicKeyText 公钥
     * @param msg 待验签内容
     * @param signatureText 签名
     * @return 校验是否成功
     * @throws Exception
     */publicstaticbooleanverifyBySHA256WithRSA(String publicKeyText,String msg,String signatureText)throwsException{returndoVerify(publicKeyText, msg, signatureText,Encryption.RSA_ECB_PKCS1,Signing.SHA256WithRSA);}/**
     * 对称加密
     * @param secretKey 密钥
     * @param iv 加密向量,只有CBC模式才支持,如果是CBC则必传
     * @param plainText 明文
     * @param algorithm 对称加密算法,如AES、DES
     * @return
     * @throws Exception
     */publicstaticStringencryptSymmetrically(String secretKey,String iv,String plainText,Algorithm algorithm)throwsException{SecretKey key =decodeSymmetricKey(secretKey, algorithm);IvParameterSpec ivParameterSpec =StringUtils.isBlank(iv)?null:decodeIv(iv);byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET);byte[] ciphertextInBytes =transform(algorithm,Cipher.ENCRYPT_MODE, key, ivParameterSpec, plainTextInBytes);returnBASE64_ENCODER.encodeToString(ciphertextInBytes);}/**
     * 对称解密
     * @param secretKey 密钥
     * @param iv 加密向量,只有CBC模式才支持,如果是CBC则必传
     * @param ciphertext 密文
     * @param algorithm 对称加密算法,如AES、DES
     * @return
     * @throws Exception
     */publicstaticStringdecryptSymmetrically(String secretKey,String iv,String ciphertext,Algorithm algorithm)throwsException{SecretKey key =decodeSymmetricKey(secretKey, algorithm);IvParameterSpec ivParameterSpec =StringUtils.isBlank(iv)?null:decodeIv(iv);byte[] ciphertextInBytes =BASE64_DECODER.decode(ciphertext);byte[] plainTextInBytes =transform(algorithm,Cipher.DECRYPT_MODE, key, ivParameterSpec, ciphertextInBytes);returnnewString(plainTextInBytes,DEFAULT_CHARSET);}/**
     * 非对称加密
     * @param publicKeyText 公钥
     * @param plainText 明文
     * @param algorithm 非对称加密算法
     * @return
     * @throws Exception
     */publicstaticStringencryptAsymmetrically(String publicKeyText,String plainText,Algorithm algorithm)throwsException{PublicKey publicKey =regeneratePublicKey(publicKeyText, algorithm);byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET);byte[] ciphertextInBytes =transform(algorithm,Cipher.ENCRYPT_MODE, publicKey, plainTextInBytes);returnBASE64_ENCODER.encodeToString(ciphertextInBytes);}/**
     * 非对称解密
     * @param privateKeyText 私钥
     * @param ciphertext 密文
     * @param algorithm 非对称加密算法
     * @return
     * @throws Exception
     */publicstaticStringdecryptAsymmetrically(String privateKeyText,String ciphertext,Algorithm algorithm)throwsException{PrivateKey privateKey =regeneratePrivateKey(privateKeyText, algorithm);byte[] ciphertextInBytes =BASE64_DECODER.decode(ciphertext);byte[] plainTextInBytes =transform(algorithm,Cipher.DECRYPT_MODE, privateKey, ciphertextInBytes);returnnewString(plainTextInBytes,DEFAULT_CHARSET);}/**
     * 生成数字签名
     * @param privateKeyText 私钥
     * @param msg 传输的数据
     * @param encryptionAlgorithm 加密算法,见Algorithm中的加密算法
     * @param signatureAlgorithm 签名算法,见Algorithm中的签名算法
     * @return 数字签名
     * @throws Exception
     */publicstaticStringdoSign(String privateKeyText,String msg,Algorithm encryptionAlgorithm,Algorithm signatureAlgorithm)throwsException{PrivateKey privateKey =regeneratePrivateKey(privateKeyText, encryptionAlgorithm);// Signature只支持签名算法Signature signature =Signature.getInstance(signatureAlgorithm.getName());
        signature.initSign(privateKey);
        signature.update(msg.getBytes(DEFAULT_CHARSET));byte[] signatureInBytes = signature.sign();returnBASE64_ENCODER.encodeToString(signatureInBytes);}/**
     * 数字签名验证
     * @param publicKeyText 公钥
     * @param msg 传输的数据
     * @param signatureText 数字签名
     * @param encryptionAlgorithm 加密算法,见Algorithm中的加密算法
     * @param signatureAlgorithm 签名算法,见Algorithm中的签名算法
     * @return 校验是否成功
     * @throws Exception
     */publicstaticbooleandoVerify(String publicKeyText,String msg,String signatureText,Algorithm encryptionAlgorithm,Algorithm signatureAlgorithm)throwsException{PublicKey publicKey =regeneratePublicKey(publicKeyText, encryptionAlgorithm);Signature signature =Signature.getInstance(signatureAlgorithm.getName());
        signature.initVerify(publicKey);
        signature.update(msg.getBytes(DEFAULT_CHARSET));return signature.verify(BASE64_DECODER.decode(signatureText));}/**
     * 将密钥进行Base64位解码,重新生成SecretKey实例
     * @param secretKey 密钥
     * @param algorithm 算法
     * @return
     */privatestaticSecretKeydecodeSymmetricKey(String secretKey,Algorithm algorithm){byte[] key =BASE64_DECODER.decode(secretKey);returnnewSecretKeySpec(key, algorithm.getName());}privatestaticIvParameterSpecdecodeIv(String iv){byte[] ivInBytes =BASE64_DECODER.decode(iv);returnnewIvParameterSpec(ivInBytes);}privatestaticPublicKeyregeneratePublicKey(String publicKeyText,Algorithm algorithm)throwsNoSuchAlgorithmException,InvalidKeySpecException{byte[] keyInBytes =BASE64_DECODER.decode(publicKeyText);KeyFactory keyFactory =getKeyFactory(algorithm);// 公钥必须使用RSAPublicKeySpec或者X509EncodedKeySpecKeySpec publicKeySpec =newX509EncodedKeySpec(keyInBytes);PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);return publicKey;}privatestaticPrivateKeyregeneratePrivateKey(String key,Algorithm algorithm)throwsException{byte[] keyInBytes =BASE64_DECODER.decode(key);KeyFactory keyFactory =getKeyFactory(algorithm);// 私钥必须使用RSAPrivateCrtKeySpec或者PKCS8EncodedKeySpecKeySpec privateKeySpec =newPKCS8EncodedKeySpec(keyInBytes);PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);return privateKey;}privatestaticKeyFactorygetKeyFactory(Algorithm algorithm)throwsNoSuchAlgorithmException{KeyFactory keyFactory =KEY_FACTORY_CACHE.get(algorithm);if(keyFactory ==null){
            keyFactory =KeyFactory.getInstance(algorithm.getName());KEY_FACTORY_CACHE.put(algorithm, keyFactory);}return keyFactory;}privatestaticbyte[]transform(Algorithm algorithm,int mode,Key key,byte[] msg)throwsException{returntransform(algorithm, mode, key,null, msg);}privatestaticbyte[]transform(Algorithm algorithm,int mode,Key key,IvParameterSpec iv,byte[] msg)throwsException{Cipher cipher =CIPHER_CACHE.get(algorithm);// double check,减少上下文切换if(cipher ==null){synchronized(CryptoUtils.class){if((cipher =CIPHER_CACHE.get(algorithm))==null){
                    cipher =determineWhichCipherToUse(algorithm);CIPHER_CACHE.put(algorithm, cipher);}
                cipher.init(mode, key, iv);return cipher.doFinal(msg);}}synchronized(CryptoUtils.class){
            cipher.init(mode, key, iv);return cipher.doFinal(msg);}}privatestaticCipherdetermineWhichCipherToUse(Algorithm algorithm)throwsNoSuchAlgorithmException,NoSuchPaddingException{Cipher cipher;String transformation = algorithm.getTransformation();// 官方推荐的transformation使用algorithm/mode/padding组合,SunJCE使用ECB作为默认模式,使用PKCS5Padding作为默认填充if(StringUtils.isNotEmpty(transformation)){
            cipher =Cipher.getInstance(transformation);}else{
            cipher =Cipher.getInstance(algorithm.getName());}return cipher;}/**
     * 算法分为加密算法和签名算法,更多算法实现见:<br/>
     * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#impl">jdk8中的标准算法</a>
     */publicstaticclassAlgorithm{publicinterfaceEncryption{AlgorithmAES_ECB_PKCS5=newAlgorithm("AES","AES/ECB/PKCS5Padding",128);AlgorithmAES_CBC_PKCS5=newAlgorithm("AES","AES/CBC/PKCS5Padding",128);AlgorithmDES_ECB_PKCS5=newAlgorithm("DES","DES/ECB/PKCS5Padding",56);AlgorithmDES_CBC_PKCS5=newAlgorithm("DES","DES/CBC/PKCS5Padding",56);AlgorithmRSA_ECB_PKCS1=newAlgorithm("RSA","RSA/ECB/PKCS1Padding",1024);AlgorithmDSA=newAlgorithm("DSA",1024);}publicinterfaceSigning{AlgorithmSHA1WithDSA=newAlgorithm("SHA1withDSA",1024);AlgorithmSHA1WithRSA=newAlgorithm("SHA1WithRSA",2048);AlgorithmSHA256WithRSA=newAlgorithm("SHA256WithRSA",2048);}@GetterprivateString name;@GetterprivateString transformation;@Getterprivateint keySize;publicAlgorithm(String name,int keySize){this(name,null, keySize);}publicAlgorithm(String name,String transformation,int keySize){this.name = name;this.transformation = transformation;this.keySize = keySize;}}@Data@NoArgsConstructor@AllArgsConstructorpublicstaticclassAsymmetricKeyPair{privateString publicKey;privateString privateKey;}}

2、测试用例

AsymmetricKeyPair keyPair =CryptoUtils.generateAsymmetricKeyPair(Encryption.RSA_ECB_PKCS1);String privateKey = keyPair.getPrivateKey();String publicKey = keyPair.getPublicKey();System.out.println("生成的私钥为:\n"+ privateKey);System.out.println("生成的公钥为:\n"+ publicKey);String cipherText =CryptoUtils.encryptByRSA(publicKey,"test");String plainText =CryptoUtils.decryptByRSA(privateKey, cipherText);System.out.println("test加密后的密文为:\n"+ cipherText);System.out.println("解密后的明文为:"+ plainText);String signature =CryptoUtils.signBySHA256WithRSA(privateKey,"message");boolean isVerified =CryptoUtils.verifyBySHA256WithRSA(publicKey,"message", signature);System.out.println("message加签后的签名为:"+ signature);System.out.println("验签是否通过:"+ isVerified);

控制台输出如下:

生成的私钥为:
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL4TdBqlxJByJURSqNzthP18t2Q6tzmdwfoTJka0yy/DjEL1/mBPdcygwWBfVYLBvwuBUOyG4pbf/de0pmgc9b7+SwNqqpHtmLxaEqW3ebovm0R2UFom0OS/5X5pdWNKuKDTCpP2xC1JSfRqS+7WNgFEhCK7hRWBzIpifXvLzZNtAgMBAAECgYAcjOd/qS6hU8PtQ01CAhtbyAPz9i3XZa7hVUcGj9mFTyYeWLzg0o6rMepaA3fgsCF2JPJ21LvsVbDXWbc1JER1LYIWYZ79XnYZQgezmfqeSFx+CJkndRZ/qXGnf/1EUJFjEafbkXGRvnv05B4QHBQGn3gfIa2xsLw2r3Yf8M5/gQJBAOXgqeH5yyJ6iNIw5S8EAR7VAUMPteQ/JqQ6l+wYcesj/prqhwRX4x2m/wKh6qM2zZcFLMujYTyJsIQkzmOkFXkCQQDTrO1bnO84dbEVOUv73g0J1jg/3EIbt8uh7T4Iu82/9ycUyQ5D8oANh53rfPf5DXycXWXRlu2gwGvsyNRW1LSVAkEAnYs6go/Cgw+9g2hVOcKhzfKnmcFDpHkPT5CEnB8ou8GAdcVz4SsmkSTpMnGrsE4X2n+Gcs23D1lCK15aQHms6QJBAJ/8GmXcph25Lj9JT/msaZReuaLimYCTmK/pPLKjJy4I4hveng6S8V/IeX4rtMwi+mTAXp1bgny2EpwjagG6wEUCQH9ap3J9fh8UicEPD1LO/GUTTNXuPiwWOcNgetntrjPAJx5b0bf6hEJOyEHtIsuSuzAD8G41o2tpsefact3EwzY=

生成的公钥为:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+E3QapcSQciVEUqjc7YT9fLdkOrc5ncH6EyZGtMsvw4xC9f5gT3XMoMFgX1WCwb8LgVDshuKW3/3XtKZoHPW+/ksDaqqR7Zi8WhKlt3m6L5tEdlBaJtDkv+V+aXVjSrig0wqT9sQtSUn0akvu1jYBRIQiu4UVgcyKYn17y82TbQIDAQAB

test加密后的密文为:
EA19/wkHbdXTc8sfLFhmnp/MWW3PLx2LeYFHWFNdhvY38+Zoa4Ci8HJw8okkxzTfsSkgsiybMaz82rwF9lfcuEWzjbuGeVOvdkI0p/Cv+PDfikMYwOsxA7OqBJ/Hktn25l/ryEv7TxYlMFQ48jB0KPw/0Ivec9qfX2pgnyBl7WM=

解密后的明文为:test

message加签后的签名为:
AByFyRoc/321db16voe9NQaicwkscTOGjBZGefWzB7dMadWXBtUPIK3CUXADLiiesehgAAcDbl06qVz++x/6xeWPCK2ucCfn9dFybZfmAIsn+3TATuDQIFvz/m2cHQAuH9fkmiGgMPOVY/VcILwri3RETuQ+wz4YSmP89o1cFqk=

验签是否通过:true

六、前后端加解密、加验签交互测试

1、前端加密,后端解密

这里我们用前端生成的密钥对做测试。

(1) 前端代码

import*as CryptoUtils from'@/utils/cryptoUtils.js';const{privateKey, publicKey}= CryptoUtils.generateRsaKeyWithPKCS8();
console.log(`生成的私钥为:\n${privateKey}`);
console.log(`生成的公钥为:\n${publicKey}`);const cipherText = CryptoUtils.encryptByRSA(publicKey,"test");
console.log(`test加密后的内容为:\n${cipherText}`);

控制台输出:

生成的私钥为:
-----BEGINPRIVATEKEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMv1adNmKNw4rtr2
Dy92DZ3Nk1SCrGGetlq0sSgLY8bJsByAvP2ZOOiiWq2xDUVu8ZpQfM8v89tjegfr
sIUcN/ZVLc68Ric3BIto85oQc9jBz+aCk1rXeNMePkSVqNaC/n4kJ73Y41ZgKAe0
GvyqMyUNhk8VZd+QSNATSv+lGep3AgMBAAECgYBoKMvDry98z+HUZsb4iQSJK1xr
U1SvgftEtXSnq7Fn6sZquABMTry2aXt/qqTJadAu653hvW5/Av1mICKEyBV3aT4O
jQRGPMgp6WhXvQepUIuyi9qlfUVsJy/+J0zGKZeKsCFlwZ2e2j4Un7Bb//pgUfjJ
rbPtwC7U85oHjtJb6QJBAOdcm07ThSXFbicj2MuX9Gh7geMjncf6aqnrOwUFjO0d
5OxfYRAxrZD1GghygHyoJ4ZOHgJ0s6HVEYjg/u6DBdsCQQDhrb4IOVdSew2cW15f
t/5DAKUXRRQBfz0OxOs0Uv5k7zqI+YmysWVRGaZgj8oMZ7gYxN1eYNOKTwVjiuwb
uyaVAkEA0OGSMpPT1WsvbVT26bFyb1Z6yTihvif/XxPKgFknh/kCcsoWFwnS+1ne
vBusl181+BLVE0CL4aM9pogEghB3GwJAWJTVzmyTdfCO+xxyAqg5yRrrsiKPI7dJ
xA5PNA6PhBbSpwkrn1Q6LIcg4y4NZKkhfbdoHK9s2REDUHsrCgd/sQJAALEe+PCX
hcHWnwbm4kRFyJCO4dWkii7o28ohTRourlNsoEmiu1+7lt7PY1+C3D+6A4FFCY/H
pGM0i0lJue8rZA==-----ENDPRIVATEKEY-----

生成的公钥为:
-----BEGINPUBLICKEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL9WnTZijcOK7a9g8vdg2dzZNU
gqxhnrZatLEoC2PGybAcgLz9mTjoolqtsQ1FbvGaUHzPL/PbY3oH67CFHDf2VS3O
vEYnNwSLaPOaEHPYwc/mgpNa13jTHj5ElajWgv5+JCe92ONWYCgHtBr8qjMlDYZP
FWXfkEjQE0r/pRnqdwIDAQAB
-----ENDPUBLICKEY-----

test加密后的内容为:
KjcaDKLnBbvxRzuKMysqoz9MHRXCUNIH67+XDiFGTJbM8Rjw4Cei0CzjAPjk2jgAR37Kgh6lX2+Xg8AI9wEmzWr08bt8i2FFxVMrcfOCs5zI1y+2T7G9034f5b0gNx/Pc4dDz+1k453vo0AhCC0vrtb1OfbsRu5oOFns0TqoAMY=

解密后的内容为:test

(2) 后端代码

String privateKey ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMv1adNmKNw4rtr2Dy92DZ3Nk1SCrGGetlq0sSgLY8bJsByAvP2ZOOiiWq2xDUVu8ZpQfM8v89tjegfrsIUcN/ZVLc68Ric3BIto85oQc9jBz+aCk1rXeNMePkSVqNaC/n4kJ73Y41ZgKAe0GvyqMyUNhk8VZd+QSNATSv+lGep3AgMBAAECgYBoKMvDry98z+HUZsb4iQSJK1xrU1SvgftEtXSnq7Fn6sZquABMTry2aXt/qqTJadAu653hvW5/Av1mICKEyBV3aT4OjQRGPMgp6WhXvQepUIuyi9qlfUVsJy/+J0zGKZeKsCFlwZ2e2j4Un7Bb//pgUfjJrbPtwC7U85oHjtJb6QJBAOdcm07ThSXFbicj2MuX9Gh7geMjncf6aqnrOwUFjO0d5OxfYRAxrZD1GghygHyoJ4ZOHgJ0s6HVEYjg/u6DBdsCQQDhrb4IOVdSew2cW15ft/5DAKUXRRQBfz0OxOs0Uv5k7zqI+YmysWVRGaZgj8oMZ7gYxN1eYNOKTwVjiuwbuyaVAkEA0OGSMpPT1WsvbVT26bFyb1Z6yTihvif/XxPKgFknh/kCcsoWFwnS+1nevBusl181+BLVE0CL4aM9pogEghB3GwJAWJTVzmyTdfCO+xxyAqg5yRrrsiKPI7dJxA5PNA6PhBbSpwkrn1Q6LIcg4y4NZKkhfbdoHK9s2REDUHsrCgd/sQJAALEe+PCXhcHWnwbm4kRFyJCO4dWkii7o28ohTRourlNsoEmiu1+7lt7PY1+C3D+6A4FFCY/HpGM0i0lJue8rZA==";String cipherText ="KjcaDKLnBbvxRzuKMysqoz9MHRXCUNIH67+XDiFGTJbM8Rjw4Cei0CzjAPjk2jgAR37Kgh6lX2+Xg8AI9wEmzWr08bt8i2FFxVMrcfOCs5zI1y+2T7G9034f5b0gNx/Pc4dDz+1k453vo0AhCC0vrtb1OfbsRu5oOFns0TqoAMY=";// 解密后的明文应该为testString plainText =CryptoUtils.decryptByRSA(privateKey, cipherText);System.out.println("解密后的明文为:"+ plainText);

控制台输出如下:

解密后的明文为:test

备注:

  • 从前端复制过来的密钥需要去掉-----BEGIN PRIVATE KEY-----前缀。
  • 从前端复制过来的密钥带有换行,记得去掉中间的换行符。

2、后端加密,前端解密

这里我们用后端生成的密钥对做测试。

(1) 后端代码

AsymmetricKeyPair keyPair =CryptoUtils.generateAsymmetricKeyPair(Encryption.RSA_ECB_PKCS1);String privateKey = keyPair.getPrivateKey();String publicKey = keyPair.getPublicKey();System.out.println("生成的私钥为:\n"+ privateKey);System.out.println("生成的公钥为:\n"+ publicKey);String cipherText =CryptoUtils.encryptByRSA(publicKey,"test");System.out.println("test加密后的内容为:\n"+ cipherText);

控制台输出为:

生成的私钥为:
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJPh8WiDo3dhKHW9w86D4DX84pHAG03PIeOHCSezbyKeyKsuHA3qayGJ7JqQgWis557uawz95/EbBzzwmO0oy+l16fkiRXcRppU/UbW6PUBbIpJNqCjnKcw+DA5UXVDmIv0xXOP34jlnkY1DxnimqMAkgut8gncgdFxO0ap0us6lAgMBAAECgYBzlVpQ/OqMCRVNiYd8ZxicOc6Aaq0skKOFKWsfa6CGZ6KiIMTun3UiXqHeYOm0fcf/MYvcOKvLh/uNRuPQIV3WKAWJ6r+dXQ+LjzmrH4QDMcmkMn0OKxxbe56MASPWka7/08GLiE1FJLDo8DEkBQnlDHqnt4e7BoZSgYVhWv52AQJBAMcr0O7xiB/Ge9aQzqYQJvdQ4JI53pM0lEx5HPzQjbrMjC1flb572js1ajKckkuTX+nxzyTzC3JtfvGCcMqaaoECQQC+E9LoSfZZHpVFCx4ZIh2VgzrGYnelktb6MenILhdji2j9i6ZyAqyg8TjL+W9/kAKnaNAV2j6GF8/bOTX0UGolAkAcUWiFcKXwDqJw4WngRo+jvkYPxFaXC3TCYr3yXByqoIaVtO9vg+CFZpTQ2V4bjLqoYo8XK89G17ai0+8Bf28BAkA+BGvRHKjDJSZg86KrYqUybjHUHraZEFMSKQz1IozBDvB/oXv6QQMgM/RrIQSPI2aqRpl2N9IkoEpSZdVD1KT9AkBtoz4Eg3Nuy1XdCCrTqTMioY0hP74xCcgURpooxmL2xhNUYu6PJr+g4lkaiq8e/2Cr0ZQlps/pEDgaPdHDf3Et
生成的公钥为:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCT4fFog6N3YSh1vcPOg+A1/OKRwBtNzyHjhwkns28insirLhwN6mshieyakIForOee7msM/efxGwc88JjtKMvpden5IkV3EaaVP1G1uj1AWyKSTago5ynMPgwOVF1Q5iL9MVzj9+I5Z5GNQ8Z4pqjAJILrfIJ3IHRcTtGqdLrOpQIDAQAB
test加密后的内容为:
RgJxG+VSizKgfLnXjsqzTl9h0cUzm460EyHhdL3/qZLNbd6IVcU1Am+OOsbFd9W8GtNhJiCERybgjCucr4c3/EQLXtF8vNHVMFp9ycDW4T+8FMmFQn0f/+oJ7/i9uEoNd9W8nWJcSRHuTw1+rl4Mc7KnmwvdaTV2ZLOxBG6oAK8=

(2) 前端代码

const privateKey =`MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJPh8WiDo3dhKHW9w86D4DX84pHAG03PIeOHCSezbyKeyKsuHA3qayGJ7JqQgWis557uawz95/EbBzzwmO0oy+l16fkiRXcRppU/UbW6PUBbIpJNqCjnKcw+DA5UXVDmIv0xXOP34jlnkY1DxnimqMAkgut8gncgdFxO0ap0us6lAgMBAAECgYBzlVpQ/OqMCRVNiYd8ZxicOc6Aaq0skKOFKWsfa6CGZ6KiIMTun3UiXqHeYOm0fcf/MYvcOKvLh/uNRuPQIV3WKAWJ6r+dXQ+LjzmrH4QDMcmkMn0OKxxbe56MASPWka7/08GLiE1FJLDo8DEkBQnlDHqnt4e7BoZSgYVhWv52AQJBAMcr0O7xiB/Ge9aQzqYQJvdQ4JI53pM0lEx5HPzQjbrMjC1flb572js1ajKckkuTX+nxzyTzC3JtfvGCcMqaaoECQQC+E9LoSfZZHpVFCx4ZIh2VgzrGYnelktb6MenILhdji2j9i6ZyAqyg8TjL+W9/kAKnaNAV2j6GF8/bOTX0UGolAkAcUWiFcKXwDqJw4WngRo+jvkYPxFaXC3TCYr3yXByqoIaVtO9vg+CFZpTQ2V4bjLqoYo8XK89G17ai0+8Bf28BAkA+BGvRHKjDJSZg86KrYqUybjHUHraZEFMSKQz1IozBDvB/oXv6QQMgM/RrIQSPI2aqRpl2N9IkoEpSZdVD1KT9AkBtoz4Eg3Nuy1XdCCrTqTMioY0hP74xCcgURpooxmL2xhNUYu6PJr+g4lkaiq8e/2Cr0ZQlps/pEDgaPdHDf3Et`;const cipherText =`RgJxG+VSizKgfLnXjsqzTl9h0cUzm460EyHhdL3/qZLNbd6IVcU1Am+OOsbFd9W8GtNhJiCERybgjCucr4c3/EQLXtF8vNHVMFp9ycDW4T+8FMmFQn0f/+oJ7/i9uEoNd9W8nWJcSRHuTw1+rl4Mc7KnmwvdaTV2ZLOxBG6oAK8=`;const plainText = CryptoUtils.decryptByRSA(privateKey, cipherText);
console.log(`解密后的内容为:${plainText}`);

控制台输出:

解密后的内容为:test

3、前端加签,后端验签

这里我们用前端生成的密钥对做测试。

(1) 前端代码

const{privateKey, publicKey}= CryptoUtils.generateRsaKeyWithPKCS8();
console.log(`生成的私钥为:\n${privateKey}`);
console.log(`生成的公钥为:\n${publicKey}`);const signature = CryptoUtils.signBySHA256WithRSA(privateKey,"test");
console.log(`生成的签名:\n${signature}`);

控制台输出如下:

生成的私钥为:
-----BEGINPRIVATEKEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALxzJ+U/N/lE+AZO
zMbzx+5WrWDu31oKlH+jth54APGHY+Cmqvi0dUeuSbv238tkem95GTy1kQRz9CMB
WvvVdNYC78E8maBaMKb+GZKVIScZ6eo8gkXxEoB7a3/y6a8L/SpQGgaI78JsnVGJ
ijf+GaGtfbl+dIQMxIc6gbNZOM/PAgMBAAECgYEAiAKE1Mwf1eSVLdhJq33e2oHs
eH1u7kmci9LYan0qESgqScWAuCdmTenYhbTUKLPIOhQoxsw0cgZOOcWMqR2SSHW/
CK0Ql/5jP94wyX5Gw62jFXpLTVKQ1piiNjoujTKOsnkdtfh/JnjdeWh7GEcHhGGw
yin0F1aHZgex4MkG0EECQQDsqJJxESC5QjZl5f6EDIbkSznmeV0IPfgIs8uN1QID
jFbS97QhClSrsev4LXxuGkltOpWbJUkG+nmjZhDPnV1nAkEAy9nzQndYxiv/XLpd
+Id2pB+SBRs/panFFEIoEEb4UoY7QPLfQ6ZOQQ9+vC5r1tWQtIhwiEjhYaGhnBZ1
TASRWQJBAOADNRMnxlT2Uu2jhobSIMFqX7VEvgY2Ollqb0yjC1P2fJ0X8X6w+7LG
KPnzfGvwH/7vzHteEME1SPydeV48tBMCQQCtCsZElar2DkMnI8zBO7yqdWIuk4Lj
zclN+RqpNpV0+B00dPaxJmsnL1AVzhIcvA2qMmfUSImJpvrY1PedIAOBAkAvjVU0
3USMjvv5iudWyqqRy8Q9s2qeWYEiv+bFeLExiqGj9kmOkIfPcm96ElZr1F7PlaQb
wj2A+D2oaQGcQqUm
-----ENDPRIVATEKEY-----

生成的公钥为:
-----BEGINPUBLICKEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8cyflPzf5RPgGTszG88fuVq1g
7t9aCpR/o7YeeADxh2Pgpqr4tHVHrkm79t/LZHpveRk8tZEEc/QjAVr71XTWAu/B
PJmgWjCm/hmSlSEnGenqPIJF8RKAe2t/8umvC/0qUBoGiO/CbJ1RiYo3/hmhrX25
fnSEDMSHOoGzWTjPzwIDAQAB
-----ENDPUBLICKEY-----

生成的签名:
Q9Mtq3gxi2YJ07FQtbry5zxGljomzKQNewhj10Ba10b3roAAdQUzqd+QyP7rqARdPQgt0ClDgvtaL2TNYLc4URh7E3Kgx8T6pSFlPnU/b3cfCoVRPrr/gJBrsCkbNMITNXpVQpwIYe3P1z+OrCUHuaQR82yCVUz3y43oOiE6qIY=

(2) 后端代码

String publicKey ="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8cyflPzf5RPgGTszG88fuVq1g7t9aCpR/o7YeeADxh2Pgpqr4tHVHrkm79t/LZHpveRk8tZEEc/QjAVr71XTWAu/BPJmgWjCm/hmSlSEnGenqPIJF8RKAe2t/8umvC/0qUBoGiO/CbJ1RiYo3/hmhrX25fnSEDMSHOoGzWTjPzwIDAQAB";String signature ="Q9Mtq3gxi2YJ07FQtbry5zxGljomzKQNewhj10Ba10b3roAAdQUzqd+QyP7rqARdPQgt0ClDgvtaL2TNYLc4URh7E3Kgx8T6pSFlPnU/b3cfCoVRPrr/gJBrsCkbNMITNXpVQpwIYe3P1z+OrCUHuaQR82yCVUz3y43oOiE6qIY=";boolean isVerified =CryptoUtils.verifyBySHA256WithRSA(publicKey,"test", signature);System.out.println("是否验签通过:"+ isVerified);

控制台输出:

是否验签通过:true

4、后端加签,前端验签

这里我们用后端生成的密钥对做测试。

(1) 后端代码

AsymmetricKeyPair keyPair =CryptoUtils.generateAsymmetricKeyPair(Encryption.RSA_ECB_PKCS1);String privateKey = keyPair.getPrivateKey();String publicKey = keyPair.getPublicKey();System.out.println("生成的私钥为:\n"+ privateKey);System.out.println("生成的公钥为:\n"+ publicKey);String signature =CryptoUtils.signBySHA256WithRSA(privateKey,"test");System.out.println("生成的签名为:\n"+ signature);

控制台输出如下:

生成的私钥为:
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKx1iT0ObyRKC06wf+WN1v9LTQwd68X1b8U5+ZAh9Qf7m77HiQtLg1y91v0b70Dr/HRP7juGLFTnK5+NJMcjGNqDfDFqCQtA3eam2UABbwHS76qRFQbSg5QKApvDcfOZtqWmbwwSDMkI5GnYKbSO3EZZCYBBXzplabKQCKcmGKOjAgMBAAECgYAovOb7RkKYxuje4LCFkDjeO3Jqz1KXg3+wjh5Wnr7b8OJ8cXP8+AyCxtFXHtcoddY/v3XeF7a3I5hZayTp6W+AI1OTYhWs9Eqas8B7bNV2rJPFnK9nTiF727bgptJfGuUG8mYxRzIQleHoWqpV9i/ttcEUPM4GGcIfpnwb16NBAQJBANPBLuTCyeDbSW79MmsiTNUeCnljM/UQYUfIpygviNX1iVbsh1lI/l85bN47niIt66j4c5MPOKJOv2Hf3yYqvIECQQDQfmzfLo7deqsizkJAFKggH99ab24iC+VEDtsHlsl212NC36xenoWwuIcP8fJd1UyWY5lwzzCdBKsrt0UeSd4jAkBwrv3AWHPLh4YFXRHGdyNBydGzFPpiL8xEwd9KADml+hqSuh2wgqpyjAGGJV2aPKuKaGRAXro5jQRFFjgOfHGBAkEAsq22ViqLa0nmgmSrqElLsIRAITvf8bOqHwJwOXfDXmLGgZg5G7nVLxdlQIgEQuA6y6O960zVB6vpmgRtasC5awJBAJkwLiKikvPxC8vwhZvkjr+UrbDorUKcuCyDVYxXsSNW8SNs+AV54wEI1Mem5LOhNPKbum6bwwfTf74gC/l4jtw=
生成的公钥为:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsdYk9Dm8kSgtOsH/ljdb/S00MHevF9W/FOfmQIfUH+5u+x4kLS4Ncvdb9G+9A6/x0T+47hixU5yufjSTHIxjag3wxagkLQN3mptlAAW8B0u+qkRUG0oOUCgKbw3Hzmbalpm8MEgzJCORp2Cm0jtxGWQmAQV86ZWmykAinJhijowIDAQAB
生成的签名为:
JQ2FWaAbHWIkl4uSIxyMNbARFzSNKc7mOtXidm7hCRN85D8DVgZll02DYcWRSnn/ejOOxOrEPF8AcYHWx1repHh/jHcwv2focjF3Yne7NkQ4yGvgILDD2s1BIEfU0EH3tFLMIebyU8V54eMMtjDLQ65LZB6PH+5X8s3F6yAPI70=

(2) 前端代码

const publicKey =`
      -----BEGIN PUBLIC KEY-----
      MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsdYk9Dm8kSgtOsH/ljdb/S00MHevF9W/FOfmQIfUH+5u+x4kLS4Ncvdb9G+9A6/x0T+47hixU5yufjSTHIxjag3wxagkLQN3mptlAAW8B0u+qkRUG0oOUCgKbw3Hzmbalpm8MEgzJCORp2Cm0jtxGWQmAQV86ZWmykAinJhijowIDAQAB
      -----END PUBLIC KEY-----`;const signature =`JQ2FWaAbHWIkl4uSIxyMNbARFzSNKc7mOtXidm7hCRN85D8DVgZll02DYcWRSnn/ejOOxOrEPF8AcYHWx1repHh/jHcwv2focjF3Yne7NkQ4yGvgILDD2s1BIEfU0EH3tFLMIebyU8V54eMMtjDLQ65LZB6PH+5X8s3F6yAPI70=`;const message =`test`;const isVerified = CryptoUtils.verifyBySHA256WithRSA(publicKey, signature, message);
console.log(`是否验签通过:${isVerified}`);

控制台输出如下:

是否验签通过:true

备注:因为我们在前端解析密钥时读取的是标准pem格式密钥,所以从后端复制过来的公钥一定要加上

-----BEGIN PUBLIC KEY-----

前缀和

-----END PUBLIC KEY-----

后缀,否则会报错。

在这里插入图片描述


本文转载自: https://blog.csdn.net/lingbomanbu_lyl/article/details/128956863
版权归原作者 凌波漫步& 所有, 如有侵权,请联系我们删除。

“前后端RSA互相加解密、加签验签、密钥对生成(Java)”的评论:

还没有评论