国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

springboot + vue 前后端加密傳輸 RSA互相加解密、加簽驗簽、密鑰對生成

這篇具有很好參考價值的文章主要介紹了springboot + vue 前后端加密傳輸 RSA互相加解密、加簽驗簽、密鑰對生成。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

參考

二、關(guān)于PKCS#1和PKCS#8格式密鑰

由于Java非對稱加解密、加驗簽都是采用PKCS#8格式的密鑰,PKCS#1格式的密鑰跑不通,這里先簡單介紹一下兩者的區(qū)別。

1、簡介

PKCS#1和PKCS#8是兩個不同的數(shù)字證書標(biāo)準(zhǔn)。

PKCS#1是一個公鑰加密標(biāo)準(zhǔn),它定義了使用RSA算法進行加密和簽名的格式。主要用于對數(shù)字簽名、加密以及數(shù)字簽名驗證等應(yīng)用。

PKCS#8則是一個私鑰保護標(biāo)準(zhǔn),它定義了私鑰的存儲格式。它主要用于在文件中對私鑰進行保護,以防止意外泄露或不當(dāng)使用。

總的來說,PKCS#1是針對公鑰的標(biāo)準(zhǔn),而PKCS#8是針對私鑰的標(biāo)準(zhǔn)。

2、區(qū)別

兩者的密鑰格式不一樣,下面以標(biāo)準(zhǔn).pem格式為例,看下PKCS#1格式和PKCS#8格式密鑰的區(qū)別:

  • 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-----

四、前端RSA加解密、加驗簽示例

1、相關(guān)依賴

// 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 {*} 密文
 */
export function encryptByRSA(publicKey, plainText) {
  const encryptor = new JSEncrypt();
  encryptor.setPublicKey(publicKey);
  return encryptor.encrypt(plainText);
}

/**
 * RSA解密
 * @param privateKey 私鑰
 * @param cipherText 密文
 * @returns {*} 明文
 */
export function decryptByRSA(privateKey, cipherText) {
  const decrypter = new JSEncrypt();
  decrypter.setPrivateKey(privateKey);
  return decrypter.decrypt(cipherText);
}

/**
 * 生成RSA密鑰對,填充模式為PKCS8。
 * 更多模式參考:<a >https://kjur.github.io/jsrsasign/api/symbols/KEYUTIL.html</a>
 * @returns {{privateKey: (string|string|*), publicKey: (string|string|*)}}
 */
export function generateRsaKeyWithPKCS8() {
  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 加簽內(nèi)容
 * @returns {string} Base64編碼簽名內(nèi)容
 */
export function signBySHA256WithRSA(privateKey, msg) {
  const key = JsRsaSign.KEYUTIL.getKey(privateKey);
  const signature = new JsRsaSign.KJUR.crypto.Signature({
    alg: "SHA256withRSA",
  });
  signature.init(key);
  signature.updateString(msg);
  // 簽名后的為16進制字符串,這里轉(zhuǎn)換為16進制字符串
  return JsRsaSign.hextob64(signature.sign());
}

/**
 * SHA256和RSA驗簽
 * @param publicKey 公鑰:必須為標(biāo)準(zhǔn)pem格式。如果是PKCS1格式,必須包含-----BEGIN RSA PRIVATE KEY-----,如果是PKCS8格式,必須包含-----BEGIN PRIVATE KEY-----
 * @param base64SignStr Base64編碼簽名字符串
 * @param msg 原內(nèi)容
 * @returns {boolean} 是否驗簽通過
 */
export function verifyBySHA256WithRSA(publicKey, base64SignStr, msg) {
  const key = JsRsaSign.KEYUTIL.getKey(publicKey);
  const signature = new JsRsaSign.KJUR.crypto.Signature({
    alg: "SHA256withRSA",
  });
  signature.init(key);
  signature.updateString(msg);
  // 需要將Base64進制簽名字符串轉(zhuǎn)換成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èi)容為:\n${cipherText}`);

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

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

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

控制臺輸出結(jié)果為:

生成的私鑰為:
-----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加密后的內(nèi)容為:
KjcaDKLnBbvxRzuKMysqoz9MHRXCUNIH67+XDiFGTJbM8Rjw4Cei0CzjAPjk2jgAR37Kgh6lX2+Xg8AI9wEmzWr08bt8i2FFxVMrcfOCs5zI1y+2T7G9034f5b0gNx/Pc4dDz+1k453vo0AhCC0vrtb1OfbsRu5oOFns0TqoAMY=

解密后的內(nèi)容為:test

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

是否驗簽通過:true
備注:為什么在前端生成PKCS#8格式密鑰呢?

因為在Java中非對稱加解密、加驗簽都是用的PKCS#8,PKCS#1格式密鑰需要轉(zhuǎn)換成PKCS#8。

五、Java后端RSA加解密、加驗簽

1、CryptoUtils工具類封裝

import com.universe.crypto.CryptoUtils.Algorithm.Encryption;
import com.universe.crypto.CryptoUtils.Algorithm.Signing;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 支持AES、DES、RSA加密、數(shù)字簽名以及生成對稱密鑰和非對稱密鑰對
 */
public class CryptoUtils {

	private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
	private static final Encoder BASE64_ENCODER = Base64.getEncoder();
	private static final Decoder BASE64_DECODER = Base64.getDecoder();

	private static final Map<Algorithm, KeyFactory> KEY_FACTORY_CACHE = new ConcurrentHashMap<>();
	private static final Map<Algorithm, Cipher> CIPHER_CACHE = new HashMap<>();

	/**
	 * 生成對稱密鑰,目前支持的算法有AES、DES
	 * @param algorithm
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	public static String generateSymmetricKey(Algorithm algorithm) throws NoSuchAlgorithmException {
		KeyGenerator generator = KeyGenerator.getInstance(algorithm.getName());
		generator.init(algorithm.getKeySize());
		SecretKey secretKey = generator.generateKey();
		return BASE64_ENCODER.encodeToString(secretKey.getEncoded());
	}

	/**
	 * 生成非對稱密鑰對,目前支持的算法有RSA、DSA。備注:默認(rèn)生成的密鑰格式為PKCS8
	 * @param algorithm
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	public static AsymmetricKeyPair generateAsymmetricKeyPair(Algorithm algorithm) throws NoSuchAlgorithmException {
		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());
		return new AsymmetricKeyPair(publicKey, privateKey);
	}

	public static String encryptByRSA(String publicKeyText, String plainText) throws Exception {
		return encryptAsymmetrically(publicKeyText, plainText, Encryption.RSA_ECB_PKCS1);
	}

	public static String decryptByRSA(String privateKeyText, String ciphertext) throws Exception {
		return decryptAsymmetrically(privateKeyText, ciphertext, Encryption.RSA_ECB_PKCS1);
	}

	/**
	 * SHA1簽名算法和DSA加密算法結(jié)合使用生成數(shù)字簽名
	 * @param privateKeyText
	 * @param msg
	 * @return 數(shù)字簽名
	 * @throws Exception
	 */
	public static String signBySHA1WithDSA(String privateKeyText, String msg) throws Exception {
		return doSign(privateKeyText, msg, Encryption.DSA, Signing.SHA1WithDSA);
	}

	/**
	 * SHA1簽名算法和RSA加密算法結(jié)合使用生成數(shù)字簽名
	 * @param privateKeyText 私鑰
	 * @param msg 待加簽內(nèi)容
	 * @return 數(shù)字簽名
	 * @throws Exception
	 */
	public static String signBySHA1WithRSA(String privateKeyText, String msg) throws Exception {
		return doSign(privateKeyText, msg, Encryption.RSA_ECB_PKCS1, Signing.SHA1WithRSA);
	}

	/**
	 * SHA256簽名算法和RSA加密算法結(jié)合使用生成數(shù)字簽名
	 * @param privateKeyText 私鑰
	 * @param msg 待加簽內(nèi)容
	 * @return 數(shù)字簽名
	 * @throws Exception
	 */
	public static String signBySHA256WithRSA(String privateKeyText, String msg) throws Exception {
		return doSign(privateKeyText, msg, Encryption.RSA_ECB_PKCS1, Signing.SHA256WithRSA);
	}

	/**
	 * SHA1簽名算法和DSA加密算法檢驗數(shù)字簽名
	 * @param publicKeyText 公鑰
	 * @param msg 待驗簽內(nèi)容
	 * @param signatureText 數(shù)字
	 * @return 檢驗是否成功
	 * @throws Exception
	 */
	public static boolean verifyBySHA1WithDSA(String publicKeyText, String msg, String signatureText) throws Exception {
		return doVerify(publicKeyText, msg, signatureText, Encryption.DSA, Signing.SHA1WithDSA);
	}

	/**
	 * SHA1簽名算法和RSA加密算法檢驗數(shù)字簽名
	 * @param publicKeyText 公鑰
	 * @param msg 待驗簽內(nèi)容
	 * @param signatureText 簽名
	 * @return 校驗是否成功
	 * @throws Exception
	 */
	public static boolean verifyBySHA1WithRSA(String publicKeyText, String msg, String signatureText) throws Exception {
		return doVerify(publicKeyText, msg, signatureText, Encryption.RSA_ECB_PKCS1, Signing.SHA1WithRSA);
	}

	/**
	 * SHA256簽名算法和RSA加密算法檢驗數(shù)字簽名
	 * @param publicKeyText 公鑰
	 * @param msg 待驗簽內(nèi)容
	 * @param signatureText 簽名
	 * @return 校驗是否成功
	 * @throws Exception
	 */
	public static boolean verifyBySHA256WithRSA(String publicKeyText, String msg, String signatureText) throws Exception {
		return doVerify(publicKeyText, msg, signatureText, Encryption.RSA_ECB_PKCS1, Signing.SHA256WithRSA);
	}

	/**
	 * 對稱加密
	 * @param secretKey 密鑰
	 * @param iv 加密向量,只有CBC模式才支持,如果是CBC則必傳
	 * @param plainText 明文
	 * @param algorithm 對稱加密算法,如AES、DES
	 * @return
	 * @throws Exception
	 */
	public static String encryptSymmetrically(String secretKey, String iv, String plainText, Algorithm algorithm) throws Exception {
		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);

		return BASE64_ENCODER.encodeToString(ciphertextInBytes);
	}

	/**
	 * 對稱解密
	 * @param secretKey 密鑰
	 * @param iv 加密向量,只有CBC模式才支持,如果是CBC則必傳
	 * @param ciphertext 密文
	 * @param algorithm 對稱加密算法,如AES、DES
	 * @return
	 * @throws Exception
	 */
	public static String decryptSymmetrically(String secretKey, String iv, String ciphertext, Algorithm algorithm) throws Exception {
		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);
		return new String(plainTextInBytes, DEFAULT_CHARSET);
	}

	/**
	 * 非對稱加密
	 * @param publicKeyText 公鑰
	 * @param plainText 明文
	 * @param algorithm 非對稱加密算法
	 * @return
	 * @throws Exception
	 */
	public static String encryptAsymmetrically(String publicKeyText, String plainText, Algorithm algorithm) throws Exception {
		PublicKey publicKey = regeneratePublicKey(publicKeyText, algorithm);
		byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET);
		byte[] ciphertextInBytes = transform(algorithm, Cipher.ENCRYPT_MODE, publicKey, plainTextInBytes);
		return BASE64_ENCODER.encodeToString(ciphertextInBytes);
	}

	/**
	 * 非對稱解密
	 * @param privateKeyText 私鑰
	 * @param ciphertext 密文
	 * @param algorithm 非對稱加密算法
	 * @return
	 * @throws Exception
	 */
	public static String decryptAsymmetrically(String privateKeyText, String ciphertext, Algorithm algorithm) throws Exception {
		PrivateKey privateKey = regeneratePrivateKey(privateKeyText, algorithm);
		byte[] ciphertextInBytes = BASE64_DECODER.decode(ciphertext);
		byte[] plainTextInBytes = transform(algorithm, Cipher.DECRYPT_MODE, privateKey, ciphertextInBytes);
		return new String(plainTextInBytes, DEFAULT_CHARSET);
	}

	/**
	 * 生成數(shù)字簽名
	 * @param privateKeyText 私鑰
	 * @param msg 傳輸?shù)臄?shù)據(jù)
	 * @param encryptionAlgorithm 加密算法,見Algorithm中的加密算法
	 * @param signatureAlgorithm 簽名算法,見Algorithm中的簽名算法
	 * @return 數(shù)字簽名
	 * @throws Exception
	 */
	public static String doSign(String privateKeyText, String msg, Algorithm encryptionAlgorithm, Algorithm signatureAlgorithm)
		throws Exception {
		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();
		return BASE64_ENCODER.encodeToString(signatureInBytes);
	}

	/**
	 * 數(shù)字簽名驗證
	 * @param publicKeyText 公鑰
	 * @param msg 傳輸?shù)臄?shù)據(jù)
	 * @param signatureText 數(shù)字簽名
	 * @param encryptionAlgorithm 加密算法,見Algorithm中的加密算法
	 * @param signatureAlgorithm 簽名算法,見Algorithm中的簽名算法
	 * @return 校驗是否成功
	 * @throws Exception
	 */
	public static boolean doVerify(String publicKeyText, String msg, String signatureText, Algorithm encryptionAlgorithm,
		Algorithm signatureAlgorithm) throws Exception {
		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
	 */
	private static SecretKey decodeSymmetricKey(String secretKey, Algorithm algorithm) {
		byte[] key = BASE64_DECODER.decode(secretKey);
		return new SecretKeySpec(key, algorithm.getName());
	}

	private static IvParameterSpec decodeIv(String iv) {
		byte[] ivInBytes = BASE64_DECODER.decode(iv);
		return new IvParameterSpec(ivInBytes);
	}

	private static PublicKey regeneratePublicKey(String publicKeyText, Algorithm algorithm)
		throws NoSuchAlgorithmException, InvalidKeySpecException {
		byte[] keyInBytes = BASE64_DECODER.decode(publicKeyText);
		KeyFactory keyFactory = getKeyFactory(algorithm);
		// 公鑰必須使用RSAPublicKeySpec或者X509EncodedKeySpec
		KeySpec publicKeySpec = new X509EncodedKeySpec(keyInBytes);
		PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
		return publicKey;
	}

	private static PrivateKey regeneratePrivateKey(String key, Algorithm algorithm) throws Exception {
		byte[] keyInBytes = BASE64_DECODER.decode(key);
		KeyFactory keyFactory = getKeyFactory(algorithm);
		// 私鑰必須使用RSAPrivateCrtKeySpec或者PKCS8EncodedKeySpec
		KeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyInBytes);
		PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
		return privateKey;
	}

	private static KeyFactory getKeyFactory(Algorithm algorithm) throws NoSuchAlgorithmException {
		KeyFactory keyFactory = KEY_FACTORY_CACHE.get(algorithm);
		if (keyFactory == null) {
			keyFactory = KeyFactory.getInstance(algorithm.getName());
			KEY_FACTORY_CACHE.put(algorithm, keyFactory);
		}

		return keyFactory;
	}

	private static byte[] transform(Algorithm algorithm, int mode, Key key, byte[] msg) throws Exception {
		return transform(algorithm, mode, key, null, msg);
	}

	private static byte[] transform(Algorithm algorithm, int mode, Key key, IvParameterSpec iv, byte[] msg) throws Exception {
		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);
		}
	}

	private static Cipher determineWhichCipherToUse(Algorithm algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException {
		Cipher cipher;
		String transformation = algorithm.getTransformation();
		// 官方推薦的transformation使用algorithm/mode/padding組合,SunJCE使用ECB作為默認(rèn)模式,使用PKCS5Padding作為默認(rèn)填充
		if (StringUtils.isNotEmpty(transformation)) {
			cipher = Cipher.getInstance(transformation);
		} else {
			cipher = Cipher.getInstance(algorithm.getName());
		}

		return cipher;
	}

	/**
	 * 算法分為加密算法和簽名算法,更多算法實現(xiàn)見:<br/>
	 * <a >jdk8中的標(biāo)準(zhǔn)算法</a>
	 */
	public static class Algorithm {

		public interface Encryption {
			Algorithm AES_ECB_PKCS5 = new Algorithm("AES", "AES/ECB/PKCS5Padding", 128);
			Algorithm AES_CBC_PKCS5 = new Algorithm("AES", "AES/CBC/PKCS5Padding", 128);
			Algorithm DES_ECB_PKCS5 = new Algorithm("DES", "DES/ECB/PKCS5Padding", 56);
			Algorithm DES_CBC_PKCS5 = new Algorithm("DES", "DES/CBC/PKCS5Padding", 56);
			Algorithm RSA_ECB_PKCS1 = new Algorithm("RSA", "RSA/ECB/PKCS1Padding", 1024);
			Algorithm DSA = new Algorithm("DSA", 1024);
		}

		public interface Signing {
			Algorithm SHA1WithDSA = new Algorithm("SHA1withDSA", 1024);
			Algorithm SHA1WithRSA = new Algorithm("SHA1WithRSA", 2048);
			Algorithm SHA256WithRSA = new Algorithm("SHA256WithRSA", 2048);
		}

		@Getter
		private String name;
		@Getter
		private String transformation;
		@Getter
		private int keySize;

		public Algorithm(String name, int keySize) {
			this(name, null, keySize);
		}

		public Algorithm(String name, String transformation, int keySize) {
			this.name = name;
			this.transformation = transformation;
			this.keySize = keySize;
		}

	}

	@Data
	@NoArgsConstructor
	@AllArgsConstructor
	public static class AsymmetricKeyPair {

		private String publicKey;
		private String 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èi)容為:\n${cipherText}`);
————————————————

控制臺輸出:

生成的私鑰為:
-----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加密后的內(nèi)容為:
KjcaDKLnBbvxRzuKMysqoz9MHRXCUNIH67+XDiFGTJbM8Rjw4Cei0CzjAPjk2jgAR37Kgh6lX2+Xg8AI9wEmzWr08bt8i2FFxVMrcfOCs5zI1y+2T7G9034f5b0gNx/Pc4dDz+1k453vo0AhCC0vrtb1OfbsRu5oOFns0TqoAMY=

解密后的內(nèi)容為: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=";

// 解密后的明文應(yīng)該為test
String plainText = CryptoUtils.decryptByRSA(privateKey, cipherText);
System.out.println("解密后的明文為:" + plainText);

控制臺輸出如下:

解密后的明文為:test
備注:
  • 從前端復(fù)制過來的密鑰需要去掉-----BEGIN PRIVATE KEY-----前綴。
  • 從前端復(fù)制過來的密鑰帶有換行,記得去掉中間的換行符。

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èi)容為:\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加密后的內(nèi)容為:
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(`解密后的內(nèi)容為:${plainText}`);

控制臺輸出:

解密后的內(nèi)容為:test

3、前端加簽,后端驗簽

這里我們用前端生成的密鑰對做測試。

(1) 前端代碼
console.log(`生成的私鑰為:\n${privateKey}`);
console.log(`生成的公鑰為:\n${publicKey}`);

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

控制臺輸出如下:

生成的私鑰為:
-----BEGIN PRIVATE KEY-----
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
-----END PRIVATE KEY-----

生成的公鑰為:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8cyflPzf5RPgGTszG88fuVq1g
7t9aCpR/o7YeeADxh2Pgpqr4tHVHrkm79t/LZHpveRk8tZEEc/QjAVr71XTWAu/B
PJmgWjCm/hmSlSEnGenqPIJF8RKAe2t/8umvC/0qUBoGiO/CbJ1RiYo3/hmhrX25
fnSEDMSHOoGzWTjPzwIDAQAB
-----END PUBLIC KEY-----

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


(2) 后端代碼
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
————————————————
備注:因為我們在前端解析密鑰時讀取的是標(biāo)準(zhǔn)pem格式密鑰,所以從后端復(fù)制過來的公鑰一定要加上

-----BEGIN PUBLIC KEY-----前綴和-----END PUBLIC KEY-----后綴,否則會報錯。文章來源地址http://www.zghlxwxcb.cn/news/detail-859683.html

到了這里,關(guān)于springboot + vue 前后端加密傳輸 RSA互相加解密、加簽驗簽、密鑰對生成的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • Springboot接口返回參數(shù)以及入?yún)SA加密解密

    Springboot接口返回參數(shù)以及入?yún)SA加密解密

    網(wǎng)上有好多通過aop切面以及自定義的RSA工具類進行加密解密的方法,期中的過程繁瑣也不好用,博主研究了一天從網(wǎng)上到了超好用的基于Springboot框架實現(xiàn)的接口RSA加密解密方式,通過 rsa-encrypt-body-spring-boot 實現(xiàn)了對Spring Boot接口返回值、參數(shù)值通過注解的方式自動加解密。

    2024年02月13日
    瀏覽(25)
  • vue前端RSA加密java后端解密的方法

    最近安全測試的總是測出安全漏洞來,讓開發(fā)改。 想了想干脆把請求參數(shù)都加密下,前端加密后端解密,這樣總差不多了。 看了下AES加密,是對稱的,前后端用這個不太行。 于是想到用RSA加密,是非對稱的,可以前端加密后端解密。 1.前端是vue項目,使用時,需要先執(zhí)行:

    2023年04月21日
    瀏覽(23)
  • Vue+Springboot前后端完整使用國密算法SM2雙公私鑰對數(shù)據(jù)加密傳輸交互完整解決方案

    Vue+Springboot 前后端完整使?國密算法SM2雙公私鑰對數(shù)據(jù)加密傳輸交互完整解決?案項?,特別是企事業(yè)單位的項?,第三方測試公司做安全測試時,常常要求使用國密算法,因涉及服務(wù)端和客戶端的交互,傳遞關(guān)鍵數(shù)據(jù)時要求使用SM2非對稱加密。 引入相關(guān)依賴 這里我使用的

    2024年01月23日
    瀏覽(28)
  • 終于把前后端sm加解密以及加簽驗證調(diào)通了。

    1.簡單說明: 前端使用sm-crypto庫 后端加密庫使用bc庫,架構(gòu)上使用aop,注解等實現(xiàn) 2.具體實現(xiàn)-前端 加密流程:生成一個對稱密鑰,對每個字段使用sm4對稱加密,然后進行base64編碼。對稱密鑰使用sm2非對稱加密 解密流程:對后端響應(yīng)的數(shù)據(jù)對象中的加密字段進行base64解碼,

    2024年02月14日
    瀏覽(20)
  • RSA雙向加解密(公鑰加密-私鑰解密;私鑰加密-公鑰解密)

    ??????? 非對稱加密算法中,提供一個公鑰一個私鑰。一般情況下,采用公鑰加密、私鑰解密的方式。 ??????? 假設(shè)有這樣一個場景:服務(wù)A與服務(wù)B需要通信,通信內(nèi)容為了安全需要進行加密傳輸,并且服務(wù)A與服務(wù)B不能互相持有對方的鑰匙。 ??????? 我首先想到的是

    2024年02月11日
    瀏覽(102)
  • 【RSA】RSA加密、解密、簽名與驗證

    【RSA】RSA加密、解密、簽名與驗證

    最近要做 iOS SDK 的聯(lián)網(wǎng)授權(quán),涉及到數(shù)據(jù)安全驗證,因此想到使用 RSA 進行簽名和驗證。 授權(quán)主要流程如下: 1、客戶方前往我方開放平臺注冊授權(quán),得到 AppId 和 AppSecret 。 2、客戶方集成 SDK ,調(diào)用 Register 接口傳入 AppId 和 AppSecret 。 3、 SDK 將 AppId 和客戶端平臺相關(guān)信息提交

    2023年04月08日
    瀏覽(27)
  • 適用于前后端公用的SM2國密加密傳輸, JAVA + VUE

    適用于前后端公用的SM2國密加密傳輸, JAVA + VUE

    由于等保和多個系統(tǒng)間的數(shù)據(jù)傳輸加密, 寫了一個共有的前端與后端, 后端與后端,的通用算法SM2簡單加密,? 不需要驗簽, 幾行代碼搞定.? 引包, 測試好幾遍, 這個包適合jdk1.8使用 引包, 沒有意外就應(yīng)該直接能用下面代碼了 ? ? publicKey:04aa909915f87880507e3de515220cc8f82b1c5693f56a0475b3

    2024年02月16日
    瀏覽(19)
  • 【SpringBoot系列】vue+SpringBoot實現(xiàn)前后端數(shù)據(jù)加解密

    保護隱私: 數(shù)據(jù)加密可以確保敏感信息在傳輸和存儲過程中不被未經(jīng)授權(quán)的人訪問。對于個人用戶來說,加密可以保護個人隱私,防止個人信息被竊取或濫用。對于企業(yè)來說,加密可以保護客戶數(shù)據(jù)、商業(yè)機密和其他敏感信息,避免泄露和損害企業(yè)聲譽。 防止數(shù)據(jù)篡改: 加

    2024年02月11日
    瀏覽(24)
  • RSA加密/解密

    1.1、RSA算法介紹 RSA加密算法是一種可逆的非對稱加密算法,即RSA加密時候用的密鑰(公鑰)和RSA解密時用的密鑰(私鑰)不是同一把?;驹硎菍蓚€很大的質(zhì)數(shù)相乘很容易得到乘積,但是該乘積分解質(zhì)因數(shù)卻很困難。RSA算法被廣泛的用于加密解密和RSA簽名/驗證等領(lǐng)域。

    2024年02月06日
    瀏覽(34)
  • Python RSA加密解密

    一、RSA加密算法 RSA加密算法是一種非對稱加密算法,加密的秘鑰是由公鑰和私鑰兩部分組成秘鑰對,公鑰用來加密消息,私鑰用來解密消息,公鑰是公開的,給對方進行加密,私鑰則是用戶自己保留,用來對加密的數(shù)據(jù)進行解密。 公鑰pem文件格式:以-----BEGIN PUBLIC KEY-----標(biāo)記

    2024年02月10日
    瀏覽(17)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包