JAVA使用RSA加密数据

密钥生成

1、 AES密钥生成:可以随机生成,用于AES加密,长度为16位,可以用26个字母和数字组成。

2、 RSA公私钥生成:

openssl genrsa -out rsa_private_key_2048.pem 2048 #生成rsa私钥,以X509编码,指定生成的密钥的位数: 2048(注:该步骤生成的私钥只为供第二步使用,并无实际用处)

openssl pkcs8 -topk8 -in rsa_private_key_2048.pem -out pkcs8_rsa_private_key_2048.pem -nocrypt #将上一步生成的rsa私钥转换成PKCS#8编码(注:该步骤生成的私钥构成实际密钥对的私钥)

openssl rsa -in rsa_private_key_2048.pem -out rsa_public_key_2048.pem -pubout #导出rsa公钥,以X509编码(注:该步骤生成的公钥构成实际密钥对的公钥)

其中openssl安装比较麻烦的,我就直接使用了二进制的exe。下载地址:http://gnuwin32.sourceforge.net/packages/openssl.htm

2 java中使用生成的公钥和私钥

产生的公私钥,其实是两个含有字符的文件,在Java中使用使用之前肯定需要转换成java.security.PrivateKey和java.security.PublicKey;

2.1 先以字符的形式读入:

InputStream is =CmbcTest.class.getClassLoader().getResourceAsStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
	String readLine = null;
	while ((readLine = br.readLine()) != null) {
		sb.append(readLine);
		sb.append('\r');
			}

2.2 转化为java对象:

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(Base64.decodeBase64(sb.toString()));
pubKey = keyFactory.generatePublic(pubX509);
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(sb.toString()));
priKey = keyFactory.generatePrivate(priPKCS8);

 2.3 使用RSA加解密(由于本人对于密码学的内部机制不熟,就从网上down了一下,仅供参考) 

public abstract class CryptoUtil {
	
    private static final String AES_ALG = "AES";
    /**
     * AES算法
     */
    private static final String AES_ECB_PCK_ALG = "AES/ECB/PKCS5Padding";
	/**
	 * 数字签名函数入口
	 * 
	 * @param plainBytes
	 *            待签名明文字节数组
	 * @param privateKey
	 *            签名使用私钥
	 * @param signAlgorithm
	 *            签名算法
	 * @return 签名后的字节数组
	 */
	public static String digitalSign(String content, PrivateKey privateKey, String signAlgorithm, String charset) throws Exception {
		Signature signature = Signature.getInstance(signAlgorithm);
		signature.initSign(privateKey);
		signature.update(content.getBytes(charset));
		return new String(Base64.encodeBase64(signature.sign()), charset);
	}

	/**
	 * 验证数字签名函数入口
	 * 
	 * @param plainBytes
	 *            待验签明文字节数组
	 * @param signBytes
	 *            待验签签名后字节数组
	 * @param publicKey
	 *            验签使用公钥
	 * @param signAlgorithm
	 *            签名算法
	 * @return 验签是否通过
	 */
	public static boolean verifyDigitalSign(byte[] plainBytes, String sign, PublicKey publicKey, String signAlgorithm, String charset) throws Exception {
		byte[] signBytes = Base64.decodeBase64(sign.getBytes(charset));
		Signature signature = Signature.getInstance(signAlgorithm);
		signature.initVerify(publicKey);
		signature.update(plainBytes);
		return signature.verify(signBytes);
	}

	/**
	 * RSA加密
	 * 
	 * @param plainBytes
	 *            明文字节数组
	 * @param publicKey
	 *            公钥
	 * @param keyLength
	 *            密钥bit长度
	 * @param reserveSize
	 *            padding填充字节数,预留11字节
	 * @param cipherAlgorithm
	 *            加解密算法,一般为RSA/ECB/PKCS1Padding
	 * @return 加密后字节数组,不经base64编码
	 */
	public static String RSAEncrypt(String key, PublicKey publicKey, int keyLength, int reserveSize, String cipherAlgorithm, String charset) throws Exception {
		byte[] plainBytes = key.getBytes(charset);
		int keyByteSize = keyLength / 8; // 密钥字节数
		int encryptBlockSize = keyByteSize - reserveSize; // 加密块大小=密钥字节数-padding填充字节数
		int nBlock = plainBytes.length / encryptBlockSize;// 计算分段加密的block数,向上取整
		if ((plainBytes.length % encryptBlockSize) != 0) { // 余数非0,block数再加1
			nBlock += 1;
		}

		Cipher cipher = Cipher.getInstance(cipherAlgorithm);
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		
		// 输出buffer,大小为nBlock个keyByteSize
		ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * keyByteSize);
		// 分段加密
		for (int offset = 0; offset < plainBytes.length; offset += encryptBlockSize) {
			int inputLen = plainBytes.length - offset;
			if (inputLen > encryptBlockSize) {
				inputLen = encryptBlockSize;
			}
			
			// 得到分段加密结果
			byte[] encryptedBlock = cipher.doFinal(plainBytes, offset, inputLen);
			// 追加结果到输出buffer中
			outbuf.write(encryptedBlock);
		}
		
		outbuf.flush();
		outbuf.close();
		return new String(Base64.encodeBase64(outbuf.toByteArray()), charset);
	}

	/**
	 * RSA解密
	 * 
	 * @param encryptedBytes
	 *            加密后字节数组
	 * @param privateKey
	 *            私钥
	 * @param keyLength
	 *            密钥bit长度
	 * @param reserveSize
	 *            padding填充字节数,预留11字节
	 * @param cipherAlgorithm
	 *            加解密算法,一般为RSA/ECB/PKCS1Padding
	 * @return 解密后字节数组,不经base64编码
	 */
	public static byte[] RSADecrypt(String encryptKey, PrivateKey privateKey, int keyLength, int reserveSize, String cipherAlgorithm, String charset) throws Exception {
		byte[] encryptedBytes = Base64.decodeBase64(encryptKey.getBytes(charset));
		int keyByteSize = keyLength / 8; // 密钥字节数
		int decryptBlockSize = keyByteSize - reserveSize; // 解密块大小=密钥字节数-padding填充字节数
		int nBlock = encryptedBytes.length / keyByteSize;// 计算分段解密的block数,理论上能整除

		Cipher cipher = Cipher.getInstance(cipherAlgorithm);
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		
		// 输出buffer,大小为nBlock个decryptBlockSize
		ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * decryptBlockSize);
		// 分段解密
		for (int offset = 0; offset < encryptedBytes.length; offset += keyByteSize) {
			// block大小: decryptBlock 或 剩余字节数
			int inputLen = encryptedBytes.length - offset;
			if (inputLen > keyByteSize) {
				inputLen = keyByteSize;
			}
			
			// 得到分段解密结果
			byte[] decryptedBlock = cipher.doFinal(encryptedBytes, offset, inputLen);
			// 追加结果到输出buffer中
			outbuf.write(decryptedBlock);
		}
		
		outbuf.flush();
		outbuf.close();
		return outbuf.toByteArray();
	}

	/**
	 * AES加密
	 * 
	 * @param plainBytes
	 *            明文字节数组
	 * @param keyBytes
	 *            密钥字节数组
	 * @param keyAlgorithm
	 *            密钥算法
	 * @param cipherAlgorithm
	 *            加解密算法
	 * @param IV
	 *            随机向量
	 * @return 加密后字节数组,不经base64编码
	 */
	public static String AESEncrypt(String content, String key, String charset) throws Exception {
		byte[] keyBytes = key.getBytes(charset);
		// AES密钥长度为128bit、192bit、256bit,默认为128bit
		if (keyBytes.length % 8 != 0 || keyBytes.length < 16 || keyBytes.length > 32) {
			throw new Exception("AES密钥长度不合法");
		}
		
		Cipher cipher = Cipher.getInstance(AES_ECB_PCK_ALG);
		SecretKey secretKey = new SecretKeySpec(keyBytes, AES_ALG);
		cipher.init(Cipher.ENCRYPT_MODE, secretKey);
		
		byte[] encryptedBytes = cipher.doFinal(content.getBytes(charset));
		return new String(Base64.encodeBase64(encryptedBytes), charset);
	}

	/**
	 * AES解密
	 * 
	 * @param encryptedBytes
	 *            密文字节数组,不经base64编码
	 * @param keyBytes
	 *            密钥字节数组
	 * @param keyAlgorithm
	 *            密钥算法
	 * @param cipherAlgorithm
	 *            加解密算法
	 * @param IV
	 *            随机向量
	 * @return 解密后字节数组
	 */
	public static byte[] AESDecrypt(String content, byte[] keyBytes, String charset) throws Exception {
		// AES密钥长度为128bit、192bit、256bit,默认为128bit
		if (keyBytes.length % 8 != 0 || keyBytes.length < 16 || keyBytes.length > 32) {
			throw new Exception("AES密钥长度不合法");
		}
		
		Cipher cipher = Cipher.getInstance(AES_ECB_PCK_ALG);
		SecretKey secretKey = new SecretKeySpec(keyBytes, AES_ALG);
		cipher.init(Cipher.DECRYPT_MODE, secretKey);
		
		return cipher.doFinal(Base64.decodeBase64(content.getBytes(charset)));
	}
}

3 使用生成RSA和AES

String key = generateLenString(16);
String encryptData = CryptoUtil.AESEncrypt(content, key, charset);
String signData = CryptoUtil.digitalSign(content, priKey, "SHA1WithRSA", charset);
String encrtptKey = CryptoUtil.RSAEncrypt(key, pubKey, 2048, 11, "RSA/ECB/PKCS1Padding", charset);

	/**
	 * 生成指定长度的随机字符串
	 * 
	 * @param length
	 *            指定字符串长度
	 * @return
	 */
	private static String generateLenString(int length) {
		char[] cResult = new char[length];
		int[] flag = { 0, 0, 0 }; // A-Z, a-z, 0-9
		int i = 0;
		while (flag[0] == 0 || flag[1] == 0 || flag[2] == 0 || i < length) {
			i = i % length;
			int f = (int) (Math.random() * 3 % 3);
			if (f == 0)
				cResult[i] = (char) ('A' + Math.random() * 26);
			else if (f == 1)
				cResult[i] = (char) ('a' + Math.random() * 26);
			else
				cResult[i] = (char) ('0' + Math.random() * 10);
			flag[f] = 1;
			i++;
		}
		return new String(cResult);
	}

byte[] keyBytes = CryptoUtil.RSADecrypt(encryptKey, priKey, 2048, 11, "RSA/ECB/PKCS1Padding", charset);
byte[] dataBytes = CryptoUtil.AESDecrypt(encryptData, keyBytes, charset);
System.out.println("@@@"+new String(dataBytes,"utf-8"));
CryptoUtil.verifyDigitalSign(dataBytes, signData, pubKey, "SHA1WithRSA", charset)



RSA算法是一种非对称加密算法,它可以用于加密数据和数字签名。在Java中,可以使用Java Cryptography Architecture(JCA)提供的API来实现RSA加密和解密。下面是简单的示例代码: ```java import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; public class RSAEncryption { public static void main(String[] args) throws Exception { String plainText = "Hello World"; // 生成RSA公钥和私钥 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048, new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); // 使用公钥加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] cipherText = cipher.doFinal(plainText.getBytes()); // 使用私钥解密 cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedText = cipher.doFinal(cipherText); System.out.println("Plain Text: " + plainText); System.out.println("Encrypted Text: " + new String(cipherText)); System.out.println("Decrypted Text: " + new String(decryptedText)); } } ``` 上面的代码先生成了一个2048RSA公钥和私钥,然后使用公钥加密了一个字符串,再使用私钥解密获得原始字符串。在实际使用中,我们通常需要将公钥和私钥保存在文件中,以便在不同的应用程序中使用。可以使用PKCS8EncodedKeySpec和X509EncodedKeySpec类来将公钥和私钥转换为字节数组,以便在文件中保存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值