Encryption 使用Coldfusion';s Encrypt函数加密十六进制块并返回块长度结果

Encryption 使用Coldfusion';s Encrypt函数加密十六进制块并返回块长度结果,encryption,coldfusion,cryptography,encryption-symmetric,block-cipher,Encryption,Coldfusion,Cryptography,Encryption Symmetric,Block Cipher,我的公司正在进行一个项目,该项目将把读卡器投入现场。读卡器使用DUKPT TripleDES加密,因此我们需要开发软件对服务器上的卡数据进行解密 我刚刚开始在这一点上触及表面,但我发现自己陷入了一个看似简单的问题。。。在尝试生成IPEK时(重新创建对称密钥的第一步) IPEK是通过连接两个三重DES加密的8字节十六进制字符串创建的16字节十六进制值 我尝试过ECB和CBC(IV为零)模式,有填充和没有填充,但每次编码的结果总是16字节或更多(2个或更多块),当我需要与输入大小相同的结果时。事实上

我的公司正在进行一个项目,该项目将把读卡器投入现场。读卡器使用DUKPT TripleDES加密,因此我们需要开发软件对服务器上的卡数据进行解密

我刚刚开始在这一点上触及表面,但我发现自己陷入了一个看似简单的问题。。。在尝试生成IPEK时(重新创建对称密钥的第一步)

IPEK是通过连接两个三重DES加密的8字节十六进制字符串创建的16字节十六进制值

我尝试过ECB和CBC(IV为零)模式,有填充和没有填充,但每次编码的结果总是16字节或更多(2个或更多块),当我需要与输入大小相同的结果时。事实上,在整个过程中,cyphertext应该与编码的明文大小相同

<cfset x = encrypt("FFFF9876543210E0",binaryEncode(binaryDecode("0123456789ABCDEFFEDCBA98765432100123456789ABCDEF", "hex"), "base64") ,"DESEDE/CBC/PKCS5Padding","hex",BinaryDecode("0000000000000000","hex"))>

结果:3C65DEC44C216A686B2481BEC788D197F730A72D4A8CDD

如果使用NoPadding标志,结果是:

3C65Dec44CC216A686B2481Beec788D1

我还尝试将明文十六进制消息编码为base64(正如密钥所示)。在上面的示例中,返回以下结果:

DE5BC68EB1B2E14CEC35EB22AF04EFC

如果您执行相同的操作,除了使用NoPadding标志外,它会出现“输入长度不是8字节的倍数”的错误

我对密码学是新手,所以希望我在这里犯了一些非常基本的错误。为什么这些分组密码算法生成的密文与明文消息的长度不同

关于更多的背景知识,作为一个“通过it工作”的练习,我一直在尝试复制这里列出的工作:


我不确定它是否相关,也可能不是您想要的答案,但我花了一些时间测试bug ID。当使用不同属性时,CF在罩下处理种子和盐的方式不同。例如,如果将变量作为要加密的字符串而不是常量(函数调用中的硬编码字符串)传入,则结果字符串每次都会更改。这可能表示不同的方法签名-在您的示例中,一个标志与另一个标志的情况类似


Adobe的回答是,无论哪种情况,结果字符串都可以不加密,这实际上不是一个bug——更需要注意的是一种行为。您的结果字符串可以不加密吗

问题是
encrypt()
希望输入是UTF-8字符串。所以你实际上是在加密文字字符F-F-F-F-9。。。。而不是解码为十六进制时该字符串的值

相反,您需要将十六进制字符串解码为二进制,然后使用
encryptBinary()
函数。(注意,我没有看到链接中提到的
iv
,因此我猜测他们使用的是ECB模式,而不是CBC。)由于函数也返回二进制,请使用
binarycode
将结果转换为更友好的十六进制字符串

编辑:切换到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位整数。因此,您可能无法单独使用来完成下一步。一种选择是使用java的类。从十六进制字符串创建一个大整数,并使用
xor()
方法应用掩码。最后,使用
toString(基数)
方法以十六进制字符串的形式返回结果:

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");
bdkText=“0123456789ABCDEFFEDCBA9876543210”;
maskText=“C000000000C0C000000000”;
//使用基数=16从十六进制字符串创建整数
bdk=createObject(“java”,“java.math.biginger”).init(bdkText,16);
mask=createObject(“java”,“java.math.biginger”).init(maskText,16);
//应用掩码并将结果转换为十六进制(大写)
newKeyHex=ucase(bdk.xor(mask.toString(16));
WriteOutput(“
newKey=“&newKeyHex”); 写输出(
预期=C1E385A789ABCDEF3E1C7A5876543210);

这应该足以让你回到正轨。考虑到CF的一些局限性,java更适合IMO。如果您对它感到满意,您可以编写一个小型java类,并从CF调用它。

我很想看到一些关于这个的对话框。我对你在这里做的事很感兴趣,Coldfusion是我的语言。如果你找到了一个好的解决方案,请编辑/更新你的问题,并链接到一篇关于你所做的事情的博文。@FrankTudor如果/当我克服了一些技术障碍时,我将很高兴提供一个关于这些障碍的说明。值得注意的是,我在这段旅程中的第一个任务是创建一个简单的Coldfusion函数,将十六进制掩码按位应用于十六进制值。考虑到这是这项特殊工作的基本需求,我怀疑CF可能不适合这项任务,解决方案可能必须用Java编写。也许对于这一特定部分……您总是可以在Coldfusion中调用经过战斗测试的Java“东西”。Coldfusion对大多数事情都有好处,但我同意,当你遇到如此具体的事情时,你可能想看看你是否
createObject()
到一些java库/包的东西来更好地处理这个问题,并向Coldfusion注册它,这样你就可以把它作为你的库的一部分,并在你的CF开发过程中继续使用它。顺便说一句,我知道如果你指定CBC模式而不提供IVor salt,CF将帮助你随机生成一个,而不是告诉你它是什么,并使用它来加密你的明文。我认为这就是“解释”这种行为的原因。为什么这么做。。还有一件事我已经添加到越来越长的我不明白的事情列表中。当我指定静脉注射或使用ECB模式时,我没有任何随机性问题。Decrypt()可以很好地将密文返回为明文,只要我应用相同的方法