打算写这个类用于spark插件加密对话消息用。
RSA的Java实现不能一次加密很大的字符,自己处理了一下,见下面的代码。
Base64编码类用的是一个Public domain Base64 for java //iharder.sourceforge.net/current/java/base64/
其他的保存公钥到文件等简单的实现,就不详细说了,看代码吧。
==============================================
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.*;
import java.io.*;
public class Encryptor {
private static final String KEY_FILENAME = "c:\\mykey.dat";
private static final String OTHERS_KEY_FILENAME = "c:\\Otherskey.dat";
// private static final int KEY_SIZE = 1024;
// private static final int BLOCK_SIZE = 117;
// private static final int OUTPUT_BLOCK_SIZE = 128;
private static final int KEY_SIZE = 2048; //RSA key 是多少位的
private static final int BLOCK_SIZE = 245; //一次RSA加密操作所允许的长度
//这个值与 KEY_SIZE 已经padding方法有关。因为 1024的key的输出是128,2048key输出是256字节
//可能11个字节用于保存padding信息了,所以多可用的就只有245字节了。
private static final int OUTPUT_BLOCK_SIZE = 256;
private SecureRandom secrand;
private Cipher rsaCipher;
private KeyPair keys;
private Map allUserKeys;
public Encryptor() throws Exception {
try {
allUserKeys = new HashMap();
secrand = new SecureRandom();
//SunJCE Provider 中只支持ECB mode,试了一下只有PKCS1PADDING可以直接还原原始数据,
//NOPadding导致解压出来的都是blocksize长度的数据,还要自己处理
//参见 //java.sun.com/javase/6/docs/technotes/guides/security/SunProviders.html#SunJCEProvider
//
//另外根据 Open-JDK-6.b17-src(//www.docjar.com/html/api/com/sun/crypto/provider/RSACipher.java.html)
// 中代码的注释,使用RSA来加密大量数据不是一种标准的用法。所以现有实现一次doFinal调用之进行一个RSA操作,
//如果用doFinal来加密超过的一个操作所允许的长度数据将抛出异常。
//根据keysize的长度,典型的1024个长度的key和PKCS1PADDING一起使用时
//一次doFinal调用只能加密117个byte的数据。(NOPadding 和1024 keysize时128个字节长度)
//(2048长度的key和PKCS1PADDING 多允许245字节一次)
//想用来加密大量数据的只能自己用其他办法实现了。可能RSA加密速度比较慢吧,要用AES才行
rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
throw e;
}
ObjectInputStream in;
try {
in = new ObjectInputStream(new FileInputStream(KEY_FILENAME));
} catch (FileNotFoundException e) {
if (false == GenerateKeys())
{
throw e;
}
LoadKeys();
return;
}
keys = (KeyPair) in.readObject();
in.close();
LoadKeys();
}
/*
* 生成自己的公钥和私钥
*/
private Boolean GenerateKeys() {
try {
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
// secrand = new SecureRandom();
// sedSeed之后会造成 生成的密钥都是一样的
// secrand.setSeed("chatencrptor".getBytes()); // 初始化随机产生器
//key长度至少512长度,不过好像说现在用2048才算比较安全的了
keygen.initialize(KEY_SIZE, secrand); // 初始化密钥生成器
keys = keygen.generateKeyPair(); // 生成密钥组
AddKey("me", EncodeKey(keys.getPublic()));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return false;
}
ObjectOutputStream out;
try {
out = new ObjectOutputStream(new FileOutputStream(KEY_FILENAME));
} catch (IOException e) {
e.printStackTrace();
return false;
}
try {
out.writeObject(keys);
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
return true;
}
来源:考试大-Java认证
责编:xxm 评论 纠错