鉴于rsa加密的重要性和相关源代码的匮乏,经过整理特此贴出。需要下载bcprov-jdk14-123.jar。
import javax.crypto.cipher;
import java.security.*;
import java.security.spec.rsapublickeyspec;
import java.security.spec.rsaprivatekeyspec;
import java.security.spec.invalidkeyspecexception;
import java.security.interfaces.rsaprivatekey;
import java.security.interfaces.rsapublickey;
import java.io.*;
import java.math.biginteger;
/**
* rsa 工具类。提供加密,解密,生成密钥对等方法。
* 需要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。
*
*/
public class rsautil {
/**
* 生成密钥对
* @return keypair
* @throws encryptexception
*/
public static keypair generatekeypair() throws encryptexception {
try {
keypairgenerator keypairgen = keypairgenerator.getinstance("rsa",
new org.bouncycastle.jce.provider.bouncycastleprovider());
final int key_size = 1024;//没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低
keypairgen.initialize(key_size, new securerandom());
keypair keypair = keypairgen.genkeypair();
return keypair;
} catch (exception e) {
throw new encryptexception(e.getmessage());
}
}
/**
* 生成公钥
* @param modulus
* @param publicexponent
* @return rsapublickey
* @throws encryptexception
*/
public static rsapublickey generatersapublickey(byte[] modulus, byte[] publicexponent) throws encryptexception {
keyfactory keyfac = null;
try {
keyfac = keyfactory.getinstance("rsa", new org.bouncycastle.jce.provider.bouncycastleprovider());
} catch (nosuchalgorithmexception ex) {
throw new encryptexception(ex.getmessage());
}
rsapublickeyspec pubkeyspec = new rsapublickeyspec(new biginteger(modulus), new biginteger(publicexponent));
try {
return (rsapublickey) keyfac.generatepublic(pubkeyspec);
} catch (invalidkeyspecexception ex) {
throw new encryptexception(ex.getmessage());
}
}
/**
* 生成私钥
* @param modulus
* @param privateexponent
* @return rsaprivatekey
* @throws encryptexception
*/
public static rsaprivatekey generatersaprivatekey(byte[] modulus, byte[] privateexponent) throws encryptexception {
keyfactory keyfac = null;
try {
keyfac = keyfactory.getinstance("rsa", new org.bouncycastle.jce.provider.bouncycastleprovider());
} catch (nosuchalgorithmexception ex) {
throw new encryptexception(ex.getmessage());
}
rsaprivatekeyspec prikeyspec = new rsaprivatekeyspec(new biginteger(modulus), new biginteger(privateexponent));
try {
return (rsaprivatekey) keyfac.generateprivate(prikeyspec);
} catch (invalidkeyspecexception ex) {
throw new encryptexception(ex.getmessage());
}
}
/**
* 加密
* @param key 加密的密钥
* @param data 待加密的明文数据
* @return 加密后的数据
* @throws encryptexception
*/
public static byte[] encrypt(key key, byte[] data) throws encryptexception {
try {
cipher cipher = cipher.getinstance("rsa", new org.bouncycastle.jce.provider.bouncycastleprovider());
cipher.init(cipher.encrypt_mode, key);
int blocksize = cipher.getblocksize();//获得加密块大小,如:加密前数据为128个byte,而key_size=1024 加密块大小为127 byte,加密后为128个byte;因此共有2个加密块,第一个127 byte第二个为1个byte
int outputsize = cipher.getoutputsize(data.length);//获得加密块加密后块大小
int leavedsize = data.length % blocksize;
int blockssize = leavedsize != 0 ? data.length / blocksize + 1 : data.length / blocksize;
byte[] raw = new byte[outputsize * blockssize];
int i = 0;
while (data.length - i * blocksize > 0) {
if (data.length - i * blocksize > blocksize)
cipher.dofinal(data, i * blocksize, blocksize, raw, i * outputsize);
else
cipher.dofinal(data, i * blocksize, data.length - i * blocksize, raw, i * outputsize);
//这里面doupdate方法不可用,查看源代码后发现每次doupdate后并没有什么实际动作除了把byte[]放到bytearrayoutputstream中,而最后dofinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了outputsize所以只好用dofinal方法。
i++;
}
return raw;
} catch (exception e) {
throw new encryptexception(e.getmessage());
}
}
/**
* 解密
* @param key 解密的密钥
* @param raw 已经加密的数据
* @return 解密后的明文
* @throws encryptexception
*/
public static byte[] decrypt(key key, byte[] raw) throws encryptexception {
try {
cipher cipher = cipher.getinstance("rsa", new org.bouncycastle.jce.provider.bouncycastleprovider());
cipher.init(cipher.decrypt_mode, key);
int blocksize = cipher.getblocksize();
bytearrayoutputstream bout = new bytearrayoutputstream(64);
int j = 0;
while (raw.length - j * blocksize > 0) {
bout.write(cipher.dofinal(raw, j * blocksize, blocksize));
j++;
}
return bout.tobytearray();
} catch (exception e) {
throw new encryptexception(e.getmessage());
}
}
/**
*
* @param args
* @throws exception
*/
public static void main(string[] args) throws exception {
file file = new file("test.html");
fileinputstream in = new fileinputstream(file);
bytearrayoutputstream bout = new bytearrayoutputstream();
byte[] tmpbuf = new byte[1024];
int count = 0;
while ((count = in.read(tmpbuf)) != -1) {
bout.write(tmpbuf, 0, count);
tmpbuf = new byte[1024];
}
in.close();
byte[] orgdata = bout.tobytearray();
keypair keypair = rsautil.generatekeypair();
rsapublickey pubkey = (rsapublickey) keypair.getpublic();
rsaprivatekey prikey = (rsaprivatekey) keypair.getprivate();
byte[] pubmodbytes = pubkey.getmodulus().tobytearray();
byte[] pubpubexpbytes = pubkey.getpublicexponent().tobytearray();
byte[] primodbytes = prikey.getmodulus().tobytearray();
byte[] pripriexpbytes = prikey.getprivateexponent().tobytearray();
rsapublickey recoverypubkey = rsautil.generatersapublickey(pubmodbytes,pubpubexpbytes);
rsaprivatekey recoveryprikey = rsautil.generatersaprivatekey(primodbytes,pripriexpbytes);
byte[] raw = rsautil.encrypt(prikey, orgdata);
file = new file("encrypt_result.dat");
outputstream out = new fileoutputstream(file);
out.write(raw);
out.close();
byte[] data = rsautil.decrypt(recoverypubkey, raw);
file = new file("decrypt_result.html");
out = new fileoutputstream(file);
out.write(data);
out.flush();
out.close();
}
}
加密可以用公钥,解密用私钥;或者加密用私钥。通常非对称加密是非常消耗资源的,因此可以对大数据用对称加密如:des(具体代码可以看我以前发的贴子),而对其对称密钥进行非对称加密,这样既保证了数据的安全,还能保证效率。
闽公网安备 35060202000074号