一、RSA简介
非对称加密算法,由一对密钥(公钥-私钥)来进行加密-解密、签名-验签的过程。公钥-私钥的生成与数学相关,算法的原理是依靠对极大整数做因数分解的困难性来保证安全性。
二、加密、签名区别
加密和签名都是为了信息传递途中的安全,原理略有不同,加密是防止信息明文传输被泄露,签名是防止信息被篡改。
三、加解密、签名及验签场景
加解密场景
:A服务器向B服务器传递一指令。
过程如下:
-
(1)B生成一对密钥(公钥-私钥),私钥B自己保留,公钥任何人可以获取。
-
(2)B传递自己的公钥给A,A用B的公钥对消息进行加密。
-
(3)B接收到A加密的消息,利用B自己的私钥对消息进行解密。
整个流程含两次传递过程,第一次是B传递公钥给A,第二次是A传递加密消息给B,即使都被第三方非法截获,也没有危险性,因为只有B的私钥才能对消息进行解密,防止了消息内容的泄露。
签名及验签场景
:B服务器收执行完A服务器发的指令后,向A回复执行结果。
过程如下:
-
(1)B用自己的私钥对回复的消息加签,形成签名,并将签名和消息本身一起传递给A。
-
(2)A收到回复后,使用B提供的公钥进行验签,如果验签解析出的内容与消息本身一致,证 明消息是B回复的。
即使回复的消息被第三方非法截获,也没有危险性,因为接收方A使用的是B的公钥进行验签,只有B的私钥生成的签名才能通过A的验签,即使第三方非法获取消息内容,也无法伪造带签名的回复给A,防止了消息内容被篡改。
但是不难发现,加密场景中,可以利用截获的公钥,将假指令进行加密,然后传递给B。验签场景中,虽然截获的消息不能被篡改,但是消息的内容可以利用公钥验签获得,并不能防止泄露。所以实际应用中要根据情况使用,最好同时使用加密和签名,比如A和B都有一套自己的公钥和私钥,当A要给B发送消息时,先用B的公钥对消息加密,再对加密的消息使用A的私钥加签名,达到既不泄露也不被篡改,从而保证消息的安全性(公钥加密、私钥解密、私钥签名、公钥验签
)。
四、RSA工具类
package com.ahysf.common.utils;
import cn.hutool.core.codec.Base64;
import com.ahysf.controller.saas.SaaSDemo;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: RSAUtil
* @author: 〆、dyh
* @since: 2022/3/3 10:38
*/
public class RSAUtil {
public static final String KEY_ALGORITHM = "RSA";
private static final String PUBLIC_KEY = "RSAPublicKey";
private static final String PRIVATE_KEY = "RSAPrivateKey";
public static final String SIGNATURE_INSTANCE = "SHA256WithRSA";
/**
* 获得公钥
*
* @param keyMap
* @return java.lang.String
* @MethodName: getPublicKey
* @author: 〆、dyh
* @since: 2022/3/4 10:30
*/
public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
//获得map中的公钥对象 转为key对象
Key key = (Key) keyMap.get(PUBLIC_KEY);
//编码返回字符串
return encryptBASE64(key.getEncoded());
}
/**
* 获得私钥
*
* @param keyMap
* @return java.lang.String
* @MethodName: getPrivateKey
* @author: 〆、dyh
* @since: 2022/3/4 10:30
*/
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
//获得map中的私钥对象 转为key对象
Key key = (Key) keyMap.get(PRIVATE_KEY);
//编码返回字符串
return encryptBASE64(key.getEncoded());
}
/**
* 解码返回byte
*
* @param key
* @return byte[]
* @MethodName: decryptBASE64
* @author: 〆、dyh
* @since: 2022/3/4 10:30
*/
public static byte[] decryptBASE64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
}
/**
* 编码返回字符串
*
* @param key
* @return java.lang.String
* @MethodName: encryptBASE64
* @author: 〆、dyh
* @since: 2022/3/4 10:30
*/
public static String encryptBASE64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
}
/**
* map对象中存放公私钥
*
* @param
* @return java.util.Map<java.lang.String, java.lang.Object>
* @MethodName: initKey
* @author: 〆、dyh
* @since: 2022/3/4 10:31
*/
public static Map<String, Object> initKey() throws Exception {
//获得对象 KeyPairGenerator 参数 RSA 1024个字节
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
//通过对象 KeyPairGenerator 获取对象KeyPair
KeyPair keyPair = keyPairGen.generateKeyPair();
//通过对象 KeyPair 获取RSA公私钥对象RSAPublicKey RSAPrivateKey
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//公私钥对象存入map中
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 实例化公钥
*
* @param publicKey
* @return java.security.PublicKey
* @MethodName: getPublicKey
* @author: 〆、dyh
* @since: 2022/3/4 10:31
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
byte[] publicKeyBytes = java.util.Base64.getMimeDecoder().decode(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
/**
* 实例化私钥
*
* @param privateKey
* @return java.security.PrivateKey
* @MethodName: getPrivateKey
* @author: 〆、dyh
* @since: 2022/3/4 10:31
*/
public static PrivateKey getPrivateKey(String privateKey) throws Exception {
byte[] privateKeyBytes = java.util.Base64.getMimeDecoder().decode(privateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
/**
* 公钥加密
*
* @param content
* @param publicKey
* @return byte[]
* @MethodName: encryptByPublicKey
* @author: 〆、dyh
* @since: 2022/3/4 10:31
*/
public static byte[] encryptByPublicKey(byte[] content, String publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
return cipher.doFinal(content);
}
/**
* 私钥解密
*
* @param content
* @param privateKey
* @return byte[]
* @MethodName: decryptByPrivateKey
* @author: 〆、dyh
* @since: 2022/3/4 10:32
*/
public static byte[] decryptByPrivateKey(byte[] content, String privateKey) throws Exception {
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
return cipher.doFinal(content);
}
/**
* 私钥签名
*
* @param content
* @param privateKey
* @return byte[]
* @MethodName: sign
* @author: 〆、dyh
* @since: 2022/3/4 10:33
*/
public static byte[] sign(byte[] content, String privateKey) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
signature.initSign(getPrivateKey(privateKey));
signature.update(content);
return signature.sign();
}
/**
* 公钥验签
*
* @param content
* @param sign
* @param publicKey
* @return boolean
* @MethodName: verify
* @author: 〆、dyh
* @since: 2022/3/4 10:33
*/
public static boolean verify(byte[] content, byte[] sign, String publicKey) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
signature.initVerify(getPublicKey(publicKey));
signature.update(content);
return signature.verify(sign);
}
public static void main(String[] args) throws Exception {
Map<String, Object> keyMap;
try {
//初始化公私钥
keyMap = initKey();
//获得公钥
String publicKey = getPublicKey(keyMap);
System.out.println("rsa公钥:" + publicKey);
//获得私钥
String privateKey = getPrivateKey(keyMap);
System.out.println("rsa私钥:" + privateKey);
String content = "我爱你你却爱着他";
//公钥加密
byte[] encrypt = encryptByPublicKey(content.getBytes(StandardCharsets.UTF_8), publicKey);
//私钥解密
byte[] decryp = decryptByPrivateKey(encrypt, privateKey);
System.out.println("明文:" + new String(decryp));
//私钥签名
byte[] sign = sign(content.getBytes(StandardCharsets.UTF_8), privateKey);
System.out.println("私钥签名:" + sign);
//公钥验签
boolean verify = verify(content.getBytes(StandardCharsets.UTF_8), sign, publicKey);
System.out.println("验签结果:" + verify);
} catch (Exception e) {
e.printStackTrace();
}
}
}