Использование Java-8 AES/GCM для аутентификации/шифрования частей блока данных

Моя задача — использовать специальную функцию AES/GCM для аутентификации части A и шифрования части B одного блока данных. У меня проблемы с реализацией решения с использованием Java-8.

В следующем примере используется блок данных размером 256 бит. Только первые 128 бит должны быть аутентифицированы. Следующие 128 бит должны быть зашифрованы. Ожидается, что результирующий тег для комбинированной операции будет 128-битным.

Я считаю, что мне удалось реализовать вариант только с шифрованием, который шифрует оба 128-битных блока данных.

SecureRandom random = new SecureRandom();
byte[] initVector   = new BigInteger(96, random).toByteArray();
byte[] data         = new BigInteger(255, random).toByteArray();
byte[] key          = new BigInteger(255, random).toByteArray();
byte[] encrypted    = new byte[data.length];

final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(16 * Byte.SIZE, initVector));
cipher.update(data, 0, data.length, encrypted, 0);
byte[] tag = cipher.doFinal();

Может ли кто-нибудь дать инструкции о том, как изменить код, чтобы аутентифицировать только первые 128 бит данных?


person Twonky    schedule 18.01.2017    source источник


Ответы (2)


Вам необходимо использовать один из updateAAD методы.

В вашем случае что-то вроде этого (обратите внимание, что вам нужно сделать вызовы updateAAD до вызовов update или doFinal):

cipher.updateAAD(data, 0, 128);              // first 128 bits are authenticated
cipher.update(data, 128, 128, encrypted, 0); // next 128 are encrypted
person matt    schedule 20.01.2017

Мэтт прав, что вам нужно использовать updateAAD. Но есть много других ошибок.

Например, вы не можете просто использовать BigInteger для создания случайных значений. Проблема в том, что для некоторых значений будет дополнительное значение 00 слева (для кодирования целого числа без знака), а иногда его нет. И он также может генерировать слишком мало байтов, если число невелико.

Кроме того, в Java тег считается частью зашифрованного текста. На мой взгляд, это ошибка, и это действительно вредит функциональности. Но в настоящее время это так.

Лучший способ запрограммировать это будет примерно так:

// --- create cipher
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

// --- generate new AES key
KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
aesKeyGen.init(256);
SecretKey aesKey = aesKeyGen.generateKey();

// --- generate IV and GCM parameters
SecureRandom random = new SecureRandom();
byte[] initVector   = new byte[96 / Byte.SIZE];
random.nextBytes(initVector);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, initVector);
cipher.init(Cipher.ENCRYPT_MODE, aesKey,
        gcmParameterSpec);

// --- process any AAD (just a bunch of zero bytes in this example)
byte[] aad = new byte[128];
cipher.updateAAD(aad);

// --- process any data (just a bunch of zero bytes in this example)
byte[] data         = new byte[128];
// use cipher itself to create the right buffer size
byte[] encrypted    = new byte[cipher.getOutputSize(data.length)];
int updateSize = cipher.update(data, 0, data.length, encrypted, 0);
cipher.doFinal(encrypted, updateSize);

Он генерирует все параметры по-разному и динамически определяет размер выходного буфера через экземпляр Cipher.

person Maarten Bodewes    schedule 21.01.2017
comment
Я уже задавался вопросом о некоторых странных случайных эффектах моей случайной инициализации байтов, касающихся количества сгенерированных байтов. Я такой глупый. Не должен был игнорировать это. - person Twonky; 23.01.2017
comment
@Twonky BigInteger и многие другие функции, такие как целочисленное шестнадцатеричное кодирование, часто используются неправильно. Простой совет: если вам нужен двоичный код и вы можете остаться двоичным, не конвертируйте в числа или строки. На самом деле это относится к большинству типов, не конвертируйте без необходимости. - person Maarten Bodewes; 23.01.2017
comment
Длина тега передается в GCMParameterSpec(128), а размер массива байтов aad(128) должен быть одинаковым? Являются ли они сородичами? - person TMtech; 09.08.2017