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;