RSA是一种非对称加密技术,应用于数据加密和数字签名
算法步骤
1、选择两个相异的质数p和q,n=p×q
2、计算 f(n)=(p-1)×(q-1),找到一个与随机整数e满足e与f(n)互质,且1<e<f(n)
3、计算d 使得(d×e)%f(n)=1且1<d<f(n)
4、其中(n,e)是公钥 (n,d)是私钥,其中n成为模,e是公钥指数,d是私钥指数
5、加密过程为c=m^e mod n
6、解密过程为m=c^d mod n
举例说明:
1、选择两个质数3 和11 ,n=33
2、f(n)=2×10=20,选择e=7满足条件
3、d×7 mod 20 =1,那么d可以选择3
4、公钥是33 、7 私钥是33、3
5、加密过程 选择对5 进行加密 5^7 mod 33 = 14
6、解密过程为 14^3 mod 33 = 5
密钥长度是指模值长度,java中提供了生成密钥的类KeyPariGenerator,可以生成相应的公钥和私钥。下面这段代码是生成RSA密钥的方法,以及密钥的模、指数、编码等
public void generateKey() throws NoSuchAlgorithmException, IOException {
String ALGORITHM = "RSA";
/**设置密钥的长度,即密钥模的长度*/
String KEYSIZE = 1024;
/** RSA算法要求有一个可信任的随机数源 */
SecureRandom secureRandom = new SecureRandom();
/** 为RSA算法创建一个KeyPairGenerator对象 */
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
keyPairGenerator.initialize(KEYSIZE, secureRandom);
/** 生成密匙对 */
KeyPair keyPair = keyPairGenerator.generateKeyPair();
/** 生成公钥 **/
String publicKey = (RSAPublicKey) keyPair.getPublic();
/** 生成私钥 **/
String privateKey = (RSAPrivateKey) keyPair.getPrivate();
/**获得指数和模**/
BigInteger modulus = publicKey.getModulus();
BigInteger publicExponent = publicKey.getPublicExponent();
BigInteger privateExponent = privateKey.getPrivateExponent();
/**生成比特编码*/
byte[] publicKeyByte = publicKey.getEncoded();
byte[] privateKeyByte = privateKey.getEncoded();
/** 生成base64编码 **/
String publicKeyString = Base64.getEncoder().encodeToString(publicKeyByte);
String privateKeyString = Base64.getEncoder().encodeToString(privateKeyByte);
}
由于程序中动态生成KeyPair对明文加密后生成的密文是不可测的,所以在实际开发中通常在生成一个KeyPair后将公钥和私钥的N、e、d这三个特征值记录下来,在真实的开发中使用这三个特征值再去将PublicKey和PrivateKey还原出来
/**
* 通过指数和模来生成公钥
*/
public RSAPublicKey generatePublicKeyByModulsAndExponent(BigInteger modulus,BigInteger publicExponent) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulus,publicExponent);
RSAPublicKey publicKey = (RSAPublicKey)keyFactory.generatePublic(rsaPublicKeySpec);
return publicKey;
}catch(Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 通过指数和模来生成私钥
*/
public RSAPrivateKey generatePrivateKeyByModulsAndExponent(BigInteger modulus,BigInteger privateExponent) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus,privateExponent);
RSAPrivateKey privateKey = (RSAPrivateKey)keyFactory.generatePrivate(rsaPrivateKeySpec);
return privateKey;
}catch(Exception e) {
e.printStackTrace();
return null;
}
}
X509EncodedKeySpec:继承EncodedKeySpec类 ,以编码格式来表示公钥
PKCS8EncodedKeySpec:继承EncodedKeySpec类,以编码格式来表示私钥
通过byte[] 方式还原密钥的时候需要注意
/**
* 通过byte编码还原公钥
*/
public RSAPublicKey generatePublicKeyByByteArray(byte[] publicKeyData) {
try {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyData);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey publicKey = (RSAPublicKey)keyFactory.generatePublic(keySpec);
return publicKey;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 通过byte编码还原私钥
*/
public RSAPrivateKey generatePrivateKeyByByteArray(byte[] privateKeyData) {
try {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyData);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKey privateKey = (RSAPrivateKey)keyFactory.generatePrivate(keySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
公钥和私钥都具备后,就可以使用加解密的工具类javax.crypto.Cipher对明文和密文进行处理了。与所有的引擎类一样,可以通过调用Cipher类中的getInstance(String transformation)静态工厂方法得到Cipher对象。该方法中的参数描述了由指定输入产生输出所进行的操作或操作集合,可以是下列两种形式之一:“algorithm/mode/padding”或“algorithm”。如果没有指定模式或填充方式,就使用特定提供者指定的默认模式或默认填充方式。
/** 加密 **/
public byte[] encrypt(RSAPublicKey publicKey, byte[] data) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] output = cipher.doFinal(data);
return output;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/** 解密 **/
public byte[] decrypt(RSAPrivateKey privateKey, byte[] data) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] output = cipher.doFinal(data);
return output;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
以上代码上传至gitHub,欢迎批评指正
github:RSAUtils
https://github.com/liujianjun93/RSAUtils
-----------------------------------分割线------------------------------------
加密长度不能超过 模长-11
解密的长度不能超过128字节
埋坑 ......
网友评论