我以加密格式从Visa Checkout获取信息。其网站上的指南提供了以下说明:
首先,您必须解密动态密钥(encKey),然后使用解密的动态密钥值来解密支付数据有效负载(encPaymentData)。
按照以下四个步骤解密encKey:
- Base64-decode encKey。
- 删除解码值的前32个字节。这是HMAC(哈希消息认证码)。计算中的SHA-256 HMAC 使用您的API共享密钥对其余的解码数据进行比较并进行比较 从前32个字节到HMAC。
- 应删除接下来的16个字节,并将其用作解密算法的IV(初始化向量)。
- 使用AES-256-CBC,步骤3中的IV以及API共享密钥的SHA-256哈希解密剩余数据。
醇>按照以下四个步骤使用。解密encPaymentData 解密的encKey:
- Base64-解码encPaymentData。
- 删除解码值的前32个字节。这是HMAC。使用计算其余解码数据的SHA-256 HMAC 该 解密的encKey并将其与前32位的HMAC进行比较 字节。
- 应删除接下来的16个字节,并将其用作解密算法的IV。
- 使用AES-256-CBC(步骤3中的IV)和SHA256-hash解密其余的encPaymentData有效负载 解密的encKey。
醇>
我尝试过使用ColdFusion但是我因为加密问题而丢失了一些,而且无法修复代码。下面我有所需要的。我被困在第3步& 4他们说比较它然后解密它。有人可以指导可以做些什么来修复它吗?
加密:
2M2WWOD4wANsGwWTmPqQIQYdz9WPwgiR0ntJHGaxm23b5a1sWUtCBcUQUMMtc9hvcYavJ6yqPgETOGZgDOdd9qjDwIb2aV9DLZT1iIcB3zNN5Ddhxd9iiui6TAlJxU/O
encPaymentData:
X2TXp0ZmwHrtfzSP5TPjUOjdZb0rjsHeDSqr8TwIF/VR8sMQhWN5hP4IRhQxWT CZcQhxZoUHP 0g/E/ot sjREAJ8YQf7c7jSzKsXRH/wrew5rQit2wJBlVSSZ YoLeIHbLrTz CfIoFv09hixl7ff27u0YCyV0zjP5vNfCBEIwfqyriqwXK2J QEOxQiKzDUW4br3o1t31aymCQC9eBBpoVKjFfSKlNXM9QEdNZBcLMZ8Wlv8lF/ua bnwshbM9u7Uhudqvut94RZEW NzkRD8MfBo12e/XhnL35qxGpHeQNPClC4EQDK6U/HmegeOj BZLbIIYBs6t9E8Q3AKBwfiPOFgB gSVnhXKnd3nKvllaG BaGrQJtk 7QAtnHMHxQAO5rdiS9465HCdiHa8zlv7SkvWh8EwcKCiT4qiZSM6QuYAeRSzDpPS1gsZ54Q9LizUnueH7yyzSd47cLPd0VlOQxobKtNN2LrsRb3IwOfzuwGnSRf2cNp49hBmmGP1b0BC hhB6UpCqP2ixTPvui NwMYzqZUe336bF1mfnKzEbEZIvIrPyx3uMiLDAns2g7S80gMNnHb/09i49xbfY3V7oudeiHV99FCh67DuG3uHE3/HzIZbcnxJwVJoJj6/3DuzK/Kw1JqSorE0M1qxUqoNkJC4aNCBrqfTlR7/eErrvB554TUZwcyQXqKCwrKv4NJEw6S0n3W1VASkfA0atbJQX2aLgx9kqnhYdDbaU8UcFIoeA45 yEuQ9vXzo2ILQhvamsAAFQd3i4mEOZ KNtMu25dDFlORn5C/oTZ1t1dzJoYMvq44gejp6L3IK e7JCugGchr963a2kd8NFa3wctRDHF8ChHxawVlU0aY7nasrVireMFLiM 9XIb4abfDtct/j1Q8IGN0hRkgCHO6dlnOrAaaQDYYH3axaMDp5Onb04whULYqGbn/XSR8Sn8gnoFbYqVJbR5aCp5Pe9TpfwxlEvV3z8ZfsASqW2y So9gpwg2y16K/FX3Io6kqeqUlAxbTRDfN/ofDIJaO H PUu2teqjvwvCkjPciGOQdXT5JxqoCiHqRwD0zeZPcG3b9Nfrq3Caf6zjwhf /CMeGc3dNHhSkXox R50MP8BlLWk/bXZRScTE/HSrVxE n073utHAnbVOM3gVha0Hr8TmoV8z1vBg5fY253so6kQX61ZIfHneCAZo0qeKRgDgLUryVPmUNc5 yKP8DxtmHl/0YUztpgyEx5njsrn1L 3EHMMUhui8d LQdNZoEpZ9U1Xb7XVsV5gnwR/mOITNOKJQsine4zMMHBcomHclrM0CuI58YrKPqworCmK6CYfzSc8UmXxXUe5dzND/DS9XgqDttQic2/OqTSAK63ynnrNqzr3D56VpDBeDeQjk3mc/0zmuFAPEXoAQoQKfD6HEuajvWJebQ6QIPgA TshqsnPlktbpftr4lsuB1tHS/W8D7SYVFMC/Kxy9QuYWs0cmRTtzfWEKIRHeDElOTQCX5JB5PgzVhhi5kYTi488Ba8j4zvNUw55hEoMxONYO7eMjJosmNjULsT492LGw3EfAgmgx9h3yFLQRZgfylg0h4PfLlcPOAdsnVX9/yLElD xu7Atwc4S7pBWTHvwue7PpRvWpTeqkU5sqiX4KcV5x8rk mBtxm48a8fsmp GNf 4IjwXu9cQaU9WLipiEnkqFsYo7/aAsmmKWBETyQg9BFXYK 165vrzSX8WTsv6ZZDnVjcE1n4Ov8Jl2cnAigoQbB0ROPpIRzZ3zH2diUv1vzlSuh9gbEJf3uQRKlYRVUbpboC0RbQ/7jgznfJAWyLykyDQ0EB8fVEOtbP1l4JEz39QwAU18ph3btnWWuKEV4 ghYvNG4m1DYntSF57s2ajRS6rPtR oYvGjrJL9zbHBhKHlfkIPC0TKotOCi96mqpikbBEfIZSomHxYgDwYCSvt60zaDIjlBxZ1UBdK JL0554Wia9W3Wg91bmYS9Q4SXMT8r4xGYB7OutEV24n7p088rVm/w2SZSiqlLqai539k6WGkzEQf19ytPtIE81a N z7aijTjy 7FCuVPF90svI5/NoGpSINqv84HUcMU71BvXUIT53Ea6CCpiWvvOPpo/XZar44emlIG0UgeB kfP6C6sis=
密码:
zRf7WZ3nM7ON{U0E6J5S}KpVm@k2ReDyq#1lG9go
CF代码:
<cfset str = "2M2WWOD4wANsGwWTmPqQIQYdz9WPwgiR0ntJHGaxm23b5a1sWUtCBcUQUMMtc9hvcYavJ6yqPgETOGZgDOdd9qjDwIb2aV9DLZT1iIcB3zNN5Ddhxd9iiui6TAlJxU/O">
<cfset tobas = tobase64(str)>
<cfset getFirst32bytes = Left(tobas,32)>
<cfset tobas2 = RemoveChars(tobas,1,32)>
<cfdump var="#tobas2#">
<cfset key = "zRf7WZ3nM7ON{U0E6J5S}KpVm@k2ReDyq##1lG9go">
<cfset x = hmac("#tobas2#","#key#","HMACSHA256")>
<cfset y = hmac("#getFirst32bytes#","#key#","HMACSHA256")>
<cfset decalgo = Left(x,16)>
<cfset decremainingData = RemoveChars(x,1,16)>
<cfset getDec = Decrypt(decalgo,"#key#","AES")>
<cfdump var="#x#"><br>
<cfdump var="#y#"><br>
<cfdump var="#decalgo#">
<cfdump var="#decremainingData#">
<cfdump var="#getDec#">
这是他们网站上的java示例:
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String HASH_ALGORITHM = "SHA-256";
private static final String HMAC_ALGORITHM = "HmacSHA256";
private static final int IV_LENGTH = 16, HMAC_LENGTH = 32;
private static final Charset utf8 = Charset.forName("UTF-8");
private static final Provider bcProvider;
static {
bcProvider = new BouncyCastleProvider();
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(bcProvider);
}
}
private static byte[] decrypt(byte[] key, byte[] data) throws GeneralSecurityException {
byte[] decodedData = Base64.decode(data);
if (decodedData == null || decodedData.length <= IV_LENGTH) {
throw new RuntimeException("Bad input data.");
}
byte[] hmac = new byte[HMAC_LENGTH];
System.arraycopy(decodedData, 0, hmac, 0, HMAC_LENGTH);
if (!Arrays.equals(hmac,
hmac(key, decodedData, HMAC_LENGTH, decodedData.length– HMAC_LENGTH))) {
throw new RuntimeException("HMAC validation failed.");
}
byte[] iv = new byte[IV_LENGTH];
System.arraycopy(decodedData, HMAC_LENGTH, iv, 0, IV_LENGTH);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, bcProvider);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(hash(key), "AES"),
new IvParameterSpec(iv));
return cipher.doFinal(decodedData, HMAC_LENGTH + IV_LENGTH,
decodedData.length– HMAC_LENGTH– IV_LENGTH);
}
private static byte[] hash(byte[] key) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(HASH_ALGORITHM);
md.update(key);
return md.digest();
}
private static byte[] hmac(byte[] key, byte[] data, int offset, int length)
throws GeneralSecurityException {
Mac mac = Mac.getInstance(HMAC_ALGORITHM, bcProvider);
mac.init(new SecretKeySpec(key, HMAC_ALGORITHM));
mac.update(data, offset, length);
return mac.doFinal();
}
答案 0 :(得分:1)
了解示例代码的一个重要事项是它引用 bytes 。您的CF代码使用的是字符。这似乎是一个微不足道的区别,但它们是完全不同的东西,会产生非常非常不同的结果。为了成功解密,您需要使用给定字符串的字节(或二进制) - 而不是字符。
尽管可以使用核心CF函数(如arraySlice())来操作二进制数组,但语法有时会变得有点笨重/笨重。原因是二进制数组是与标准CF数组不同的对象类型,即byte []与java.util.List。因此,根据使用的函数,您可能需要javacast将变量强制转换为期望的类型。考虑到这一点..
- Base64-decode encKey。
- 删除解码值的前32个字节。这是HMAC(哈希消息认证码)。计算一个SHA-256 HMAC 其余的解码数据使用您的API共享密钥并进行比较 从前32个字节到HMAC。
醇>
首先使用binaryDecode将base64字符串转换为二进制。然后从返回的数组中提取适当数量的字节。这是预期的 HMAC值:
hmacSize = 32;
binaryToDecrypt = binaryDecode(encryptedKey, "base64");
expectedHMAC = binaryEncode( javacast("byte[]", arraySlice(binaryToDecrypt, 1, hmacSize))
, "hex" );
接下来,提取所有剩余字节,并使用它们来计算实际的HMAC。根据预期值进行验证。如果两者不匹配,就会出现问题。
remainData = arraySlice(binaryToDecrypt, hmacSize + 1);
actualHMAC = hmac( javacast("byte[]", remainData ), sharedSecret, "HMACSHA256");
if (compare(actualHMAC, expectedHMAC) != 0) {
throw("ERROR: Invalid HMAC ["& actualHMAC &"]. Expected ["& expectedHMAC &"]");
}
- 应删除接下来的16个字节,并将其用作解密算法的IV(初始化向量)。
醇>
其余字节包含IV,后跟加密值。在解密后者之前,您需要提取并分离两者:
ivSize = 16;
ivValue = javacast("byte[]", arraySlice(remainData, 1, ivSize));
encryptedValue = javacast("byte[]", arraySlice(remainData, ivSize + 1));
- 使用AES-256-CBC,步骤3中的IV以及API共享密钥的SHA-256哈希解密剩余数据。
醇>
解密之前的最后一步是通过散列共享密钥来生成解密密钥。不幸的是,CF的hash()函数总是返回一个十六进制字符串。因此必须将其转换为base64格式以与解密功能兼容。
keyHex = hash(sharedSecret, "SHA-256", "utf-8");
keyBase64 = binaryEncode(binaryDecode(keyHex, "hex"), "base64");
最后,使用所有三个值进行解密。返回的二进制文件将包含第二部分中使用的加密密钥。
decryptedKeyBinary = decryptBinary( encryptedValue
, keyBase64
, "AES/CBC/PKCS5Padding"
, ivValue);
使用与第一部分完全相同的过程,只需交换变量:
encPaymentData
代替encryptedKey
decryptedKeyBinary
代替sharedSecret
。最终的解密结果将是二进制的。使用charsetEncode将其转换回人类可读的字符串:
result = charsetEncode(decryptedResult, "utf-8");
NB:您发布的示例值似乎已损坏,因为它们甚至不能与java示例一起使用。当使用有效值(密钥,数据等)时,上述步骤会产生正确的结果。