AESWrap и длина ключа / обернуть длина ключа / проблема заполнения - PullRequest
0 голосов
/ 13 мая 2018

Мне нужно обернуть личное значение с AESWrap. У меня есть проблема с этой операцией из-за длины моей строки частного значения (ключ, который будет обернут).

Это моя реализация:

final byte[] kek = // ... generate SHA-256 key via `PBKDF2WithHmacSHA256`        
SecretKey sKey = new SecretKeySpec(kek, "AES");

Cipher c = Cipher.getInstance("AESWrap", "SunJCE");
c.init(Cipher.WRAP_MODE, sKey);

byte[] bytes = privateValue.getBytes();
SecretKeySpec wk = new SecretKeySpec(bytes, "AES");
byte[] result = c.wrap(wk);

Поскольку SunJCE провайдер не поддерживает какие-либо дополнения для переноса ключей, поэтому частное значение должно быть кратно 8 байтам, и это моя проблема, которую мне нужно решить.

Вопрос: Как решить эту ситуацию, когда частная стоимость не имеет достаточной длины. Есть ли какой-нибудь рекомендуемый способ сделать заполнение самостоятельно?

P.S. Я хотел бы избежать внешних библиотек, таких как BC и т. Д.


Что касается ответа @ Maarten, я создал эту реализацию. Он работает (успешно оборачивает и разворачивает мою личную ценность), но действительно ли эта реализация безопасна ?

Обертывание

byte[] salt = .... // 32 random bytes...
byte[] kek = ... // PBKDF2WithHmacSHA256 hash from private value and salt

SecretKey sKey = new SecretKeySpec(kek, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");

SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[c.getBlockSize()];
rng.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);

c.init(Cipher.WRAP_MODE, sKey, iv);
SecretKeySpec wk = new SecretKeySpec(privateValue.getBytes(), "AES");
byte[] result = c.wrap(wk); // wrapped private value

Разворачивание

byte[] kek = ... // PBKDF2WithHmacSHA256 hash from private value and previous salt

SecretKey sKey = new SecretKeySpec(kek, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");

IvParameterSpec iv = new IvParameterSpec(parsed.getIv()); // previously created iv
c.init(Cipher.UNWRAP_MODE, sKey, iv);

SecretKeySpec wk = new SecretKeySpec(privateValue.getBytes(), "AES");
Key result = c.unwrap(parsed.getKey(), "AES", Cipher.SECRET_KEY);

byte[] pv = result.getEncoded(); // unwrapped private value

1 Ответ

0 голосов
/ 14 мая 2018

Для AES можно использовать обычный режим работы, а не специальный режим заполнения.Режим заполнения приятнее, но достаточно и CBC с дополнением PKCS # 7.

Было бы разумно использовать IV и хранить его с завернутым ключом.Закрытые ключи, как правило, представляют собой не просто двоичные данные, но имеют структуру, и вы можете потерять крошечную информацию, если вы закроете несколько ключей таким образом.Для RSA рандомизированный модуль приходит перед параметрами частного экспоненты / CRT, поэтому вы также должны быть защищены с нулевым IV.

// --- key pair with private key for testing
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(4096);
KeyPair kp = gen.generateKeyPair();

// --- create KEK
final byte[] kek = new byte[16]; // test value
SecretKey sKey = new SecretKeySpec(kek, "AES");

// --- the cipher, not a special wrapping algorithm
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");

// --- create IV
// not really necessary because the modulus comes first, but nicer
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[c.getBlockSize()];
rng.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);

// --- init & wrap by normal encryption
c.init(Cipher.WRAP_MODE, sKey, iv);
byte[] result = c.wrap(kp.getPrivate());

AES-SIV будет лучше,но это не входит в провайдера SunJCE.Вы можете использовать AES-GCM, который рекламирует целостность, но помните, что повторение 12-байтового IV (nonce) для этого может быть катастрофическим для этого режима.

...