Как мне усечь HmacSHA256 до 128 бит?
Java поддерживает три алгоритма MAC:
- HmacMD5
- HmacSHA1
- HmacSHA256
Однако мне нужно подписать что-то, используя HMAC-SHA256-128, который является HmacSHA256, но урезан до 128 бит.
Этот пример и варианты распространены по stackru:
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-битный результат, возвращая известный результат выше?
1 ответ
Следующая строка всегда добавляет 3 символа в строку, начиная с "1". Закомментированная подстрока (1) удаляет 1. Она используется для того, чтобы односимвольные результаты получались с нулем в начале.
result += Integer.toString((element & 0xff) + 0x100, 16);//.substring(1);
Однако даже если вы исправите это, результат не будет содержать ожидаемого усеченного результата.
05cd81829e26f44089fd91a9cfbc75db3e067c221323c3ab563f442c68d73278
Это, конечно, зависит от значения bgcSecretKey.
Вам нужно использовать тот же ключ / алгоритм / усечение, который вы использовали для получения ожидаемого результата.
Проблема в том, что "ключ" должен быть преобразован в его двоичное представление, а не в двоичное представление строкового значения!
Т.е. 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());
}