前言
RSA 是一种非对称加密算法,它的公钥和私钥是一对,其中公钥可以公开,任何人都可以用它来加密信息,而私钥只有密钥持有人才能拥有,用于解密加密信息。
一、RSA 算法 过程
- 选择两个质数 p 和 q,计算它们的积 n=p*q,把 n 称为模数(modulus)。
- 根据欧拉函数定义,计算 φ(n)=(p-1)(q-1),它表示小于 n 的正整数中与 n 互质的数的个数。
- 选择一个比 φ(n) 小又与 φ(n) 互质的正整数 e,把 e 称为公钥(public key)。
- 找到一个数 d,使得 e*d ≡ 1 (mod φ(n)),把 d 称为私钥(private key)。
- 把公钥和模数(n)组合成公钥对(public key pair),把私钥和模数(n)组合成私钥对(private key pair)。
- 加密消息 m 时,用公钥对 m 加密成密文 c=m^e(mod n)。
- 解密密文 c 时,用私钥对 c 解密成明文 m=c^d(mod n)。
二、RSA 在Java中使用
1.依赖
代码如下(示例):
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
2.构建一个RSAManager类 对应构造 加密方法 和 使用 私匙解密
/**
*
* @param data 加密数据
* @param publicKey 公钥
* @return 加密后的数据
*/
public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) {
//使用公钥创建 x509EncodedKeySpec 对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
KeyFactory keyFactory = null;
Cipher cp = null;
byte[] byteArr = null;
try {
//使用RSA 算法生产 KeyFactory 对象,并使用generatePublic 方法从 KeySpec中 提取公钥
keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
// 加密数据 生成Cipher对象并指定使用RSA/ECB/PKCS1Padding加密。
cp = Cipher.getInstance("RSA/ECB/PKCS1Padding");
//初始化Cipher对象并加密数据。
cp.init(Cipher.ENCRYPT_MODE, pubKey);
byteArr = cp.doFinal(data);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException
| IllegalBlockSizeException | BadPaddingException | InvalidKeyException e) {
e.printStackTrace();
}
return byteArr;
}
/**
* 使用私匙解密
* @param encrypted 加密的数据(密文)
* @param privateKey 私钥
* @return
*/
public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) {
// 得到私钥对象 PKCS8EncodedKeySpec
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = null;
byte[] byteArr = null;
try {
//使用RSA算法生成KeyFactory对象,并使用generatePrivate方法从KeySpec中提取私钥。
kf = KeyFactory.getInstance("RSA");
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
// 解密数据 生成Cipher对象并指定使用RSA/ECB/PKCS1Padding解密。
Cipher cp = Cipher.getInstance("RSA/ECB/PKCS1Padding");
//初始化Cipher对象并解密数据。
cp.init(Cipher.DECRYPT_MODE, keyPrivate);
byteArr = cp.doFinal(encrypted);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
e.printStackTrace();
}
return byteArr;
}
3.测试
public static void main(String[] args) {
try {
// 生成RSA密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keyPair = keyGen.generateKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
// 使用公钥加密数据
byte[] data = "Hello world ".getBytes();
byte[] encrypted = RSAManager.encryptByPublicKey(data, publicKey);
// 使用私钥解密数据
byte[] decrypted = RSAManager.decryptByPrivateKey(encrypted, privateKey);
// 输出加密前后以及解密后的数据
System.out.println("原始数据:" + new String(data));
System.out.println("加密后的数据:" + new String(encrypted));
System.out.println("解密后的数据:" + new String(decrypted));
} catch (Exception e) {
e.printStackTrace();
}
}
结果输出
原始数据:Hello world
加密后的数据:w�u;1����a#�c�Q`��7F�W'�z�V�N�4[�t�NjMӼ��LJY��f�.T��4�Q�CE"�@s�ZXVò���f;RH4C�`o{%^<���^�0�mA�o٠v��U�vw�F<x
解密后的数据:Hello world
进程已结束,退出代码为 0
总结
- 加密:
- 具体实现过程是:使用公钥创建X509EncodedKeySpec对象;
- 使用RSA算法生成KeyFactory对象,并使用generatePublic方法从KeySpec中提取公钥;
- 生成Cipher对象并指定使用RSA/ECB/PKCS1Padding加密;初始化Cipher对象并加密数据;
- 返回加密后的数据。
- 解密:
- 具体实现过程是:使用私钥创建PKCS8EncodedKeySpec对象;
- 使用RSA算法生成KeyFactory对象,并使用generatePrivate方法从KeySpec中提取私钥;
- 生成Cipher对象并指定使用RSA/ECB/PKCS1Padding解密;
- 初始化Cipher对象并解密数据;返回解密后的数据。