# RSA-签名与校验-前端与后端(Java)
# 1. 介绍
前端使用 私钥 对摘要进行签名
后端(Java)使用 公钥 验证签名是否有效
# 2. Java
public final class RsaEncryptUtil {
// 生成 公钥、私钥 字符串
public static HashMap<String, String> genKeyPair() {
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024, new SecureRandom());
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
String publicKeyString = Base64.encode(publicKey.getEncoded());
String privateKeyString = Base64.encode(privateKey.getEncoded());
HashMap<String, String> map = Maps.newHashMap();
map.put("pub", publicKeyString);
map.put("pri", privateKeyString);
return map;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
// 公钥字符串 转 RSAPublicKey 对象
public static RSAPublicKey strToRsaPublicKey(String publicKeyStr) throws Exception {
byte[] buffer = Base64.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
// 私钥字符串 转 RSAPrivateKey 对象
public static RSAPrivateKey strToRsaPrivateKey(String privateKeyStr) throws Exception {
byte[] buffer = Base64.decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
/**
* 验证签名
* @param algorithm "SHA256withRSA" | "MD5withRSA"
*/
public static Boolean validateSignature(RSAPublicKey publicKey, String digest, String signedDigest, String algorithm) throws Exception {
byte[] signedDigestBytes = Base64.decode(signedDigest);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey.getEncoded()));
java.security.Signature signature = java.security.Signature.getInstance(algorithm);
signature.initVerify(pubKey);
signature.update(digest.getBytes(StandardCharsets.UTF_8));
return signature.verify(signedDigestBytes);
}
public static Boolean validateSignature(String publicKey, String digest, String signedDigest, String algorithm) throws Exception {
return validateSignature(strToRsaPublicKey(publicKey),digest, signedDigest, algorithm);
}
}
# 3. 前端
/*
"crypto-js": "^4.2.0",
"jsencrypt": "^3.5.4",
*/
import CryptoJS from 'crypto-js';
import { JSEncrypt } from 'jsencrypt';
export enum HashType {
SHA256 = 'sha256',
MD5 = 'md5'
}
class RsaUtil {
toDigest(content: string, hashType = HashType.MD5): string {
if (hashType === HashType.SHA256) {
return CryptoJS.SHA256(content).toString(CryptoJS.enc.Hex);
}
return CryptoJS.MD5(content).toString(CryptoJS.enc.Hex);
}
signContentWithPrivateKey(privateKey: string, content: string, hashType = HashType.MD5) {
const digest = this.toDigest(content, hashType);
this.signDigestWithPrivateKey(privateKey, digest, hashType);
}
signDigestWithPrivateKey(privateKey: string, digest: string, hashType = HashType.MD5) {
const encrypt = new JSEncrypt();
encrypt.setPrivateKey(privateKey);
return encrypt.sign(digest, (data) => this.toDigest(data, hashType), hashType);
}
}
export const rasUtil = new RsaUtil();
# 4. 测试
# 4.1. 生成 公钥、私钥
HashMap<String, String> map = RsaEncryptUtil.genKeyPair();
map.forEach((key, val) -> {
System.out.println(key + " = " + val);
});
/*
私钥 = MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK8cceYQYB657UizmY1kq3uScZKtIFNltl0n5Br6DwEPm5mgPBCLDhvfX5rcLdrrdKRwkvuT7ElT/CPpGccYCbluVg/kXUU4kfFp5htrt38stA3pzIXpkmD6J4xVFET7OtDyJYr3gY0XmHDuTFXFfWYK2f3hGTJgZD2gpnToIPzxAgMBAAECgYAmY0b413gq5DmHaY/s9je9lEH/lKJ0heSvkVIpM85cPi6vQ/hG7CUAqTxNN51504ozjlY6fpgbDyVEPhKfmb5voPdJq1KlIvgm8PE6CQ6a3Fhhl+1k2dfS2kN+8kUx35TLjOU0q+uPb6UKsCb+UJrd1kuwC5mgpqBF0yQ3H7JaDQJBAPsqXbkWkwYvZEXvtCGVa11xsPY0vNhKDlfA5yW2i29GRy4GolFsM9Ugb1JH/RN4+rV4ms7xvWZhm/UDLBJYGHMCQQCye1DneII8aWUwgPquGhiajCarqM5fjDMFyXaqL/I7UGiX5je5u7JnCrgD3pkrlyXNakEsvs3DIVxQI3eFfFALAkEAr+xs2UfGk35+bb4IHb3bBgisOseVvqmggjbLsM67u6UuFj7vUrjHVXDyiF+EFC+Y66MeS/VnBF86LdOa+v5ZoQJARRxtEoReYcgp76Mx7nKablWwr62449Sk+SuusG3KbV9QcOkrUNc2WKIU6SKryu5HLAhl3k6v3Ewxs7JYGK8vSwJBAPBwyLILDySqeEVnr0lIhWuOLDn5lejMGQ0VqOnnhCwB1e3TU3SiYa0jit/tlLI1yHVBb3vm1QIE911oiY17d9s=
公钥 = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvHHHmEGAeue1Is5mNZKt7knGSrSBTZbZdJ+Qa+g8BD5uZoDwQiw4b31+a3C3a63SkcJL7k+xJU/wj6RnHGAm5blYP5F1FOJHxaeYba7d/LLQN6cyF6ZJg+ieMVRRE+zrQ8iWK94GNF5hw7kxVxX1mCtn94RkyYGQ9oKZ06CD88QIDAQAB
*/
# 4.2. 前端使用私钥进行签名
import { HashType, rasUtil } from '@/commons/utils/RsaUtil';
const privateKey = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK8cceYQYB657UizmY1kq3uScZKtIFNltl0n5Br6DwEPm5mgPBCLDhvfX5rcLdrrdKRwkvuT7ElT/CPpGccYCbluVg/kXUU4kfFp5htrt38stA3pzIXpkmD6J4xVFET7OtDyJYr3gY0XmHDuTFXFfWYK2f3hGTJgZD2gpnToIPzxAgMBAAECgYAmY0b413gq5DmHaY/s9je9lEH/lKJ0heSvkVIpM85cPi6vQ/hG7CUAqTxNN51504ozjlY6fpgbDyVEPhKfmb5voPdJq1KlIvgm8PE6CQ6a3Fhhl+1k2dfS2kN+8kUx35TLjOU0q+uPb6UKsCb+UJrd1kuwC5mgpqBF0yQ3H7JaDQJBAPsqXbkWkwYvZEXvtCGVa11xsPY0vNhKDlfA5yW2i29GRy4GolFsM9Ugb1JH/RN4+rV4ms7xvWZhm/UDLBJYGHMCQQCye1DneII8aWUwgPquGhiajCarqM5fjDMFyXaqL/I7UGiX5je5u7JnCrgD3pkrlyXNakEsvs3DIVxQI3eFfFALAkEAr+xs2UfGk35+bb4IHb3bBgisOseVvqmggjbLsM67u6UuFj7vUrjHVXDyiF+EFC+Y66MeS/VnBF86LdOa+v5ZoQJARRxtEoReYcgp76Mx7nKablWwr62449Sk+SuusG3KbV9QcOkrUNc2WKIU6SKryu5HLAhl3k6v3Ewxs7JYGK8vSwJBAPBwyLILDySqeEVnr0lIhWuOLDn5lejMGQ0VqOnnhCwB1e3TU3SiYa0jit/tlLI1yHVBb3vm1QIE911oiY17d9s=';
const data = '123';
const digest = rasUtil.toDigest(data);
const signature = rasUtil.signDigestWithPrivateKey(privateKey, digest, HashType.MD5);
console.log('data: ', data);
console.log('digest: ', digest);
console.log('signature: ', signature);
/*
data: 123
digest: 202cb962ac59075b964b07152d234b70
signature: PmpYH2NAYUwszIJBuoR9D6Tw6fBz0Rt+9qYpJ/jm0QgG4mAuHwRgWlWT9IIajFWdWze2Ui4O0planno9vz9pwHdnwgAfToFvVPjQ/amB7xUOHiLnLYBiYyWlyRsO2WZUpVdM/HNH5uZE9xuuEqS1Ee7QkWobFfc8TYzULieof/g=
*/
# 4.3. 后端(Java)使用公钥验证签名
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvHHHmEGAeue1Is5mNZKt7knGSrSBTZbZdJ+Qa+g8BD5uZoDwQiw4b31+a3C3a63SkcJL7k+xJU/wj6RnHGAm5blYP5F1FOJHxaeYba7d/LLQN6cyF6ZJg+ieMVRRE+zrQ8iWK94GNF5hw7kxVxX1mCtn94RkyYGQ9oKZ06CD88QIDAQAB";
String digest = "202cb962ac59075b964b07152d234b70";
String signedDigest = "PmpYH2NAYUwszIJBuoR9D6Tw6fBz0Rt+9qYpJ/jm0QgG4mAuHwRgWlWT9IIajFWdWze2Ui4O0planno9vz9pwHdnwgAfToFvVPjQ/amB7xUOHiLnLYBiYyWlyRsO2WZUpVdM/HNH5uZE9xuuEqS1Ee7QkWobFfc8TYzULieof/g=";
Boolean isValid = RsaEncryptUtil.validateSignature(publicKey, digest, signedDigest, "MD5withRSA");
System.out.println("isValid = " + isValid);
# 5. 参考
上一篇: 下一篇:
本章目录