Как проверить GMAC?

В соответствии с разделом 5.2 (Две функции GCM) Рекомендации для режимов работы блочного шифра: режим Галуа / Счетчик (GCM) и GMAC, в нем упоминается, что для случая GMAC функции аутентифицированного шифрования и дешифрования становятся функциями для генерации и проверка тега аутентификации на неконфиденциальных данных.

Глядя онлайн и на справочную страницу JCA, я понимаю, что GMAC генерируется так:

Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
cipher.init(ENCRYPT_MODE, encryptionKey, new GCMParameterSpec(96, iv), new SecureRandom());
cipher.updateAAD(aadData);
byte[] gmac = cipher.doFinal();

Однако у меня есть сомнения относительно проверки GMAC. Это правильный способ проверки GMAC?

Cipher decryptCipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
decryptCipher.init(DECRYPT_MODE, encryptionKey, new GCMParameterSpec(96, iv), new SecureRandom());
decryptCipher.updateAAD(aadData);
decryptCipher.update(gmac);
byte[] verifiedGmac = decryptCipher.doFinal();

Где проверен размер файла == 0?

Вот полный код с входами и выходами:

import org.hamcrest.core.Is;
import org.junit.Test;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.SecureRandom;

import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import static javax.xml.bind.DatatypeConverter.parseHexBinary;
import static javax.xml.bind.DatatypeConverter.printHexBinary;
import static org.junit.Assert.assertThat;

public class TestGmac {

    @Test
    public void generateAndVerifyGmac() throws Exception {
        final byte[] message = parseHexBinary("AAAAAAAAAAAA");
        final byte[] authenticatedKey = parseHexBinary("63509E5A672C092CAD0B1DC6CE009A61");
        final byte[] aadData = buildAadForAuthenticationOnly(message, authenticatedKey);
        final byte[] iv = parseHexBinary("BBBBBBBBBBBBBBBBBBBBBBBB");
        SecretKeySpec encryptionKey = new SecretKeySpec(parseHexBinary("55804F3AEB4E914DC91255944A1F565A"), "AES");

        // Generate GMAC
        Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
        cipher.init(ENCRYPT_MODE, encryptionKey, new GCMParameterSpec(96, iv), new SecureRandom());
        cipher.updateAAD(aadData);
        byte[] gmac = cipher.doFinal();
        assertThat(printHexBinary(gmac), Is.is("44C955D63799428524E97993"));

        // Verify GMAC
        Cipher decryptCipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
        decryptCipher.init(DECRYPT_MODE, encryptionKey, new GCMParameterSpec(96, iv), new SecureRandom());
        decryptCipher.updateAAD(aadData);
        decryptCipher.update(gmac);
        byte[] verifiedGmac = decryptCipher.doFinal();
        assertThat(printHexBinary(verifiedGmac), Is.is(""));
    }

    private byte[] buildAadForAuthenticationOnly(byte[] message, byte[] authenticatedKey) throws IOException {
        ByteArrayOutputStream aaDoutputStream = new ByteArrayOutputStream();
        aaDoutputStream.write(parseHexBinary("10"));
        aaDoutputStream.write(authenticatedKey);
        aaDoutputStream.write(message);
        return aaDoutputStream.toByteArray();
    }

}

1 ответ

Решение

Да, это правильно. Java API проверяет MAC, выдавая исключение в случае сбоя. Он возвращает зашифрованное текстовое сообщение, но в вашем случае оно пустое.

Существует два варианта дизайна для создания API GCM: обрабатывать тег аутентификации отдельно или предполагать, что он является частью зашифрованного текста. Хотя я предпочитаю раздельную обработку зашифрованного текста и тега аутентификации, Java/Oracle решила придерживаться AEAD RFC и включить тег аутентификации с зашифрованным текстом (требующий дополнительной буферизации, увеличения размера кода примерно на 30% и устранения вероятности выполнения онлайн дешифрование).

Так что, хотя ваш код может показаться немного странным, передача MAC выглядит нормально - если бы это было не так, вы бы получили AEADBadTagException в призыве к doFinal во время расшифровки.


Использование статического ключа и IV, конечно, не в порядке, но я предполагаю, что они использовались в целях тестирования - верно?

Другие вопросы по тегам