我正在开发一个项目,以解密作为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/