web-dev-qa-db-ja.com

javax.crypto.AEADBadTagException:タグが一致しません!文字列の暗号化時のエラー

文字列を安全に暗号化して保存するために、Androidアプリ用の簡単な暗号化および復号化ヘルパークラスを作成しました。

これは、暗号化する単一の静的パブリックメソッドで構成され、次にプライベート静的メソッドを呼び出して暗号化されたメッセージを復号化して返します。暗号化/復号化後にメッセージが完全であるかどうかを確認するために、この方法をこの方法で記述しました。

私は文字列を使用して簡単なJUnitテストを作成し、暗号化暗号化メソッドに送信する前後に文字列に対してAssertEqualsを呼び出しました。

テストを実行すると、次のエラーが発生します。

_javax.crypto.AEADBadTagException: Tag mismatch!
_

エラースタック:

_at com.Sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.Java:571)
at com.Sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.Java:1046)
at com.Sun.crypto.provider.CipherCore.doFinal(CipherCore.Java:983)
at com.Sun.crypto.provider.CipherCore.doFinal(CipherCore.Java:845)
at com.Sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.Java:446)
at javax.crypto.Cipher.doFinal(Cipher.Java:2165)
at util.Crypto.decrypt(Crypto.Java:94)
at util.Crypto.encrypt(Crypto.Java:64)
at com.example.ALi.meappley.CryptoTest.encryptAndDecryptTest(CryptoTest.Java:29)
_

私は暗号化の初心者ですが、さまざまなスタックオーバーフローの返信を読みましたが、何の助けも見つかりませんでした。一部のユーザーは、cipher.update(someByteArray)を呼び出す前にcipher.doFinal(someByteArray)を呼び出すことを提案しましたが、うまく機能させることができませんでした。助言がありますか?

これは私のヘルパークラスです

_public class Crypto {

//public methods

//public static encrypt method
public static String encrypt(String messageToEncrypt, @Nullable byte[] associatedData) throws NoSuchPaddingException,
        NoSuchAlgorithmException,
        InvalidAlgorithmParameterException,
        InvalidKeyException,
        BadPaddingException,
        IllegalBlockSizeException {

    byte[] plainBytes = messageToEncrypt.getBytes();
/////////////////////////////////////////////////////////////////
    SecureRandom secureRandom = new SecureRandom();
    byte[] key = new byte[16];
    secureRandom.nextBytes(key);
    SecretKey secretKey = new SecretKeySpec(key, "AES");

    byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
    secureRandom.nextBytes(iv);

    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);

    if (associatedData != null) {
        cipher.updateAAD(associatedData);
    }

    byte[] cipherText = cipher.doFinal(plainBytes);

    ByteBuffer byteBuffer = ByteBuffer.allocate(4 + iv.length + cipherText.length);
    byteBuffer.putInt(iv.length);
    byteBuffer.put(iv);
    byteBuffer.put(cipherText);
    byte[] cipherMessage = byteBuffer.array();

    Arrays.fill(key,(byte) 0); //overwrite the content of key with zeros
    ///////////////////////////////////////////////////////////////////

    byte[] decrypted = decrypt(cipherMessage, null, key);

    return decrypted.toString();
}

//public static decrypt method
private static byte[] decrypt(byte[] cipherMessage, @Nullable byte[] associatedData, byte[] key) throws NoSuchPaddingException,
        NoSuchAlgorithmException,
        InvalidAlgorithmParameterException,
        InvalidKeyException,
        BadPaddingException,
        IllegalBlockSizeException {

    ByteBuffer byteBuffer = ByteBuffer.wrap(cipherMessage);
    int ivLength = byteBuffer.getInt();
    if(ivLength < 12 || ivLength >= 16) { // check input parameter
        throw new IllegalArgumentException("invalid iv length");
    }
    byte[] iv = new byte[ivLength];
    byteBuffer.get(iv);
    byte[] cipherText = new byte[byteBuffer.remaining()];
    byteBuffer.get(cipherText);

    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
    if (associatedData != null) {
        cipher.updateAAD(associatedData);
    }

    cipher.update(cipherText);
    byte[] plainText= cipher.doFinal(cipherText);

    return plainText;
}
_
5
Carlton

コードにはいくつかの問題があります:

1)暗号化メソッドで次の行を削除します(またはそれを復号化呼び出しの後ろに移動します)。

 Arrays.fill(key, (byte) 0); // overwrite the content of key with zeros

それ以外の場合、暗号化と復号化のキーは異なります。

2)暗号化メソッドで、関連付けられたデータを復号化呼び出しで渡します。

 byte[] decrypted = decrypt(cipherMessage, null, key);

 byte[] decrypted = decrypt(cipherMessage, associatedData, key);

暗号化と復号化のために渡されたassociatedDataは、有効性のために一致する必要があります。 associatedDataの目的については、たとえば、 https://crypto.stackexchange.com/questions/6711/how-to-use-gcm-mode-and-associated-data-properly

3)復号化メソッドで行を削除します

 cipher.update(cipherText);

更新方法の目的については、例えばを参照してください。 Javaでのcipher.updateの機能

3つの問題すべてがAEADBadTagExceptionを引き起こします。

4)テスト目的で、あなたの暗号化メソッドが復号化された.toString()を返すのではないかと思いますが、オブジェクトのクラスとハッシュコードしか提供しません。返すことはより理にかなっています新しい文字列(復号化)。

3
Topaco