如何使用Android AES加密与coldfusion encrypt相同

How to use Android AES encryption same as coldfusion encrypt

我们在网络上使用 coldfusion encrypt 方法。

Encrypt(plainText, key, "AES", "Hex")

而在 Android 中,我们使用以下方式使用加密方法:

public static String aesEncryption(String plainText, String key) {
        try {
            SecretKey secKey = new SecretKeySpec(key.getBytes(), "AES");
            Cipher aesCipher = Cipher.getInstance("AES");
            aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
            aesCipher.update(plainText.getBytes());
            byte[] cipherText = aesCipher.doFinal();
            return bytesToHex(cipherText);
        } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return null;
    }


    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

但是在Android中加密的输出不匹配,如何使用Android AES加密与coldfusion encrypt相同?

加密需要比"AES"更多的细节,根据符号,它必须是这样的:AES/CBC/PKCS7Padding,即它应该是:

Cipher.getInstance(transformation);

其中 transformation 应由 [Algorithm]/[Mode]/[Padding] 组成,可能值的范围取决于基础密码。 Java 是这样的:

AES/CBC/NoPadding
AES/CBC/PKCS5Padding
AES/ECB/NoPadding
AES/ECB/PKCS5Padding
DES/CBC/NoPadding
etc...

如果您不指定模式和填充,在这种情况下密码将使用默认值。

我不知道 ColdFusion 方面的默认值是什么,无论如何我建议在 ColdFusion 和 Android 方面都使用完整规范,例如:AES/CBC/PKCS5Padding - 是一个很好的做法。

AES 被指定为算法 [1]. In Java/Android the provider decides which mode and padding is used if only AES is specified [2] 时,Coldfusion 的 encrypt 默认使用 AES/ECB/PKCS5 填充,但通常它也是 AES/ECB/PKCS5 填充(就像我的机器,Android 9,API 28)。因此算法的规范是可能不是原因。尽管如此,最好在 Java 代码中使用完整规范 AES/ECB/PKCS5Padding 而不是 AES.

可能是 Coldfusion 代码中的密钥在 Java 代码中使用不正确。在 Coldfusion 中,密钥通常使用 generateSecretKey [3] 生成,其中 returns 密钥采用 Base64 编码。这意味着在 Android 代码中,密钥首先必须使用 Base64 解码:

SecretKey secKey = new SecretKeySpec(Base64.decode(key, Base64.DEFAULT), "AES");

此外,如果密钥是为 AES-128 生成的,则不会抛出异常,因为密钥长 16 个字节,而 Base64 编码仅 24 个字节,在当前 Android 代码中会生成 AES因为

相同长度的密钥
SecretKey secKey = new SecretKeySpec(key.getBytes(), "AES"); 

因此,将使用 AES-192 而不是 AES-128,当然会产生不同的密文。

更新:正如评论中已经提到的,ECB 是一种不安全的操作模式,不应使用[4]. A more secure alternative is CBC [5], which is supported in both Java/Android and Coldfusion [6]. Even more secure and modern is GCM, an authenticated encryption algorithm that guarantees both data authenticity and confidentiality [7], which, if supported, should be preferred. Here a description of further modes can be found [8]