Надежная реализация PBKDF2-HMAC-SHA256 для JAVA

ОБНОВЛЕНО 2019: Bouncycastle теперь поддерживает PBKDF2-HMAC-SHA256, начиная с


person dgregory    schedule 22.03.2014    source источник
comment
stackoverflow.com/questions/9147463 /   -  person Konstantin V. Salikhov    schedule 22.03.2014
comment
@ KonstantinV.Salikhov Я уже читал, но сложно поверить, что это полностью доказано. И если я использую это, мне нужно реализовать код для Jasypt API.   -  person dgregory    schedule 22.03.2014
comment
Для будущих читателей: см. mkyong.com/java/java-aes-encryption-and -расшифровка   -  person granadaCoder    schedule 01.12.2020


Ответы (3)


Прямое использование классов BouncyCastle:

PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
gen.init("password".getBytes("UTF-8"), "salt".getBytes(), 4096);
byte[] dk = ((KeyParameter) gen.generateDerivedParameters(256)).getKey();
person Pasi    schedule 24.03.2014

Он доступен в Java 8:

public static byte[] getEncryptedPassword(
                                         String password,
                                         byte[] salt,
                                         int iterations,
                                         int derivedKeyLength
                                         ) throws NoSuchAlgorithmException, InvalidKeySpecException {
    KeySpec spec = new PBEKeySpec(
                                 password.toCharArray(),
                                 salt,
                                 iterations,
                                 derivedKeyLength * 8
                                 );

    SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");

    return f.generateSecret(spec).getEncoded();
}
person mjrduran    schedule 13.01.2015
comment
Странно, мне не удалось заставить версию Java 8 корректно работать. Он генерировал выходные данные, но отличался от Bouncy Castle и эквивалента Node.js. - person Kirby; 21.01.2015
comment
@Kirby Убедитесь, что вы используете только ASCII, Java 8 немного странный в том смысле, что он использует только младшие 8 бит char (т.е. кодировку символов, совместимую с Windows-1252). - person Maarten Bodewes; 15.09.2015
comment
Работает как шарм. Кстати, если вы хотите использовать 512-байтовый дайджест, просто измените PBKDF2WithHmacSHA256 на PBKDF2WithHmacSHA512. - person Yev Kanivets; 28.12.2018
comment
@MaartenBodewes Он использует UTF8.encode для преобразования char[] в ByteBuffer. Т.е. все, что выходит за рамки 7-битного ASCII, будет генерировать многобайтовые последовательности, что даст вам неожиданные результаты, если вы сравните с байтовой последовательностью UTF-16, но это потому, что кодировка неожиданная, а не потому, что Java что-то игнорирует. - person toolforger; 09.09.2020
comment
@toolforger Из PBEKeySpec (Java 14): Различные механизмы PBE могут использовать разные биты каждого символа пароля. Например, механизм PBE, определенный в PKCS # 5, смотрит только на 8 младших битов каждого символа, тогда как PKCS # 12 смотрит на все 16 бит каждого символа. А PBKDF2 указан в PKCS # 5. Так что, если используется UTF-8, документация не в порядке. Можете ли вы показать, где вы нашли эту функцию кодирования? - person Maarten Bodewes; 09.09.2020
comment
@MaartenBodewes хм ... больше не могу найти этот код. Может, я случайно набрал код Bouncycastle. В любом случае, PBEKeySpec Javadoc, безусловно, достаточно авторитетен. Тем не менее, я не думаю, что советовать придерживаться ASCII - хорошая идея, это слишком ограничительно для многих ситуаций; людям лучше по возможности кодировать строки в кодировке UTF8. (Кроме того, форматы PKCS не обязательно являются тем, для чего вы используете механизмы PBE, возможно, Javadoc просто предупреждал, что ввод или вывод могут быть не такими, как вы думаете? Не уверен, не хватает времени на проверку, извините.) - person toolforger; 10.09.2020
comment
PKCS # 5 - это стандарт шифрования на основе пароля. Я не уверен, что вы имеете в виду под форматами PKCS. Старые стандарты PKCS, разработанные лабораториями RSA, охватывают большую криптографическую экосистему, в основном они действуют, хотя и теряют свою значимость. - person Maarten Bodewes; 10.09.2020
comment
Чтобы уточнить, стандарт PKCS # 5, версия 2.0 RFC 2898 и 2.1 RFC 8018 оставляют кодировку символов для паролей явно неуказанной, но, в интересах взаимодействия используйте общие правила, например ASCII или UTF-8. Хорошо спроектированный API либо использует массив байтов, либо позволяет вызывающей стороне указывать кодировку символов. - person Charlie Reitzel; 29.06.2021

Использование spongycastle (java на android)

Замените spongycastle на bouncycastle, если вы напрямую используете bouncycastle на java.

import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.spongycastle.crypto.digests.SHA256Digest;
import org.spongycastle.crypto.params.KeyParameter;

public class Crypto {
    public String pbkdf2(String secret, String salt, int iterations, int keyLength) {
        PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
        byte[] secretData = secret.getBytes();
        byte[] saltData = salt.getBytes();
        gen.init(secretData, saltData, iterations);
        byte[] derivedKey = ((KeyParameter)gen.generateDerivedParameters(keyLength * 8)).getKey();    
        return toHex(derivedKey);
    }

    private static String toHex(byte[] bytes) {
        BigInteger bi = new BigInteger(1, bytes);
        return String.format("%0" + (bytes.length << 1) + "x", bi);
    }
}
person Guillaume Vincent    schedule 05.12.2018