RSA 工具包

这是一个Java实现的RSA加密工具类,包含公钥私钥的生成、转换以及加密解密功能。支持字符串与Base64编码的密钥转换,详细介绍了加密解密的分段处理以及密钥长度的选择。同时提供了公钥加密、私钥解密以及签名验证的方法。
摘要由CSDN通过智能技术生成

博文目录

文章目录


JDK Version: Oracle JDK 1.8.0_202

package com.mrathena.toolkit;

import javax.crypto.Cipher;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * RSA 加密工具
 * <p>
 * 公钥加密/私钥加密/公钥解密/私钥解密
 * 私钥签名/公钥验签
 * 密钥生成/密钥转换
 * <p>
 * 注意: JAVA 生成的私钥是 PKCS8 格式, 公钥是 X.509 格式
 * <p>
 * 业内规范: 字符串格式的 密钥/密文/签名 等默认都使用 BASE64 编码
 * <p>
 * Java Cryptography Architecture
 * Standard Algorithm Name Documentation for JDK 8
 * Java密码体系结构 JDK 8的标准算法名称文档
 * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
 * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator
 * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyFactory
 * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#algspec
 * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher
 * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Signature
 * <p>
 * 参考
 * java RSA加密解密实现(含分段加密)
 * https://www.cnblogs.com/jiafuwei/p/7054500.html
 * JDK安全模块JCE核心Cipher使用详解
 * https://blog.csdn.net/zcmain/article/details/90640797
 * 加密与安全:非对称加密算法 RSA 1024 公钥、秘钥、明文和密文长度
 * https://blog.csdn.net/liwei16611/article/details/83751851
 */
public final class RSAKit {

	private RSAKit() {}

	/**
	 * UTF-8编码
	 */
	private static final Charset UTF8 = StandardCharsets.UTF_8;
	/**
	 * 加密算法
	 */
	private static final String ALGORITHM = "RSA";
	/**
	 * 单例 KeyFactory, 用于转换字符串公私钥到标准公私钥
	 */
	private static volatile KeyFactory instance;
	/**
	 * 密钥长度(位),RSA密钥长度必须是8的倍数且必须大于等于512,建议1024起步(1024以下已有破解先例)
	 */
	public enum KeySizeEnum {
		BIT_1024(1024),
		BIT_2048(2048),
		BIT_4096(4096);
		KeySizeEnum(int length) {
			this.length = length;
		}
		private final int length;
		public int getLength() {
			return this.length;
		}
	}

	// 以下是密钥相关方法 ---------- ---------- ---------- ---------- ----------

	/**
	 * 生成公私钥对
	 *
	 * @param keySize 密钥长度,RSA密钥长度必须是8的倍数且必须大于等于512,建议1024起步(1024以下已有破解先例)
	 */
	public static KeyPair generateKeyPair(KeySizeEnum keySize) {
		try {
			KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
			keyPairGenerator.initialize(keySize.getLength());
			return keyPairGenerator.generateKeyPair();
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	/**
	 * 生成公私钥对(1024位)
	 */
	public static KeyPair generateKeyPair() {
		return generateKeyPair(KeySizeEnum.BIT_1024);
	}

	/**
	 * 单例获取 KeyFactory
	 */
	private static KeyFactory getKeyFactory() {
		try {
			if (null == instance) {
				synchronized (RSAKit.class) {
					if (null == instance) {
						instance = KeyFactory.getInstance(ALGORITHM);
					}
				}
			}
			return instance;
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	/**
	 * 字符串公钥转标准公钥
	 */
	public static PublicKey toPublicKey(String publicKeyStr) {
		try {
			return getKeyFactory().generatePublic(new X509EncodedKeySpec(decode(publicKeyStr)));
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	/**
	 * 字符串私钥转标准私钥
	 */
	public static PrivateKey toPrivateKey(String privateKeyStr) {
		try {
			return getKeyFactory().generatePrivate(new PKCS8EncodedKeySpec(decode(privateKeyStr)));
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	/**
	 * 标准密钥转字符串密钥
	 */
	public static String toKeyStr(Key key) {
		return encode(key.getEncoded());
	}

	// 以下是密钥加密解密通用依赖方法 ---------- ---------- ---------- ---------- ----------

	/**
	 * 密钥加密
	 * <p>
	 * RSA加密时最大分段长度
	 * 512  - 512/8-11=64-11=53
	 * 1024 - 1024/8-11=128-11=117
	 * 2048 - 2048/8-11=256-11=245
	 * 4096 - 4096/8-11=512-11=501
	 * 加密时,最大分段长度,是密钥长度的八分之一减十一,加密分段你长度有一个可选范围
	 * 1024可以使用117,2048也可以使用117,但最大可使用245,4096也可以使用117,但最大可使用501
	 */
	private static byte[] encryptByKey(Key key, byte[] data) {
		try {
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE, key);
			return segmentedDoFinal(cipher, getBlockLength(key) / 8 - 11, data);
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	/**
	 * 密钥解密
	 * <p>
	 * RSA解密时分段长度
	 * 512  - 512/8=64
	 * 1024 - 1024/8=128
	 * 2048 - 2048/8=256
	 * 4096 - 4096/8=512
	 * 这个长度是固定的,正好是密钥长度的八分之一,不像加密时是一个范围
	 */
	private static byte[] decryptByKey(Key key, byte[] data) {
		try {
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, key);
			return segmentedDoFinal(cipher, getBlockLength(key) / 8, data);
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	/**
	 * 获取加解密基础分段长度
	 */
	private static int getBlockLength(Key key) {
		try {
			if (key instanceof PublicKey) {
				// 获取公钥长度(位)
				return getKeyFactory().getKeySpec(key, RSAPublicKeySpec.class).getModulus().toString(2).length();
			} else {
				// 获取私钥长度(位)
				return getKeyFactory().getKeySpec(key, RSAPrivateKeySpec.class).getModulus().toString(2).length();
			}
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	/**
	 * 加密解密流程
	 * 加密过程使用二维数组存储分块加密结果,最终转换为一维数组存储完整加密结果
	 * 也可使用ByteArrayOutputStream的write()方法把分块解密结果写到流,toByteArray()方法转换称为完成加密结果
	 *
	 * @param data           数据
	 * @param cipher         密码器
	 * @param maxBlockLength 加密/解密块大小, 加密117, 解密128
	 * @return 加密/解密结果
	 */
	private static byte[] segmentedDoFinal(Cipher cipher, int maxBlockLength, byte[] data) {
		try {
			int lines = data.length % maxBlockLength == 0 ? data.length / maxBlockLength : data.length / maxBlockLength + 1;
			byte[][] tempArray = new byte[lines][];
			for (int i = 0; i < lines; i++) {
				int offset = i * maxBlockLength;
				tempArray[i] = cipher.doFinal(data, offset, i == lines - 1 ? data.length - offset : maxBlockLength);
			}
			int tempArrayTotalLength = 0;
			for (byte[] bytes : tempArray) {
				tempArrayTotalLength = tempArrayTotalLength + bytes.length;
			}
			byte[] targetArray = new byte[tempArrayTotalLength];
			int index = 0;
			for (byte[] byteArray : tempArray) {
				for (byte aByte : byteArray) {
					targetArray[index] = aByte;
					index++;
				}
			}
			return targetArray;
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	// 以下是公钥加密相关方法 ---------- ---------- ---------- ---------- ----------

	/**
	 * 公钥加密
	 */
	public static byte[] encryptByPublicKey(PublicKey publicKey, byte[] data) {
		return encryptByKey(publicKey, data);
	}

	/**
	 * 公钥加密
	 */
	public static byte[] encryptByPublicKey(PublicKey publicKey, String data) {
		return encryptByKey(publicKey, data.getBytes(UTF8));
	}

	/**
	 * 公钥加密
	 */
	public static byte[] encryptByPublicKeyStr(String publicKeyStr, byte[] data) {
		return encryptByKey(toPublicKey(publicKeyStr), data);
	}

	/**
	 * 公钥加密
	 */
	public static byte[] encryptByPublicKeyStr(String publicKeyStr, String data) {
		return encryptByKey(toPublicKey(publicKeyStr), data.getBytes(UTF8));
	}

	/**
	 * 公钥加密
	 */
	public static String encryptToStrByPublicKey(PublicKey publicKey, byte[] data) {
		return encode(encryptByKey(publicKey, data));
	}

	/**
	 * 公钥加密
	 */
	public static String encryptToStrByPublicKey(PublicKey publicKey, String data) {
		return encode(encryptByKey(publicKey, data.getBytes(UTF8)));
	}

	/**
	 * 公钥加密
	 */
	public static String encryptToStrByPublicKeyStr(String publicKeyStr, byte[] data) {
		return encode(encryptByKey(toPublicKey(publicKeyStr), data));
	}

	/**
	 * 公钥加密
	 */
	public static String encryptToStrByPublicKeyStr(String publicKeyStr, String data) {
		return encode(encryptByKey(toPublicKey(publicKeyStr), data.getBytes(UTF8)));
	}

	// 以下是公钥解密相关方法 ---------- ---------- ---------- ---------- ----------

	/**
	 * 公钥解密
	 */
	public static byte[] decryptByPublicKey(PublicKey publicKey, byte[] data) {
		return decryptByKey(publicKey, data);
	}

	/**
	 * 公钥解密
	 */
	public static byte[] decryptByPublicKey(PublicKey publicKey, String data) {
		return decryptByKey(publicKey, decode(data));
	}

	/**
	 * 公钥解密
	 */
	public static byte[] decryptByPublicKeyStr(String publicKeyStr, byte[] data) {
		return decryptByKey(toPublicKey(publicKeyStr), data);
	}

	/**
	 * 公钥解密
	 */
	public static byte[] decryptByPublicKeyStr(String publicKeyStr, String data) {
		return decryptByKey(toPublicKey(publicKeyStr), decode(data));
	}

	/**
	 * 公钥解密
	 */
	public static String decryptToStrByPublicKey(PublicKey publicKey, byte[] data) {
		return new String(decryptByKey(publicKey, data), UTF8);
	}

	/**
	 * 公钥解密
	 */
	public static String decryptToStrByPublicKey(PublicKey publicKey, String data) {
		return new String(decryptByKey(publicKey, decode(data)), UTF8);
	}

	/**
	 * 公钥解密
	 */
	public static String decryptToStrByPublicKeyStr(String publicKeyStr, byte[] data) {
		return new String(decryptByKey(toPublicKey(publicKeyStr), data), UTF8);
	}

	/**
	 * 公钥解密
	 */
	public static String decryptToStrByPublicKeyStr(String publicKeyStr, String data) {
		return new String(decryptByKey(toPublicKey(publicKeyStr), decode(data)), UTF8);
	}

	// 以下是私钥加密相关方法 ---------- ---------- ---------- ---------- ----------

	/**
	 * 私钥加密
	 */
	public static byte[] encryptByPrivateKey(PrivateKey privateKey, byte[] data) {
		return encryptByKey(privateKey, data);
	}

	/**
	 * 私钥加密
	 */
	public static byte[] encryptByPrivateKey(PrivateKey privateKey, String data) {
		return encryptByKey(privateKey, data.getBytes(UTF8));
	}

	/**
	 * 私钥加密
	 */
	public static byte[] encryptByPrivateKeyStr(String privateKeyStr, byte[] data) {
		return encryptByKey(toPrivateKey(privateKeyStr), data);
	}

	/**
	 * 私钥加密
	 */
	public static byte[] encryptByPrivateKeyStr(String privateKeyStr, String data) {
		return encryptByKey(toPrivateKey(privateKeyStr), data.getBytes(UTF8));
	}

	/**
	 * 私钥加密
	 */
	public static String encryptToStrByPrivateKey(PrivateKey privateKey, byte[] data) {
		return encode(encryptByKey(privateKey, data));
	}

	/**
	 * 私钥加密
	 */
	public static String encryptToStrByPrivateKey(PrivateKey privateKey, String data) {
		return encode(encryptByKey(privateKey, data.getBytes(UTF8)));
	}

	/**
	 * 私钥加密
	 */
	public static String encryptToStrByPrivateKeyStr(String privateKeyStr, byte[] data) {
		return encode(encryptByKey(toPrivateKey(privateKeyStr), data));
	}

	/**
	 * 私钥加密
	 */
	public static String encryptToStrByPrivateKeyStr(String privateKeyStr, String data) {
		return encode(encryptByKey(toPrivateKey(privateKeyStr), data.getBytes(UTF8)));
	}

	// 以下是私钥解密相关方法 ---------- ---------- ---------- ---------- ----------

	/**
	 * 私钥解密
	 */
	public static byte[] decryptByPrivateKey(PrivateKey privateKey, byte[] data) {
		return decryptByKey(privateKey, data);
	}

	/**
	 * 私钥解密
	 */
	public static byte[] decryptByPrivateKey(PrivateKey privateKey, String data) {
		return decryptByKey(privateKey, decode(data));
	}

	/**
	 * 私钥解密
	 */
	public static byte[] decryptByPrivateKeyStr(String privateKeyStr, byte[] data) {
		return decryptByKey(toPrivateKey(privateKeyStr), data);
	}

	/**
	 * 私钥解密
	 */
	public static byte[] decryptByPrivateKeyStr(String privateKeyStr, String data) {
		return decryptByKey(toPrivateKey(privateKeyStr), decode(data));
	}

	/**
	 * 私钥解密
	 */
	public static String decryptToStrByPrivateKey(PrivateKey privateKey, byte[] data) {
		return new String(decryptByKey(privateKey, data), UTF8);
	}

	/**
	 * 私钥解密
	 */
	public static String decryptToStrByPrivateKey(PrivateKey privateKey, String data) {
		return new String(decryptByKey(privateKey, decode(data)), UTF8);
	}

	/**
	 * 私钥解密
	 */
	public static String decryptToStrByPrivateKeyStr(String privateKeyStr, byte[] data) {
		return new String(decryptByKey(toPrivateKey(privateKeyStr), data), UTF8);
	}

	/**
	 * 私钥解密
	 */
	public static String decryptToStrByPrivateKeyStr(String privateKeyStr, String data) {
		return new String(decryptByKey(toPrivateKey(privateKeyStr), decode(data)), UTF8);
	}

	// 以下是私钥签名相关方法 ---------- ---------- ---------- ---------- ----------

	/**
	 * 私钥签名
	 *
	 * @param privateKey 私钥
	 * @param algorithm  签名算法,NONEwithRSA,MD2withRSA,MD5withRSA,SHA1withRSA,SHA224withRSA,SHA256withRSA,SHA384withRSA,SHA512withRSA,SHA512/224withRSA,SHA512/256withRSA
	 * @param data       待签名数据
	 */
	private static byte[] sign(PrivateKey privateKey, String algorithm, byte[] data) {
		try {
			Signature signature = Signature.getInstance(algorithm);
			signature.initSign(privateKey);
			signature.update(data);
			return signature.sign();
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	/**
	 * 私钥签名
	 */
	public static String signToStr(PrivateKey privateKey, String algorithm, byte[] data) {
		return encode(sign(privateKey, algorithm, data));
	}

	/**
	 * 私钥签名
	 */
	public static String signToStr(String privateKeyStr, String algorithm, byte[] data) {
		return encode(sign(toPrivateKey(privateKeyStr), algorithm, data));
	}

	/**
	 * 私钥签名
	 */
	public static String signToStr(PrivateKey privateKey, String algorithm, String data) {
		return encode(sign(privateKey, algorithm, data.getBytes(UTF8)));
	}

	/**
	 * 私钥签名
	 */
	public static String signToStr(String privateKeyStr, String algorithm, String data) {
		return encode(sign(toPrivateKey(privateKeyStr), algorithm, data.getBytes(UTF8)));
	}

	// 以下是公钥验签相关方法 ---------- ---------- ---------- ---------- ----------

	public static boolean verify(PublicKey publicKey, String algorithm, byte[] data, String sign) {
		try {
			Signature signature = Signature.getInstance(algorithm);
			signature.initVerify(publicKey);
			signature.update(data);
			return signature.verify(decode(sign));
		} catch (Throwable cause) {
			throw new RuntimeException(cause);
		}
	}

	public static boolean verify(String publicKeyStr, String algorithm, byte[] data, String sign) {
		return verify(toPublicKey(publicKeyStr), algorithm, data, sign);
	}

	public static boolean verify(PublicKey publicKey, String algorithm, String data, String sign) {
		return verify(publicKey, algorithm, data.getBytes(UTF8), sign);
	}

	public static boolean verify(String publicKeyStr, String algorithm, String data, String sign) {
		return verify(toPublicKey(publicKeyStr), algorithm, data.getBytes(UTF8), sign);
	}

	/**
	 * 编码
	 */
	private static String encode(byte[] data) {
		return Base64.getEncoder().encodeToString(data);
	}

	/**
	 * 解码
	 */
	private static byte[] decode(String data) {
		return Base64.getDecoder().decode(data);
	}

	public static void main(String[] args) {
        /*
        // 公私钥生成方式
        KeyPair keyPair = RSAKit.generateKeyPair();
        System.out.println(RSAKit.toKeyStr(keyPair.getPublic()));
        System.out.println(RSAKit.toKeyStr(keyPair.getPrivate()));
        // 生成的公私钥
        MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC73t3jWrk6qHZ8XO40nxg7QiFCYbjt0W85fuQvIBHFHWcn873c7GR7kucpQ/VwO9XrydB2SvhD+rjitnHTNkpPMC+euizl6wSLvhClPB4KBRYCG33ive91TedkHr8S/7FlNjT/+G1PORV7lyC1t1Rs/Mt/IGRun8081nqhjh+NLwIDAQAB
        MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALve3eNauTqodnxc7jSfGDtCIUJhuO3Rbzl+5C8gEcUdZyfzvdzsZHuS5ylD9XA71evJ0HZK+EP6uOK2cdM2Sk8wL566LOXrBIu+EKU8HgoFFgIbfeK973VN52QevxL/sWU2NP/4bU85FXuXILW3VGz8y38gZG6fzTzWeqGOH40vAgMBAAECgYA27XUgWNEZJlHmEGGQvwcdpDsHJn0kAvyq6b+bS5wGbo9PbgMPyYmjW5L8TKNA2i20T4AEZezqKy7NEhx7bT8SIO90TE2Txb7PjhAmF1qY0XRIRC23adAd4naSZakggF3FESQu5C+FAJh8qfuNChlPdKEwtpQtUIJTSvL8jh/PGQJBAPVbWC8mbo5XKfsupD2v96erdWFHg71M2uXoIAEtaUOjG/1Dxu8FB6D9F5JW+JJdIPKZ7mFiLH0V5WTH2SDWat0CQQDEBSUhu6jzp/rw1VzhZt4+udI1hDOIpqs0uhZhJxIuH7c0/2JsLQKV83jlFK1sfkipEVXbM20iQN0SaGKUGzl7AkBgUBEXwSBY48JpBXAXfwHaYaXcH/SI1KiA41Pc4nSVxmtwSbDHltPd0Dv2iAlfews58E7xD1aja3r2yrRi/YhJAkAeMaixlIWG2rY1yLfg5IaRZPAzXCTQBNRUb+Gon2sWfb4rxLb1cM14KaPSrae1EZLBsDDobfh+kT08a6XbqIHnAkB1YLletXrz49gMQsgDwAsWd4/Qs3o9laTEh738K6HWxIEIJuwjZCvpKkCLP/D4oZN2LsmScogeUH12gCzMsQm6
        */

        /*
        // 前端使用后端生成的公私钥对中的公钥加密数据, 后端用私钥解密数据, 验证没有问题
        // 前端加密代码
<script type="text/javascript" src="https://passport.cnblogs.com/scripts/jsencrypt.min.js"></script>

var encrypt = new JSEncrypt();
encrypt.setPublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC73t3jWrk6qHZ8XO40nxg7QiFCYbjt0W85fuQvIBHFHWcn873c7GR7kucpQ/VwO9XrydB2SvhD+rjitnHTNkpPMC+euizl6wSLvhClPB4KBRYCG33ive91TedkHr8S/7FlNjT/+G1PORV7lyC1t1Rs/Mt/IGRun8081nqhjh+NLwIDAQAB");
var encryptData = encrypt.encrypt("mrathena");
console.log(encryptData)

        // 前端加密后的数据
F0mE9RaXIWDbGuzU2XPuzlIdx6Nm81PdmMfUfPjzPdxbuHBWTKo3yp9QAqwoYy1l49NBQle9/Dx5a0pvTmEU0gAPc0+kyhhdnOyizq5tQxG37ieB0rTUwvxdue5qteuwLMcpbI0CLSEFYGgny3L87aoTfBKjffc4FKqleJShFk8=
        */

		// 后端验证解密
		String data = "F0mE9RaXIWDbGuzU2XPuzlIdx6Nm81PdmMfUfPjzPdxbuHBWTKo3yp9QAqwoYy1l49NBQle9/Dx5a0pvTmEU0gAPc0+kyhhdnOyizq5tQxG37ieB0rTUwvxdue5qteuwLMcpbI0CLSEFYGgny3L87aoTfBKjffc4FKqleJShFk8=";
		String privateKeyStr = "xxxxxxx";

		System.out.println(RSAKit.decryptToStrByPrivateKeyStr(privateKeyStr, data));
	}

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值