我正在开发一个项目,以解密作为URL参数传递的ColdFusion中的AES-128加密字符串。

供应商采用一个密码短语并将其转换为有效的AES-128密钥,“使用与Microsoft的使用SHA-1哈希函数的CryptDeriveKey等效的算法”。我需要在ColdFusion中复制此generateKey,以便可以在我的crypto()调用中使用该值。

使用CryptDeriveKey时,您传递加密类型,哈希类型,块长度和0 iv数组,并返回哈希。资料来源:Generating a Key from a Password


// generate an RC2 key
byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] key = cdk.CryptDeriveKey(“RC2”, “SHA1”, 128, iv);



在供应商的测试工具中,密码短语“ test1234”导致散列为:

 A6455C7A24BC5E869B0DDF647238F5DA


我发现了genAESKeyFromPW() UDF,它似乎是最接近的,但是需要CryptDeriveKey不使用的盐。我也尝试了下面的代码。但是,由于Hash()未创建有效的AES-128密钥,因此它不起作用:

<cfset generatedKey = Hash('test1234', 'SHA-1')>
<cfset decrypted=decrypt(encryptedString, generatedKey, 'AES/CBC/PKCS7Padding', 'Base64', '0')>


我需要复制CryptDeriveKey函数的哪些步骤?

更新:

供应商提供了以下C#解密示例:

public static byte[] AesDecryptBytes(byte[] cipherText, byte[] key)
{
    byte[] IV = new byte[16];

    AesManaged aes = new AesManaged();
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7;
    ICryptoTransform decryptor = aes.CreateDecryptor(key, IV);

    byte[] plainBytes;

    using (MemoryStream memoryStream = new MemoryStream())
    {
        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
        {
            cryptoStream.Write(cipherText, 0, cipherText.Length);
        }

        plainBytes = memoryStream.ToArray();
    }

    return plainBytes;
}

最佳答案

根据我在this documentation中所读的内容,听起来该函数本质上是对二进制密码进行哈希处理,然后对两个数组进行XOR。我不是100%,但我认为他们描述的方法与PBKDF1或PBKDF2相同。


令n为所需的派生密钥长度(以字节为单位)。派生密钥是
哈希计算后的哈希值的前n个字节为
由CryptDeriveKey完成。如果哈希值不是
SHA-2系列,并且所需的密钥是3DES或AES的密钥
推导如下:


通过重复常数0x36 64次来形成64字节的缓冲区。令k为由输入表示的哈希值的长度
参数hBaseData。将缓冲区的前k个字节设置为结果
缓冲区的前k个字节与哈希进行XOR操作的结果
输入参数hBaseData表示的值。
通过重复常数0x5C 64次来形成64字节的缓冲区。将缓冲区的前k个字节设置为XOR操作的结果
哈希值是以下值的缓冲区的前k个字节
由输入参数hBaseData表示。
通过使用与用于计算hBaseData表示的哈希值的哈希算法相同的哈希算法来哈希步骤1的结果
参数。
通过使用与用于计算由hBaseData表示的哈希值的算法相同的哈希算法来哈希步骤2的结果
参数。
将步骤3的结果与步骤4的结果连接起来。
使用步骤5的结果的前n个字节作为派生密钥。





CF密钥生成

hashing密码开头,然后使用binaryDecode将其转换为二进制文件:

hBaseData = binaryDecode(hash("test1234", "SHA1"), "hex");


用指定的常量构建并填充两个缓冲区:

// 0x36 (i.e. 54 decimal)
buff1 = listToArray(repeatString("54,", 64));
// 0x5C (i.e. 92 decimal)
buff2 = listToArray(repeatString("92,", 64));


然后进行按位异或,将结果存储在缓冲区中:

for (k = 1; k <= arrayLen(hBaseData); k++) {
    buff1[k] = BitXOR( buff1[k], hBaseData[k]);
    buff2[k] = BitXOR( buff2[k], hBaseData[k]);
}


下一个hash()都缓冲并连接结果:

hash1 = hash( javacast("byte[]", buff1), "SHA1");
hash2 = hash( javacast("byte[]", buff2), "SHA1");
combined = hash1 & hash2;


最后,提取第一个n字节(16 == 128位/ 8)作为新密钥。由于CF的hash()函数返回十六进制(每字节始终两个字符),因此可以在此处使用字符串函数。

keySize = 128 / 8;
newKey = left(combined, keySize *2);


结果:A6455C7A24BC5E869B0DDF647238F5DA



在CF中解密

在解密之前,请注意以下重要事项:


CF的加密/解密功能希望密钥被编码为base64。上面生成的密钥为十六进制格式。所以必须先转换:
“ PKCS7Padding”对于CF / Java无效。 Instead use PKCS5Padding
“ CBC”模式始终需要IV。 IV是一个二进制数组,其长度与算法的块大小相同(AES块大小= 16字节)。它必须是“ ...用于成功解密数据的相同值(用于加密)”。根据您API中的描述,您的IV应该为全零。 (这在实践中不是很好,但是对于一个测试用例是可以的)。


有关更多详细信息,请参见Strong encryption in ColdFusion

例:

encrypted = "1lqcm0Jiy4Rs29tz2jpuoQ==";
newKeyHex = "A6455C7A24BC5E869B0DDF647238F5DA";
keyBase64 = binaryEncode(binaryDecode(newKeyHex, "hex"), "base64");
iv = javacast("byte[]", [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
decrypted = decrypt(encrypted, keyBase64, "AES/CBC/PKCS5Padding", "Base64", iv);
writeOutput("<br>"& decrypted);


结果:recordID=000001

关于encryption - 在Coldfusion中复制CryptDeriveKey,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44571303/

10-11 04:43