RSA加密原理超经典解析链接:
http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
密码算法应用规范
规则:使用RSA算法时要选取合适的公共指数e
说明:公共指数e位长越小,RSA加密或签名校验时的效率越高。但位长过小时(如e=3)可能会遭受一系列安全攻击[1]。如e=3时,若两不同消息m1、m2都使用RSA加密且使用相同的模N,当m1和m2满足某些特定的关系m1=ƒ(m2) mod N 时,攻击者有可能恢复出m1和m2
规则:使用RSA算法进行加密操作时,应优先选择OAEP填充方式
说明:对数据进行填充要非常谨慎,因为一些有经验的黑客有可能从中找到一些线索。早期的PKCS#1填充标准就曾受到一种自适应选择明文攻击的威胁。RSA实验室在PKCS#1 V1.5以后的标准中增加了OAEP(Optimal Asymmetric Encryption Padding)填充模式,可以有效阻止这类威胁。一般算法库提供的接口函数中都会有填充方式选择参数,如OpenSSL中为RSA_PKCS1_OAEP_PADDING
规则:使用RSA算法时,加密和签名要使用不同的密钥对
说明:RSA算法的通常用法是用对方的公钥进行加密,用自己的私钥进行签名。当加密和签名使用相同的密钥对时,如果签名时没有进行哈希,实际上是对数据进行了解密的操作。这样如果攻击者让密钥所有者对一段密文进行签名,他就得到了相应的明文。
另外,加密和签名的密钥对的管理方式和使用时限不同。用于验证签名的公钥需要长期有效,而用于签名的私钥在有效期之后必须销毁。用于解密的私钥需要长期有效, 而用于加密的公钥在有效期之后需要销毁。
2 非对称加密的基本流程
1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。
2)甲方获取乙方的公钥,然后用它对信息加密。
3)乙方得到加密后的信息,用私钥解密。
3 应用场景
对称加密一般来讲速度比较慢,一般会结合AES等对称加密来使用;因为RSA的安全性性比较高,而AES又面临者密钥保存难的风险,所有在客户端和服务器交互的过程中,一般会使用RSA的方式,协商当前的AES密钥的方式;
package rsa_encrytion;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
public class RSA_Test {
private static final String KEY_ALGORITH = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; //这里应该OAEP
private static final String PUBLICKEY = "RSAPublicKey";
private static final String PRIVATEKEY = "RSAPrivateKey";
private static final int MAX_ENCRYT_BLOCK = 245;
private static final int MAX_DECRYT_BLOCK = 256;
//生成密钥对
public static Map<String,Object> genkeyPair () throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITH);
keyPairGen.initialize(2048);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String,Object> keyMap = new HashMap<String,Object>(2);
keyMap.put(PUBLICKEY, rsaPublicKey);
keyMap.put(PRIVATEKEY, rsaPrivateKey);
return keyMap;
}
//公玥加密
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
byte[] keyBytes = Base64Utils.decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyfactory = KeyFactory.getInstance(KEY_ALGORITH);
Key publicK = keyfactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyfactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicK);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int inputLen = data.length;
int offset = 0;
byte[] cache;
int i = 0;
while(inputLen - offset > 0) {
if(inputLen - offset > MAX_ENCRYT_BLOCK) {
cache = cipher.doFinal(data,offset,MAX_ENCRYT_BLOCK);
}
else {
cache = cipher.doFinal(data,offset,inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_ENCRYT_BLOCK;
}
byte[] byteEncryptData = out.toByteArray();
out.close();
return byteEncryptData;
}
//私玥解密
public static byte[] decryptByPrivateKey(byte[] encodedData, String privateKey) throws Exception {
byte[] keyBytes = Base64Utils.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyfactory = KeyFactory.getInstance(KEY_ALGORITH);
Key privateK = keyfactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyfactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int inputLen = encodedData.length;
int offset = 0;
byte[] cache;
int i = 0;
while(inputLen - offset > 0) {
if(inputLen - offset > MAX_DECRYT_BLOCK) {
cache = cipher.doFinal(encodedData,offset,MAX_DECRYT_BLOCK);
}
else {
cache = cipher.doFinal(encodedData,offset,inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_DECRYT_BLOCK;
}
byte[] bytedecryptData = out.toByteArray();
out.close();
return bytedecryptData;
}
//获取公玥
public static String getPublicKey(Map<String,Object> mapkey) throws Exception {
Key key = (Key) mapkey.get(PUBLICKEY);
return Base64Utils.encode(key.getEncoded());
}
//获取私玥
public static String getPrivateKey(Map<String,Object> mapkey) throws Exception {
Key key = (Key) mapkey.get(PRIVATEKEY);
return Base64Utils.encode(key.getEncoded());
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String publicKey,privateKey;
try {
Map<String,Object> keymap = genkeyPair();
publicKey = getPublicKey(keymap);
privateKey = getPrivateKey(keymap);
System.out.println("公玥:" + publicKey);
System.out.println("私玥:" + privateKey);
String plaintext = "我们要对这段文字开始加密,加密使用的算法是RSA,大家注意看好了";
System.out.println("加密明文为:" + plaintext);
byte[] data = plaintext.getBytes();
byte[] encodedData = encryptByPublicKey(data,publicKey);
System.out.println("加密密文为:" + new String(encodedData));
byte[] decodedData = decryptByPrivateKey(encodedData, privateKey);
System.out.println("解密明文为:" + new String(decodedData));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}