【问题标题】:why PHP's hash_hmac('sha256') gives different result than java sha256_HMAC为什么 PHP 的 hash_hmac('sha256') 给出的结果与 java sha256_HMAC 不同
【发布时间】:2014-06-26 11:49:22
【问题描述】:

在 PHP 中我有以下功能:

base64_encode(hash_hmac('sha256', $data, $secret, false));

我正在尝试在 Java 中创建一个函数,该函数将为相同的“数据”和“秘密”参数提供相同的结果。

我尝试使用这个功能:

public static String base64sha256(String data, String secret) {
    Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
    SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
    sha256_HMAC.init(secret_key);
    byte[] res = sha256_HMAC.doFinal(data.getBytes());
    return Base64.encodeToString(res, Base64.NO_WRAP);
}

但是对于相同的输入,我得到不同的结果


更新:此功能有效。享受吧。

public static String base64sha256(String data, String secret) {
    String hash = null;
    try {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] res = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
        hash = getHex(res);
        hash = Base64.encodeToString(hash.getBytes("UTF-8"), Base64.NO_WRAP);
    } catch (Exception e){}
    return hash;
}

static final String HEXES = "0123456789abcdef";
public static String getHex( byte [] raw ) {
    if ( raw == null ) {
        return null;
    }
    final StringBuilder hex = new StringBuilder( 2 * raw.length );
    for ( final byte b : raw ) {
        hex.append(HEXES.charAt((b & 0xF0) >> 4))
                .append(HEXES.charAt((b & 0x0F)));
    }
    return hex.toString();
}

【问题讨论】:

  • 数据编码可能吗?例如 ANSI 与 UTF-8?
  • 我尝试在两个参数上使用 getBytes("UTF-8") ,结果仍然与 PHP 版本不同
  • 查看此问答stackoverflow.com/q/4680661,他们在其中谈论String.getBytes(),而此stackoverflow.com/q/23066005 位于“相关”下。
  • 我查看了这些链接,似乎没有一个示例使用密钥......不过,我根据我在那里阅读的内容创建了一个新的更新版本的代码(你可以看到它在上面)但仍然没有得到我从 php 代码中得到的结果。
  • 这行得通!。需要这个来为 Facebook Graph API 生成appsecret_proof。这会生成与 PHP 中相同的哈希。

标签: java php sha256


【解决方案1】:

当第四个参数为假时,php函数的输出为小写十六进制数字。但是,您的第二个 java 版本会生成大写的十六进制数字。要么纠正大小写差异,要么将 hash_hmac 的第四个参数更改为 true,它可能会与您的第一个 Java 版本匹配。

【讨论】:

    【解决方案2】:

    如果尝试将 drupal_hmac_base64 的输出与 Java 8 匹配,您可以使用以下代码:

    final String ALGORITHM = "HmacSHA256";
            Mac mac = Mac.getInstance(ALGORITHM);
            SecretKeySpec secret = new SecretKeySpec(authorizationKey.getBytes(), ALGORITHM);
    
            mac.init(secret);
            byte[] digest = mac.doFinal(body.getBytes());
    
            hash = Base64.getUrlEncoder().withoutPadding().encodeToString(digest);
    
            return signature.equals(hash);
    

    请注意,drupal 使用原始二进制数据(第三个参数 TRUE)返回哈希值。此外,PHP 中的 base64 编码与 Java https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html#url 中的 URL 和文件名安全 base64 编码器相匹配。

    【讨论】:

    • 这与使用 Java 8 的 base64_encode(hash_hmac('sha256', $data, $secret, false)) 相同(这就是我想要实现的目标)?
    【解决方案3】:

    对于与 PHP 相比,Java 结果可能面临轻微变化(不起作用)的人,我的问题是从 HmacSHA256 返回哈希作为字符串,而您应该返回它并作为 byte[] 传递给十六进制. 下面是模拟PHP的hash_hmac()的工作方法

    public String hashValue(String message) {
        byte[] hash = toHmacSHA256(message);
        String hashHexed = toHex(hash);
        return hashHexed;
    }
    
    private String toHex(byte[] value) {
        String hexed = String.format("%040x", new BigInteger(1, value));
        return hexed;
    }
    
    private byte[] toHmacSHA256(String value) {
        byte[] hash = null;
        try {
            SecretKey secretKey = new SecretKeySpec(PRIVATE_KEY.getBytes("UTF-8"), "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(secretKey);
            hash = mac.doFinal(value.getBytes("UTF-8"));
    
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    
        return hash;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-12-10
      • 2017-01-02
      • 1970-01-01
      • 2013-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多