我的公司正在开展一个将读卡器放在现场的项目。读者使用DUKPT TripleDES加密,因此我们需要开发能够解密服务器卡数据的软件。
我刚刚开始研究这个问题,但我发现自己陷入了一个看似简单的问题......试图生成IPEK(重新创建对称密钥的第一步)。
IPEK是一个16字节的十六进制值,它是通过连接两个三重DES加密的8字节十六进制字符串而创建的。
我尝试过使用和不使用填充的ECB和CBC(IV为零)模式,但是当我需要一个结果时,每个单独编码的结果总是16个字节或更多(2个或更多个块)与输入相同的大小。实际上,在整个过程中,cyphertexts的大小应与编码的明文相同。
<cfset x = encrypt("FFFF9876543210E0",binaryEncode(binaryDecode("0123456789ABCDEFFEDCBA98765432100123456789ABCDEF", "hex"), "base64") ,"DESEDE/CBC/PKCS5Padding","hex",BinaryDecode("0000000000000000","hex"))>
结果:3C65DEC44CC216A686B2481BECE788D197F730A72D4A8CDD
如果使用NoPadding标志,则结果为:
3C65DEC44CC216A686B2481BECE788D1
我还尝试将明文十六进制消息编码为base64(如关键所示)。在上面的示例中,返回结果:
DE5BCC68EB1B2E14CEC35EB22AF04EFC。
如果你这样做,除了使用NoPadding标志外,它的错误为&#34;输入长度不是8字节的倍数。&#34;
我是密码学的新手,所以希望我在这里犯了一些非常基本的错误。为什么这些分组密码算法生成的密文长度与明文消息的长度不同?
对于更多的背景,作为一个&#34;通过它工作&#34;练习,我一直试图复制这里的工作:
https://www.parthenonsoftware.com/blog/how-to-decrypt-magnetic-stripe-scanner-data-with-dukpt/
答案 0 :(得分:2)
我不确定它是否相关,可能不是您正在寻找的答案,但我花了一些时间来测试错误ID 3842326。当使用不同的属性时,CF在引擎盖下不同地处理种子和盐。例如,如果将变量作为要加密的字符串而不是常量(函数调用中的硬编码字符串)传递,则结果字符串每次都会更改 。这可能表示不同的方法签名 - 在您的示例中,一个标志与另一个标志,您看到类似的东西。
Adobe的回应是,鉴于结果字符串在任何一种情况下都可以不加密,这实际上不是一个错误 - 更多的行为需要注意。您的结果字符串是否可以未加密?
答案 1 :(得分:1)
问题是encrypt()
期望输入是UTF-8字符串。所以你实际上在解码为十六进制时加密文字字符F-F-F-F-9 ....而不是该字符串的值。
相反,您需要将十六进制字符串解码为二进制,然后使用encryptBinary()
函数。 (注意,我没有在链接中看到iv
,所以我猜他们正在使用ECB模式,而不是CBC。)由于该函数也返回二进制,使用binaryEncode
将结果转换为更友好的十六进制字符串。
编辑:切换到ECB +“NoPadding”会产生所需的结果:
ksnInHex = "FFFF9876543210E0";
bdkInHex = "0123456789ABCDEFFEDCBA98765432100123456789ABCDEF";
ksnBytes = binaryDecode(ksnInHex, "hex");
bdkBase64 = binaryEncode(binaryDecode(bdkInHex, "hex"), "base64");
bytes = encryptBinary(ksnBytes, bdkBase64, "DESEDE/ECB/NoPadding");
leftRegister = binaryEncode(bytes, "hex");
......产生:
6AC292FAA1315B4D
为了做到这一点,我们想从我们原来的16字节BDK开始 ......并使用以下面具对其进行异或....
不幸的是,大多数CF数学函数仅限于32位整数。所以你可能不能单独使用native CF functions来完成下一步。一种选择是使用java的BigInteger类。从十六进制字符串创建一个大整数,并使用xor()
方法应用掩码。最后,使用toString(radix)
方法将结果作为十六进制字符串返回:
bdkText ="0123456789ABCDEFFEDCBA9876543210";
maskText = "C0C0C0C000000000C0C0C0C000000000";
// use radix=16 to create integers from the hex strings
bdk = createObject("java", "java.math.BigInteger").init(bdkText, 16);
mask = createObject("java", "java.math.BigInteger").init(maskText, 16);
// apply the mask and convert the result to hex (upper case)
newKeyHex = ucase( bdk.xor(mask).toString(16) );
WriteOutput("<br>newKey="& newKeyHex);
writeOutput("<br>expected=C1E385A789ABCDEF3E1C7A5876543210");
这应该足以让你回到正轨。考虑到CF的一些限制,java将更适合IMO。如果你对它感到满意,你可以编写一个小的java类,然后从CF调用它。