From 1b88359909c5445992f9e08cd98128aa6dd0eaef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Tue, 15 Feb 2022 19:13:45 +0100 Subject: [PATCH 1/2] Add support for Argon2 (i, d, id, and ds variants) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 1 + AUTHORS | 9 ++ LICENSING | 3 + Makefile.am | 2 + NEWS | 4 +- README.md | 2 +- TODO.md | 1 - configure.ac | 24 ++++- doc/crypt.5 | 22 +++++ lib/crypt-argon2.c | 232 ++++++++++++++++++++++++++++++++++++++++++++ lib/hashes.conf | 38 ++++---- lib/libxcrypt.pc.in | 4 +- test/crypt-argon2.c | 150 ++++++++++++++++++++++++++++ 13 files changed, 469 insertions(+), 23 deletions(-) create mode 100644 lib/crypt-argon2.c create mode 100644 test/crypt-argon2.c diff --git a/.gitignore b/.gitignore index 0b5b4b52..f25c01c9 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ test/bigcrypt test/byteorder test/checksalt test/compile-strong-alias +test/crypt-argon2 test/crypt-badargs test/crypt-bcrypt test/crypt-des diff --git a/AUTHORS b/AUTHORS index 1371508f..509a0f5c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,6 +2,15 @@ The yescrypt code comes from yescrypt by Solar Designer . It builds upon Colin Percival's scrypt. See: http://openwall.com/yescrypt/ for reference. +The Argon2 hash module use an independent implementation by Mattias +Andrée of the Argon2 algorithm by Alex Biryukov, Daniel Dinu, and +Dmitry Khovratovich (see https://github.com/P-H-C/phc-winner-argon2 +for referenced) as well as the underlying BLAKE2b algorithm by +Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, Christian +Winnerlein. The Argon2 hash modules uses libar2simplified and +libar2 which depend on libblake for the BLAKE2b implementation. +These libraries are licensed under the ISC license. + The bcrypt hash module comes from crypt_blowfish, originally written by Solar Designer and based on algorithms and ideas by Niels Provos and David Mazieres diff --git a/LICENSING b/LICENSING index c6d90fcb..8e053811 100644 --- a/LICENSING +++ b/LICENSING @@ -26,6 +26,9 @@ source tree. For specific licensing terms consult the files themselves. alg-md4.h, alg-md4.c, alg-md5.h, alg-md5.c, crypt-bcrypt.c, crypt-gensalt.c, test-crypt-bcrypt.c + * Copyright Mattias Andrée; ISC: + crypt-argon2.c + * Copyright Solar Designer, Colin Percival; 0-clause BSD: alg-yescrypt-common.c, alg-yescrypt-platform.c diff --git a/Makefile.am b/Makefile.am index 676135a9..5bb23c84 100644 --- a/Makefile.am +++ b/Makefile.am @@ -110,6 +110,7 @@ libcrypt_la_SOURCES = \ lib/alg-sha512.c \ lib/alg-yescrypt-common.c \ lib/alg-yescrypt-opt.c \ + lib/crypt-argon2.c \ lib/crypt-bcrypt.c \ lib/crypt-des.c \ lib/crypt-gensalt-static.c \ @@ -369,6 +370,7 @@ check_PROGRAMS = \ test/byteorder \ test/checksalt \ test/compile-strong-alias \ + test/crypt-argon2 \ test/crypt-badargs \ test/crypt-gost-yescrypt \ test/explicit-bzero \ diff --git a/NEWS b/NEWS index c427ee30..c10d631a 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,9 @@ libxcrypt NEWS -- history of user-visible changes. Please send bug reports, questions and suggestions to . -Version 4.4.29 +Version 4.5.0 +* Implement Argon2 ($argon2i$, $argon2d$, $argon2id$, $argon2ds$) + hashing algorithms. Version 4.4.28 * Add glibc-on-or1k (OpenRISC 1000) entry to libcrypt.minver. diff --git a/README.md b/README.md index 45b7f02f..df3b15b7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ README for libxcrypt libxcrypt is a modern library for one-way hashing of passwords. It supports a wide variety of both modern and historical hashing methods: -yescrypt, gost-yescrypt, scrypt, bcrypt, sha512crypt, sha256crypt, +argon2i, yescrypt, gost-yescrypt, scrypt, bcrypt, sha512crypt, sha256crypt, md5crypt, SunMD5, sha1crypt, NT, bsdicrypt, bigcrypt, and descrypt. It provides the traditional Unix `crypt` and `crypt_r` interfaces, as well as a set of extended interfaces pioneered by Openwall Linux, diff --git a/TODO.md b/TODO.md index e6b8f257..7303d2d8 100644 --- a/TODO.md +++ b/TODO.md @@ -35,7 +35,6 @@ It was last updated 20 October 2018. whether we can use these. * Additional hashing methods - * Argon2 * ...? * Runtime configurability (in progress on the [crypt.conf branch][]) diff --git a/configure.ac b/configure.ac index 7cb19dcf..63ddb04e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # Process this file with autoconf to produce a configure script. m4_include([build-aux/m4/zw_automodern.m4]) AC_INIT([xcrypt], - [4.4.29], + [4.5.0], [https://github.com/besser82/libxcrypt/issues], [libxcrypt], [https://github.com/besser82/libxcrypt]) @@ -427,6 +427,28 @@ case "$hashes_enabled" in ;; esac + +# The Argon2 hash module requires libar2simplified, libar2, libblake, and libpthread. +case "$hashes_enabled" in + *,argon2*) + AC_SEARCH_LIBS([libar2simplified_init_context], [ar2simplified]) + if test x"$ac_cv_search_libar2simplified_init_context" = xno; then + AC_MSG_ERROR([Could not find libar2simplified version 1.1+, required for the Argon2 hash module]) + fi + AC_SEARCH_LIBS([libar2_hash_buf_size], [ar2]) + if test x"$ac_cv_search_libar2_hash_buf_size" = xno; then + AC_MSG_ERROR([Could not find libar2 version 1.1+, required for the Argon2 hash module]) + fi + AC_SEARCH_LIBS([libblake_blake2b_init], [blake]) + if test x"$ac_cv_search_libblake_blake2b_init" = xno; then + AC_MSG_ERROR([Could not find libblake, required for the Argon2 hash module]) + fi + AX_PTHREAD + ;; +esac + + + # If the obsolete APIs are disabled, the stubs implicitly disabled as well. if test x"$COMPAT_ABI" = xno && test x"$enable_obsolete_api_enosys" = x1; then AC_MSG_WARN( diff --git a/doc/crypt.5 b/doc/crypt.5 index e3186bc7..ea43fff6 100644 --- a/doc/crypt.5 +++ b/doc/crypt.5 @@ -189,6 +189,28 @@ The algorithm was specifically designed to make it costly to perform large-scale custom hardware attacks by requiring large amounts of memory. In 2016, the scrypt algorithm was published by IETF as RFC 7914. .hash "$7$" "\e$7\e$[./A-Za-z0-9]{11,97}\e$[./A-Za-z0-9]{43}" unlimited 8 256 256 "up to 512 (128+ recommended)" "6 to 11 (logarithmic)" +.Ss argon2_d +argon2_d is one of the variants of Argon2 key derivation functions that won +the Password Hashing Competition 2015. argon2d is designed for environments +taht are safe from side-channel attacks. Acceptable for new hashes, but +not widely supported. +.hash "$argon2d$" "\e$argon2d\e$(v=(16|19)\e$)?m=[1-9][0-9]*,t=[1-9][0-9]*,p=[1-9][0-9]*\e$[A-Za-z0-9+/]{11,}\e$[A-Za-z0-9+/]{6,}" 4,294,967,295 8 "32 to 34,359,738,360 (256 default)" "32 to 34,359,738,360 (256 default)" "64 to 34,359,738,360 (128+ recommended)" "1 to 4,294,967,295" +.Ss argon2_i +argon2_i is one of the variants of Argon2 key derivation functions that won +the Password Hashing Competition 2015. argon2i is designed for environments +taht are not safe from side-channel attacks. Acceptable for new hashes, but +not widely supported. +.hash "$argon2i$" "\e$argon2i\e$(v=(16|19)\e$)?m=[1-9][0-9]*,t=[1-9][0-9]*,p=[1-9][0-9]*\e$[A-Za-z0-9+/]{11,}\e$[A-Za-z0-9+/]{6,}" 4,294,967,295 8 "32 to 34,359,738,360 (256 default)" "32 to 34,359,738,360 (256 default)" "64 to 34,359,738,360 (128+ recommended)" "1 to 4,294,967,295" +.Ss argon2_id +argon2_id is one of the variants of Argon2 key derivation functions that won +the Password Hashing Competition 2015. argon2id is a hybrid construction +between argon2i and argon2d. Acceptable for new hashes, but not widely supported. +.hash "$argon2id$" "\e$argon2id\e$(v=(16|19)\e$)?m=[1-9][0-9]*,t=[1-9][0-9]*,p=[1-9][0-9]*\e$[A-Za-z0-9+/]{11,}\e$[A-Za-z0-9+/]{6,}" 4,294,967,295 8 "32 to 34,359,738,360 (256 default)" "32 to 34,359,738,360 (256 default)" "64 to 34,359,738,360 (128+ recommended)" "1 to 4,294,967,295" +.Ss argon2_ds +argon2_ds is a later addition to the Argon2 family of key derivation functions. +It adds a substitution-box mechanism to argon2d. Acceptable for new hashes, but +not widely supported. +.hash "$argon2ds$" "\e$argon2ds\e$(v=(16|19)\e$)?m=[1-9][0-9]*,t=[1-9][0-9]*,p=[1-9][0-9]*\e$[A-Za-z0-9+/]{11,}\e$[A-Za-z0-9+/]{6,}" 4,294,967,295 8 "32 to 34,359,738,360 (256 default)" "32 to 34,359,738,360 (256 default)" "64 to 34,359,738,360 (128+ recommended)" "1 to 4,294,967,295" .Ss bcrypt A hash based on the Blowfish block cipher, modified to have an extra-expensive key schedule. diff --git a/lib/crypt-argon2.c b/lib/crypt-argon2.c new file mode 100644 index 00000000..fec2bf0e --- /dev/null +++ b/lib/crypt-argon2.c @@ -0,0 +1,232 @@ +/** + * ISC License + * + * © 2022 Mattias Andrée + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "crypt-port.h" +#include "crypt-hashes.h" + +#if INCLUDE_argon2_d || INCLUDE_argon2_i || INCLUDE_argon2_id || INCLUDE_argon2_ds + +#include +#include + +#include +#include +#include + +#define REMOVE_CONST(X)\ + (*(void **)(void *)&(X)) + +#define DEFAULT_TAG_SIZE 32 +#define DEFAULT_VERSION LIBAR2_ARGON2_VERSION_13 +#define DEFAULT_M_COST 4096 +#define DEFAULT_LANES 1 + +static void +crypt_argon2_rn (const char *prefix, + const char *phrase, size_t phr_size, + const char *setting, size_t set_size, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size) +{ + struct libar2_argon2_parameters *params = NULL; + struct libar2_context ctx; + char *settings_end; + int free_scratch = 0; + size_t required_s_size; + size_t required_o_size; + size_t offset; + + if (strncmp (setting, prefix, strlen (prefix)) || !set_size) + goto einval; + + params = libar2simplified_decode (setting, NULL, &settings_end, NULL); + if (!params) + goto fail; + if (*settings_end) + goto einval; + if (!params->hashlen) + params->hashlen = DEFAULT_TAG_SIZE; + + required_o_size = libar2_encode_params (NULL, params) - 1; + required_o_size += libar2_encode_base64 (NULL, NULL, params->hashlen); + if (o_size < required_o_size) + goto einval; + + libar2simplified_init_context (&ctx); + ctx.autoerase_message = 0; /* allows `phrase` to be read-only */ + required_s_size = libar2_hash_buf_size (params); + if (required_s_size > s_size) + { + if (free_scratch) + free (scratch); + scratch = malloc (required_s_size); + if (!scratch) + { + errno = ENOMEM; + goto fail; + } + free_scratch = 1; + } + + if (libar2_hash (scratch, REMOVE_CONST (phrase), phr_size, params, &ctx)) + goto fail; + + offset = libar2_encode_params ((char *) output, params) - 1; + libar2_encode_base64 ((char *) &output[offset], scratch, params->hashlen); + + free(params); + errno = 0; + return; + + einval: + errno = EINVAL; + fail: + free (params); + if (free_scratch) + { + free (scratch); + } + return; +} + +static void +gensalt_argon2_rn (enum libar2_argon2_type type, + unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size) +{ + struct libar2_argon2_parameters params; + + if (count >> 31 > 1) + goto erange; + + memset (¶ms, 0, sizeof (params)); + params.type = type; + params.version = DEFAULT_VERSION; + params.t_cost = (uint_least32_t) count; + params.m_cost = DEFAULT_M_COST; + params.lanes = DEFAULT_LANES; + params.salt = REMOVE_CONST (rbytes); /* libar2 does not use `const` because + * it has an option to erase the salt */ + params.saltlen = nrbytes; + params.hashlen = DEFAULT_TAG_SIZE; + if (libar2_validate_params (¶ms, NULL) != LIBAR2_OK) + goto erange; + + if (o_size < libar2_encode_params (NULL, ¶ms)) + goto erange; + + if (libar2_encode_params ((char *) output, ¶ms) > o_size) + abort(); + + return; + + erange: + errno = ERANGE; + return; +} + +#if INCLUDE_argon2_d +void +crypt_argon2_d_rn (const char *phrase, size_t phr_size, + const char *setting, size_t set_size, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size) +{ + crypt_argon2_rn ("$argon2d$", phrase, phr_size, setting, + set_size, output, o_size, scratch, s_size); +} +#endif /* INCLUDE_argon2_d */ + +#if INCLUDE_argon2_i +void +crypt_argon2_i_rn (const char *phrase, size_t phr_size, + const char *setting, size_t set_size, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size) +{ + crypt_argon2_rn ("$argon2i$", phrase, phr_size, setting, + set_size, output, o_size, scratch, s_size); +} +#endif /* INCLUDE_argon2_i */ + +#if INCLUDE_argon2_id +void +crypt_argon2_id_rn (const char *phrase, size_t phr_size, + const char *setting, size_t set_size, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size) +{ + crypt_argon2_rn ("$argon2id$", phrase, phr_size, setting, + set_size, output, o_size, scratch, s_size); +} +#endif /* INCLUDE_argon2_id */ + +#if INCLUDE_argon2_ds +void +crypt_argon2_ds_rn (const char *phrase, size_t phr_size, + const char *setting, size_t set_size, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size) +{ + crypt_argon2_rn ("$argon2ds$", phrase, phr_size, setting, + set_size, output, o_size, scratch, s_size); +} +#endif /* INCLUDE_argon2_ds */ + +#if INCLUDE_argon2_d +void +gensalt_argon2_d_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size) +{ + gensalt_argon2_rn(LIBAR2_ARGON2D, count, rbytes, nrbytes, output, o_size); +} +#endif /* INCLUDE_argon2_d */ + +#if INCLUDE_argon2_i +void +gensalt_argon2_i_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size) +{ + gensalt_argon2_rn(LIBAR2_ARGON2I, count, rbytes, nrbytes, output, o_size); +} +#endif /* INCLUDE_argon2_i */ + +#if INCLUDE_argon2_id +void +gensalt_argon2_id_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size) +{ + gensalt_argon2_rn(LIBAR2_ARGON2ID, count, rbytes, nrbytes, output, o_size); +} +#endif /* INCLUDE_argon2_ds */ + +#if INCLUDE_argon2_ds +void +gensalt_argon2_ds_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size) +{ + gensalt_argon2_rn(LIBAR2_ARGON2DS, count, rbytes, nrbytes, output, o_size); +} +#endif /* INCLUDE_argon2_ds */ + +#endif /* INCLUDE_argon2_d || INCLUDE_argon2_i || INCLUDE_argon2_id || INCLUDE_argon2_ds */ diff --git a/lib/hashes.conf b/lib/hashes.conf index 094f7cc6..3a6bda86 100644 --- a/lib/hashes.conf +++ b/lib/hashes.conf @@ -38,20 +38,24 @@ # descrypt) must be last (conveniently, these are also the weakest # supported hashes). # -#name h_prefix nrbytes flags -yescrypt $y$ 16 STRONG,DEFAULT,ALT,DEBIAN,FEDORA -gost_yescrypt $gy$ 16 STRONG,ALT -scrypt $7$ 16 STRONG -bcrypt $2b$ 16 STRONG,DEFAULT,ALT,FREEBSD,NETBSD,OPENBSD,OWL,SOLARIS,SUSE -bcrypt_y $2y$ 16 STRONG,ALT,OWL,SUSE -bcrypt_a $2a$ 16 STRONG,ALT,FREEBSD,NETBSD,OPENBSD,OWL,SOLARIS,SUSE -bcrypt_x $2x$ 16 ALT,OWL,SUSE -sha512crypt $6$ 15 STRONG,DEFAULT,GLIBC,FREEBSD,SOLARIS -sha256crypt $5$ 15 GLIBC,FREEBSD,SOLARIS -sha1crypt $sha1 20 NETBSD -sunmd5 $md5 8 SOLARIS -md5crypt $1$ 9 GLIBC,FREEBSD,NETBSD,OPENBSD,SOLARIS -nt $3$ 1 FREEBSD -bsdicrypt _ 3 FREEBSD,NETBSD,OPENBSD,OSX -bigcrypt : 2 : -descrypt : 2 GLIBC,FREEBSD,NETBSD,OPENBSD,SOLARIS,OSX +#name h_prefix nrbytes flags +yescrypt $y$ 16 STRONG,DEFAULT,ALT,DEBIAN,FEDORA +gost_yescrypt $gy$ 16 STRONG,ALT +argon2_id $argon2id$ 16 STRONG +argon2_i $argon2i$ 16 STRONG,NETBSD +argon2_d $argon2d$ 16 STRONG +argon2_ds $argon2ds$ 16 STRONG +scrypt $7$ 16 STRONG +bcrypt $2b$ 16 STRONG,DEFAULT,ALT,FREEBSD,NETBSD,OPENBSD,OWL,SOLARIS,SUSE +bcrypt_y $2y$ 16 STRONG,ALT,OWL,SUSE +bcrypt_a $2a$ 16 STRONG,ALT,FREEBSD,NETBSD,OPENBSD,OWL,SOLARIS,SUSE +bcrypt_x $2x$ 16 ALT,OWL,SUSE +sha512crypt $6$ 15 STRONG,DEFAULT,GLIBC,FREEBSD,SOLARIS +sha256crypt $5$ 15 GLIBC,FREEBSD,SOLARIS +sha1crypt $sha1 20 NETBSD +sunmd5 $md5 8 SOLARIS +md5crypt $1$ 9 GLIBC,FREEBSD,NETBSD,OPENBSD,SOLARIS +nt $3$ 1 FREEBSD +bsdicrypt _ 3 FREEBSD,NETBSD,OPENBSD,OSX +bigcrypt : 2 : +descrypt : 2 GLIBC,FREEBSD,NETBSD,OPENBSD,SOLARIS,OSX diff --git a/lib/libxcrypt.pc.in b/lib/libxcrypt.pc.in index 2c75dc20..3f9bf8db 100644 --- a/lib/libxcrypt.pc.in +++ b/lib/libxcrypt.pc.in @@ -11,5 +11,5 @@ includedir=@includedir@ Name: @PACKAGE@ Version: @VERSION@ Description: Extended crypt library for DES, MD5, Blowfish and others -Libs: -L${libdir} -lcrypt -Cflags: -I${includedir} +Libs: -L${libdir} -lcrypt -lar2simplified -lar2 -lblake -pthread +Cflags: -I${includedir} -pthread diff --git a/test/crypt-argon2.c b/test/crypt-argon2.c new file mode 100644 index 00000000..d7c43383 --- /dev/null +++ b/test/crypt-argon2.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2022 Mattias Andrée + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "crypt-port.h" + +#if INCLUDE_argon2_i && INCLUDE_argon2_d && INCLUDE_argon2_id && INCLUDE_argon2_ds + +#include +#include +#include +#include + +#include "../lib/crypt-argon2.c" + +static const char * +xcrypt (const char *phrase, const char *setting) +{ + static char output[CRYPT_OUTPUT_SIZE]; + static char scratch[ALG_SPECIFIC_SIZE]; + + if (!strncmp (setting, "$argon2d$", sizeof ("$argon2d$") - 1)) + { + crypt_argon2_d_rn (phrase, strlen (phrase), + setting, strlen (setting), + (uint8_t *) output, sizeof (output), + scratch, sizeof(scratch)); + } + else if (!strncmp (setting, "$argon2i$", sizeof ("$argon2i$") - 1)) + { + crypt_argon2_i_rn (phrase, strlen (phrase), + setting, strlen (setting), + (uint8_t *) output, sizeof (output), + scratch, sizeof(scratch)); + } + else if (!strncmp (setting, "$argon2id$", sizeof ("$argon2id$") - 1)) + { + crypt_argon2_id_rn (phrase, strlen (phrase), + setting, strlen (setting), + (uint8_t *) output, sizeof (output), + scratch, sizeof(scratch)); + } + else if (!strncmp (setting, "$argon2ds$", sizeof ("$argon2ds$") - 1)) + { + crypt_argon2_ds_rn (phrase, strlen (phrase), + setting, strlen (setting), + (uint8_t *) output, sizeof (output), + scratch, sizeof(scratch)); + } + else + { + abort(); + } + + return errno ? NULL : output; +} + +static int +test_crypt (const char *phrase, const char *input, const char *output) +{ + const char *result; + if (!output) + output = input; + result = xcrypt (phrase, input); + if (!result) + { + fprintf (stderr, "ERROR: crypt (\"%s\", \"%s\") failed, error: %s\n", phrase, output, strerror (errno)); + return 1; + } + else if (strcmp (result, output)) + { + fprintf (stderr, "ERROR: crypt (\"%s\", \"%s\") failed: incorrect hash (%s)\n", phrase, output, result); + return 1; + } + return 0; +} + +int +main (void) +{ + char output[CRYPT_OUTPUT_SIZE]; + int result = 0; + + /* These are just some tests to verify that the implementation works, + * the correctness of the algorithm is tested in libar2's test code. */ + result |= test_crypt ("password", "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ$/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY", NULL); + result |= test_crypt ("password", "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ$", + "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ$/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY"); + result |= test_crypt ("password", "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ$iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8", NULL); + result |= test_crypt ("password", "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", NULL); + result |= test_crypt ("", "$argon2ds$v=16$m=8,t=1,p=1$ICAgICAgICA$zgdykk9ZjN5VyrW0LxGw8LmrJ1Z6fqSC+3jPQtn4n0s", NULL); + result |= test_crypt ("", "$argon2d$v=16$m=8,t=1,p=1$ICAgICAgICA$NjODMrWrS7zeivNNpHsuxD9c6uDmUQ6YqPRhb8H5DSNw" + "9n683FUCJZ3tyxgfJpYYANI+01WT/S5zp1UVs+qNRwnkdEyLKZMg+DIOXVc9z1po9ZlZG8+Gp4g5brqfza3lvkR9vw", NULL); + + errno = 0; + + gensalt_argon2_d_rn (12, (const uint8_t *) "\1\1\1\1\1\1\1\1", 8, (uint8_t *) output, sizeof (output)); + if (errno || strcmp(output, "$argon2d$v=19$m=4096,t=12,p=1$AQEBAQEBAQE$")) + { + fprintf (stderr, "ERROR: gensalt_argon2_d_rn failed: %s\n", errno ? strerror (errno) : "incorrect output"); + return 1; + } + + gensalt_argon2_i_rn (13, (const uint8_t *) "\2\2\2\2\2\2\2\2", 8, (uint8_t *) output, sizeof (output)); + if (errno || strcmp(output, "$argon2i$v=19$m=4096,t=13,p=1$AgICAgICAgI$")) + { + fprintf (stderr, "ERROR: gensalt_argon2_i_rn failed: %s\n", errno ? strerror (errno) : "incorrect output"); + return 1; + } + + gensalt_argon2_id_rn (14, (const uint8_t *) "\3\3\3\3\3\3\3\3", 8, (uint8_t *) output, sizeof (output)); + if (errno || strcmp(output, "$argon2id$v=19$m=4096,t=14,p=1$AwMDAwMDAwM$")) + { + fprintf (stderr, "ERROR: gensalt_argon2_id_rn failed: %s\n", errno ? strerror (errno) : "incorrect output"); + return 1; + } + + gensalt_argon2_ds_rn (15, (const uint8_t *) "\0\1\2\3\4\5\6\7\10\11\12\13", 12, (uint8_t *) output, sizeof (output)); + if (errno || strcmp(output, "$argon2ds$v=19$m=4096,t=15,p=1$AAECAwQFBgcICQoL$")) + { + fprintf (stderr, "ERROR: gensalt_argon2_ds_rn failed: %s\n", errno ? strerror (errno) : "incorrect output"); + return 1; + } + + return result; +} + +#else + +int +main (void) +{ + return 77; /* UNSUPPORTED */ +} + +#endif /* INCLUDE_argon2_i && INCLUDE_argon2_d && INCLUDE_argon2_id && INCLUDE_argon2_ds */ From e72e23e0f1e4867b22243387d1ed44b8c8316056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Andr=C3=A9e?= Date: Thu, 22 Jun 2023 17:30:03 +0200 Subject: [PATCH 2/2] Fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- doc/crypt.5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/crypt.5 b/doc/crypt.5 index ea43fff6..3f7e8c5f 100644 --- a/doc/crypt.5 +++ b/doc/crypt.5 @@ -192,13 +192,13 @@ In 2016, the scrypt algorithm was published by IETF as RFC 7914. .Ss argon2_d argon2_d is one of the variants of Argon2 key derivation functions that won the Password Hashing Competition 2015. argon2d is designed for environments -taht are safe from side-channel attacks. Acceptable for new hashes, but +that are safe from side-channel attacks. Acceptable for new hashes, but not widely supported. .hash "$argon2d$" "\e$argon2d\e$(v=(16|19)\e$)?m=[1-9][0-9]*,t=[1-9][0-9]*,p=[1-9][0-9]*\e$[A-Za-z0-9+/]{11,}\e$[A-Za-z0-9+/]{6,}" 4,294,967,295 8 "32 to 34,359,738,360 (256 default)" "32 to 34,359,738,360 (256 default)" "64 to 34,359,738,360 (128+ recommended)" "1 to 4,294,967,295" .Ss argon2_i argon2_i is one of the variants of Argon2 key derivation functions that won the Password Hashing Competition 2015. argon2i is designed for environments -taht are not safe from side-channel attacks. Acceptable for new hashes, but +that are not safe from side-channel attacks. Acceptable for new hashes, but not widely supported. .hash "$argon2i$" "\e$argon2i\e$(v=(16|19)\e$)?m=[1-9][0-9]*,t=[1-9][0-9]*,p=[1-9][0-9]*\e$[A-Za-z0-9+/]{11,}\e$[A-Za-z0-9+/]{6,}" 4,294,967,295 8 "32 to 34,359,738,360 (256 default)" "32 to 34,359,738,360 (256 default)" "64 to 34,359,738,360 (128+ recommended)" "1 to 4,294,967,295" .Ss argon2_id