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羣哦!