2012-03-12 53 views
2

まず、私が持っている問題について説明し、次に何をしようとしているのかを説明します。最後に、関連するコードスニペットを貼り付けます。Javaで解読しようとすると「間違ったアルゴリズム」エラーが発生する

https://stackoverflow.com/a/992413/171993で指定された方法を使用して、秘密鍵の暗号化/復号化を実装しようとしています。この例をそのまま使用すると、(私はCipherクラスを再インスタンス化する必要があることに気付いたが、それ以外の場合は復号化によってガーベッジが生成される)。しかし、私の実装では、私は次の例外を取得します:実際に、私は定数にAES/CBC/PKCS5Paddingを割り当てられ、両方のインスタンス化のためにそれを使用します。

java.security.InvalidKeyException: Wrong algorithm: AES or Rijndael required 
    at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:77) 
    at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:91) 
    at com.sun.crypto.provider.CipherCore.init(CipherCore.java:469) 
    at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:217) 
    at javax.crypto.Cipher.implInit(Cipher.java:790) 
    at javax.crypto.Cipher.chooseProvider(Cipher.java:848) 
    at javax.crypto.Cipher.init(Cipher.java:1347) 
    at javax.crypto.Cipher.init(Cipher.java:1281) 
    at securitytest.SecurityManager.getCipher(SecurityManager.java:175) 
    at securitytest.SecurityManager.decryptSecretKey(SecurityManager.java:379) 
    at securitytest.SecurityManager.<init>(SecurityManager.java:82) 
    at securitytest.Test.main(Test.java:44) 

は明白な疑問、はい、私は同じアルゴリズムを使用して行うを撃退するには暗号化と復号化のためのクラスCipher。私はまた、AESだけを使用して復号化のためにCipherをインスタンス化しようとしましたが、どちらもうまくいかなかった。

私がしようとしているのは、AES/CBC/PKCS5Paddingを使用して秘密鍵をパスワードで保護することです。ランダムな塩と初期化ベクトルを生成します。秘密鍵を暗号化した後、暗号化された値(バイトの配列、新しい配列を作成する)に初期化ベクトル(バイトの配列)を追加します。私はこの値をBase64でエンコードし、塩と一緒にSqliteデータベースに保存します(簡単にするため、コンマで区切った値の文字列として保存します)。しかし私が解読しようとすると、上記の例外が発生します。私は直接暗号化方式へと直接復号化方法の前に私の呼び出しの後、次の値が正確であることを確認することができ、同じ(Base64でに変換するとき、私はそれをプリントアウトすることができるように):

  1. 塩を
  2. 初期ベクトル
  3. 暗号化された秘密鍵(すなわち暗号文)

私は、Java 6と7の両方を試してみました:両方が同じ結果を与えます。私はまた、無制限の権限管轄のポリシーファイルを問題として排除しました。実際には、別のアルゴリズムで "AES"を置き換えて、それに応じて塩の長さを調整すると、同様のエラーが発生します(たとえば、BlowfishのIV長は、java.security.InvalidKeyException: Wrong algorithm: Blowfish requiredです)。

Googleではこの問題を解決できませんでした。誰かがこれについて少しの光を当てることができれば、私は非常に感謝しています。ここで

は、いくつかのコードスニペットです(私の謝罪、それは少し荒いです):

private static final int INIT_VECTOR_LENGTH = 16; 
private static final int PRIVATE_KEY_LENGTH = 128; 
private static final int SALT_LENGTH = 16; 
private static final int PBE_KEYSPEC_ITERATIONS = 65536; 

private static final String CIPHER_ALGORITHM = "AES"; 
private static final String CIPHER_ALGORITHM_MODE = "CBC"; 
private static final String CIPHER_ALGORITHM_PADDING = "PKCS5Padding"; 
private static final String DIGEST = "SHA1"; 
private static final String PLAINTEXT_ENCODING = "UTF8"; 
private static final String PRNG = DIGEST + "PRNG"; 
private static final String SECRET_KEY_FACTORY = "PBKDF2WithHmac" + DIGEST; 

private static final String CIPHER = CIPHER_ALGORITHM + "/" + CIPHER_ALGORITHM_MODE + "/" + CIPHER_ALGORITHM_PADDING; 

private IvParameterSpec ivSpec; 
private final BASE64Encoder encoder = new BASE64Encoder(); 
private final BASE64Decoder decoder = new BASE64Decoder(); 

private Cipher getCipher(SecretKey key, int mode) { 

    Cipher cipher = null; 

    try { 
     cipher = Cipher.getInstance(CIPHER); 
    } 
    catch (NoSuchAlgorithmException e) {System.err.println(System.err.println(e.getMessage());} 
    catch (NoSuchPaddingException e) {System.err.println(e.getMessage());} 

    try { 
     if (mode == Cipher.ENCRYPT_MODE) { 
      cipher.init(mode, key); 
      AlgorithmParameters params = cipher.getParameters(); 
      ivSpec = params.getParameterSpec(IvParameterSpec.class); 
     } 
     else { 
      /* This is my point-of-failure. */ 
      cipher.init(mode, key, ivSpec); 
     } 
    } 
    catch (InvalidKeyException e) {System.err.println(e.getMessage());} 
    catch (InvalidAlgorithmParameterException e) {System.err.println(e.getMessage());} 
    catch (InvalidParameterSpecException e) {System.err.println(e.getMessage());} 

    return cipher; 

} 

private SecurityData.Secrets generateSecrets(SecretKey decryptedKey, byte[] salt, String passphrase) { 

    /* Generate a new key for encrypting the secret key. */ 
    byte[] raw = null; 
    PBEKey key = null; 
    PBEKeySpec password = new PBEKeySpec(passphrase.toCharArray(), salt, PBE_KEYSPEC_ITERATIONS, PRIVATE_KEY_LENGTH); 
    SecretKeyFactory factory = null; 
    byte[] initVector = null; 
    byte[] secretKeyBytes = decryptedKey.getEncoded(); 

    try { 
     factory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY); 
     key = (PBEKey) factory.generateSecret(password); 
    } 
    catch (NoSuchAlgorithmException e) {System.err.println(e.getMessage());} 
    catch (InvalidKeySpecException e) {System.err.println(e.getMessage());} 

    SecretKeySpec newKey = new SecretKeySpec(key.getEncoded(), CIPHER_ALGORITHM); 

    /* Encrypt the secret key. */ 
    IvParameterSpec ivSpec = new IvParameterSpec(initVector); 
    Cipher cipher = getCipher(newKey, ivSpec, Cipher.ENCRYPT_MODE); 

    try { 
     raw = cipher.doFinal(secretKeyBytes); 
    } 
    catch (IllegalBlockSizeException e) {System.err.println(e.getMessage());} 
    catch (BadPaddingException e) {System.err.println(e.getMessage());} 

    return new SecurityData.Secrets(encoder.encode(concatByteArrays(initVector, raw)), joinByteArray(salt)); 

} 

private SecretKey decryptSecretKey(String encryptedKey, String salt, String passphrase) { 

    /* Get initialisation vector. */ 
    byte[] raw = null, decoded = null, initVector = new byte[INIT_VECTOR_LENGTH]; 
    try { 
     decoded = decoder.decodeBuffer(encryptedKey); 
    } catch (IOException e) {System.err.println(e.getMessage());} 
    System.arraycopy(decoded, 0, initVector, 0, INIT_VECTOR_LENGTH); 
    raw = new byte[decoded.length-INIT_VECTOR_LENGTH]; 
    System.arraycopy(decoded, INIT_VECTOR_LENGTH, raw, 0, decoded.length-INIT_VECTOR_LENGTH); 
    IvParameterSpec ivSpec = new IvParameterSpec(initVector); 

    /* Generate the key. */ 
    byte[] rawSalt = splitByteArrayString(salt); 
    PBEKeySpec password = new PBEKeySpec(passphrase.toCharArray(), rawSalt, PBE_KEYSPEC_ITERATIONS, PRIVATE_KEY_LENGTH); 
    SecretKeyFactory factory = null; 
    PBEKey key = null; 
    try { 
     factory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY); 
     key = (PBEKey) factory.generateSecret(password); 
    } 
    catch (NoSuchAlgorithmException e) {System.err.println(e.getMessage());} 
    catch (InvalidKeySpecException e) {System.err.println(e.getMessage());} 

    Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE); 

    /* Decrypt the message. */ 
    byte[] stringBytes = null; 
    try { 
     stringBytes = cipher.doFinal(raw); 
    } 
    catch (IllegalBlockSizeException e) {System.err.println(e.getMessage());} 
    catch (BadPaddingException e) {System.err.println(e.getMessage());} 

    /* Converts the decoded message to a String. */ 
    String clear = null; 
    try { 
     clear = new String(stringBytes, PLAINTEXT_ENCODING); 
    } 
    catch (UnsupportedEncodingException e) {System.err.println(e.getMessage());} 

    return new SecretKeySpec(clear.getBytes(), CIPHER_ALGORITHM); 

} 
+0

マイたとえば、あなたが引用され、*ない*再インスタンス化および再初期化「であるとして、」、 'Cipher'を:例では、これらの手順を持っている理由です。 – erickson

答えて

3

SecretKeyオブジェクトがそのgetAlgorithm()メソッドから「AES」を返す必要があります。

SecretKey tmp = factory.generateSecret(spec); 
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); 
+0

興味深いことに、 'SecretKey'オブジェクトはそのアルゴリズムを' SecretKeyFactory'アルゴリズム "PBKDF2WithHmacSHA1"として報告します... –

+1

右。あなたがその情報を提供していないとき、どのようにキーファクトリが正しいアルゴリズムでキーを生成することができるでしょうか?そして、それを行うためのAPIはありません。そのため、SecretKeySpecの作成が必要です。 – erickson

+0

ああ、はい、私は今あなたが意味するものを参照してください!どうもありがとうございました! –

関連する問題