SecretKeyFactory.generateSecret умирает с InvalidKeySpecException на IBM Java

Мы хэшируем пароль с помощью алгоритма PBKDF2, используя SecretKeyFactory.generateSecret, например:

final SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm);
final PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iterations, hashLength);
final SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
return secretKey.getEncoded();

Кажется, все работает нормально, однако на рабочем сервере, когда он работает в IBM Java, он умирает с java.security.spec.InvalidKeySpecException: Не удалось сгенерировать секретный ключ:

Caused by: java.security.spec.InvalidKeySpecException: Could not generate secret key
    at javax.crypto.SecretKeyFactory.generateSecret(Unknown Source)
    at our.Implementation.doHash(Hasher.java:71)
    ... 48 more
Caused by: java.lang.RuntimeException: Error deriving PBKDF2 keys
    at com.ibm.crypto.provider.PBKDF2KeyImpl.a(Unknown Source)
    at com.ibm.crypto.provider.PBKDF2KeyImpl.<init>(Unknown Source)
    at com.ibm.crypto.provider.PBKDF2HmacSHA1Factory.engineGenerateSecret(Unknown Source)
    ... 50 more

Мы пытались изменить количество итераций, размер сгенерированного хеша и размер соли, но ничего не помогло. Что я делаю неправильно?


person Mormegil    schedule 08.04.2017    source источник


Ответы (1)


Судя по всему, похоже, что реализация PBKDF2 в IBM Java настаивает на том, чтобы пароль не был пустым. Когда это так, реализация выдает исключение.

Пустые пароли, возможно, являются пограничным случаем, однако первый тестовый пример был именно таким, поэтому казалось, что код вообще не работает. Кроме того, в крайнем случае вам либо нужно убедиться, что этого никогда не произойдет (проверки требуют, чтобы у пользователя не было пустого пароля), либо вы должны обработать его изящно.

Если вам действительно нужно поддерживать пустые пароли, вам нужно либо обрабатывать их как особый случай, либо просто нормализовать все пароли, чтобы ввод в PBKDF2 никогда не был пустым. Тем не менее, вы должны убедиться, что таким образом вы не нарушите безопасность.

В конце концов, мы решили добавлять ко всем паролям префикс их длины, так что даже пустые пароли заканчиваются непустой строкой. Как это:

final String prefixedPassword = String.format(Locale.ROOT, "%08x%s", password.length(), password);
person Mormegil    schedule 08.04.2017