简体   繁体   English

Java Argon2 散列

[英]Java Argon2 Hashing

I'm trying to figure out how to practically use argon2 hashing for passwords in Java.我试图弄清楚如何在 Java 中实际使用 argon2 散列作为密码。 I've got to be missing something, because none of the APIs return discrete fields for the hash or the salt.我必须遗漏一些东西,因为没有一个 API 返回 hash 或盐的离散字段。 I've tried both a JVM binding for argon2 and also spring-security + bouncy castle and both give me a String, but it's also serialized with information beyond just the hashed password and salt.我已经尝试了用于 argon2 的 JVM 绑定以及spring-security + 充气城堡,它们都给了我一个字符串,但它也被序列化,除了散列密码和盐之外的信息。

public static void main(String[] args) {
        final String rawPass = "badPassword";

        // argon2-jvm
        Argon2 argon2jvm = Argon2Factory.create(Argon2Factory.Argon2Types.ARGON2id, 16, 32);
        String arg2JvmHash = argon2jvm.hash(10, 65536, 1, rawPass.getBytes(StandardCharsets.UTF_8));
        System.out.println("argon2-jvm:");
        System.out.println(arg2JvmHash);
        System.out.println("\n\n");

        // spring security + bouncy castle
        Argon2PasswordEncoder arg2SpringSecurity = new Argon2PasswordEncoder(16, 32, 1, 65536, 10);
        String springBouncyHash = arg2SpringSecurity.encode(rawPass);
        System.out.println("spring security + bouncy castle:");
        System.out.println(springBouncyHash);
        System.out.println("\n\n");
}

And then here are the results:然后是结果:

argon2-jvm:
$argon2id$v=19$m=65536,t=10,p=1$BeHo0SdgM6vt5risz+yuLg$dOBFlfeoPPGCk/OLCGJ9sRhyPl0zMqMAUZvkltFWxnA



spring security + bouncy castle:
$argon2id$v=19$m=65536,t=10,p=1$i9iHBeHankerOJhfUvXrnQ$8Ldr1QkPglW0DSjYqoaoAy0brxs1vPVhlm4174NdR80

How do I get the discrete values of the hashes and salts?如何获得散列和盐的离散值? In my research, it sounds like I can parse out this output by myself, but that sounds like a bad idea.在我的研究中,听起来我可以自己解析出这个 output,但这听起来是个坏主意。

Am I using the wrong libraries?我使用了错误的库吗? I've been doing a lot of research and these are the two most popular libraries that keep showing up.我一直在做很多研究,这是两个最受欢迎的图书馆。

I'm using Bouncy Castle to implement Argon2id as it allows to set the parameters and salt instead of parsing the output.我正在使用 Bouncy Castle 来实现 Argon2id,因为它允许设置参数和盐,而不是解析 output。

The below full running program uses 4 parameter sets - the parameter were taken from PHP's OpenSSL implementation but you can choose the parameter individually of course.下面的完整运行程序使用 4 个参数集 - 参数取自 PHP 的 OpenSSL 实现,但您当然可以单独选择参数。

As the program is taken from a Cross platform project it uses a fixed salt that is UNSECURE - in production you need to use a randomly generated salt.由于该程序取自跨平台项目,它使用不安全固定盐- 在生产中您需要使用随机生成的盐。

This is an output:这是一个 output:

Generate a 32 byte long encryption key with Argon2id
password: secret password
salt (Base64): AAAAAAAAAAAAAAAAAAAAAA==
encryptionKeyArgon2id (Base64) minimal:     e9G7+HHmftUaCEP2O1NwCSJkfyAT0QBzod3Szm1elf0=
encryptionKeyArgon2id (Base64) interactive: FZcsUwo7wf7V24qWTwKeSN9//+Pxy2gCKN35KZX2hXs=
encryptionKeyArgon2id (Base64) moderate:    gdizE6kia1W/CgTA3bRKKjtaf8cgZL1BIe6jeDegg0c=
encryptionKeyArgon2id (Base64) sensitive:   19Uym9wI6e/l5f0NocZmNEaouoHvsSyVfrp9iRYl/C8=

code:代码:

import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
import org.bouncycastle.crypto.params.Argon2Parameters;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class Argon2id {
    public static void main(String[] args) {
        // uses Bouncy Castle
        System.out.println("Generate a 32 byte long encryption key with Argon2id");

        String password = "secret password";
        System.out.println("password: " + password);

        // ### security warning - never use a fixed salt in production, this is for compare reasons only
        byte[] salt = generateFixedSalt16Byte();
        // please use below generateSalt16Byte()
        //byte[] salt = generateSalt16Byte();
        System.out.println("salt (Base64): " + base64Encoding(salt));

        // ### the minimal parameter set is probably UNSECURE ###
        String encryptionKeyArgon2id = base64Encoding(generateArgon2idMinimal(password, salt));
        System.out.println("encryptionKeyArgon2id (Base64) minimal:     " + encryptionKeyArgon2id);

        encryptionKeyArgon2id = base64Encoding(generateArgon2idInteractive(password, salt));
        System.out.println("encryptionKeyArgon2id (Base64) interactive: " + encryptionKeyArgon2id);

        encryptionKeyArgon2id = base64Encoding(generateArgon2idModerate(password, salt));
        System.out.println("encryptionKeyArgon2id (Base64) moderate:    " + encryptionKeyArgon2id);

        encryptionKeyArgon2id = base64Encoding(generateArgon2idSensitive(password, salt));
        System.out.println("encryptionKeyArgon2id (Base64) sensitive:   " + encryptionKeyArgon2id);
    }

    // ### the minimal parameter set is probably UNSECURE ###
    public static byte[] generateArgon2idMinimal(String password, byte[] salt) {
        int opsLimit = 2;
        int memLimit = 8192;
        int outputLength = 32;
        int parallelism = 1;
        Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withVersion(Argon2Parameters.ARGON2_VERSION_13) // 19
                .withIterations(opsLimit)
                .withMemoryAsKB(memLimit)
                .withParallelism(parallelism)
                .withSalt(salt);
        Argon2BytesGenerator gen = new Argon2BytesGenerator();
        gen.init(builder.build());
        byte[] result = new byte[outputLength];
        gen.generateBytes(password.getBytes(StandardCharsets.UTF_8), result, 0, result.length);
        return result;
    }

    public static byte[] generateArgon2idInteractive(String password, byte[] salt) {
        int opsLimit = 2;
        int memLimit = 66536;
        int outputLength = 32;
        int parallelism = 1;
        Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withVersion(Argon2Parameters.ARGON2_VERSION_13) // 19
                .withIterations(opsLimit)
                .withMemoryAsKB(memLimit)
                .withParallelism(parallelism)
                .withSalt(salt);
        Argon2BytesGenerator gen = new Argon2BytesGenerator();
        gen.init(builder.build());
        byte[] result = new byte[outputLength];
        gen.generateBytes(password.getBytes(StandardCharsets.UTF_8), result, 0, result.length);
        return result;
    }

    public static byte[] generateArgon2idModerate(String password, byte[] salt) {
        int opsLimit = 3;
        int memLimit = 262144;
        int outputLength = 32;
        int parallelism = 1;
        Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withVersion(Argon2Parameters.ARGON2_VERSION_13) // 19
                .withIterations(opsLimit)
                .withMemoryAsKB(memLimit)
                .withParallelism(parallelism)
                .withSalt(salt);
        Argon2BytesGenerator gen = new Argon2BytesGenerator();
        gen.init(builder.build());
        byte[] result = new byte[outputLength];
        gen.generateBytes(password.getBytes(StandardCharsets.UTF_8), result, 0, result.length);
        return result;
    }

    public static byte[] generateArgon2idSensitive(String password, byte[] salt) {
        int opsLimit = 4;
        int memLimit = 1048576;
        int outputLength = 32;
        int parallelism = 1;
        Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withVersion(Argon2Parameters.ARGON2_VERSION_13) // 19
                .withIterations(opsLimit)
                .withMemoryAsKB(memLimit)
                .withParallelism(parallelism)
                .withSalt(salt);
        Argon2BytesGenerator gen = new Argon2BytesGenerator();
        gen.init(builder.build());
        byte[] result = new byte[outputLength];
        gen.generateBytes(password.getBytes(StandardCharsets.UTF_8), result, 0, result.length);
        return result;
    }

    private static byte[] generateSalt16Byte() {
        SecureRandom secureRandom = new SecureRandom();
        byte[] salt = new byte[16];
        secureRandom.nextBytes(salt);
        return salt;
    }

    private static byte[] generateFixedSalt16Byte() {
        // ### security warning - never use this in production ###
        byte[] salt = new byte[16]; // 16 x0's
        return salt;
    }

    private static String base64Encoding(byte[] input) {
        return Base64.getEncoder().encodeToString(input);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM