1. 介绍
RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
这里提供一个在线进行RSA加密解密:http://tool.chacuo.net/cryptrsapubkey
2. 具体实现
密钥可以是字节数组,也可以是Base64编码过的。加密后对数据的输出采用2种方式:Base64、Hex,其中Base64使用的是Android SDK里面的API,具体代码如下:
package com.fantasy.blogdemo.crypto.utils;
import android.util.Base64;
import com.fantasy.blogdemo.utils.ConvertUtils;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
/**
* RSA加解密工具类
* <pre>
* author : Fantasy
* version : 1.0, 2019-08-25
* since : 1.0, 2019-08-25
* </pre>
*/
public class RSAUtils {
private static final String CHARSET = "UTF-8";
/**
* 加密,输出Base64字符串密文
*
* @param data 明文
* @param publicKey 公钥
* @param keySize 公钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @return 密文
*/
public static String encryptBase64(String data, byte[] publicKey, int keySize, String transformation) {
try {
return Base64.encodeToString(handle(data.getBytes(CHARSET), publicKey, keySize, transformation,
true), Base64.NO_WRAP);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 加密,输出Base64字符串密文
*
* @param data 明文
* @param publicKey 公钥(Base64字符串)
* @param keySize 公钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @return 密文
*/
public static String encryptBase64(String data, String publicKey, int keySize, String transformation) {
try {
return Base64.encodeToString(handle(data.getBytes(CHARSET), Base64.decode(publicKey, Base64.NO_WRAP),
keySize, transformation, true), Base64.NO_WRAP);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 加密,输出十六进制字符串密文
*
* @param data 明文
* @param publicKey 公钥
* @param keySize 公钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @return 密文
*/
public static String encryptHex(String data, byte[] publicKey, int keySize, String transformation) {
try {
return ConvertUtils.bytesToHexString(handle(data.getBytes(CHARSET), publicKey, keySize,
transformation, true));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 加密,输出十六进制字符串密文
*
* @param data 明文
* @param publicKey 公钥(Base64字符串)
* @param keySize 公钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @return 密文
*/
public static String encryptHex(String data, String publicKey, int keySize, String transformation) {
try {
return ConvertUtils.bytesToHexString(handle(data.getBytes(CHARSET),
Base64.decode(publicKey, Base64.NO_WRAP), keySize, transformation, true));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解密,密文为Base64字符串
*
* @param data 密文
* @param privateKey 私钥
* @param keySize 私钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @return 明文
*/
public static String decryptBase64(String data, byte[] privateKey, int keySize, String transformation) {
try {
return new String(handle(Base64.decode(data, Base64.NO_WRAP), privateKey, keySize,
transformation, false), CHARSET);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解密,密文为Base64字符串
*
* @param data 密文
* @param privateKey 私钥(Base64字符串)
* @param keySize 私钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @return 明文
*/
public static String decryptBase64(String data, String privateKey, int keySize, String transformation) {
try {
return new String(handle(Base64.decode(data, Base64.NO_WRAP), Base64.decode(privateKey, Base64.NO_WRAP),
keySize, transformation, false), CHARSET);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解密,密文为十六进制字符串
*
* @param data 密文
* @param privateKey 私钥
* @param keySize 私钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @return 明文
*/
public static String decryptHex(String data, byte[] privateKey, int keySize, String transformation) {
try {
return new String(handle(ConvertUtils.hexStringToBytes(data), privateKey, keySize, transformation, false), CHARSET);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解密,密文为十六进制字符串
*
* @param data 密文
* @param privateKey 私钥(Base64字符串)
* @param keySize 私钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @return 明文
*/
public static String decryptHex(String data, String privateKey, int keySize, String transformation) {
try {
return new String(handle(ConvertUtils.hexStringToBytes(data), Base64.decode(privateKey, Base64.NO_WRAP),
keySize, transformation, false), CHARSET);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 处理数据,加密或解密
*
* @param data 数据
* @param key 密钥
* @param keySize 密钥大小,举例:1024, 2048...
* @param transformation 类型,格式为:加密算法/加密模式/填充方式,举例:<i>RSA/None/PKCS1Padding</i>。<br/>
* 相关取值可以查看下列两个文档:
* <ul>
* <li><a href="https://docs.oracle.com/javase/8/docs/api">JavaSE 8 API</a>
* 中的 javax.crypto.Cipher</li>
* <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
* Standard Algorithm Name Documentation</a></li>
* </ul>
* @param isEncrypt 如果是加密,则为true;如果为解密,则为false
* @return 加密后或解密后的字节数组
* @throws Exception 异常
*/
private static byte[] handle(byte[] data, byte[] key, int keySize, String transformation,
boolean isEncrypt) throws Exception {
Key rsaKey;
if (isEncrypt) {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
rsaKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);
} else {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key);
rsaKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
}
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(isEncrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, rsaKey);
int len = data.length;
int maxLen = keySize / 8;
if (isEncrypt) {
String lowerTrans = transformation.toLowerCase();
if (lowerTrans.endsWith("pkcs1padding")) {
maxLen -= 11;
}
}
int count = len / maxLen;
if (count > 0) {
byte[] ret = new byte[0];
byte[] buff = new byte[maxLen];
int index = 0;
for (int i = 0; i < count; i++) {
System.arraycopy(data, index, buff, 0, maxLen);
ret = joins(ret, cipher.doFinal(buff));
index += maxLen;
}
if (index != len) {
int restLen = len - index;
buff = new byte[restLen];
System.arraycopy(data, index, buff, 0, restLen);
ret = joins(ret, cipher.doFinal(buff));
}
return ret;
} else {
return cipher.doFinal(data);
}
}
/**
* 合并两个字节数组
*
* @param prefix 前一个字节数组
* @param suffix 后一个字节数组
* @return 字节数组
*/
private static byte[] joins(byte[] prefix, byte[] suffix) {
byte[] ret = new byte[prefix.length + suffix.length];
System.arraycopy(prefix, 0, ret, 0, prefix.length);
System.arraycopy(suffix, 0, ret, prefix.length, suffix.length);
return ret;
}
}
3. 使用方式
举例:使用"RSA/None/PKCS1Padding"模式,公钥和密钥都是Base64字符串,密钥长度为1024,输出的密文为Base64字符串。 对于Android,RSA/ECB/PKCS1padding 和 RSA/None/PKCS1Padding 等效。
// 对于Android,RSA/ECB/PKCS1padding 和 RSA/None/PKCS1Padding 等效
//String transformation = "RSA/ECB/PKCS1padding";
String transformation = "RSA/None/PKCS1Padding";
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhSzPPnFn41iaz+t4tI4kbaXNuNFOsI8hFeCYtlwPFKRbETHbBS10bMvUbOWLFtRgZV3L924GQ9orbomEmJ1nWyaSO8iBbZAyiWUP5PJJh/b9kHj1MMwG712bGfYYPdjkRprNpzU9w4UBzUMKKUoHU4c/Gbb4XeBK9LNTPWQL4YwIDAQAB";
String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOFLM8+cWfjWJrP63i0jiRtpc240U6wjyEV4Ji2XA8UpFsRMdsFLXRsy9Rs5YsW1GBlXcv3bgZD2ituiYSYnWdbJpI7yIFtkDKJZQ/k8kmH9v2QePUwzAbvXZsZ9hg92ORGms2nNT3DhQHNQwopSgdThz8Ztvhd4Er0s1M9ZAvhjAgMBAAECgYEAxwNLTUXsJGfn4Gzm/jC52MEZ+mu2zgT90IAGGZeg+PUG63gwHyeXo4MsCVRz7/m8xAX/ykew+IEQwFt8Pdvc+rrs5yml4gOBPfhpau5QaI75xNjnyH7UA3mbRCZeyZrvuKqtY/f8pCgzy3EBWnRpkcsqeE6bsOQrD45mltr+0QECQQDynvhKEh+hD5xBpF/DIP8Fp6fizexHdA6+aZT/gLaFA4XgZ9HEDDBhvNdadyYUNOLWhkxRHv6CkT5azfLXsJEhAkEA7begtbBCDXDf1+DRh3j2S8zcv6+utYgcpjvxZqjbPi6UIWXLxI80PIwQ0uouHCUMjikBA6VX9vTbw9TZ/IelAwJBAKI3W7baiz86mrTg3A4w/5GeWQexuurDVCBHo5F5U493nYk+oOe9ZpPSmQIpa9JS0d+xB1GtsWlHBzPbQySnL0ECQACjqvT1QTl6EbPXwp92eqQtQmQMbNW4RiaUjlpyrVs5zkAho1T9EyMqJPNI71n6VVa/8k8WxyAdkZ7ZlBikCQEkNe1+sAKnh+AFGCJ+6WAq1J2RuIgcA6bVL3ip7F2NHdE+N+tR9JqWw3JNCweWmAlzKIGs6eKSVD5egzKaLXss=";
String data = "blogDemo123"; // 待加密的数据
// 公钥加密,输出Base64字符串
String result1 = RSAUtils.encryptBase64(data, publicKey, 1024, transformation);;
// 私钥解密
String result2 = RSAUtils.decryptBase64(result1, privateKey, 1024, transformation);
想看更多例子可以到我的GitHub上面看看BlogDemo。
如果想进一步交流和学习的同学,可以加一下QQ群哦!