文字列を安全に暗号化して保存するために、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;
}
_
コードにはいくつかの問題があります:
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()を返すのではないかと思いますが、オブジェクトのクラスとハッシュコードしか提供しません。返すことはより理にかなっています新しい文字列(復号化)。