2012-03-03 23 views
2

JavaのRSAアルゴリズムによる文字列の信頼性の低い暗号化と復号化には、非常に迷惑な問題があります。それは時代の約35%しか働かず、なぜ時にはうまくやっていないのか分かりません。暗号化/復号化のランダム性を検証するために書いたテストコードです。これは、100のラップを実行し、それが毎回暗号化し、同じ文字列を復号化し、それが成功した回数を出力します。Javaの信頼性の低い文字列のRSA暗号化/復号化

public static void main(String[] args) throws Exception { 
    byte[] dataToEncrypt = "Hello World!".getBytes("UTF-16LE"); 
    byte[] cipherData = null; 
    byte[] decryptedData; 

    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); 
    kpg.initialize(512); 
    KeyPair kp = kpg.genKeyPair(); 
    Key publicKey = kp.getPublic(); 
    Key privateKey = kp.getPrivate(); 
    KeyFactory fact = KeyFactory.getInstance("RSA"); 

    RSAPublicKeySpec pub = (RSAPublicKeySpec) fact.getKeySpec(publicKey, 
      RSAPublicKeySpec.class); 

    RSAPublicKeySpec spec = new RSAPublicKeySpec(pub.getModulus(), pub 
      .getPublicExponent()); 
    KeyFactory factory = KeyFactory.getInstance("RSA"); 

    PublicKey publicKeyRSA = factory.generatePublic(spec); 
    Cipher cipher = Cipher.getInstance("RSA"); 

    int k = 0; 
    for (int i = 0; i < 100; i++) { 
     try { 
      cipher.init(Cipher.ENCRYPT_MODE, publicKeyRSA); 
      cipherData = cipher.doFinal(dataToEncrypt); 
     } catch (Exception e1) { 
      System.out.println("Encrypt error"); 
     } 

     String s = new String(cipherData, "UTF-16LE"); 
     cipher.init(Cipher.DECRYPT_MODE, privateKey); 

     try { 
      decryptedData = cipher.doFinal(s.getBytes("UTF-16LE")); 
      System.out.println("Decrypted: " 
        + new String(decryptedData, "UTF-16LE")); 
      k += 1; 
     } catch (Exception e1) { 
      System.out.println("Decrypt error"); 
     } 
    } 
    System.out.println("Number of correct decryptions is: " + k); 

} 

私は成功せず、様々な値とするKeyPairGeneratorを初期化しようとしました。

編集: 今では魔法のように動作し、Base64のおかげ:

import java.io.FileOutputStream; 
    import java.io.OutputStream; 
    import java.security.Key; 
    import java.security.KeyFactory; 
    import java.security.KeyPair; 
    import java.security.KeyPairGenerator; 
    import java.security.PublicKey; 
    import java.security.spec.RSAPublicKeySpec; 
    import javax.crypto.Cipher; 

    public class Test { 

    public static void main(String[] args) throws Exception { 
    byte[] dataToEncrypt = "Hello World!".getBytes("UTF-16LE"); 
    byte[] cipherData = null; 
    byte[] decryptedData; 


    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); 
    kpg.initialize(512); 
    KeyPair kp = kpg.genKeyPair(); 
    Key publicKey = kp.getPublic(); 
    Key privateKey = kp.getPrivate(); 
    KeyFactory fact = KeyFactory.getInstance("RSA"); 

    RSAPublicKeySpec pub = (RSAPublicKeySpec) fact.getKeySpec(publicKey, 
      RSAPublicKeySpec.class); 

    RSAPublicKeySpec spec = new RSAPublicKeySpec(pub.getModulus(), pub 
      .getPublicExponent()); 
    KeyFactory factory = KeyFactory.getInstance("RSA"); 

    PublicKey publicKeyRSA = factory.generatePublic(spec); 
    Cipher cipher = Cipher.getInstance("RSA"); 

    int k = 0; 
    for (int i = 0; i < 100; i++) { 
     try { 
      cipher.init(Cipher.ENCRYPT_MODE, publicKeyRSA); 
      cipherData = cipher.doFinal(dataToEncrypt); 
     } catch (Exception e1) { 
      System.out.println("Encrypt error"); 
     } 

     String s = Base64.encodeBytes(cipherData); 
     cipher.init(Cipher.DECRYPT_MODE, privateKey); 

     try { 
      decryptedData = cipher.doFinal(Base64.decode(s)); 
      System.out.println("Decrypted: " 
        + new String(decryptedData, "UTF-16LE")); 
      k += 1; 
     } catch (Exception e1) { 
      System.out.println("Decrypt error"); 
     } 
    } 
    System.out.println("Number of correct decryptions is: " + k); 

} 

}

+0

通常、ユーザーデータ(文字列など)はRSAで直接暗号化しません。しかし、むしろランダムな対称鍵を作成し、その鍵を使って実際のユーザデータを暗号化し、RSAで鍵を暗号化するだけです。それはあなたの直面する問題の原因ではありませんが、あなたはそれを念頭に置いておくべきです。 – CodesInChaos

答えて

5

これが問題である、または少なくとも問題:

String s = new String(cipherData, "UTF-16LE"); 

任意のバイナリデータを取得していて、st UTF-16でエンコードされたテキストのように扱います。そうではありません。任意のバイナリデータです。

byte[]のように)バイナリ形式にしておくか、またはbase64を使用して、安全でリバーシブルな方法でテキストに変換します。

4

暗号化されたバイトストリームをUTF16-LEに変換する可能性があるためです。