JAVA的可靠PBKDF2-HMAC-SHA256实现

27

2019年更新: Bouncycastle现在支持PBKDF2-HMAC-SHA256,自从 bouncycastle 1.60


有没有可靠的JAVA PBKDF2-HMAC-SHA256实现?

我以前使用bouncycastle进行加密,但它不提供“PBKDF2WithHmacSHA256”。

我不想自己编写加密模块。

你能否推荐任何替代库或算法(如果我可以继续使用bouncycastle)?

(以下是bouncycastle支持的算法列表) http://www.bouncycastle.org/specifications.html


1
https://dev59.com/JGox5IYBdhLWcg3whUum - Konstantin V. Salikhov
@KonstantinV.Salikhov 我已经阅读了,但很难相信它完全被证明。如果我使用它,我必须实现Jasypt API的代码。 - dgregory
未来的读者:请参阅 https://mkyong.com/java/java-aes-encryption-and-decryption/。 - granadaCoder
4个回答

40

直接使用BouncyCastle类:

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

39

它可在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();
}

1
奇怪的是,我无法使Java 8版本正常工作。它生成了输出,但与Bouncy Castle和Node.js等效版本不同。 - Kirby
3
请使用 ASCII 字符集,Java 8 在 char 类型中只使用了低 8 位(即兼容 Windows-1252 字符编码),这点有些奇怪。请注意。 - Maarten Bodewes
运行得非常好。顺便说一下,如果你想使用512字节的摘要,只需将“PBKDF2WithHmacSHA256”更改为“PBKDF2WithHmacSHA512”。 - Yev Kanivets
@toolforger 从PBEKeySpec(Java 14)中:不同的PBE机制可能会消耗每个密码字符的不同位。例如,PKCS#5中定义的PBE机制仅查看每个字符的低8位,而PKCS#12则查看每个字符的所有16位。 PBKDF2在PKCS#5中指定。因此,如果使用UTF-8,则文档已经失效。您能展示一下您找到的编码函数吗? - Maarten Bodewes
仅澄清一下,PKCS#5标准2.0版[RFC 2898]和2.1版[RFC 8018]明确未指定密码的字符编码,但是为了实现互操作性而使用常见规则,例如ASCII或UTF-8。一个设计良好的API应该使用字节数组或允许调用者指定字符编码。 - Charlie Reitzel
显示剩余3条评论

2

使用spongycastle(在Android上的Java)

如果您直接在Java中使用bouncycastle,请将spongycastle替换为bouncycastle

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);
    }
}

1

如果您正在使用Spring Boot设置,则可以在加密库中找到它。

org.springframework.security.crypto.password.Pbkdf2PasswordEncoder

Pbkdf2PasswordEncoder pbkdf2PasswordEncoder = new Pbkdf2PasswordEncoder();
pbkdf2PasswordEncoder.encode(password)

在内部,它使用PBEKeySpec,其优势是参数自动配置。您还可以设置这些参数。

此外,它使用随机盐,使得很难破解。要检查匹配,请使用pbkdf2PasswordEncoder.matches(rawPassword, password);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接