开发者社区> 问答> 正文

JAVA里面RSA加密算法的使用

打算写这个类用于spark插件加密对话消息用。

展开
收起
知与谁同 2018-07-21 12:15:08 2637 0
1 条回答
写回答
取消 提交回答
  • TA有点害羞,没有介绍自己...
    RSA的Java实现不能一次加密很大的字符,自己处理了一下,见下面的代码。  Base64编码类用的是一个Public domain Base64 for java http://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;  }
    2019-07-17 22:56:32
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
JAVA开发手册1.5.0 立即下载