RSA算法是一种非对称加密算法,所谓非对称就是该算法需要一对密钥,若使用其中一个加密,则需要用另一个才能解密。目前它是最有影响力和最常用的公钥加密算法,能够抵抗已知的绝大多数密码攻击。从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。
该算法基于一个的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。由于进行的都是大数计算,RSA 最快的情况也比 DES 慢上好几倍,比对应同样安全级别的对称密码算法要慢 1000 倍左右。所以 RSA 一般只用于少量数据加密,比如说交换对称加密的密钥。
使用 RSA 加密主要有这么几步:生成密钥对、公开公钥、公钥加密私钥解密、私钥加密公钥解密。
示例代码:
import com.sun.org.apache.xml.internal.security.utils.Base64;import javax.crypto.Cipher;import org.apache.commons.io.FileUtils;import java.io.ByteArrayOutputStream;import java.io.File;import java.nio.charset.Charset;import java.security.*;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;public class RsaUtil {/*** 生成密钥对并保存在本地文件中** @param algorithm : 算法* @param pubPath : 公钥保存路径* @param priPath : 私钥保存路径* @throws Exception*/private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {// 获取密钥对生成器KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);// 获取密钥对KeyPair keyPair = keyPairGenerator.generateKeyPair();// 获取公钥PublicKey publicKey = keyPair.getPublic();// 获取私钥PrivateKey privateKey = keyPair.getPrivate();// 获取byte数组byte[] publicKeyEncoded = publicKey.getEncoded();byte[] privateKeyEncoded = privateKey.getEncoded();// 进行Base64编码String publicKeyString = Base64.encode(publicKeyEncoded);String privateKeyString = Base64.encode(privateKeyEncoded);// 保存文件FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));}/*** 从文件中加载公钥** @param algorithm : 算法* @param filePath : 文件路径* @return : 公钥* @throws Exception*/private static PublicKey loadPublicKeyFromFile(String algorithm, String filePath) throws Exception {// 将文件内容转为字符串String keyString = FileUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));return loadPublicKeyFromString(algorithm, keyString);}/*** 从字符串中加载公钥** @param algorithm : 算法* @param keyString : 公钥字符串* @return : 公钥* @throws Exception*/private static PublicKey loadPublicKeyFromString(String algorithm, String keyString) throws Exception {// 进行Base64解码byte[] decode = Base64.decode(keyString);// 获取密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(algorithm);// 构建密钥规范X509EncodedKeySpec keyspec = new X509EncodedKeySpec(decode);// 获取公钥return keyFactory.generatePublic(keyspec);}/*** 从文件中加载私钥** @param algorithm : 算法* @param filePath : 文件路径* @return : 私钥* @throws Exception*/private static PrivateKey loadPrivateKeyFromFile(String algorithm, String filePath) throws Exception {// 将文件内容转为字符串String keyString = FileUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));return loadPrivateKeyFromString(algorithm, keyString);}/*** 从字符串中加载私钥** @param algorithm : 算法* @param keyString : 私钥字符串* @return : 私钥* @throws Exception*/private static PrivateKey loadPrivateKeyFromString(String algorithm, String keyString) throws Exception {// 进行Base64解码byte[] decode = Base64.decode(keyString);// 获取密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(algorithm);// 构建密钥规范PKCS8EncodedKeySpec keyspec = new PKCS8EncodedKeySpec(decode);// 生成私钥return keyFactory.generatePrivate(keyspec);}/*** 使用密钥加密数据** @param algorithm : 算法* @param input : 原文* @param key : 密钥* @param maxEncryptSize : 最大加密长度(需要根据实际情况进行调整)* @return : 密文* @throws Exception*/private static String encrypt(String algorithm, String input, Key key, int maxEncryptSize) throws Exception {// 获取Cipher对象Cipher cipher = Cipher.getInstance(algorithm);// 初始化模式(加密)和密钥cipher.init(Cipher.ENCRYPT_MODE, key);// 将原文转为byte数组byte[] data = input.getBytes();// 总数据长度int total = data.length;// 输出流ByteArrayOutputStream baos = new ByteArrayOutputStream();decodeByte(maxEncryptSize, cipher, data, total, baos);// 对密文进行Base64编码return Base64.encode(baos.toByteArray());}/*** 解密数据** @param algorithm : 算法* @param encrypted : 密文* @param key : 密钥* @param maxDecryptSize : 最大解密长度(需要根据实际情况进行调整)* @return : 原文* @throws Exception*/private static String decrypt(String algorithm, String encrypted, Key key, int maxDecryptSize) throws Exception {// 获取Cipher对象Cipher cipher = Cipher.getInstance(algorithm);// 初始化模式(解密)和密钥cipher.init(Cipher.DECRYPT_MODE, key);// 由于密文进行了Base64编码, 在这里需要进行解码byte[] data = Base64.decode(encrypted);// 总数据长度int total = data.length;// 输出流ByteArrayOutputStream baos = new ByteArrayOutputStream();decodeByte(maxDecryptSize, cipher, data, total, baos);// 输出原文return baos.toString();}/*** 分段处理数据** @param maxSize : 最大处理能力* @param cipher : Cipher对象* @param data : 要处理的byte数组* @param total : 总数据长度* @param baos : 输出流* @throws Exception*/private static void decodeByte(int maxSize, Cipher cipher, byte[] data, int total, ByteArrayOutputStream baos) throws Exception {// 偏移量int offset = 0;// 缓冲区byte[] buffer;// 如果数据没有处理完, 就一直继续while (total - offset > 0) {// 如果剩余的数据 >= 最大处理能力, 就按照最大处理能力来加密数据if (total - offset >= maxSize) {// 加密数据buffer = cipher.doFinal(data, offset, maxSize);// 偏移量向右侧偏移最大数据能力个offset += maxSize;} else {// 如果剩余的数据 < 最大处理能力, 就按照剩余的个数来加密数据buffer = cipher.doFinal(data, offset, total - offset);// 偏移量设置为总数据长度, 这样可以跳出循环offset = total;}// 向输出流写入数据baos.write(buffer);}}}
