0

Java 支持三种 MAC 算法:

  • HmacMD5
  • HmacSHA1
  • HmacSHA256

但是,我需要使用 HMAC-SHA256-128 对某些内容进行签名,它是 HmacSHA256,但被截断为 128 位。

此示例及其变体已在 stackoverflow 上流传:

String MAC = hmacHelper.calculatePlainMAC("00000000", "HmacSHA256");

String bgSecretKey="1234567890ABCDEF1234567890ABCDEF";

public String calculatePlainMAC(String ascii, String algorithm)
{
  Mac mac = null;
  final Charset asciiCs = Charset.forName("US-ASCII");
  try
  {
    SecretKeySpec signingKey = new SecretKeySpec(bgcSecretKey.getBytes(), algorithm);
    mac = Mac.getInstance(algorithm);
    mac.init(signingKey);
    byte[] rawHmac = mac.doFinal(asciiCs.encode(ascii).array());

    String result = "";
    for (final byte element : rawHmac)
    {
      result += Integer.toString((element & 0xff) + 0x100, 16);//.substring(1);
    }
    log.debug("Result: " + result);
    return result;
  }
  catch (NoSuchAlgorithmException e)
  {
    e.printStackTrace();
    return null;
  }
  catch (InvalidKeyException e)
  {
    e.printStackTrace();
    return null;
  }
}

结果:

1051cd18118219e1261f41401891fd1911a91cf1bc1751db13e10617c1221131231c31ab15613f14412c1681d7132178

这一切都很好,除了我需要一个 128 位的结果,我知道这是

FF365893D899291C3BF505FB3175E880

我不知道他们是如何达到这个结果的。我所知道的是使用的 HMAC 算法是 HmacSHA256-128。据我了解,该算法将生成 256 位结果,问题是,如何将其截断为 128 位结果,返回上面的已知结果?

4

2 回答 2

0

以下行总是向字符串添加 3 个字符,从 '1' 开始。注释的 substring(1) 删除了 1。它用于使单个字符的结果在前面加上零。

result += Integer.toString((element & 0xff) + 0x100, 16);//.substring(1);

但是,即使您修复了此问题,结果也不包含您期望的截断结果。

05cd81829e26f44089fd91a9cfbc75db3e067c221323c3ab563f442c68d73278

这当然取决于 bgcSecretKey 的值。

您需要使用与导出预期结果相同的密钥/算法/截断。

于 2014-10-23T23:20:07.937 回答
0

问题是“键”应该转换为它的二进制表示,而不是字符串值的二进制表示!

IE。bgcSecretKey.getBytes() 应该是 javax.xml.bind.DatatypeConverter.parseHexBinary(bgcSecretKey) 或您喜欢将十六进制转换为二进制值的任何函数。然后一切正常。整个代码:

 @Test
    public void test_key() throws Exception
    {
        String SECRET = "1234567890ABCDEF1234567890ABCDEF";
        Charset CHARSET = Charset.forName("ISO-8859-1");
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new javax.crypto.spec.SecretKeySpec(DatatypeConverter.parseHexBinary(SECRET), "HmacSHA256");
        try
        {
            sha256_HMAC.init(secret_key);
        }
        catch (InvalidKeyException e1)
        {
            throw new RuntimeException("Sha key couldn't be initialized", e1);
        }
        //Create KVV key, it's HMAC of eight zeros
        final byte[] kvv_bytes = sha256_HMAC.doFinal(CHARSET.encode("00000000").array());
        StringBuilder kvv = new StringBuilder(16);
        for (int i = 0; i < Math.min(16, kvv_bytes.length); i++) //KVV, max 16 bytes
        {
            kvv.append(Integer.toString((kvv_bytes[i] & 0xff) + 0x100, 16).substring(1));
        }
        System.out.println(kvv.toString().toUpperCase());
    }
于 2020-06-11T13:56:50.127 回答