参考了网上的一些资料:
http://blog.sina.com.cn/s/blog_76550fd7010147tp.html
http://blog.csdn.net/centralperk/article/details/8538697
http://dustin.iteye.com/blog/763931
RSA算法密钥长度的选择是安全性和程序性能平衡的结果,密钥长度越长,安全性越好,加密解密所需时间越长。
1. 非对称加密算法中1024 bit密钥的强度相当于对称加密算法80bit密钥的强度。有资料上说以当前的软硬件水平,破解1024bit的RSA加密密文,需要一套10亿美金的系统使用若干十年的时间,所以2015年前,1024bit的还无需太担心暴力破解的危险。
2. 密钥长度增长一倍,公钥操作所需时间增加约4倍,私钥操作所需时间增加约8倍,公私钥生成时间约增长16倍。
3. 一次能加密的密文长度与密钥长度成正比, len_in_byte(raw_data) = len_in_bit(key)/8 -11,如1024bit的密钥,一次能加密的内容长度为 1024/8 -11 = 117 byte。所以非对称加密一般都用于加密对称加密算法的密钥,而不是直接加密内容。
4. 加密后密文的长度为密钥的长度,如密钥长度为1024b(128Byte),最后生成的密文固定为 1024b(128Byte)
现整理如下:
import java.io.*;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
public class RSAUtil{
private static final String KEY_ALGORITHM = "RSA";//签名算法
/**
* RSA解密要求密文最大长度为128字节,加密明文最大长度117字节
* 如果加密数据过大需要在加密和解密的过程中需要分块进行
* 块数=(明文长度(bytes)/(密钥长度(需要将bit转换为bytes)-11))向上取整,就是不满一片的按一片算
* 所以密文的长度设置直接影响块数的大小,可以根据项目需要灵活分配分块的个数
* RSA最大密文长度 单位:byte
*/
private static final int DECRYPT_LENGTH = 128;
/**
* RSA最大明文长度 单位:byte
*/
private static final int ENCRYPT_LENGTH = DECRYPT_LENGTH - 11;
/**
*密钥长度 单位:bit 1byte=8bit
*加密n byte的明文,需要至少(n+11)bytes的密钥
*因为该单位是bit 所以换算成bit就要乘以8
*/
private static final int ENCRYTLENGTH = (ENCRYPT_LENGTH + 11) * 8;
/**
* 注意下面两个路径必须存在,否则在初始化过程中会发生异常
*/
private static final String PUBLICKEYPATH = "/home/key/public.key";
private static final String PRIVATEKEYPATH = "/home/key/private.key";
private static RSAPublicKey publicKey;
private static RSAPrivateKey privateKey;
public enum KeyType{ PUBLIC,PRIVATE; }
static{
try {
initKey(true);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("初始化key异常!!");
}
}
public static void main(String[] args) throws Exception {
String data = "hello world";
File publickeyFile = new File(PUBLICKEYPATH);
File privatekeyFile = new File(PRIVATEKEYPATH);
byte[] encryptData,decryptData;
if(publickeyFile.exists() && privatekeyFile.exists()){
Key publickey = getKey(publickeyFile, KeyType.PUBLIC);
Key privatekey = getKey(privatekeyFile, KeyType.PRIVATE);
encryptData = encrypt(data.getBytes(), publickey);
decryptData = decrypt(encryptData, privatekey);
System.out.println("用文件路径方式的key进行加密!!!");
}else{
encryptData = encrypt(data.getBytes());
decryptData = decrypt(encryptData);
System.out.println("用系统初始化的key进行加密!!!");
}
System.out.println("加密后:" + new String(encryptData, "UTF-8"));
System.out.println(new String(decryptData));
}
/**
* @param isSaveKey //初始化是否将key保存为文件 true是 false不是
* @throws Exception
*/
private static void initKey(boolean isSaveKey) throws Exception {
KeyPairGenerator kg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
kg.initialize(ENCRYTLENGTH);
KeyPair keypair = kg.generateKeyPair();
//得到公钥和私钥
publicKey = (RSAPublicKey) keypair.getPublic();
privateKey = (RSAPrivateKey) keypair.getPrivate();
if(isSaveKey){
File publicKeyFile = new File(PUBLICKEYPATH);
File privateKeyFile = new File(PRIVATEKEYPATH);
if(publicKeyFile.exists() && privateKeyFile.exists()){
generateKeyToFile(publicKey, publicKeyFile);
generateKeyToFile(privateKey, privateKeyFile);
}else{
throw new RuntimeException("生成key文件的路径错误!!!");
}
}
}
/**
* 将key生成到文件
* @param key
* @param file
* @return
* @throws IOException
*/
private static boolean generateKeyToFile(Key key,File file) throws IOException {
boolean flag = false;
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
//公钥默认使用的是X.509编码,私钥默认采用的是PKCS8编码
byte [] encode = key.getEncoded();
//注意,此处采用writeObject方法,读取时也要采用readObject方法
oos.writeObject(encode);
flag = true;
} catch (IOException e) {
throw e;
} finally {
if(fos != null) fos.close();
if(oos != null) oos.close();
}
return flag;
}
/**
* @param keybyte
* @param type
* @return
* @throws Exception
*/
private static Key getKey( byte[] keybyte, KeyType type) throws Exception {
KeyFactory keyfactory = KeyFactory.getInstance(KEY_ALGORITHM);
if (type == KeyType.PUBLIC) {
X509EncodedKeySpec x509eks = new X509EncodedKeySpec(keybyte);
RSAPublicKey publicKey = (RSAPublicKey) keyfactory.generatePublic(x509eks);
return publicKey;
} else if (type == KeyType.PRIVATE) {
PKCS8EncodedKeySpec pkcs8eks = new PKCS8EncodedKeySpec(keybyte);
RSAPrivateKey privateKey = (RSAPrivateKey) keyfactory.generatePrivate(pkcs8eks);
return privateKey;
}
return null;
}
/**
* @param keyFile
* @param type
* @return
* @throws Exception
*/
private static Key getKey(File keyFile, KeyType type) throws Exception {
FileInputStream fis = new FileInputStream(keyFile);
ObjectInputStream ois = new ObjectInputStream(fis);
byte[] keybyte = (byte[]) ois.readObject();
ois.close();
return getKey(keybyte,type);
}
/**
* @param type
* @return
* @throws Exception
*/
private static Key getKey(KeyType type) throws Exception {
if (type == KeyType.PUBLIC) {
return publicKey;
} else if (type == KeyType.PRIVATE) {
return privateKey;
}
return null;
}
/**
* @param data
* @param publicKey
* @return
* @throws Exception
*/
private static byte[] encrypt(byte[] data, Key publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > ENCRYPT_LENGTH) {
cache = cipher.doFinal(data, offSet, ENCRYPT_LENGTH);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * ENCRYPT_LENGTH;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/**
* @param data
* @param keyFile
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] data,File keyFile) throws Exception {
Key publicKey = getKey(keyFile, KeyType.PUBLIC);
return encrypt(data,publicKey);
}
/**
* @param data
* @param keyByte
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] data,byte[] keyByte) throws Exception {
Key publicKey = getKey(keyByte,KeyType.PUBLIC);
return encrypt(data,publicKey);
}
/**
* @param data
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] data) throws Exception {
return encrypt(data,publicKey);
}
/**
*
* @param data
* @param privateKey
* @return
* @throws Exception
*/
private static byte[] decrypt(byte[] data, Key privateKey) throws Exception {
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > DECRYPT_LENGTH) {
cache = cipher.doFinal(data, offSet, DECRYPT_LENGTH);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * DECRYPT_LENGTH;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
/**
* @param data
* @param privateKeyBytes
* @return
* @throws Exception
*/
public static byte[] decrypt(byte[] data, byte[] privateKeyBytes) throws Exception {
Key privateKey = getKey(privateKeyBytes,KeyType.PRIVATE);
return decrypt(data,privateKey);
}
/**
* @param data
* @param keyFile
* @return
* @throws Exception
*/
public static byte[] decrypt(byte[] data,File keyFile) throws Exception {
Key privateKey = getKey(keyFile, KeyType.PRIVATE);
return decrypt(data,privateKey);
}
/**
* @param data
* @return
* @throws Exception
*/
public static byte[] decrypt(byte[] data) throws Exception {
return decrypt(data,privateKey);
}
}