Flutter 中的 AES/GCM 加密 (Dart)

May*_*kur 1 encryption cryptography aes aes-gcm flutter

我正在尝试在 flutter 中实现 AES/GCM/NoPadding 加密。我已经在JAVA中成功实现了它,但是当我尝试在flutter中解密它时,我没有成功。

我尝试在 dart 中编写解密代码,但出现 未处理的异常:SecretBox 有错误的消息身份验证代码 (MAC)

我的Java代码

public class GCMEncryption {
    public static final int AES_KEY_SIZE = 128;
    public static final int GCM_IV_LENGTH = 12;
    public static final int GCM_TAG_LENGTH = 16;

    public String getEncryptedText(String plainText) {
        try {
            byte[] IV = new byte[GCM_IV_LENGTH];
            SecureRandom random = new SecureRandom();
            random.nextBytes(IV);
            String iv = Base64.getEncoder().encodeToString(IV);
            System.out.println("IV : "+iv);
            
            byte[] cipherText = encrypt(plainText.getBytes(), getKeySpec(), IV);
            String text = Base64.getEncoder().encodeToString(cipherText);
            text = iv+text; // Concating iv and encrypted text together 
            return text;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public String getDecryptedText(String cipherText) {
        try {

            // Splitting IV and Encrypted text
            String iv = cipherText.substring(0,16);
            System.out.println("IV : "+iv);
            byte[] IV = Base64.getDecoder().decode(iv);
            cipherText = cipherText.substring(16);
            
            
            byte[] data = Base64.getDecoder().decode(cipherText);
            return decrypt(data, getKeySpec(), IV);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    private SecretKeySpec getKeySpec() {
        SecretKeySpec spec = null;

        try {
            byte[] bytes = new byte[32];
            String pwd = "Test!ng012345678"; //Temporary
            bytes = pwd.getBytes();
            spec = new SecretKeySpec(bytes, "AES");
            return spec;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return spec;
    }

    private byte[] encrypt(byte[] plaintext, SecretKey key, byte[] IV) throws Exception {
        // Get Cipher Instance
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        // Create SecretKeySpec
        SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");

        // Create GCMParameterSpec
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV);

        // Initialize Cipher for ENCRYPT_MODE
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);

        // Perform Encryption
        byte[] cipherText = cipher.doFinal(plaintext);

        return cipherText;
    }

    private String decrypt(byte[] cipherText, SecretKey key, byte[] IV) throws Exception {
        // Get Cipher Instance
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        // Create SecretKeySpec
        SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");

        // Create GCMParameterSpec
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV);

        // Initialize Cipher for DECRYPT_MODE
        cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);

        // Perform Decryption
        byte[] decryptedText = cipher.doFinal(cipherText);

        return new String(decryptedText);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的飞镖代码

 Future<String> decrypt(String textBlock) async {
    Uint8List data  = base64.decode("4NA09I5VpmdD0o1k3VP8eIfyZRKDtzOwgJv5nh0nmEPZ/Q==");
    Uint8List passphrase = utf8.encode('Test!ng012345678');
    SecretKey secretKey = new SecretKey(passphrase);

    Uint8List iv = utf8.encode('/U0OI/AdHDM4QFVC');
    SecretBox secretBox = new SecretBox(data, nonce: iv);
    List<int> decrypted = await AesGcm.with128bits().decrypt(secretBox, secretKey: secretKey);
    String dec = utf8.decode(decrypted);
    print("DATA : "+dec);
    return dec;
  }
Run Code Online (Sandbox Code Playgroud)

为此,我在 Flutter 中遇到了以下错误

未处理的异常:SecretBox 有错误的消息身份验证代码 (MAC) #0 DartAesGcm.decryptSync (package:cryptography/src/dart/aes_gcm.dart:112:7) #1 DartAesGcm.decrypt (package:cryptography/src/dart/aes_gcm. dart:58:12) #2 EncryptionHandler.decrypt (包:investment_app/加密/加密_handler.dart:45:27)

你能帮我解决这个问题吗?示例代码会很有帮助。

Top*_*aco 6

Java 中的 SunJCE 提供程序连接密文和 MAC:ciphertext|MAC。在 Dart 代码中,两者都必须单独指定,这在发布的代码中不会发生。此外,IV 未经过 Base64 解码。

以下代码是修复错误的可能实现:

Uint8List ivCiphertextMac = base64.decode("/U0OI/AdHDM4QFVC4NA09I5VpmdD0o1k3VP8eIfyZRKDtzOwgJv5nh0nmEPZ/Q=="); // from the Java code
Uint8List iv = ivCiphertextMac.sublist(0, 12);
Uint8List ciphertext  = ivCiphertextMac.sublist(12, ivCiphertextMac.length - 16);
Uint8List mac = ivCiphertextMac.sublist(ivCiphertextMac.length - 16);

Uint8List passphrase = utf8.encode('Test!ng012345678');
SecretKey secretKey = new SecretKey(passphrase);

SecretBox secretBox = new SecretBox(ciphertext, nonce: iv, mac: new Mac(mac));

List<int> decrypted = await AesGcm.with128bits().decrypt(secretBox, secretKey: secretKey);
String dec = utf8.decode(decrypted);
print("Decrypted text : " + dec); // Decrypted text : Mayur, You got it!
Run Code Online (Sandbox Code Playgroud)

解密结果是:Mayur,你明白了!

实际上提供了将IV、密文和MAC 串联起来的SecretBox方法。fromConcatenation()但这个实现似乎返回了一个损坏的密文,这可能是一个错误。

编辑:

关于您在评论中提出的问题:MAC是在加密过程中自动生成的。以下代码实现了加密,其中ivCiphertextMacB64包含 IV | 的 Base64 编码 密文| 苹果:

Uint8List plaintext  = utf8.encode("Mayur, You got it!");
Uint8List iv = AesGcm.with128bits().newNonce();
Uint8List passphrase = utf8.encode('Test!ng012345678');
SecretKey secretKey = new SecretKey(passphrase);

SecretBox secretBox = await AesGcm.with128bits().encrypt(plaintext, nonce: iv, secretKey: secretKey);
String ivCiphertextMacB64 = base64.encode(secretBox.concatenation()); // Base64 encoding of: IV | ciphertext | MAC
print("ivCiphertextMacB64 : " + ivCiphertextMacB64);
Run Code Online (Sandbox Code Playgroud)