ColdFusion 的 SecretKeySpec

SecretKeySpec for ColdFusion

我正在尝试将此代码转换为 java 但结果不准确

private String hmacDigest(String msg, String keyString, String algo) throws Exception {
    String digest = null;
    SecretKeySpec key = new SecretKeySpec((keyString).getBytes("UTF-8"), algo);
    Mac mac = Mac.getInstance(algo);
    mac.init(key);

    byte[] bytes = mac.doFinal(msg.getBytes("ASCII"));

    StringBuffer hash = new StringBuffer();
    for (int i = 0; i < bytes.length; i++) {
        String hex = Integer.toHexString(0xFF & bytes[i]);
        if (hex.length() == 1) {
            hash.append('0');
        }
        hash.append(hex);
    }
    digest = hash.toString();
    return digest;
}

我的 codfusion 尝试到此为止

<cfset keybytes = BinaryDecode(SECRET_KEY, "Hex")>
<cfset databytes = CharsetDecode(data, "UTF-8")>
<cfset secret = createObject("java", "javax.crypto.spec.SecretKeySpec").Init(keybytes,"HmacSHA256")>
<cfset mac = createObject("java", "javax.crypto.Mac")>
<cfset mac = mac.getInstance("HmacSHA256")>
<cfset mac.init(secret)>
<cfset digest = mac.doFinal(databytes)>
<cfset result = BinaryEncode(digest, "Base64")>

我对java的了解非常有限,所以我不确定我做的对还是错

您混淆了字符串编码,因此 CFML 实际上使用的输入值与 java 代码不同。这就是您的结果不匹配的原因

  1. java 方法将密钥解码为“UTF-8”

    (keyString).getBytes("UTF-8")
    

    .. 但 CFML 使用的是“十六进制”

    <cfset keybytes = BinaryDecode(SECRET_KEY, "Hex")>
    
  2. java 方法将消息解码为“ASCII”

    msg.getBytes("ASCII")
    

    ...但是 CFML 使用的是“UTF-8”

    CharsetDecode(data, "UTF-8")
    
  3. java 结果编码为“十六进制”,但 CFML 使用“base64”

    BinaryEncode(digest, "Base64")
    
  4. \n 被解释为 java 中的换行符。它在 CF 中的工作方式不同。而是使用 chr(10).

虽然错误很容易修复,但甚至不需要 java 代码。使用内置 HMAC function instead. It produces the same result. The only difference being that CF returns hexadecimal in all upper case, so you must wrap it in LCASE() 获得精确匹配。

Lcase( HMac( messageString, keyAsString, algorithm, "ASCII") )