RSA —— JAVA代码
二话不说,先把代码实现再学习原理!
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* @author : R&M www.rmworking.com/blog
* 2019/8/17 22:09
* demo
* org.security.utils
*/
public class RSAUtil {
public static void main(String[] args) throws Exception {
// 需要加密的数据
String str = "qnloft.com(青柠Loft)";
// keySize 推荐使用2046,必须使用1024以上大小,因为512已经被破解。
RSAUtil rsa = new RSAUtil(1024);
System.out.println("------------- 生成密匙对 (见图1) ---------------");
String publicKey = rsa.getPublicKeyString();
String privateKey = rsa.getPrivateKeyString();
System.out.println(publicKey);
System.out.println(privateKey);
System.out.println("-------------- 加解密数据 (见图2) ---------------");
// 私匙加密数据
byte[] encryptRes1 = RSAUtil.encryptByPrivateKey(str.getBytes(), privateKey);
System.out.println("私匙加密结果是:" + encodeBase64(encryptRes1));
// 公匙解密数据
byte[] decryptRes1 = RSAUtil.decryptByPublicKey(encryptRes1, publicKey);
assert decryptRes1 != null;
System.out.println("公匙解密结果是:" + new String(decryptRes1));
System.out.println("-------------- 加解密数据 (见图3) ---------------");
// 公匙加密数据
byte[] encryptRes2 = RSAUtil.encryptByPublicKey(str.getBytes(), publicKey);
System.out.println("公匙加密结果是:" + encodeBase64(encryptRes2));
// 私匙解密数据
byte[] decryptRes2 = RSAUtil.decryptByPrivateKey(encryptRes2, privateKey);
assert decryptRes2 != null;
System.out.println("私匙解密结果是:" + new String(decryptRes2));
}
//非对称密钥算法
private static final String KEY_ALGORITHM = "RSA";
private KeyPair keyPair = null;
public RSAUtil(int keySize) throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(keySize);
keyPair = keyPairGen.generateKeyPair();
}
// ------------------ 生成密匙 -----------------------
/**
* 获取私匙 byte[]
*
* @return
*/
public byte[] getPrivateKey() {
Key key = keyPair.getPrivate();
return key.getEncoded();
}
/**
* 获取公匙
*
* @return
* @throws Exception
*/
public byte[] getPublicKey() throws Exception {
Key key = keyPair.getPublic();
return key.getEncoded();
}
/**
* 获取私匙 String
*
* @return
*/
public String getPrivateKeyString() {
return encodeBase64(this.getPrivateKey());
}
/**
* 获取公匙
*
* @return
* @throws Exception
*/
public String getPublicKeyString() throws Exception {
return encodeBase64(this.getPublicKey());
}
// ------------------ 加密 ---------------------------
/**
* 私匙加密
*
* @param data 需要加密的数据
* @param key 私匙
* @return
* @throws Exception
*/
public static byte[] encryptByPrivateKey(byte[] data, Object key) throws Exception {
return byPrivateKey(data, key, Cipher.ENCRYPT_MODE);
}
/**
* 公匙加密
*
* @param data
* @param key
* @return
* @throws Exception
*/
public static byte[] encryptByPublicKey(byte[] data, Object key) throws Exception {
return byPublicKey(data, key, Cipher.ENCRYPT_MODE);
}
// ------------------ 解密 ---------------------------
/**
* 公钥解密
*
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
*/
public static byte[] decryptByPublicKey(byte[] data, Object key) throws Exception {
return byPublicKey(data, key, Cipher.DECRYPT_MODE);
}
/**
* 私钥解密
*
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
*/
public static byte[] decryptByPrivateKey(byte[] data, Object key) throws Exception {
return byPrivateKey(data, key, Cipher.DECRYPT_MODE);
}
public static byte[] byPublicKey(byte[] data, Object key, int cipherMode) throws Exception {
if (data.length != 0 && key != null) {
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公钥
//密钥材料转换
X509EncodedKeySpec x509KeySpec = null;
if (key instanceof String) {
byte[] publicKey = decodeBase64(String.valueOf(key));
x509KeySpec = new X509EncodedKeySpec(publicKey);
} else if (key instanceof byte[]) {
x509KeySpec = new X509EncodedKeySpec((byte[]) key);
}
//产生公钥
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
//数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(cipherMode, pubKey);
return cipher.doFinal(data);
}
return null;
}
private static byte[] byPrivateKey(byte[] data, Object key ,int cipherMode) throws Exception {
if (data.length != 0 && key != null) {
// 使用私钥
PKCS8EncodedKeySpec pkcs8KeySpec = null;
if (key instanceof String) {
byte[] privateKey = decodeBase64(String.valueOf(key));
pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
} else if (key instanceof byte[]) {
pkcs8KeySpec = new PKCS8EncodedKeySpec((byte[]) key);
}
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 加解密操作
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(cipherMode, privateKey);
return cipher.doFinal(data);
}
return null;
}
public static String encodeBase64(byte[] binaryData) {
return Base64.getEncoder().encodeToString(binaryData);
}
public static byte[] decodeBase64(String encoded) {
return Base64.getDecoder().decode(encoded);
}
}
RSA —— 加密过程图解
(图1)构建RSA算法密匙对

构建公钥和私钥,将私钥自己保存,然后将公钥发送给乙方。注意:密匙是一对形式存在的,必须一次生成公钥和私钥,以本次生成的密匙对进行数据加解密操作。
RSAUtil rsa = new RSAUtil(1024);
// publicKey 发送给乙方
String publicKey = rsa.getPublicKeyString();
// privateKey 自己留存
String privateKey = rsa.getPrivateKeyString();
(图2)甲方向乙方发送RSA加密数据

使用自己留存密匙对中的私钥进行数据加密操作,然后乙方会根据密匙对中的公匙进行数据解密。
// 私匙加密数据
byte[] encryptRes1 = RSAUtil.encryptByPrivateKey(str.getBytes(), privateKey);
System.out.println("自己[甲方]私钥加密结果是:" + encodeBase64(encryptRes1));
// 公匙解密数据
byte[] decryptRes1 = RSAUtil.decryptByPublicKey(encryptRes1, publicKey);
assert decryptRes1 != null;
System.out.println("测试[乙方]公钥解密结果是:" + new String(decryptRes1));
(图3) 乙方向甲方发送RSA加密数据

当乙方向甲方发送加密数据时,可以使用密匙对中的公匙进行数据加密,甲方使用密匙对中的私钥进行数据解密操作。
// 公匙加密数据
byte[] encryptRes2 = RSAUtil.encryptByPublicKey(str.getBytes(), publicKey);
System.out.println("模拟[乙方]公钥加密,结果是:" + encodeBase64(encryptRes2));
// 私匙解密数据
byte[] decryptRes2 = RSAUtil.decryptByPrivateKey(encryptRes2, privateKey);
assert decryptRes2 != null;
System.out.println("自己[甲方]私钥解密,结果是:" + new String(decryptRes2));
RSA —— 简述
RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA底层的单向函数就死整数因式分解的问题:两个大素数相乘在计算是非常简单的,但是对其乘积结果做因式分解确实非常难的。
所以:对极大整数做因数分解的难度决定了RSA算法的可靠性,假如有人找到一种快速因数分解的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。
但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。
已公开的或已知的攻击方法编辑
- 针对RSA最流行的攻击一般是基于大数因数分解。1999年,RSA-155 (512 bits)被成功分解,花了五个月时间(约8000 MIPS年)和224 CPU hours在一台有3.2G中央内存的Cray C916计算机上完成。
RSA-158表示如下:
39505874583265144526419767800614481996020776460304936454139376051579355626529450683609727842468219535093544305870490251995655335710209799226484977949442955603= 3388495837466721394368393204672181522815830368604993048084925840555281177× 11658823406671259903148376558383270818131012258146392600439520994131344334162924536139
- 2009年12月12日,编号为RSA-768(768 bits, 232 digits)数也被成功分解。这一事件威胁了现通行的1024-bit密钥的安全性,普遍认为用户应尽快升级到2048-bit或以上。
RSA-768表示如下:
1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413= 3347807169895689878604416984821269081770479498371376856891 2431388982883793878002287614711652531743087737814467999489× 3674604366679959042824463379962795263227915816434308764267 6032283815739666511279233373417143396810270092798736308917
- 秀尔算法
量子计算里的秀尔算法能使穷举的效率大大的提高。由于RSA算法是基于大数分解(无法抵抗穷举攻击),因此在未来量子计算能对RSA算法构成较大的威胁。一个拥有N量子比特的量子计算机,每次可进行2^N
次运算,理论上讲,密钥为1024位长的RSA算法,用一台512量子比特位的量子计算机在1秒内即可破解。
RSA —— 数学公式
密匙对生成


加密与解密


参考文献
- 《深入浅出密码学》
- 《JAVA加密与解密的艺术--第2版》
--Posted from Rpc