打算写这个类用于spark插件加密对话消息用。
RSA的Java实现不能一次加密很大的字符,自己处理了一下,见下面的代码。
Base64编码类用的是一个Public domain Base64 for javahttp://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<String, Key> allUserKeys; 

public Encryptor() throws Exception { 

try { 

allUserKeys = new HashMap<String, Key>(); 

secrand = new SecureRandom(); 

//SunJCE Provider 中只支持ECB mode,试了一下只有PKCS1PADDING可以直接还原原始数据, 

//NOPadding导致解压出来的都是blocksize长度的数据,还要自己处理 

//参见http://java.sun.com/javase/6/docs/technotes/guides/security/SunProviders.html#SunJCEProvider 

// 

//另外根据 Open-JDK-6.b17-src(http://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; 

} 


public String EncryptMessage(String toUser, String Message) throws IOException { 

Key pubkey = allUserKeys.get(toUser); 

if ( pubkey == null ) 

{ 

throw new IOException("NoKeyForThisUser") ; 

} 

try { 

//PublicKey pubkey = keys.getPublic(); 

rsaCipher.init(Cipher.ENCRYPT_MODE, pubkey, secrand); 

//System.out.println(rsaCipher.getBlockSize()); 返回0,非block 加密算法来的? 

//System.out.println(Message.getBytes("utf-8").length); 

//byte[] encryptedData = rsaCipher.doFinal(Message.getBytes("utf-8")); 

byte[] data = Message.getBytes("utf-8"); 

int blocks = data.length / BLOCK_SIZE ; 

int lastBlockSize = data.length % BLOCK_SIZE ; 

byte [] encryptedData = new byte[ (lastBlockSize == 0 ? blocks : blocks + 1)* OUTPUT_BLOCK_SIZE]; 

for (int i=0; i < blocks; i++) 

{ 

//int thisBlockSize = ( i + 1 ) * BLOCK_SIZE > data.length ? data.length - i * BLOCK_SIZE : BLOCK_SIZE ; 

rsaCipher.doFinal(data,i * BLOCK_SIZE, BLOCK_SIZE, encryptedData ,i * OUTPUT_BLOCK_SIZE); 

} 

if (lastBlockSize != 0 ){ 

rsaCipher.doFinal(data, blocks * BLOCK_SIZE, lastBlockSize,encryptedData ,blocks * OUTPUT_BLOCK_SIZE); 

} 

//System.out.println(encrypted.length); 如果要机密的数据不足128/256字节,加密后补全成为变为256长度的。 

//数量比较小时,Base64.GZIP产生的长度更长,没什么优势 

//System.out.println(Base64.encodeBytes(encrypted,Base64.GZIP).length()); 

//System.out.println(Base64.encodeBytes(encrypted).length()); 

//System.out.println (rsaCipher.getOutputSize(30)); 

//这个getOutputSize 只对 输入小于最大的block时才能得到正确的结果。其实就是补全 数据为128/256 字节 

return Base64.encodeBytes(encryptedData); 

} catch (InvalidKeyException e) { 

e.printStackTrace(); 

throw new IOException("InvalidKey") ; 

}catch (ShortBufferException e) { 

e.printStackTrace(); 

throw new IOException("ShortBuffer") ; 

} 

catch (UnsupportedEncodingException e) { 

e.printStackTrace(); 

throw new IOException("UnsupportedEncoding") ; 

} catch (IllegalBlockSizeException e) { 

e.printStackTrace(); 

throw new IOException("IllegalBlockSize") ; 

} catch (BadPaddingException e) { 

e.printStackTrace(); 

throw new IOException("BadPadding") ; 

}finally { 

//catch 中 return 或者throw之前都会先调用一下这里 

} 

} 

public String DecryptMessage(String Message) throws IOException { 

byte[] decoded = Base64.decode(Message); 

PrivateKey prikey = keys.getPrivate(); 

try { 

rsaCipher.init(Cipher.DECRYPT_MODE, prikey, secrand); 

int blocks = decoded.length / OUTPUT_BLOCK_SIZE; 

ByteArrayOutputStream decodedStream = new ByteArrayOutputStream(decoded.length); 

for (int i =0 ;i < blocks ; i ++ ) 

{ 

decodedStream.write (rsaCipher.doFinal(decoded,i * OUTPUT_BLOCK_SIZE, OUTPUT_BLOCK_SIZE)); 

} 

return new String(decodedStream.toByteArray(), "UTF-8"); 

} catch (InvalidKeyException e) { 

e.printStackTrace(); 

throw new IOException("InvalidKey"); 

} catch (UnsupportedEncodingException e) { 

e.printStackTrace(); 

throw new IOException("UnsupportedEncoding"); 

} catch (IllegalBlockSizeException e) { 

e.printStackTrace(); 

throw new IOException("IllegalBlockSize"); 

} catch (BadPaddingException e) { 

e.printStackTrace(); 

throw new IOException("BadPadding"); 

} finally { 

// catch 中 return 或者throw之前都会先调用一下这里。 

} 

} 

public boolean AddKey(String user, String key) { 

PublicKey publickey; 

try { 

publickey = DecodePublicKey(key); 

} catch (Exception e) { 

return false; 

} 

allUserKeys.put(user, publickey); 

SaveKeys(); 

return true; 

} 


private boolean LoadKeys() { 

BufferedReader input; 

try { 

input = new BufferedReader(new InputStreamReader( 

new FileInputStream(OTHERS_KEY_FILENAME))); 

} catch (FileNotFoundException e1) { 

// e1.printStackTrace(); 

return false; 

} 

try { 

allUserKeys.clear(); 

String line; 

while ((line = input.readLine()) != null) { 

String[] temp = line.split("\\|"); 

String user = temp[0]; 

PublicKey key = DecodePublicKey(temp[1]); 

allUserKeys.put(user, key); 

} 

} catch (Exception e) { 

return false; 

} finally { 

try { 

input.close(); 

} catch (Exception e) { 

return false; 

} 

} 

return true; 

} 

private boolean SaveKeys() { 

FileWriter output; 

try { 

output = new FileWriter(OTHERS_KEY_FILENAME); 

} catch (IOException e1) { 

// 1.printStackTrace(); 

return false; 

} 

try { 

for (String user : allUserKeys.keySet()) { 

Key key = allUserKeys.get(user); 

output.write(user + "|" + EncodeKey(key) + "\n"); 

} 

} catch (IOException e1) { 

// 1.printStackTrace(); 

return false; 

} finally { 

try { 

output.close(); 

} catch (Exception e) { 

return false; 

} 

} 

return true; 

} 

/** 

* 解密base64编码得到公钥 

* 

* @param key 

* 密钥字符串(经过base64编码) 

* @throws Exception 

*/ 

public static PublicKey DecodePublicKey(String key) throws Exception { 

byte[] keyBytes; 

keyBytes = Base64.decode(key); 

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); 

KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 

PublicKey publicKey = keyFactory.generatePublic(keySpec); 

return publicKey; 

} 

/** 

* 解密base64编码得到私钥 

* 

* @param key 

* 密钥字符串(经过base64编码) 

* @throws Exception 

*/ 

public static PrivateKey DecodePrivateKey(String key) throws Exception { 

byte[] keyBytes; 

keyBytes = Base64.decode(key); 

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); 

KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 

PrivateKey privateKey = keyFactory.generatePrivate(keySpec); 

return privateKey; 

} 

/** 

* 编码key为base64字符串 

* 

* @return 

*/ 

public static String EncodeKey(Key key) { 

byte[] keyBytes = key.getEncoded(); 

// System.out.print(key.getFormat()) ; 

String s = Base64.encodeBytes(keyBytes); 

return s; 

} 

} 

===============测试类============================ 

import java.util.Iterator ; 

import java.security.Security ; 

import java.security.Provider ; 

public class Test { 

/** 

* @param args 

*/ 

public static void main(String[] args) { 

// Provider [ ] providers = Security.getProviders () ; 

// for ( int i = 0 ; i < providers.length ; i++ ) 

// { 

// String name = providers[i].getName () ; 

// String info = providers[i].getInfo () ; 

// double version = providers[i].getVersion () ; 

// System.out.println ("-------------------------------------" ) ; 

// System.out.println ( "name: " + name ) ; 

// System.out.println ( "info: " + info ) ; 

// System.out.println ( "version: " + version ) ; 

// 

// for ( Iterator iter = providers[i].keySet().iterator () ; iter.hasNext () ; ) 

// { 

// String key = (String) iter.next () ; 

// System.out.println ( "\t" + key + 

// "\t" + 

// providers[i].getProperty ( key ) ) ; 

// } 

// 

// System.out.println ( 

// 

// "-------------------------------------" ); 

// } 

// 

// int i = 123/ 256; 

// System.out.println(i); 

// i = 257/ 256; 

// System.out.println(i); 

// i = 512/ 256; 

// System.out.println(i); 

// i = 513/ 256; 

// System.out.println(i); 

//String str = "widebriht的测试,哈哈^_^"; 

//String str = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4dYTv3xxgsu2SmgqJzPWzSOziMDnOV+tAxQGumNAJKcBxOlD5hQlqTGRnUoqIp8z3brioFJBtMs8wAeA+pfpJhFyqodI9frr0I3Y4PUgwRlL7ozGA9hu9CBOADQNKE7g7UgOTQ/joE26YoYPCHKx/vYQncOe45axOCqcXBWViw20WgPr1g0qj9CarQLM7e4dUNMCYcX0ZGvqIy7Js2FjuLsNaK249k9y2fjIqqu8FzhjvIEDCtrMNyTvV5coV5rDGTEC5KfJft0oeCTXrhcgzMBdaG9DXFQezQIepMdPAT+kga/qJ69b95I02LMwyCDhwPmH873UNQAmdMpJ7bZTTwIDAQAB"; 

String str = "MIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0BMIIBIjANBgkqhkiG9w0Bddddd"; 

try { 

Encryptor ddd = new Encryptor(); 

str = ddd.EncryptMessage("me", str); 

// System.out.println(str.length()); 

String str2 = "jhahahh my god "; 

str2 = ddd.EncryptMessage("me", str2); 

str2 = ddd.DecryptMessage(str2); 

str = ddd.DecryptMessage(str); 

} catch (Exception e) { 

if (e.getMessage() == "NoKeyForThisUser") { 

System.out.println("NoKeyForThisUser"); 

} 

} 

// str = ddd.DecryptMessage( 

// "inI5y3PfFXt0oNWXuYLBbTkIaaxZFzgWuMfYTqpT91b51UUQN0T8iK6l8XnS+WShC/ZGL9noX6vO8sDmiJ+z1I7/WTgvOOW5XE+G7+edGzh6bfRGPxhG16MJpl2y/FsIErsKgZmybERE8F0IP551/b0xGmrZhyj09/NwZln3qUg="); 

//System.out.println(str); 

} 

}