Java:RSA加密工具
RSA工具示例:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintWriter;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
/**
* 此类是非对称加密算法RSA的工具类,方便对传输数据进行基于密钥的加密和解密。
*
* 一般情况下,私钥是服务器端不公开的,公钥公开给每个客户端。
* 客户端向服务器发送需要加密的消息时,可以用公钥加密后进行传送,服务器端受到密文后可以用私钥进行解密。
* 服务器端可以对发送的消息进行数字签名,传给客户端,这样客户端受到签名后用公钥进行签名校验,若通过校验说明消息未被修改。
*
* 由于RSA算法速度比对称加密算法AES慢很多,所以一般仅仅用来和服务器完成对接认证,和AES密钥传输。
* 一旦AES密钥传输完成,客户服务器端就可以用AES加密进行通信。
* 认证过程可以如下:
* 1、客户端生成伪随机数D,用公钥加密后传给服务器。
* 2、服务器收到密文用私钥进行解密得到D,然后用私钥对D进行数字签名,将签名发送给客户端。
* 3、客户端收到签名,用公钥和D进行签名校验,通过校验说明认证通过。
* 4、通过认证后,客户端可以将自己选择的AES加密算法和密钥用公钥加密后传给服务器。
* 简单情况下可以只进行第4步,但最好跟一个随机数(加盐),防止其他拥有公钥的人进行穷举法破解。
*
* @author liuweitao
*/
public class RSAUtil {
private RSAPrivateKey key_pri = null;
private RSAPublicKey key_pub = null;
private int KEYSIZE = 0;
private static int D = 11; // java算法要求加密数据长度不能超过密钥长度减去11字节。
private static final String SIGN_ALGORITHMS = "SHA256WithRSA";
// 检查公钥私钥,若都为空则抛出异常。
private void check() throws Exception {
if ("none".equals(type())) {
throw new Exception("密钥为空!");
}
if (key_pub != null) {
KEYSIZE = key_pub.getModulus().bitLength();
} else {
KEYSIZE = key_pri.getModulus().bitLength();
}
KEYSIZE /= Byte.SIZE;
}
/**
* @return pub:公钥填充完成; pri:私钥填充完成; all:公钥私钥都填充完成。
*/
public String type() {
String res = null;
if (key_pub == null && key_pri == null) {
res = "none";
} else if (key_pub != null && key_pri == null) {
res = "pub";
} else if (key_pub == null && key_pri != null) {
res = "pri";
} else if (key_pub != null && key_pri != null) {
res = "all";
}
return res;
}
/**
* @param key_pub
* 公钥,若不指定则传入null
* @param key_pri
* 私钥,若不指定则传入null
* @throws Exception
*/
public RSAUtil(RSAPublicKey key_pub, RSAPrivateKey key_pri) throws Exception {
this.key_pub = key_pub;
this.key_pri = key_pri;
check();
}
/**
* @param bytes_pub
* 公钥字节流,若不指定则传入null
* @param bytes_pri
* 私钥字节流,若不指定则传入null
* @throws Exception
*/
public RSAUtil(byte[] bytes_pub, byte[] bytes_pri) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("rsa");
if (bytes_pub != null && bytes_pub.length != 0) {
X509EncodedKeySpec keySpec_pub = new X509EncodedKeySpec(bytes_pub);
key_pub = (RSAPublicKey) keyFactory.generatePublic(keySpec_pub);
}
if (bytes_pri != null && bytes_pri.length != 0) {
PKCS8EncodedKeySpec keySpec_pri = new PKCS8EncodedKeySpec(bytes_pri);
key_pri = (RSAPrivateKey) keyFactory.generatePrivate(keySpec_pri);
}
check();
}
/**
* @param str_pub
* 公钥字符串:Base64表示,若不指定则传入null
* @param str_pri
* 私钥字符串:Base64表示,若不指定则传入null
* @throws Exception
*/
public RSAUtil(String str_pub, String str_pri) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("rsa");
if (str_pub != null) {
byte[] bytes_pub = Base64.decode(str_pub);
X509EncodedKeySpec keySpec_pub = new X509EncodedKeySpec(bytes_pub);
key_pub = (RSAPublicKey) keyFactory.generatePublic(keySpec_pub);
}
if (str_pri != null) {
byte[] bytes_pri = Base64.decode(str_pri);
PKCS8EncodedKeySpec keySpec_pri = new PKCS8EncodedKeySpec(bytes_pri);
key_pri = (RSAPrivateKey) keyFactory.generatePrivate(keySpec_pri);
}
check();
}
/**
* @param file_pub
* 公钥文件,内容给为Base64表示的字符串,若不指定则传入null
* @param file_pri
* 私钥文件,内容给为Base64表示的字符串,若不指定则传入null
* @throws Exception
*/
public RSAUtil(File file_pub, File file_pri) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("rsa");
if (file_pub != null) {
String str_pub = FileUtil.readStringFile(file_pub);
byte[] bytes_pub = Base64.decode(str_pub);
X509EncodedKeySpec keySpec_pub = new X509EncodedKeySpec(bytes_pub);
key_pub = (RSAPublicKey) keyFactory.generatePublic(keySpec_pub);
}
if (file_pri != null) {
String str_pri = FileUtil.readStringFile(file_pri);
byte[] bytes_pri = Base64.decode(str_pri);
PKCS8EncodedKeySpec keySpec_pri = new PKCS8EncodedKeySpec(bytes_pri);
key_pri = (RSAPrivateKey) keyFactory.generatePrivate(keySpec_pri);
}
check();
}
/**
* @param dir_path
* 密钥文件保存目录路径,字符串
* @param keysize
* 密钥文件大小,最小为512,推荐1024和2048
* @throws Exception
*/
public static void genKeyFile(String dir_path, int keysize) throws Exception {
File file = new File(dir_path);
genKeyFile(file, keysize);
}
/**
* @param dir
* 密钥文件保存目录路径,文件
* @param keysize
* 密钥文件大小,最小为512,推荐1024和2048
* @throws Exception
*/
public static void genKeyFile(File dir, int keysize) throws Exception {
if (!dir.isDirectory()) {
throw new Exception("接收参数不为目录!");
}
String path = dir.getAbsolutePath() + File.separatorChar;
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("rsa");
keyGenerator.initialize(keysize, new SecureRandom());
KeyPair keyPair = keyGenerator.generateKeyPair();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
String rsaPrivateKeyString = Base64.encode(rsaPrivateKey.getEncoded());
String rsaPublicKeyString = Base64.encode(rsaPublicKey.getEncoded());
PrintWriter out1;
PrintWriter out2;
out1 = new PrintWriter(path + "id_rsa.pub");
out2 = new PrintWriter(path + "id_rsa.pri");
out1.write(rsaPublicKeyString);
out2.write(rsaPrivateKeyString);
out1.close();
out2.close();
}
// 加密内容
private byte[] encrypt(Cipher cipher, byte[] content) throws Exception {
final int groupsize = KEYSIZE - D;
int group_num = content.length % groupsize == 0 ? content.length / groupsize : content.length / groupsize + 1;
byte[] outBuffer = new byte[KEYSIZE * group_num];
for (int i = 0; i * groupsize < content.length; i++) {
if (content.length - i * groupsize > groupsize) {
cipher.doFinal(content, i * groupsize, groupsize, outBuffer, KEYSIZE * i);
} else {
cipher.doFinal(content, i * groupsize, content.length - i * groupsize, outBuffer, KEYSIZE * i);
}
}
return outBuffer;
}
// 解密内容
private byte[] decrypt(Cipher cipher, byte[] secret) throws Exception {
int count = secret.length / KEYSIZE;
ByteArrayOutputStream out = new ByteArrayOutputStream();
for (int i = 0; i < count; i++) {
out.write(cipher.doFinal(secret, KEYSIZE * i, KEYSIZE));
}
byte[] res = out.toByteArray();
out.reset();
out.close();
return res;
}
/**
* 公钥加密
*
* @param content
* 要加密的数据
* @return 加密后的数据
* @throws Exception
*/
public byte[] encrypt_pub(byte[] content) throws Exception {
if (key_pub == null) {
throw new Exception("公钥为null!");
}
Cipher cipher = Cipher.getInstance("rsa");
cipher.init(Cipher.ENCRYPT_MODE, key_pub);
return encrypt(cipher, content);
}
/**
* 公钥解密
*
* @param secret
* 要解密的数据
* @return 解密后的数据
* @throws Exception
*/
public byte[] decrypt_pub(byte[] secret) throws Exception {
if (key_pub == null) {
throw new Exception("公钥为null!");
}
Cipher cipher = Cipher.getInstance("rsa");
cipher.init(Cipher.DECRYPT_MODE, key_pub);
return decrypt(cipher, secret);
}
/**
* 私钥加密
*
* @param content
* 要加密的数据
* @return 加密后的数据
* @throws Exception
*/
public byte[] encrypt_pri(byte[] content) throws Exception {
if (key_pri == null) {
throw new Exception("私钥为null!");
}
Cipher cipher = Cipher.getInstance("rsa");
cipher.init(Cipher.ENCRYPT_MODE, key_pri);
return encrypt(cipher, content);
}
/**
* 私钥解密
*
* @param secret
* 要解密的数据
* @return 解密后的数据
* @throws Exception
*/
public byte[] decrypt_pri(byte[] secret) throws Exception {
if (key_pri == null) {
throw new Exception("私钥为null!");
}
Cipher cipher = Cipher.getInstance("rsa");
cipher.init(Cipher.DECRYPT_MODE, key_pri);
return decrypt(cipher, secret);
}
/**
* 生成数字签名,签名算法SHA256WithRSA
*
* @param content
* 数据内容
* @return 签名
* @throws Exception
*/
public byte[] sign(byte[] content) throws Exception {
if (key_pri == null) {
throw new Exception("私钥为null!");
}
java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
signature.initSign(key_pri);
signature.update(content);
return signature.sign();
}
/**
* 校验签名,签名算法SHA256WithRSA
*
* @param content
* 数据内容
* @param sign
* 签名
* @return 是否通过校验
* @throws Exception
*/
public boolean check_sign(byte[] content, byte[] sign) throws Exception {
if (key_pub == null) {
throw new Exception("公钥为null!");
}
java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
signature.initVerify(key_pub);
signature.update(content);
return signature.verify(sign);
}
/**
* 对二进制数据进行Base64编码
*
* @param binaryData
* 要编码的原始二进制数据
* @return
* com.sun.org.apache.xml.internal.security.utils.Base64.encode(binaryData);
*/
public static String base64Encode(byte[] binaryData) {
return Base64.encode(binaryData);
}
/**
* 对Base64编码字符串解码为二进制数,此方法能自动忽略原始字符串中的换行符。
*
* @param encoded
* 表示Base64编码的字符串
* @return
* com.sun.org.apache.xml.internal.security.utils.Base64.decode(encoded);
* @throws Base64DecodingException
*/
public static byte[] base64Decode(String encoded) throws Base64DecodingException {
return Base64.decode(encoded);
}
}