Вычислить HMAC на базе SHA2 или SHA3 Java

Я генерирую случайный 128 битный ключ используя SecureRandom:

SecureRandom secureRandom = new SecureRandom();
byte []bytes = new byte[16];
secureRandom.nextBytes(bytes);

Подскажите, как используя данный ключ перевести какое-либо сообщение в hex строку


Ответы (1 шт):

Автор решения: Pak Uula

Доступ к реализациям HMAC в Java осуществляется через универсальный интерфейс javax.crypto.Mac

Вот пример вычисления HMAC подписи алгоритмом SHA2 c размером подписи 512 бит. Для замены алгоритма достаточно поменять имя алгоритма в константе HMAC_ALGO. Список имён стандартных алгоритмов приведён в документации.

Алгоритмы на базе SHA2:

  • HmacSHA224
  • HmacSHA256
  • HmacSHA384
  • HmacSHA512
  • HmacSHA512/224
  • HmacSHA512/256

Алгоритмы на базе SHA-3:

  • HmacSHA3-224
  • HmacSHA3-256
  • HmacSHA3-384
  • HmacSHA3-512
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class Main {
    private static final String HMAC_ALGO = "HmacSHA512";

    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b: bytes) {
           sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, IllegalStateException, UnsupportedEncodingException {
        SecureRandom secureRandom = new SecureRandom();
        byte []bytes = new byte[16];
        secureRandom.nextBytes(bytes);

        Mac signer = Mac.getInstance(HMAC_ALGO);
        SecretKeySpec keySpec = new SecretKeySpec(bytes, HMAC_ALGO);
        signer.init(keySpec);

        String messageStr = "Hello, world!";
        byte[] digest = signer.doFinal(messageStr.getBytes("utf-8"));
        
        System.out.println("Message: " + messageStr);
        System.out.println("Key: " + bytesToHex(bytes));
        System.out.println("Digest: " + bytesToHex(digest));
    }
}

Вот пример одного из прогонов:

Message: Hello, world!
Key: d29841be3f11c4f2130c1c2d0b1cdedb
Digest: ca2bcd4cdd2dc24796a3edc0edd0aa3e102b579be9d91b81765e35cb79d49a950da9d8e6235fe1334fc15c343d2d43884ac38659b3647dc66bb9ec8046544626

Для проверки HMAC подпись строки Hello, world! средствами openssl:

$ echo -n 'Hello, world!' > hello.txt
$ echo -n "d29841be3f11c4f2130c1c2d0b1cdedb" | xxd -r -p - > key.bin
$ openssl dgst -sha512 -hmac "$(cat key.bin)" -hex hello.txt
HMAC-SHA512(hello.txt)= ca2bcd4cdd2dc24796a3edc0edd0aa3e102b579be9d91b81765e35cb79d49a950da9d8e6235fe1334fc15c343d2d43884ac38659b3647dc66bb9ec8046544626

Как видно, результаты совпали, что не может не радовать.

→ Ссылка