2015-06-22 158 views
1

我想在使用RSA密鑰的JAVA中使用非對稱密鑰進行簡單的加密/解密,並且我有一些麻煩。這是我的代碼:在JAVA中使用公共和私有RSA密鑰進行加密和解密

import java.io.BufferedInputStream; 
import java.io.BufferedOutputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.RandomAccessFile; 
import java.math.BigInteger; 
import java.security.Key; 
import java.security.KeyFactory; 
import java.security.KeyPairGenerator; 
import java.security.KeyPair; 
import java.security.NoSuchAlgorithmException; 
import java.security.PublicKey; 
import java.security.PrivateKey; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.KeySpec; 
import java.security.spec.PKCS8EncodedKeySpec; 
import java.security.spec.RSAPrivateKeySpec; 
import java.security.spec.RSAPublicKeySpec; 

import javax.crypto.Cipher; 

public class AsymmetricCipherTestFiles 
{ 
    public static void main(String[] unused) throws Exception 
    { 
     // 1. Generating keys 
     System.out.println("Generating keys ..."); 
     PublicKey publicKey; 
     PrivateKey privateKey; 
     // generateKeys(512); 

     // 2. read them from file 
     System.out.println("Read from file"); 
     publicKey = readPublicKeyFromFile("public.key"); 
     privateKey = readPrivateKeyFromFileTest("private.key"); 

     System.exit(0); 

     // 3. encrypt data 
     System.out.println("Encrypt data"); 
     byte[] dataBytes = "some string to encrypt".getBytes(); 
     byte[] encBytes = encrypt(dataBytes, publicKey, "RSA"); 
     printByteArray(encBytes); 

     // 4. decrypt data 
     byte[] decBytes = decrypt(encBytes, privateKey, "RSA"); 
     printByteArray(decBytes); 
     // String decryptedThing = convert(decBytes); 

    } 

    public static void generateKeys(int keySize) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException 
    { 
     // Create key 
     // System.out.println("Generating keys"); 
     KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); 
     kpg.initialize(keySize); 
     KeyPair kp = kpg.genKeyPair(); 

     /* 
     Key publicKey = kp.getPublic(); 
     Key privateKey = kp.getPrivate(); 
     */ 

     KeyFactory fact = KeyFactory.getInstance("RSA"); 
     RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(),RSAPublicKeySpec.class); 
     RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(),RSAPrivateKeySpec.class); 

     saveKeyToFile("bin/public.key", pub.getModulus(), pub.getPublicExponent()); 
     saveKeyToFile("bin/private.key", priv.getModulus(),priv.getPrivateExponent()); 

     // System.out.println("Keys generated"); 
    } 

    private static byte[] encrypt(byte[] inpBytes, PublicKey key,String xform) throws Exception 
    { 
     Cipher cipher = Cipher.getInstance(xform); 
     cipher.init(Cipher.ENCRYPT_MODE, key); 
     return cipher.doFinal(inpBytes); 
    } 

    private static byte[] decrypt(byte[] inpBytes, PrivateKey key,String xform) throws Exception 
    { 
     Cipher cipher = Cipher.getInstance(xform); 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     return cipher.doFinal(inpBytes); 
    } 

    public static String convert(byte[] data) 
    { 
     StringBuilder sb = new StringBuilder(data.length); 
     for (int i = 0; i < data.length; ++ i) 
     { 
      if (data[i] < 0) throw new IllegalArgumentException(); 
      sb.append((char) data[i]); 
     } 
     return sb.toString(); 
    } 

    public static PublicKey readPublicKeyFromFile(String keyFileName) throws IOException 
    { 
     InputStream in = (InputStream) AsymmetricCipherTestFiles.class.getResourceAsStream(keyFileName); 
     ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in)); 
     try 
     { 
      BigInteger m = (BigInteger) oin.readObject(); 
      BigInteger e = (BigInteger) oin.readObject(); 
      RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e); 
      KeyFactory fact = KeyFactory.getInstance("RSA"); 
      PublicKey pubKey = fact.generatePublic(keySpec); 
      return pubKey; 
     } 
     catch (Exception e) 
     { 
      throw new RuntimeException("Spurious serialisation error", e); 
     } finally { 
      oin.close(); 
     } 
    } 

    public static PrivateKey readPrivateKeyFromFile(String keyFileName) throws IOException 
    { 
     InputStream in = (InputStream) AsymmetricCipherTestFiles.class.getResourceAsStream(keyFileName); 
     ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in)); 
     try 
     { 
      BigInteger m = (BigInteger) oin.readObject(); 
      BigInteger e = (BigInteger) oin.readObject(); 

      byte[] byteArray = new byte[512]; 
      byteArray = m.toByteArray(); 

      KeySpec keySpec = new PKCS8EncodedKeySpec(byteArray); 
      // RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e); 
      KeyFactory fact = KeyFactory.getInstance("RSA"); 
      PrivateKey privateKey = fact.generatePrivate(keySpec); 
      return privateKey; 
     } 
     catch (Exception e) 
     { 
      throw new RuntimeException("Spurious serialisation error", e); 
     } finally { 
      oin.close(); 
     } 
    } 

    public static PrivateKey readPrivateKeyFromFileTest(String filename) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException 
    { 
     RandomAccessFile raf = new RandomAccessFile(filename, "r"); 
     byte[] buf = new byte[(int)raf.length()]; 
     raf.readFully(buf); 
     raf.close(); 
     PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(buf); 
     KeyFactory kf = KeyFactory.getInstance("RSA"); 
     PrivateKey privKey = kf.generatePrivate(kspec); 

     return privKey; 
    } 

    public static void saveKeyToFile(String fileName,BigInteger mod, BigInteger exp) throws IOException 
    { 
     ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName))); 
     try 
     { 
      oout.writeObject(mod); 
      oout.writeObject(exp); 
     } 
     catch (Exception e) 
     { 
      throw new IOException("Unexpected error", e); 
     } 
     finally 
     { 
      oout.close(); 
     } 
    } 

    public static void printByteArray(byte[] byteArray) 
    { 
     int increment = 0; 
     for(byte b : byteArray) 
     { 
      System.out.println("B["+increment+"] = "+b); 
      increment++; 
     } 
    } 
} 

當我運行它,它給了我這個錯誤:

Generating keys ... 
Read from file 
Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=109, too big. 
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(Unknown Source) 
    at java.security.KeyFactory.generatePrivate(Unknown Source) 
    at AsymmetricCipherTestFiles.readPrivateKeyFromFileTest(AsymmetricCipherTestFiles.java:160) 
    at AsymmetricCipherTestFiles.main(AsymmetricCipherTestFiles.java:40) 
Caused by: java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=109, too big. 
    at sun.security.pkcs.PKCS8Key.decode(Unknown Source) 
    at sun.security.pkcs.PKCS8Key.decode(Unknown Source) 
    at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(Unknown Source) 
    at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(Unknown Source) 
    at sun.security.rsa.RSAKeyFactory.generatePrivate(Unknown Source) 
    ... 4 more 

的事情是,在生成/讀/加密公鑰一切工作順利,當讀取私鑰並嘗試將其放入PrivateKey對象時發生錯誤。

我在做什麼錯了,我該如何解決這個問題?

謝謝。

+0

ObjectOutputStream是保存公鑰/私鑰的不好選擇。使用'getEncoded()'鍵獲取x.509/PKCS#8格式的數據。 – Robert

+0

感謝您的迴應,首先,什麼是'x.509/PKCS#8'以及我如何使用getEncoded()函數? – user2747636

+0

如果您不知道術語,請首先詢問Google/Wikipedia,然後再次詢問...'getEncoded'是每個Key實例上可用的方法,因此也可以在'PublicKey'和'PrivateKey'上使用。注意:我犯了一個錯誤,公鑰當然不是編碼爲x.509(不確定那個pkcs#1使用什麼標準?)。 – Robert

回答

2

您正在使用兩個writeObject()呼叫保存密鑰,但只通過一個readFully()呼叫進行回扣。您需要:

  • 保存與write(byte[])的關鍵,提供的結果getEncoded()readFully(),
  • 保存它writeObject()閱讀與閱讀readObject().

不是兩者的混合物。

+0

嘿,謝謝你的迴應,我不太明白它,我也得到錯誤的功能'公共靜態PrivateKey readPrivateKeyFromFile(字符串keyFileName)'它是http://pastebin.com/tDzERLQF ...你能幫助嗎?我修改了函數'readPrivateKeyFromFile'?感謝您的建議 – user2747636

+0

沒有人看到新代碼就可以告訴你新代碼有什麼問題。如果你對這個問題有一個修正,你應該編輯它。並沒有鏈接,或文字圖片。只是代碼和錯誤消息或異常堆棧跟蹤。 – EJP

相關問題