java rsa加密解密

rsa加密:公钥加密,私钥解密。

首先,我们先要生成密钥对:

public static void createRSAKey(String privateKeyPath, String publicKeyPath) throws BasicException {
	KeyPairGenerator kpg = null;
	try {
		kpg = KeyPairGenerator.getInstance("RSA");
	} catch (NoSuchAlgorithmException e) {
		throw new RsaException(e);
	}
	kpg.initialize(1024); // 指定密钥长度
	KeyPair kp = kpg.genKeyPair(); // 生成密钥对
	PublicKey public_key = kp.getPublic(); // 获得公钥
	PrivateKey private_key = kp.getPrivate(); // 获得私钥

	String publicKeyStr = Base64
			.encodeBase64String(public_key.getEncoded());
	// 创建公钥
	FileUtil.createFile(publicKeyPath, publicKeyStr.getBytes());

	String privateKeyStr = Base64.encodeBase64String(private_key
			.getEncoded());
	// 创建私钥
	FileUtil.createFile(privateKeyPath, privateKeyStr.getBytes());
	
}

需要注意的是,密钥的长度是跟加密后的密文长度有关。当密钥长度加倍时,rsa解密密文的最大值也要加倍。

然后,我们就要对明文进行加密解密了。但是rsa对加密明文的长度是有限制的,最大长度为117字节,否则就会抛出异常:

Data must not be longer than 117 bytes

所以我们要采用分段加密的方式:

// rsa最大加密明文大小
private static final int MAX_ENCRYPT_BLOCK = 117;
// rsa最大解密密文大小
private static final int MAX_DECRYPT_BLOCK = 128;
// 分段加密
private static String encryptByKey(String data, Key key) throws BasicException {
	Cipher cipher;
	try {
		cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, key);
	} catch (Exception e) {
		throw new RsaException(e);
	} 

	int length = data.length();
	int offset = 0;
	byte[] result = null;
	int i = 0;
	while (length - offset > 0) {
		byte[] cache;
		try {
			if (length - offset > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(data.getBytes(), offset, length - offset);
			}
		} catch (Exception e) {
			throw new RsaException(e);
		}
		result = VDILicenseCreator.concat(result, cache);
		i++;
		offset = i * MAX_ENCRYPT_BLOCK;
	}
	
	return Base64.encodeBase64String(result);
}
// 分段解密
private static String decryptByKey(String data, Key key) throws BasicException {
	Cipher cipher;
	try {
		cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, key);
	} catch (Exception e) {
		throw new RsaException(e);
	}
	
	byte[] data64 = Base64.decodeBase64(data);
	int length = data64.length;
	int offset = 0;
	byte[] result = null;
	int i = 0;
	while (length - offset > 0) {
		byte[] cache;
		try {
			if (length - offset > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(data64, offset, MAX_DECRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(data64, offset, length - offset);
			}
		} catch (Exception e) {
			throw new RsaException(e);
		}
		result = VDILicenseCreator.concat(result, cache);
		i++;
		offset = i * MAX_DECRYPT_BLOCK;
	}
	
	return new String(result);
}

上面的代码中,还有一个rsa最大解密密文大小。加密分段,解密当然也要分段了。当密钥的长度为1024时,小于117字节的明文,加密后长度都是128字节(所以分段加密后,密文的长度都是128的整数倍),所以上面rsa最大解密密文大小设置为128。但是,如果密钥的长度为2048时,这个值就要随之翻倍,设置为256。如果仍设置为128,则会抛出异常:

Data must start with zero

下面备注了我们所用到的jar包:

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
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;

import org.apache.commons.codec.binary.Base64;

发表评论