Argon2

Build Status Build status codecov.io

这是 Argon2 的参考 C 实现。Argon2 是密码哈希函数,赢得了密码哈希竞赛 (PHC)

Argon2 是一种密码哈希函数,总结了内存硬函数设计的最新技术,可用于对密码进行哈希以进行凭据存储、密钥派生或其他应用。

它具有一个简单的设计,旨在实现最高的内存填充率和多个计算单元的有效利用,同时仍通过利用最新处理器的缓存和内存组织来防御权衡攻击。

Argon2 有三个变体:Argon2i、Argon2d 和 Argon2id。Argon2d 更快,并使用数据相关的内存访问,这使其具有很强的抵抗 GPU 破解攻击的能力,并且适用于没有来自侧信道定时攻击的威胁的应用(例如,加密货币)。Argon2i 则使用数据独立的内存访问,这对于密码哈希和基于密码的密钥派生是首选,但速度较慢,因为它会在内存上进行更多传递,以防止权衡攻击。Argon2id 是 Argon2i 和 Argon2d 的混合体,它结合了数据相关和数据独立的内存访问,这使其具有 Argon2i 的一些抵抗侧信道缓存定时攻击的能力和 Argon2d 的大部分抵抗 GPU 破解攻击的能力。

Argon2i、Argon2d 和 Argon2id 由以下参数确定:

Argon2 文档 提供了详细的规范和设计原理。

请将错误作为 issue 在此存储库中报告。

用法

make 构建可执行文件 argon2、静态库 libargon2.a 和共享库 libargon2.so(或者在 macOS 上,是动态库 libargon2.dylib -- 确保在编译时指定安装前缀:make PREFIX=/usr)。确保运行 make test 以验证你的构建是否产生有效结果。sudo make install PREFIX=/usr 将其安装到你的系统。

命令行实用程序

argon2 是一个命令行实用程序,用于在你的系统上测试特定的 Argon2 实例。要显示使用说明,请运行 ./argon2 -h,例如:

Usage:  ./argon2 [-h] salt [-i|-d|-id] [-t iterations] [-m memory] [-p parallelism] [-l hash length] [-e|-r] [-v (10|13)]
        Password is read from stdin
Parameters:
        salt            The salt to use, at least 8 characters
        -i              Use Argon2i (this is the default)
        -d              Use Argon2d instead of Argon2i
        -id             Use Argon2id instead of Argon2i
        -t N            Sets the number of iterations to N (default = 3)
        -m N            Sets the memory usage of 2^N KiB (default 12)
        -p N            Sets parallelism to N threads (default 1)
        -l N            Sets hash output length to N bytes (default 32)
        -e              Output only encoded hash
        -r              Output only the raw bytes of the hash
        -v (10|13)      Argon2 version (defaults to the most recent version, currently 13)
        -h              Print argon2 usage

例如,使用 "somesalt" 作为 salt 对 "password" 进行哈希,进行 2 次迭代,消耗 64 MiB,使用四个并行线程,输出哈希值为 24 字节:

$ echo -n "password" | ./argon2 somesalt -t 2 -m 16 -p 4 -l 24
Type:           Argon2i
Iterations:     2
Memory:         65536 KiB
Parallelism:    4
Hash:           45d7ac72e76f242b20b77b9bf9bf9d5915894e669a24e6c6
Encoded:        $argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG
0.188 seconds
Verification ok

libargon2 提供了一个 API,用于使用 Argon2 的低级和高级函数。

下面的示例程序使用高级 API 和低级 API,使用 Argon2i 对字符串 "password" 进行哈希。高级 API 接受三个成本参数(时间、内存和并行度)、密码输入缓冲区、salt 输入缓冲区和输出缓冲区,而低级 API 接受这些参数以及 include/argon2.h 中定义的其他参数。

还有许多额外的参数,但我们将在此处重点介绍其中三个。

  1. secret 参数,用于密钥哈希。 这允许在哈希时输入一个密钥(从某些外部位置),并将其折叠到哈希值中。 这意味着即使您的 salt 和哈希受到威胁,攻击者也无法在没有密钥的情况下进行暴力破解以查找密码。

  2. ad 参数,用于将任何额外数据折叠到哈希值中。在功能上,它的行为几乎与 secretsalt 参数完全相同; ad 参数被折叠到哈希值中。但是,此参数用于不同的数据。 salt 应该是一个与您的密码一起存储的随机字符串。 secret 应该是一个仅在哈希时可用的随机密钥。 ad 用于任何其他数据。

  3. flags 参数,它确定哪些内存应该被安全擦除。 如果您想在使用后立即安全地删除 pwdsecret 字段,这将非常有用。 为此,请将 flags 设置为 ARGON2_FLAG_CLEAR_PASSWORDARGON2_FLAG_CLEAR_SECRET。 要更改内部内存的清除方式,请更改全局标志 FLAG_clear_internal_memory(默认为清除内部内存)。

这里,时间成本 t_cost 设置为 2 次迭代,内存成本 m_cost 设置为 216 千字节(64 mebibytes),并行度设置为 1(单线程)。

如果下面的程序命名为 test.c 并放置在项目的根目录中,则可以例如编译为 gcc test.c libargon2.a -Isrc -o test

#include "argon2.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define HASHLEN 32
#define SALTLEN 16
#define PWD "password"

int main(void)
{
    uint8_t hash1[HASHLEN];
    uint8_t hash2[HASHLEN];

    uint8_t salt[SALTLEN];
    memset( salt, 0x00, SALTLEN );

    uint8_t *pwd = (uint8_t *)strdup(PWD);
    uint32_t pwdlen = strlen((char *)pwd);

    uint32_t t_cost = 2;            // 2-pass computation
    uint32_t m_cost = (1<<16);      // 64 mebibytes memory usage
    uint32_t parallelism = 1;       // number of threads and lanes

    // high-level API
    argon2i_hash_raw(t_cost, m_cost, parallelism, pwd, pwdlen, salt, SALTLEN, hash1, HASHLEN);

    // low-level API
    argon2_context context = {
        hash2,  /* output array, at least HASHLEN in size */
        HASHLEN, /* digest length */
        pwd, /* password array */
        pwdlen, /* password length */
        salt,  /* salt array */
        SALTLEN, /* salt length */
        NULL, 0, /* optional secret data */
        NULL, 0, /* optional associated data */
        t_cost, m_cost, parallelism, parallelism,
        ARGON2_VERSION_13, /* algorithm version */
        NULL, NULL, /* custom memory allocation / deallocation functions */
        /* by default only internal memory is cleared (pwd is not wiped) */
        ARGON2_DEFAULT_FLAGS
    };

    int rc = argon2i_ctx( &context );
    if(ARGON2_OK != rc) {
        printf("Error: %s\n", argon2_error_message(rc));
        exit(1);
    }
    free(pwd);

    for( int i=0; i<HASHLEN; ++i ) printf( "%02x", hash1[i] ); printf( "\n" );
    if (memcmp(hash1, hash2, HASHLEN)) {
        for( int i=0; i<HASHLEN; ++i ) {
            printf( "%02x", hash2[i] );
        }
        printf("\nfail\n");
    }
    else printf("ok\n");
    return 0;
}

要使用 Argon2d 代替 Argon2i,请在使用高级 API 时调用 argon2d_hash_raw 而不是 argon2i_hash_raw,在使用低级 API 时调用 argon2d 而不是 argon2i。对于 Argon2id,类似地,调用 argon2id_hash_rawargon2id

要生成类似 crypt 的编码而不是原始哈希,对于 Argon2i,请调用 argon2i_hash_encoded,对于 Argon2d,请调用 argon2d_hash_encoded,对于 Argon2id,请调用 argon2id_hash_encoded

有关 API 详细信息,请参见include/argon2.h

注意:在此示例中,为了简单起见,salt 设置为全 0x00 字符串,但在你的应用程序中,你应该使用随机 salt。

基准测试

make bench 创建可执行文件 bench,它测量各种 Argon2 实例的执行时间。

$ ./bench
Argon2d 1 iterations  1 MiB 1 threads:  5.91 cpb 5.91 Mcycles
Argon2i 1 iterations  1 MiB 1 threads:  4.64 cpb 4.64 Mcycles
0.0041 seconds

Argon2d 1 iterations  1 MiB 2 threads:  2.76 cpb 2.76 Mcycles
Argon2i 1 iterations  1 MiB 2 threads:  2.87 cpb 2.87 Mcycles
0.0038 seconds

Argon2d 1 iterations  1 MiB 4 threads:  3.25 cpb 3.25 Mcycles
Argon2i 1 iterations  1 MiB 4 threads:  3.57 cpb 3.57 Mcycles
0.0048 seconds

(...)

Argon2d 1 iterations  4096 MiB 2 threads:  2.15 cpb 8788.08 Mcycles
Argon2i 1 iterations  4096 MiB 2 threads:  2.15 cpb 8821.59 Mcycles
13.0112 seconds

Argon2d 1 iterations  4096 MiB 4 threads:  1.79 cpb 7343.72 Mcycles
Argon2i 1 iterations  4096 MiB 4 threads:  2.72 cpb 11124.86 Mcycles
19.3974 seconds

(...)

绑定

以下语言提供了绑定(请确保阅读它们的文档):

测试套件

有两组测试套件。一个是哈希函数的低级测试,另一个测试更高级的 API。 两者都是通过运行以下命令构建和执行的:

make test

知识产权

除了下面列出的组件外,此存储库中的 Argon2 代码的版权归 (c) 2015 Daniel Dinu、Dmitry Khovratovich(主要作者)、Jean-Philippe Aumasson 和 Samuel Neves 所有,并根据CC0 许可证Apache 2.0 许可证双重许可。 有关更多信息,请参见 LICENSE 文件。

src/encoding.c 中的字符串编码例程的版权归 (c) 2015 Thomas Pornin 所有,并根据CC0 许可证获得许可。

src/blake2/ 中的 BLAKE2 代码的版权归 (c) Samuel Neves, 2013-2015 所有,并根据CC0 许可证获得许可。

因此,所有许可证都与 GPL 兼容。