🍓 简介:java系列技术分享(👉持续更新中…🔥)
🍓 初衷:一起学习、一起进步、坚持不懈
🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏
🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝
一、RSA算法简介
RSA加密
(Rivest-Shamir-Adleman加密)是一种非对称加密算法
- 加密算法是目前最有影响力的
公钥加密算法
,并且被普遍认为是目前最优秀的公钥方案 之一
。RSA 是第一个能同时用于 加密 和 数字签名 的算法,它能够 抵抗 到目前为止已知的 所有密码攻击,已被ISO
推荐为公钥数据加密标准。
RSA加密算法基于一个简单的数论事实:
将两个大素数相乘容易,但是将其乘积分解成原始的两个大素数却非常困难。RSA算法的核心思想就是利用这个数论事实来实现加密和解密。
在RSA加密中,每个参与者拥有一对密钥:
公钥和私钥
。公钥可以自由分发,而私钥必须保密。发送方使用接收方的公钥对消息进行加密,接收方使用自己的私钥对加密后的消息进行解密。公钥和私钥是通过一系列数学运算生成的,并且在算法中使用了大数的运算,使得破解RSA加密变得困难。RSA算法的安全性基于两个数论问题的难解性:
大整数的因数分解和模取指数的离散对数问题。由于目前没有高效的算法能够在合理时间内解决这两个问题,因此RSA算法被认为是一种安全可靠的加密算法。
二、对称加密和非对称加密
加密算法分 对称加密 和 非对称加密,其中对称加密算法的加密与解密 密钥相同,非对称加密算法的加密密钥与解密 密钥不同,此外,还有一类 不需要密钥 的 散列算法。
常见的 对称加密 算法主要有
DES
、3DES
、AES
等,常见的 非对称算法 主要有RSA
、DSA
等,散列算法 主要有SHA-1
、MD5
等。
2.1 对称加密
对称加密算法 是应用较早的加密算法,又称为 共享密钥加密算法。在 对称加密算法 中,使用的密钥只有一个,发送 和 接收 双方都使用这个密钥对数据进行 加密和解密
。这就要求加密和解密方事先都必须知道加密的密钥。
-
数据加密过程:在对称加密算法中,数据发送方 将 明文 (原始数据) 和 加密密钥 一起经过特殊 加密处理,生成复杂的 加密密文 进行发送。
-
数据解密过程:数据接收方 收到密文后,若想读取原数据,则需要使用 加密使用的密钥 及相同算法的 逆算法 对加密的密文进行解密,才能使其恢复成 可读明文。
2.2. 非对称加密
非对称加密算法,又称为 公开密钥加密算法。它需要两个密钥,一个称为 公开密钥 (public key
),即 公钥,另一个称为 私有密钥 (private key
),即 私钥。
因为 加密 和 解密 使用的是两个不同的密钥,所以这种算法称为 非对称加密算法。
-
如果使用 公钥 对数据 进行加密,只有用对应的 私钥 才能 进行解密(
推荐
)。 -
如果使用 私钥 对数据 进行加密,只有用对应的 公钥 才能 进行解密。
三、代码实现
import cn.hutool.core.codec.Base64Encoder;
import com.web.exception.enums.ErrorCodeEnum;
import com.web.exception.exception.BizException;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.UUID;
public class SecureRSAUtil {
/**
* Base64编码
*/
private static Base64.Encoder encoder = Base64.getEncoder();
/**
* Base64解码
*/
private static Base64.Decoder decoder = Base64.getDecoder();
private static final String ALGORITHM = "RSA";
private static final int KEY_SIZE = 1024;
/**
* 生成密钥对
*
* @return Map对象 (private=私钥, public=公钥)
* @throws Exception 异常
*/
public static HashMap<String, String> rsaGenerateKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
KeyPair keyPair;
try {
keyPairGenerator.initialize(KEY_SIZE,
new SecureRandom(UUID.randomUUID().toString().replaceAll("-", "").getBytes()));
keyPair = keyPairGenerator.generateKeyPair();
} catch (InvalidParameterException e) {
throw e;
} catch (NullPointerException e) {
throw e;
}
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
HashMap<String, String> map = new HashMap<String, String>(16);
map.put("private", Base64Encoder.encode(rsaPrivateKey.getEncoded()));
map.put("public", Base64Encoder.encode(rsaPublicKey.getEncoded()));
return map;
}
/**
* RSA公钥加密
*
* @param publicKeyString 公钥
* @param content 内容
* @return 加密后内容
*/
public static String rsaEncryptByPublic(String publicKeyString, String content) {
try {
// 获得公钥对象
PublicKey publicKey = getPublicKeyFromString(publicKeyString);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 该密钥能够加密的最大字节长度
int splitLength = ((RSAPublicKey) publicKey).getModulus().bitLength() / 8 - 11;
byte[][] arrays = splitBytes(content.getBytes(), splitLength);
StringBuffer stringBuffer = new StringBuffer();
for (byte[] array : arrays) {
stringBuffer.append(bytesToHexString(cipher.doFinal(array)));
}
return stringBuffer.toString();
} catch (Exception e) {
throw new BizException(ErrorCodeEnum.SECURE_ERROR);
}
}
/**
* RSA私钥加密
*
* @param privateKeyString 私钥
* @param content 内容
* @return 加密后内容
*/
public static String rsaEncryptByPrivate(String privateKeyString, String content) {
try {
PrivateKey privateKey = getPrivateKeyFromString(privateKeyString);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
// 该密钥能够加密的最大字节长度
int splitLength = ((RSAPrivateKey) privateKey).getModulus().bitLength() / 8 - 11;
byte[][] arrays = splitBytes(content.getBytes(), splitLength);
StringBuffer stringBuffer = new StringBuffer();
for (byte[] array : arrays) {
stringBuffer.append(bytesToHexString(cipher.doFinal(array)));
}
return stringBuffer.toString();
} catch (Exception e) {
throw new BizException(ErrorCodeEnum.SECURE_ERROR);
}
}
/**
* RSA公钥解密
*
* @param publicKeyString 公钥
* @param content 已加密内容
* @return 解密后内容
*/
public static String rsaDecryptByPublic(String publicKeyString, String content) {
try {
PublicKey publicKey = getPublicKeyFromString(publicKeyString);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
// 该密钥能够加密的最大字节长度
int splitLength = ((RSAPublicKey) publicKey).getModulus().bitLength() / 8;
byte[] contentBytes = hexStringToBytes(content);
byte[][] arrays = splitBytes(contentBytes, splitLength);
StringBuffer stringBuffer = new StringBuffer();
for (byte[] array : arrays) {
stringBuffer.append(new String(cipher.doFinal(array)));
}
return stringBuffer.toString();
} catch (Exception e) {
throw new BizException(ErrorCodeEnum.SECURE_ERROR);
}
}
/**
* RSA私钥解密
*
* @param privateKeyString 公钥
* @param content 已加密内容
* @return 解密后内容
*/
public static String rsaDecryptByPrivate(String privateKeyString, String content) {
try {
PrivateKey privateKey = getPrivateKeyFromString(privateKeyString);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 该密钥能够加密的最大字节长度
int splitLength = ((RSAPrivateKey) privateKey).getModulus().bitLength() / 8;
byte[] contentBytes = hexStringToBytes(content);
byte[][] arrays = splitBytes(contentBytes, splitLength);
StringBuffer stringBuffer = new StringBuffer();
for (byte[] array : arrays) {
stringBuffer.append(new String(cipher.doFinal(array)));
}
return stringBuffer.toString();
} catch (Exception e) {
throw new BizException(ErrorCodeEnum.SECURE_ERROR);
}
}
// ---------- 获取*钥
/**
* 根据公钥字符串获取 公钥对象
*/
private static PublicKey getPublicKeyFromString(String key)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// 过滤掉\r\n
key = key.replace("\r\n", "");
// 取得公钥
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(decoder.decode(key));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
return publicKey;
}
/**
* 根据私钥字符串获取 私钥对象
*/
private static PrivateKey getPrivateKeyFromString(String key)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// 过滤掉\r\n
key = key.replace("\r\n", "");
// 取得私钥
PKCS8EncodedKeySpec x509KeySpec = new PKCS8EncodedKeySpec(decoder.decode(key));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(x509KeySpec);
return privateKey;
}
// ---------- 一些辅助方法
/**
* 根据限定的每组字节长度,将字节数组分组
*/
private static byte[][] splitBytes(byte[] bytes, int splitLength) {
// bytes与splitLength的余数
int remainder = bytes.length % splitLength;
// 数据拆分后的组数,余数不为0时加1
int quotient = remainder != 0 ? bytes.length / splitLength + 1 : bytes.length / splitLength;
byte[][] arrays = new byte[quotient][];
byte[] array = null;
for (int i = 0; i < quotient; i++) {
// 如果是最后一组(quotient-1),同时余数不等于0,就将最后一组设置为remainder的长度
if (i == quotient - 1 && remainder != 0) {
array = new byte[remainder];
System.arraycopy(bytes, i * splitLength, array, 0, remainder);
} else {
array = new byte[splitLength];
System.arraycopy(bytes, i * splitLength, array, 0, splitLength);
}
arrays[i] = array;
}
return arrays;
}
/**
* 将字节数组转换成16进制字符串
*/
private static String bytesToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer(bytes.length);
String temp = null;
for (int i = 0; i < bytes.length; i++) {
temp = Integer.toHexString(0xFF & bytes[i]);
if (temp.length() < 2) {
sb.append(0);
}
sb.append(temp);
}
return sb.toString();
}
/**
* 将16进制字符串转换成字节数组
*/
private static byte[] hexStringToBytes(String hex) {
int len = (hex.length() / 2);
hex = hex.toUpperCase();
byte[] result = new byte[len];
char[] chars = hex.toCharArray();
for (int i = 0; i < len; i++) {
int pos = i * 2;
result[i] = (byte) (toByte(chars[pos]) << 4 | toByte(chars[pos + 1]));
}
return result;
}
/**
* 将char转换为byte
*/
private static byte toByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
public static void main(String[] args) throws Exception {
String password = "123456789";
System.out.println("原始密码:"+password);
//生成秘钥对
HashMap<String, String> stringStringHashMap = rsaGenerateKeyPair();
// 定义私钥和公钥
String privateKey = stringStringHashMap.get("private");
String publicKey = stringStringHashMap.get("public");
System.out.println("公钥:"+publicKey);
System.out.println("私钥:"+privateKey);
//私钥加密,公钥解密----测试
String encryptPwd1 = rsaEncryptByPrivate(privateKey, password);
System.out.println("私钥加密,公钥解密后" + rsaDecryptByPublic(publicKey, encryptPwd1));
System.out.println("================================================================");
//公钥加密,私钥解密----测试
String encryptPwd2 = rsaEncryptByPublic(publicKey, password);
System.out.println("公钥加密,私钥解密后" + rsaDecryptByPrivate(privateKey, encryptPwd2));
}
}
调用上方main方法得到结果
注意
- 双方需要使用
同一个密钥对
数据进行 加密和解密