mirror of
https://github.com/libtom/libtomcrypt
synced 2026-08-25 20:26:07 -04:00
Argon2 password hashing function (RFC 9106)
This commit is contained in:
parent
3223b87588
commit
458b392d01
15 changed files with 819 additions and 76 deletions
|
|
@ -7589,6 +7589,46 @@ The \textit{out} parameter shall be a pointer to a buffer of at least 32 octets,
|
|||
where \textit{outlen} contains the available buffer size on input and the written size after the invocation.
|
||||
|
||||
|
||||
\subsection{Argon2}
|
||||
\index{Argon2}
|
||||
\label{argon2}
|
||||
|
||||
Argon2 is a memory-hard password hashing function defined in \href{https://datatracker.ietf.org/doc/html/rfc9106}{\texttt{RFC 9106}}.
|
||||
It is the winner of the 2015 \href{https://www.password-hashing.net/}{Password Hashing Competition} and is recommended for new applications that require password hashing or key derivation from passwords.
|
||||
|
||||
Three variants are provided:
|
||||
|
||||
\begin{description}
|
||||
\item[Argon2d] uses data-dependent memory access, which makes it faster but susceptible to side-channel attacks. Suitable for applications with no threats from side-channels.
|
||||
\item[Argon2i] uses data-independent memory access, which is preferred when side-channel resistance is needed.
|
||||
\item[Argon2id] is a hybrid that uses data-independent addressing for the first half of the first pass and data-dependent addressing for the remainder. This is the recommended variant for password hashing.
|
||||
\end{description}
|
||||
|
||||
The implementation uses the BLAKE2b hash function internally. To enable Argon2, define \texttt{LTC\_ARGON2} in \textit{tomcrypt\_custom.h} (it also requires \texttt{LTC\_BLAKE2B}).
|
||||
|
||||
\index{argon2\_hash()}
|
||||
\begin{alltt}
|
||||
int argon2_hash(const unsigned char *pwd, unsigned long pwdlen,
|
||||
const unsigned char *salt, unsigned long saltlen,
|
||||
const unsigned char *secret, unsigned long secretlen,
|
||||
const unsigned char *ad, unsigned long adlen,
|
||||
unsigned int t_cost, unsigned int m_cost,
|
||||
unsigned int parallelism,
|
||||
argon2_type type,
|
||||
unsigned char *out, unsigned long outlen);
|
||||
\end{alltt}
|
||||
|
||||
The \textit{pwd} parameter is the password of length \textit{pwdlen}.
|
||||
The \textit{salt} parameter is a random salt of length \textit{saltlen}; a minimum of 16 bytes is recommended.
|
||||
The \textit{secret} and \textit{ad} parameters are optional (may be \texttt{NULL} with a length of zero); they allow passing a secret key and associated data respectively.
|
||||
The \textit{t\_cost} parameter is the number of passes over the memory (minimum 1).
|
||||
The \textit{m\_cost} parameter is the memory usage in kibibytes (minimum $8 \times \textit{parallelism}$).
|
||||
The \textit{parallelism} parameter is the number of lanes (minimum 1); note that this implementation is single-threaded, so increasing this value changes the algorithm output but does not improve performance.
|
||||
The \textit{type} parameter selects the variant: \texttt{ARGON2\_D}, \texttt{ARGON2\_I}, or \texttt{ARGON2\_ID}.
|
||||
The output tag of length \textit{outlen} (minimum 4 bytes) is written to \textit{out}.
|
||||
The function returns \texttt{CRYPT\_OK} on success, \texttt{CRYPT\_MEM} if memory allocation fails, or \texttt{CRYPT\_INVALID\_ARG} if any parameter is out of range.
|
||||
|
||||
|
||||
\mysection{PKCS \#8}
|
||||
\index{PKCS \#8}
|
||||
\label{pkcs8}
|
||||
|
|
|
|||
|
|
@ -1407,6 +1407,14 @@
|
|||
RelativePath="src\misc\zeromem.c"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="argon2"
|
||||
>
|
||||
<File
|
||||
RelativePath="src\misc\argon2\argon2.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="base16"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -92,22 +92,23 @@ src/mac/xcbc/xcbc_file.o src/mac/xcbc/xcbc_init.o src/mac/xcbc/xcbc_memory.o \
|
|||
src/mac/xcbc/xcbc_memory_multi.o src/mac/xcbc/xcbc_process.o src/mac/xcbc/xcbc_test.o \
|
||||
src/math/fp/ltc_ecc_fp_mulmod.o src/math/gmp_desc.o src/math/ltm_desc.o src/math/multi.o \
|
||||
src/math/radix_to_bin.o src/math/rand_bn.o src/math/rand_prime.o src/math/tfm_desc.o src/misc/adler32.o \
|
||||
src/misc/base16/base16_decode.o src/misc/base16/base16_encode.o src/misc/base32/base32_decode.o \
|
||||
src/misc/base32/base32_encode.o src/misc/base64/base64_decode.o src/misc/base64/base64_encode.o \
|
||||
src/misc/bcrypt/bcrypt.o src/misc/burn_stack.o src/misc/compare_testvector.o src/misc/copy_or_zeromem.o \
|
||||
src/misc/crc32.o src/misc/crypt/crypt.o src/misc/crypt/crypt_argchk.o \
|
||||
src/misc/crypt/crypt_cipher_descriptor.o src/misc/crypt/crypt_cipher_is_valid.o \
|
||||
src/misc/crypt/crypt_constants.o src/misc/crypt/crypt_find_cipher.o \
|
||||
src/misc/crypt/crypt_find_cipher_any.o src/misc/crypt/crypt_find_cipher_id.o \
|
||||
src/misc/crypt/crypt_find_hash.o src/misc/crypt/crypt_find_hash_any.o \
|
||||
src/misc/crypt/crypt_find_hash_id.o src/misc/crypt/crypt_find_hash_oid.o \
|
||||
src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o src/misc/crypt/crypt_hash_descriptor.o \
|
||||
src/misc/crypt/crypt_hash_is_valid.o src/misc/crypt/crypt_inits.o \
|
||||
src/misc/crypt/crypt_ltc_mp_descriptor.o src/misc/crypt/crypt_prng_descriptor.o \
|
||||
src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_prng_rng_descriptor.o \
|
||||
src/misc/crypt/crypt_register_all_ciphers.o src/misc/crypt/crypt_register_all_hashes.o \
|
||||
src/misc/crypt/crypt_register_all_prngs.o src/misc/crypt/crypt_register_cipher.o \
|
||||
src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
|
||||
src/misc/argon2/argon2.o src/misc/base16/base16_decode.o src/misc/base16/base16_encode.o \
|
||||
src/misc/base32/base32_decode.o src/misc/base32/base32_encode.o src/misc/base64/base64_decode.o \
|
||||
src/misc/base64/base64_encode.o src/misc/bcrypt/bcrypt.o src/misc/burn_stack.o \
|
||||
src/misc/compare_testvector.o src/misc/copy_or_zeromem.o src/misc/crc32.o src/misc/crypt/crypt.o \
|
||||
src/misc/crypt/crypt_argchk.o src/misc/crypt/crypt_cipher_descriptor.o \
|
||||
src/misc/crypt/crypt_cipher_is_valid.o src/misc/crypt/crypt_constants.o \
|
||||
src/misc/crypt/crypt_find_cipher.o src/misc/crypt/crypt_find_cipher_any.o \
|
||||
src/misc/crypt/crypt_find_cipher_id.o src/misc/crypt/crypt_find_hash.o \
|
||||
src/misc/crypt/crypt_find_hash_any.o src/misc/crypt/crypt_find_hash_id.o \
|
||||
src/misc/crypt/crypt_find_hash_oid.o src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o \
|
||||
src/misc/crypt/crypt_hash_descriptor.o src/misc/crypt/crypt_hash_is_valid.o \
|
||||
src/misc/crypt/crypt_inits.o src/misc/crypt/crypt_ltc_mp_descriptor.o \
|
||||
src/misc/crypt/crypt_prng_descriptor.o src/misc/crypt/crypt_prng_is_valid.o \
|
||||
src/misc/crypt/crypt_prng_rng_descriptor.o src/misc/crypt/crypt_register_all_ciphers.o \
|
||||
src/misc/crypt/crypt_register_all_hashes.o src/misc/crypt/crypt_register_all_prngs.o \
|
||||
src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \
|
||||
src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
|
||||
src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \
|
||||
src/misc/crypt/crypt_unregister_prng.o src/misc/deprecated.o src/misc/error_to_string.o \
|
||||
src/misc/hkdf/hkdf.o src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
|
||||
|
|
@ -234,9 +235,9 @@ src/stream/sober128/sober128_test.o src/stream/sosemanuk/sosemanuk.o \
|
|||
src/stream/sosemanuk/sosemanuk_memory.o src/stream/sosemanuk/sosemanuk_test.o
|
||||
|
||||
#List of test objects to compile
|
||||
TOBJECTS=tests/base16_test.o tests/base32_test.o tests/base64_test.o tests/bcrypt_test.o \
|
||||
tests/cipher_hash_test.o tests/common.o tests/deprecated_test.o tests/der_test.o tests/dh_test.o \
|
||||
tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/file_test.o tests/mac_test.o \
|
||||
TOBJECTS=tests/argon2_test.o tests/base16_test.o tests/base32_test.o tests/base64_test.o \
|
||||
tests/bcrypt_test.o tests/cipher_hash_test.o tests/common.o tests/deprecated_test.o tests/der_test.o \
|
||||
tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/file_test.o tests/mac_test.o \
|
||||
tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o \
|
||||
tests/no_null_termination_check_test.o tests/no_prng.o tests/padding_test.o tests/pem_test.o \
|
||||
tests/pk_oid_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
|
||||
|
|
|
|||
|
|
@ -85,22 +85,23 @@ src/mac/xcbc/xcbc_file.obj src/mac/xcbc/xcbc_init.obj src/mac/xcbc/xcbc_memory.o
|
|||
src/mac/xcbc/xcbc_memory_multi.obj src/mac/xcbc/xcbc_process.obj src/mac/xcbc/xcbc_test.obj \
|
||||
src/math/fp/ltc_ecc_fp_mulmod.obj src/math/gmp_desc.obj src/math/ltm_desc.obj src/math/multi.obj \
|
||||
src/math/radix_to_bin.obj src/math/rand_bn.obj src/math/rand_prime.obj src/math/tfm_desc.obj src/misc/adler32.obj \
|
||||
src/misc/base16/base16_decode.obj src/misc/base16/base16_encode.obj src/misc/base32/base32_decode.obj \
|
||||
src/misc/base32/base32_encode.obj src/misc/base64/base64_decode.obj src/misc/base64/base64_encode.obj \
|
||||
src/misc/bcrypt/bcrypt.obj src/misc/burn_stack.obj src/misc/compare_testvector.obj src/misc/copy_or_zeromem.obj \
|
||||
src/misc/crc32.obj src/misc/crypt/crypt.obj src/misc/crypt/crypt_argchk.obj \
|
||||
src/misc/crypt/crypt_cipher_descriptor.obj src/misc/crypt/crypt_cipher_is_valid.obj \
|
||||
src/misc/crypt/crypt_constants.obj src/misc/crypt/crypt_find_cipher.obj \
|
||||
src/misc/crypt/crypt_find_cipher_any.obj src/misc/crypt/crypt_find_cipher_id.obj \
|
||||
src/misc/crypt/crypt_find_hash.obj src/misc/crypt/crypt_find_hash_any.obj \
|
||||
src/misc/crypt/crypt_find_hash_id.obj src/misc/crypt/crypt_find_hash_oid.obj \
|
||||
src/misc/crypt/crypt_find_prng.obj src/misc/crypt/crypt_fsa.obj src/misc/crypt/crypt_hash_descriptor.obj \
|
||||
src/misc/crypt/crypt_hash_is_valid.obj src/misc/crypt/crypt_inits.obj \
|
||||
src/misc/crypt/crypt_ltc_mp_descriptor.obj src/misc/crypt/crypt_prng_descriptor.obj \
|
||||
src/misc/crypt/crypt_prng_is_valid.obj src/misc/crypt/crypt_prng_rng_descriptor.obj \
|
||||
src/misc/crypt/crypt_register_all_ciphers.obj src/misc/crypt/crypt_register_all_hashes.obj \
|
||||
src/misc/crypt/crypt_register_all_prngs.obj src/misc/crypt/crypt_register_cipher.obj \
|
||||
src/misc/crypt/crypt_register_hash.obj src/misc/crypt/crypt_register_prng.obj src/misc/crypt/crypt_sizes.obj \
|
||||
src/misc/argon2/argon2.obj src/misc/base16/base16_decode.obj src/misc/base16/base16_encode.obj \
|
||||
src/misc/base32/base32_decode.obj src/misc/base32/base32_encode.obj src/misc/base64/base64_decode.obj \
|
||||
src/misc/base64/base64_encode.obj src/misc/bcrypt/bcrypt.obj src/misc/burn_stack.obj \
|
||||
src/misc/compare_testvector.obj src/misc/copy_or_zeromem.obj src/misc/crc32.obj src/misc/crypt/crypt.obj \
|
||||
src/misc/crypt/crypt_argchk.obj src/misc/crypt/crypt_cipher_descriptor.obj \
|
||||
src/misc/crypt/crypt_cipher_is_valid.obj src/misc/crypt/crypt_constants.obj \
|
||||
src/misc/crypt/crypt_find_cipher.obj src/misc/crypt/crypt_find_cipher_any.obj \
|
||||
src/misc/crypt/crypt_find_cipher_id.obj src/misc/crypt/crypt_find_hash.obj \
|
||||
src/misc/crypt/crypt_find_hash_any.obj src/misc/crypt/crypt_find_hash_id.obj \
|
||||
src/misc/crypt/crypt_find_hash_oid.obj src/misc/crypt/crypt_find_prng.obj src/misc/crypt/crypt_fsa.obj \
|
||||
src/misc/crypt/crypt_hash_descriptor.obj src/misc/crypt/crypt_hash_is_valid.obj \
|
||||
src/misc/crypt/crypt_inits.obj src/misc/crypt/crypt_ltc_mp_descriptor.obj \
|
||||
src/misc/crypt/crypt_prng_descriptor.obj src/misc/crypt/crypt_prng_is_valid.obj \
|
||||
src/misc/crypt/crypt_prng_rng_descriptor.obj src/misc/crypt/crypt_register_all_ciphers.obj \
|
||||
src/misc/crypt/crypt_register_all_hashes.obj src/misc/crypt/crypt_register_all_prngs.obj \
|
||||
src/misc/crypt/crypt_register_cipher.obj src/misc/crypt/crypt_register_hash.obj \
|
||||
src/misc/crypt/crypt_register_prng.obj src/misc/crypt/crypt_sizes.obj \
|
||||
src/misc/crypt/crypt_unregister_cipher.obj src/misc/crypt/crypt_unregister_hash.obj \
|
||||
src/misc/crypt/crypt_unregister_prng.obj src/misc/deprecated.obj src/misc/error_to_string.obj \
|
||||
src/misc/hkdf/hkdf.obj src/misc/hkdf/hkdf_test.obj src/misc/mem_neq.obj src/misc/padding/padding_depad.obj \
|
||||
|
|
@ -227,9 +228,9 @@ src/stream/sober128/sober128_test.obj src/stream/sosemanuk/sosemanuk.obj \
|
|||
src/stream/sosemanuk/sosemanuk_memory.obj src/stream/sosemanuk/sosemanuk_test.obj
|
||||
|
||||
#List of test objects to compile
|
||||
TOBJECTS=tests/base16_test.obj tests/base32_test.obj tests/base64_test.obj tests/bcrypt_test.obj \
|
||||
tests/cipher_hash_test.obj tests/common.obj tests/deprecated_test.obj tests/der_test.obj tests/dh_test.obj \
|
||||
tests/dsa_test.obj tests/ecc_test.obj tests/ed25519_test.obj tests/file_test.obj tests/mac_test.obj \
|
||||
TOBJECTS=tests/argon2_test.obj tests/base16_test.obj tests/base32_test.obj tests/base64_test.obj \
|
||||
tests/bcrypt_test.obj tests/cipher_hash_test.obj tests/common.obj tests/deprecated_test.obj tests/der_test.obj \
|
||||
tests/dh_test.obj tests/dsa_test.obj tests/ecc_test.obj tests/ed25519_test.obj tests/file_test.obj tests/mac_test.obj \
|
||||
tests/misc_test.obj tests/modes_test.obj tests/mpi_test.obj tests/multi_test.obj \
|
||||
tests/no_null_termination_check_test.obj tests/no_prng.obj tests/padding_test.obj tests/pem_test.obj \
|
||||
tests/pk_oid_test.obj tests/pkcs_1_eme_test.obj tests/pkcs_1_emsa_test.obj tests/pkcs_1_oaep_test.obj \
|
||||
|
|
|
|||
|
|
@ -106,22 +106,23 @@ src/mac/xcbc/xcbc_file.o src/mac/xcbc/xcbc_init.o src/mac/xcbc/xcbc_memory.o \
|
|||
src/mac/xcbc/xcbc_memory_multi.o src/mac/xcbc/xcbc_process.o src/mac/xcbc/xcbc_test.o \
|
||||
src/math/fp/ltc_ecc_fp_mulmod.o src/math/gmp_desc.o src/math/ltm_desc.o src/math/multi.o \
|
||||
src/math/radix_to_bin.o src/math/rand_bn.o src/math/rand_prime.o src/math/tfm_desc.o src/misc/adler32.o \
|
||||
src/misc/base16/base16_decode.o src/misc/base16/base16_encode.o src/misc/base32/base32_decode.o \
|
||||
src/misc/base32/base32_encode.o src/misc/base64/base64_decode.o src/misc/base64/base64_encode.o \
|
||||
src/misc/bcrypt/bcrypt.o src/misc/burn_stack.o src/misc/compare_testvector.o src/misc/copy_or_zeromem.o \
|
||||
src/misc/crc32.o src/misc/crypt/crypt.o src/misc/crypt/crypt_argchk.o \
|
||||
src/misc/crypt/crypt_cipher_descriptor.o src/misc/crypt/crypt_cipher_is_valid.o \
|
||||
src/misc/crypt/crypt_constants.o src/misc/crypt/crypt_find_cipher.o \
|
||||
src/misc/crypt/crypt_find_cipher_any.o src/misc/crypt/crypt_find_cipher_id.o \
|
||||
src/misc/crypt/crypt_find_hash.o src/misc/crypt/crypt_find_hash_any.o \
|
||||
src/misc/crypt/crypt_find_hash_id.o src/misc/crypt/crypt_find_hash_oid.o \
|
||||
src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o src/misc/crypt/crypt_hash_descriptor.o \
|
||||
src/misc/crypt/crypt_hash_is_valid.o src/misc/crypt/crypt_inits.o \
|
||||
src/misc/crypt/crypt_ltc_mp_descriptor.o src/misc/crypt/crypt_prng_descriptor.o \
|
||||
src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_prng_rng_descriptor.o \
|
||||
src/misc/crypt/crypt_register_all_ciphers.o src/misc/crypt/crypt_register_all_hashes.o \
|
||||
src/misc/crypt/crypt_register_all_prngs.o src/misc/crypt/crypt_register_cipher.o \
|
||||
src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
|
||||
src/misc/argon2/argon2.o src/misc/base16/base16_decode.o src/misc/base16/base16_encode.o \
|
||||
src/misc/base32/base32_decode.o src/misc/base32/base32_encode.o src/misc/base64/base64_decode.o \
|
||||
src/misc/base64/base64_encode.o src/misc/bcrypt/bcrypt.o src/misc/burn_stack.o \
|
||||
src/misc/compare_testvector.o src/misc/copy_or_zeromem.o src/misc/crc32.o src/misc/crypt/crypt.o \
|
||||
src/misc/crypt/crypt_argchk.o src/misc/crypt/crypt_cipher_descriptor.o \
|
||||
src/misc/crypt/crypt_cipher_is_valid.o src/misc/crypt/crypt_constants.o \
|
||||
src/misc/crypt/crypt_find_cipher.o src/misc/crypt/crypt_find_cipher_any.o \
|
||||
src/misc/crypt/crypt_find_cipher_id.o src/misc/crypt/crypt_find_hash.o \
|
||||
src/misc/crypt/crypt_find_hash_any.o src/misc/crypt/crypt_find_hash_id.o \
|
||||
src/misc/crypt/crypt_find_hash_oid.o src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o \
|
||||
src/misc/crypt/crypt_hash_descriptor.o src/misc/crypt/crypt_hash_is_valid.o \
|
||||
src/misc/crypt/crypt_inits.o src/misc/crypt/crypt_ltc_mp_descriptor.o \
|
||||
src/misc/crypt/crypt_prng_descriptor.o src/misc/crypt/crypt_prng_is_valid.o \
|
||||
src/misc/crypt/crypt_prng_rng_descriptor.o src/misc/crypt/crypt_register_all_ciphers.o \
|
||||
src/misc/crypt/crypt_register_all_hashes.o src/misc/crypt/crypt_register_all_prngs.o \
|
||||
src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \
|
||||
src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
|
||||
src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \
|
||||
src/misc/crypt/crypt_unregister_prng.o src/misc/deprecated.o src/misc/error_to_string.o \
|
||||
src/misc/hkdf/hkdf.o src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
|
||||
|
|
@ -248,9 +249,9 @@ src/stream/sober128/sober128_test.o src/stream/sosemanuk/sosemanuk.o \
|
|||
src/stream/sosemanuk/sosemanuk_memory.o src/stream/sosemanuk/sosemanuk_test.o
|
||||
|
||||
#List of test objects to compile (all goes to libtomcrypt_prof.a)
|
||||
TOBJECTS=tests/base16_test.o tests/base32_test.o tests/base64_test.o tests/bcrypt_test.o \
|
||||
tests/cipher_hash_test.o tests/common.o tests/deprecated_test.o tests/der_test.o tests/dh_test.o \
|
||||
tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/file_test.o tests/mac_test.o \
|
||||
TOBJECTS=tests/argon2_test.o tests/base16_test.o tests/base32_test.o tests/base64_test.o \
|
||||
tests/bcrypt_test.o tests/cipher_hash_test.o tests/common.o tests/deprecated_test.o tests/der_test.o \
|
||||
tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/file_test.o tests/mac_test.o \
|
||||
tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o \
|
||||
tests/no_null_termination_check_test.o tests/no_prng.o tests/padding_test.o tests/pem_test.o \
|
||||
tests/pk_oid_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
|
||||
|
|
|
|||
|
|
@ -277,22 +277,23 @@ src/mac/xcbc/xcbc_file.o src/mac/xcbc/xcbc_init.o src/mac/xcbc/xcbc_memory.o \
|
|||
src/mac/xcbc/xcbc_memory_multi.o src/mac/xcbc/xcbc_process.o src/mac/xcbc/xcbc_test.o \
|
||||
src/math/fp/ltc_ecc_fp_mulmod.o src/math/gmp_desc.o src/math/ltm_desc.o src/math/multi.o \
|
||||
src/math/radix_to_bin.o src/math/rand_bn.o src/math/rand_prime.o src/math/tfm_desc.o src/misc/adler32.o \
|
||||
src/misc/base16/base16_decode.o src/misc/base16/base16_encode.o src/misc/base32/base32_decode.o \
|
||||
src/misc/base32/base32_encode.o src/misc/base64/base64_decode.o src/misc/base64/base64_encode.o \
|
||||
src/misc/bcrypt/bcrypt.o src/misc/burn_stack.o src/misc/compare_testvector.o src/misc/copy_or_zeromem.o \
|
||||
src/misc/crc32.o src/misc/crypt/crypt.o src/misc/crypt/crypt_argchk.o \
|
||||
src/misc/crypt/crypt_cipher_descriptor.o src/misc/crypt/crypt_cipher_is_valid.o \
|
||||
src/misc/crypt/crypt_constants.o src/misc/crypt/crypt_find_cipher.o \
|
||||
src/misc/crypt/crypt_find_cipher_any.o src/misc/crypt/crypt_find_cipher_id.o \
|
||||
src/misc/crypt/crypt_find_hash.o src/misc/crypt/crypt_find_hash_any.o \
|
||||
src/misc/crypt/crypt_find_hash_id.o src/misc/crypt/crypt_find_hash_oid.o \
|
||||
src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o src/misc/crypt/crypt_hash_descriptor.o \
|
||||
src/misc/crypt/crypt_hash_is_valid.o src/misc/crypt/crypt_inits.o \
|
||||
src/misc/crypt/crypt_ltc_mp_descriptor.o src/misc/crypt/crypt_prng_descriptor.o \
|
||||
src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_prng_rng_descriptor.o \
|
||||
src/misc/crypt/crypt_register_all_ciphers.o src/misc/crypt/crypt_register_all_hashes.o \
|
||||
src/misc/crypt/crypt_register_all_prngs.o src/misc/crypt/crypt_register_cipher.o \
|
||||
src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
|
||||
src/misc/argon2/argon2.o src/misc/base16/base16_decode.o src/misc/base16/base16_encode.o \
|
||||
src/misc/base32/base32_decode.o src/misc/base32/base32_encode.o src/misc/base64/base64_decode.o \
|
||||
src/misc/base64/base64_encode.o src/misc/bcrypt/bcrypt.o src/misc/burn_stack.o \
|
||||
src/misc/compare_testvector.o src/misc/copy_or_zeromem.o src/misc/crc32.o src/misc/crypt/crypt.o \
|
||||
src/misc/crypt/crypt_argchk.o src/misc/crypt/crypt_cipher_descriptor.o \
|
||||
src/misc/crypt/crypt_cipher_is_valid.o src/misc/crypt/crypt_constants.o \
|
||||
src/misc/crypt/crypt_find_cipher.o src/misc/crypt/crypt_find_cipher_any.o \
|
||||
src/misc/crypt/crypt_find_cipher_id.o src/misc/crypt/crypt_find_hash.o \
|
||||
src/misc/crypt/crypt_find_hash_any.o src/misc/crypt/crypt_find_hash_id.o \
|
||||
src/misc/crypt/crypt_find_hash_oid.o src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o \
|
||||
src/misc/crypt/crypt_hash_descriptor.o src/misc/crypt/crypt_hash_is_valid.o \
|
||||
src/misc/crypt/crypt_inits.o src/misc/crypt/crypt_ltc_mp_descriptor.o \
|
||||
src/misc/crypt/crypt_prng_descriptor.o src/misc/crypt/crypt_prng_is_valid.o \
|
||||
src/misc/crypt/crypt_prng_rng_descriptor.o src/misc/crypt/crypt_register_all_ciphers.o \
|
||||
src/misc/crypt/crypt_register_all_hashes.o src/misc/crypt/crypt_register_all_prngs.o \
|
||||
src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \
|
||||
src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
|
||||
src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \
|
||||
src/misc/crypt/crypt_unregister_prng.o src/misc/deprecated.o src/misc/error_to_string.o \
|
||||
src/misc/hkdf/hkdf.o src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
|
||||
|
|
@ -424,9 +425,9 @@ LTC_CFLAGS := $(LTC_CFLAGS) -Wno-shadow -Isrc/ciphers/aes -Isrc/ciphers/safer -I
|
|||
endif
|
||||
|
||||
# List of test objects to compile (all goes to libtomcrypt_prof.a)
|
||||
TOBJECTS=tests/base16_test.o tests/base32_test.o tests/base64_test.o tests/bcrypt_test.o \
|
||||
tests/cipher_hash_test.o tests/common.o tests/deprecated_test.o tests/der_test.o tests/dh_test.o \
|
||||
tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/file_test.o tests/mac_test.o \
|
||||
TOBJECTS=tests/argon2_test.o tests/base16_test.o tests/base32_test.o tests/base64_test.o \
|
||||
tests/bcrypt_test.o tests/cipher_hash_test.o tests/common.o tests/deprecated_test.o tests/der_test.o \
|
||||
tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/file_test.o tests/mac_test.o \
|
||||
tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o \
|
||||
tests/no_null_termination_check_test.o tests/no_prng.o tests/padding_test.o tests/pem_test.o \
|
||||
tests/pk_oid_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ src/math/rand_bn.c
|
|||
src/math/rand_prime.c
|
||||
src/math/tfm_desc.c
|
||||
src/misc/adler32.c
|
||||
src/misc/argon2/argon2.c
|
||||
src/misc/base16/base16_decode.c
|
||||
src/misc/base16/base16_encode.c
|
||||
src/misc/base32/base32_decode.c
|
||||
|
|
|
|||
|
|
@ -514,6 +514,8 @@
|
|||
#define LTC_BCRYPT_DEFAULT_ROUNDS 10
|
||||
#endif
|
||||
|
||||
#define LTC_ARGON2
|
||||
|
||||
/* Keep LTC_NO_HKDF for compatibility reasons
|
||||
* superseeded by LTC_NO_MISC*/
|
||||
#ifndef LTC_NO_HKDF
|
||||
|
|
@ -681,6 +683,10 @@
|
|||
#error LTC_BCRYPT requires LTC_BLOWFISH
|
||||
#endif
|
||||
|
||||
#if defined(LTC_ARGON2) && !defined(LTC_BLAKE2B)
|
||||
#error LTC_ARGON2 requires LTC_BLAKE2B
|
||||
#endif
|
||||
|
||||
#if defined(LTC_CHACHA20POLY1305_MODE) && (!defined(LTC_CHACHA) || !defined(LTC_POLY1305))
|
||||
#error LTC_CHACHA20POLY1305_MODE requires LTC_CHACHA + LTC_POLY1305
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -53,6 +53,23 @@ int base16_decode(const char *in, unsigned long inlen,
|
|||
unsigned char *out, unsigned long *outlen);
|
||||
#endif
|
||||
|
||||
/* ---- Argon2 password hashing function (RFC 9106) ---- */
|
||||
#ifdef LTC_ARGON2
|
||||
typedef enum {
|
||||
ARGON2_D = 0,
|
||||
ARGON2_I = 1,
|
||||
ARGON2_ID = 2
|
||||
} argon2_type;
|
||||
int argon2_hash(const unsigned char *pwd, unsigned long pwdlen,
|
||||
const unsigned char *salt, unsigned long saltlen,
|
||||
const unsigned char *secret, unsigned long secretlen,
|
||||
const unsigned char *ad, unsigned long adlen,
|
||||
unsigned int t_cost, unsigned int m_cost,
|
||||
unsigned int parallelism,
|
||||
argon2_type type,
|
||||
unsigned char *out, unsigned long outlen);
|
||||
#endif /* LTC_ARGON2 */
|
||||
|
||||
#ifdef LTC_BCRYPT
|
||||
int bcrypt_pbkdf_openbsd(const void *secret, unsigned long secret_len,
|
||||
const unsigned char *salt, unsigned long salt_len,
|
||||
|
|
|
|||
568
src/misc/argon2/argon2.c
Normal file
568
src/misc/argon2/argon2.c
Normal file
|
|
@ -0,0 +1,568 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file argon2.c
|
||||
Argon2 password hashing function (RFC 9106)
|
||||
*/
|
||||
#ifdef LTC_ARGON2
|
||||
|
||||
#define ARGON2_BLOCK_SIZE 1024
|
||||
#define ARGON2_QWORDS_IN_BLOCK 128
|
||||
#define ARGON2_ADDRESSES_IN_BLOCK 128
|
||||
#define ARGON2_PREHASH_DIGEST_LEN 64
|
||||
#define ARGON2_PREHASH_SEED_LEN 72
|
||||
#define ARGON2_SYNC_POINTS 4
|
||||
#define ARGON2_VERSION 0x13
|
||||
#define ARGON2_MIN_OUTLEN 4
|
||||
#define ARGON2_BLAKE2B_OUTBYTES 64
|
||||
|
||||
/* 1024-byte memory block */
|
||||
typedef struct argon2_block_ {
|
||||
ulong64 v[ARGON2_QWORDS_IN_BLOCK];
|
||||
} argon2_block;
|
||||
|
||||
/* instance state */
|
||||
typedef struct {
|
||||
argon2_block *memory;
|
||||
ulong32 passes;
|
||||
ulong32 memory_blocks;
|
||||
ulong32 segment_length;
|
||||
ulong32 lane_length;
|
||||
ulong32 lanes;
|
||||
int type; /* 0=d 1=i 2=id */
|
||||
} argon2_instance;
|
||||
|
||||
/* position within the memory matrix */
|
||||
typedef struct {
|
||||
ulong32 pass;
|
||||
ulong32 lane;
|
||||
unsigned char slice;
|
||||
ulong32 index;
|
||||
} argon2_position;
|
||||
|
||||
static void s_block_init(argon2_block *b, unsigned char v)
|
||||
{
|
||||
XMEMSET(b->v, v, sizeof(b->v));
|
||||
}
|
||||
|
||||
static void s_block_copy(argon2_block *dst, const argon2_block *src)
|
||||
{
|
||||
XMEMCPY(dst->v, src->v, sizeof(dst->v));
|
||||
}
|
||||
|
||||
static void s_block_xor(argon2_block *dst, const argon2_block *src)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
|
||||
dst->v[i] ^= src->v[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void s_block_load(argon2_block *dst, const unsigned char *input)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
|
||||
LOAD64L(dst->v[i], input + i * 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_block_store(unsigned char *output, const argon2_block *src)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
|
||||
STORE64L(src->v[i], output + i * 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Variable-length hash H' (RFC 9106 Section 3.2) */
|
||||
static int s_blake2b_hash(unsigned char *out, unsigned long outlen, const unsigned char *in, unsigned long inlen)
|
||||
{
|
||||
hash_state md;
|
||||
int err;
|
||||
|
||||
if ((err = blake2b_init(&md, outlen, NULL, 0)) != CRYPT_OK) return err;
|
||||
if ((err = blake2b_process(&md, in, inlen)) != CRYPT_OK) return err;
|
||||
if ((err = blake2b_done(&md, out)) != CRYPT_OK) return err;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int s_blake2b_long(unsigned char *out, unsigned long outlen, const unsigned char *in, unsigned long inlen)
|
||||
{
|
||||
unsigned char outlen_le[4];
|
||||
int err;
|
||||
|
||||
STORE32L((ulong32)outlen, outlen_le);
|
||||
|
||||
if (outlen <= ARGON2_BLAKE2B_OUTBYTES) {
|
||||
/* single hash with truncated output */
|
||||
hash_state md;
|
||||
if ((err = blake2b_init(&md, outlen, NULL, 0)) != CRYPT_OK) return err;
|
||||
if ((err = blake2b_process(&md, outlen_le, 4)) != CRYPT_OK) return err;
|
||||
if ((err = blake2b_process(&md, in, inlen)) != CRYPT_OK) return err;
|
||||
if ((err = blake2b_done(&md, out)) != CRYPT_OK) return err;
|
||||
}
|
||||
else {
|
||||
/* chained hashing for longer outputs */
|
||||
ulong32 toproduce;
|
||||
unsigned char out_buffer[ARGON2_BLAKE2B_OUTBYTES];
|
||||
unsigned char in_buffer[ARGON2_BLAKE2B_OUTBYTES];
|
||||
hash_state md;
|
||||
|
||||
if ((err = blake2b_init(&md, ARGON2_BLAKE2B_OUTBYTES, NULL, 0)) != CRYPT_OK) return err;
|
||||
if ((err = blake2b_process(&md, outlen_le, 4)) != CRYPT_OK) return err;
|
||||
if ((err = blake2b_process(&md, in, inlen)) != CRYPT_OK) return err;
|
||||
if ((err = blake2b_done(&md, out_buffer)) != CRYPT_OK) return err;
|
||||
|
||||
XMEMCPY(out, out_buffer, ARGON2_BLAKE2B_OUTBYTES / 2);
|
||||
out += ARGON2_BLAKE2B_OUTBYTES / 2;
|
||||
toproduce = (ulong32)outlen - ARGON2_BLAKE2B_OUTBYTES / 2;
|
||||
|
||||
while (toproduce > ARGON2_BLAKE2B_OUTBYTES) {
|
||||
XMEMCPY(in_buffer, out_buffer, ARGON2_BLAKE2B_OUTBYTES);
|
||||
if ((err = s_blake2b_hash(out_buffer, ARGON2_BLAKE2B_OUTBYTES, in_buffer, ARGON2_BLAKE2B_OUTBYTES)) != CRYPT_OK) return err;
|
||||
XMEMCPY(out, out_buffer, ARGON2_BLAKE2B_OUTBYTES / 2);
|
||||
out += ARGON2_BLAKE2B_OUTBYTES / 2;
|
||||
toproduce -= ARGON2_BLAKE2B_OUTBYTES / 2;
|
||||
}
|
||||
|
||||
XMEMCPY(in_buffer, out_buffer, ARGON2_BLAKE2B_OUTBYTES);
|
||||
if ((err = s_blake2b_hash(out_buffer, toproduce, in_buffer, ARGON2_BLAKE2B_OUTBYTES)) != CRYPT_OK) return err;
|
||||
XMEMCPY(out, out_buffer, toproduce);
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* BlaMka compression G (RFC 9106 Section 3.4 / 3.5) */
|
||||
static LTC_INLINE ulong64 s_fBlaMka(ulong64 x, ulong64 y)
|
||||
{
|
||||
ulong64 m = CONST64(0xFFFFFFFF);
|
||||
ulong64 xy = (x & m) * (y & m);
|
||||
return x + y + 2 * xy;
|
||||
}
|
||||
|
||||
#define ARGON2_GB(a, b, c, d) \
|
||||
do { \
|
||||
a = s_fBlaMka(a, b); \
|
||||
d = ROR64(d ^ a, 32); \
|
||||
c = s_fBlaMka(c, d); \
|
||||
b = ROR64(b ^ c, 24); \
|
||||
a = s_fBlaMka(a, b); \
|
||||
d = ROR64(d ^ a, 16); \
|
||||
c = s_fBlaMka(c, d); \
|
||||
b = ROR64(b ^ c, 63); \
|
||||
} while (0)
|
||||
|
||||
#define ARGON2_ROUND(v0,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15) \
|
||||
do { \
|
||||
ARGON2_GB(v0, v4, v8, v12); \
|
||||
ARGON2_GB(v1, v5, v9, v13); \
|
||||
ARGON2_GB(v2, v6, v10, v14); \
|
||||
ARGON2_GB(v3, v7, v11, v15); \
|
||||
ARGON2_GB(v0, v5, v10, v15); \
|
||||
ARGON2_GB(v1, v6, v11, v12); \
|
||||
ARGON2_GB(v2, v7, v8, v13); \
|
||||
ARGON2_GB(v3, v4, v9, v14); \
|
||||
} while (0)
|
||||
|
||||
/* Fill a new block from prev_block and ref_block. If with_xor, XOR result with existing next_block content. */
|
||||
static void s_fill_block(const argon2_block *prev_block, const argon2_block *ref_block, argon2_block *next_block, int with_xor)
|
||||
{
|
||||
argon2_block blockR, block_tmp;
|
||||
unsigned i;
|
||||
|
||||
s_block_copy(&blockR, ref_block);
|
||||
s_block_xor(&blockR, prev_block);
|
||||
s_block_copy(&block_tmp, &blockR);
|
||||
|
||||
if (with_xor) {
|
||||
s_block_xor(&block_tmp, next_block);
|
||||
}
|
||||
|
||||
/* Apply P on columns: (0..15), (16..31), ..., (112..127) */
|
||||
for (i = 0; i < 8; ++i) {
|
||||
ARGON2_ROUND(
|
||||
blockR.v[16*i], blockR.v[16*i+1], blockR.v[16*i+2], blockR.v[16*i+3],
|
||||
blockR.v[16*i+4], blockR.v[16*i+5], blockR.v[16*i+6], blockR.v[16*i+7],
|
||||
blockR.v[16*i+8], blockR.v[16*i+9], blockR.v[16*i+10], blockR.v[16*i+11],
|
||||
blockR.v[16*i+12], blockR.v[16*i+13], blockR.v[16*i+14], blockR.v[16*i+15]);
|
||||
}
|
||||
|
||||
/* Apply P on rows: (0,1,16,17,32,33,...,112,113), etc. */
|
||||
for (i = 0; i < 8; ++i) {
|
||||
ARGON2_ROUND(
|
||||
blockR.v[2*i], blockR.v[2*i+1], blockR.v[2*i+16], blockR.v[2*i+17],
|
||||
blockR.v[2*i+32], blockR.v[2*i+33], blockR.v[2*i+48], blockR.v[2*i+49],
|
||||
blockR.v[2*i+64], blockR.v[2*i+65], blockR.v[2*i+80], blockR.v[2*i+81],
|
||||
blockR.v[2*i+96], blockR.v[2*i+97], blockR.v[2*i+112],blockR.v[2*i+113]);
|
||||
}
|
||||
|
||||
s_block_copy(next_block, &block_tmp);
|
||||
s_block_xor(next_block, &blockR);
|
||||
}
|
||||
|
||||
/* Generate next pseudo-random addresses for data-independent indexing */
|
||||
static void s_next_addresses(argon2_block *address_block, argon2_block *input_block, const argon2_block *zero_block)
|
||||
{
|
||||
input_block->v[6]++;
|
||||
s_fill_block(zero_block, input_block, address_block, 0);
|
||||
s_fill_block(zero_block, address_block, address_block, 0);
|
||||
}
|
||||
|
||||
/* Index computation (RFC 9106 Section 3.3) */
|
||||
static ulong32 s_index_alpha(const argon2_instance *instance, const argon2_position *position, ulong32 pseudo_rand, int same_lane)
|
||||
{
|
||||
ulong32 reference_area_size;
|
||||
ulong64 relative_position;
|
||||
ulong32 start_position, absolute_position;
|
||||
|
||||
if (position->pass == 0) {
|
||||
if (position->slice == 0) {
|
||||
reference_area_size = position->index - 1;
|
||||
}
|
||||
else {
|
||||
if (same_lane) {
|
||||
reference_area_size = position->slice * instance->segment_length + position->index - 1;
|
||||
}
|
||||
else {
|
||||
reference_area_size = position->slice * instance->segment_length + ((position->index == 0) ? ((ulong32)-1) : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (same_lane) {
|
||||
reference_area_size = instance->lane_length - instance->segment_length + position->index - 1;
|
||||
}
|
||||
else {
|
||||
reference_area_size = instance->lane_length - instance->segment_length + ((position->index == 0) ? ((ulong32)-1) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Map pseudo_rand to 0..reference_area_size-1 */
|
||||
relative_position = (ulong64)pseudo_rand;
|
||||
relative_position = relative_position * relative_position >> 32;
|
||||
relative_position = reference_area_size - 1 - ((ulong64)reference_area_size * relative_position >> 32);
|
||||
|
||||
start_position = 0;
|
||||
if (position->pass != 0) {
|
||||
start_position = (position->slice == ARGON2_SYNC_POINTS - 1) ? 0 : (position->slice + 1) * instance->segment_length;
|
||||
}
|
||||
absolute_position = (start_position + (ulong32)relative_position) % instance->lane_length;
|
||||
return absolute_position;
|
||||
}
|
||||
|
||||
/* Fill one segment (lane x slice intersection) */
|
||||
static void s_fill_segment(const argon2_instance *instance, argon2_position position)
|
||||
{
|
||||
argon2_block *ref_block, *curr_block;
|
||||
argon2_block address_block, input_block, zero_block;
|
||||
ulong64 pseudo_rand;
|
||||
ulong32 ref_index, prev_offset, curr_offset;
|
||||
ulong32 starting_index, i;
|
||||
ulong64 ref_lane;
|
||||
int data_independent;
|
||||
|
||||
data_independent = (instance->type == ARGON2_I) || (instance->type == ARGON2_ID && position.pass == 0 && position.slice < ARGON2_SYNC_POINTS / 2);
|
||||
|
||||
if (data_independent) {
|
||||
s_block_init(&zero_block, 0);
|
||||
s_block_init(&input_block, 0);
|
||||
input_block.v[0] = position.pass;
|
||||
input_block.v[1] = position.lane;
|
||||
input_block.v[2] = position.slice;
|
||||
input_block.v[3] = instance->memory_blocks;
|
||||
input_block.v[4] = instance->passes;
|
||||
input_block.v[5] = instance->type;
|
||||
}
|
||||
|
||||
starting_index = 0;
|
||||
if (position.pass == 0 && position.slice == 0) {
|
||||
starting_index = 2;
|
||||
if (data_independent) {
|
||||
s_next_addresses(&address_block, &input_block, &zero_block);
|
||||
}
|
||||
}
|
||||
|
||||
curr_offset = position.lane * instance->lane_length + position.slice * instance->segment_length + starting_index;
|
||||
|
||||
if (curr_offset % instance->lane_length == 0) {
|
||||
prev_offset = curr_offset + instance->lane_length - 1;
|
||||
}
|
||||
else {
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
for (i = starting_index; i < instance->segment_length; ++i, ++curr_offset, ++prev_offset) {
|
||||
if (curr_offset % instance->lane_length == 1) {
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
/* Get pseudo-random value */
|
||||
if (data_independent) {
|
||||
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
|
||||
s_next_addresses(&address_block, &input_block, &zero_block);
|
||||
}
|
||||
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
|
||||
}
|
||||
else {
|
||||
pseudo_rand = instance->memory[prev_offset].v[0];
|
||||
}
|
||||
|
||||
ref_lane = (pseudo_rand >> 32) % instance->lanes;
|
||||
if (position.pass == 0 && position.slice == 0) {
|
||||
ref_lane = position.lane;
|
||||
}
|
||||
|
||||
position.index = i;
|
||||
ref_index = s_index_alpha(instance, &position, (ulong32)(pseudo_rand & CONST64(0xFFFFFFFF)), ref_lane == position.lane);
|
||||
ref_block = instance->memory + instance->lane_length * (ulong32)ref_lane + ref_index;
|
||||
curr_block = instance->memory + curr_offset;
|
||||
|
||||
if (position.pass == 0) {
|
||||
s_fill_block(instance->memory + prev_offset, ref_block, curr_block, 0);
|
||||
}
|
||||
else {
|
||||
s_fill_block(instance->memory + prev_offset, ref_block, curr_block, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Initial hash H_0 (RFC 9106 Section 3.1 step 1) */
|
||||
static int s_initial_hash(unsigned char *blockhash,
|
||||
const unsigned char *pwd, unsigned long pwdlen,
|
||||
const unsigned char *salt, unsigned long saltlen,
|
||||
const unsigned char *secret, unsigned long secretlen,
|
||||
const unsigned char *ad, unsigned long adlen,
|
||||
ulong32 t_cost, ulong32 m_cost, ulong32 parallelism,
|
||||
ulong32 outlen, int type)
|
||||
{
|
||||
hash_state md;
|
||||
unsigned char value[4];
|
||||
int err;
|
||||
|
||||
if ((err = blake2b_init(&md, ARGON2_PREHASH_DIGEST_LEN, NULL, 0)) != CRYPT_OK) return err;
|
||||
|
||||
STORE32L(parallelism, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
|
||||
STORE32L(outlen, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
|
||||
STORE32L(m_cost, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
|
||||
STORE32L(t_cost, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
|
||||
STORE32L((ulong32)ARGON2_VERSION, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
|
||||
STORE32L((ulong32)type, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
|
||||
STORE32L((ulong32)pwdlen, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
if (pwdlen > 0) {
|
||||
if ((err = blake2b_process(&md, pwd, pwdlen)) != CRYPT_OK) return err;
|
||||
}
|
||||
|
||||
STORE32L((ulong32)saltlen, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
if (saltlen > 0) {
|
||||
if ((err = blake2b_process(&md, salt, saltlen)) != CRYPT_OK) return err;
|
||||
}
|
||||
|
||||
STORE32L((ulong32)secretlen, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
if (secretlen > 0 && secret != NULL) {
|
||||
if ((err = blake2b_process(&md, secret, secretlen)) != CRYPT_OK) return err;
|
||||
}
|
||||
|
||||
STORE32L((ulong32)adlen, value);
|
||||
if ((err = blake2b_process(&md, value, 4)) != CRYPT_OK) return err;
|
||||
if (adlen > 0 && ad != NULL) {
|
||||
if ((err = blake2b_process(&md, ad, adlen)) != CRYPT_OK) return err;
|
||||
}
|
||||
|
||||
if ((err = blake2b_done(&md, blockhash)) != CRYPT_OK) return err;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Generate first two blocks in each lane */
|
||||
|
||||
static int s_fill_first_blocks(unsigned char *blockhash, const argon2_instance *instance)
|
||||
{
|
||||
ulong32 l;
|
||||
unsigned char blockhash_bytes[ARGON2_BLOCK_SIZE];
|
||||
int err;
|
||||
|
||||
for (l = 0; l < instance->lanes; ++l) {
|
||||
/* B[i][0] = H'(H_0 || LE32(0) || LE32(i)) */
|
||||
STORE32L(0, blockhash + ARGON2_PREHASH_DIGEST_LEN);
|
||||
STORE32L(l, blockhash + ARGON2_PREHASH_DIGEST_LEN + 4);
|
||||
if ((err = s_blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, ARGON2_PREHASH_SEED_LEN)) != CRYPT_OK) return err;
|
||||
s_block_load(&instance->memory[l * instance->lane_length + 0], blockhash_bytes);
|
||||
|
||||
/* B[i][1] = H'(H_0 || LE32(1) || LE32(i)) */
|
||||
STORE32L(1, blockhash + ARGON2_PREHASH_DIGEST_LEN);
|
||||
if ((err = s_blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, ARGON2_PREHASH_SEED_LEN)) != CRYPT_OK) return err;
|
||||
s_block_load(&instance->memory[l * instance->lane_length + 1], blockhash_bytes);
|
||||
}
|
||||
|
||||
zeromem(blockhash_bytes, ARGON2_BLOCK_SIZE);
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Finalize: XOR last blocks, produce tag */
|
||||
static int s_finalize(unsigned char *out, unsigned long outlen,
|
||||
const argon2_instance *instance)
|
||||
{
|
||||
argon2_block blockhash;
|
||||
unsigned char blockhash_bytes[ARGON2_BLOCK_SIZE];
|
||||
ulong32 l;
|
||||
int err;
|
||||
|
||||
s_block_copy(&blockhash, instance->memory + instance->lane_length - 1);
|
||||
|
||||
for (l = 1; l < instance->lanes; ++l) {
|
||||
ulong32 last = l * instance->lane_length + (instance->lane_length - 1);
|
||||
s_block_xor(&blockhash, instance->memory + last);
|
||||
}
|
||||
|
||||
s_block_store(blockhash_bytes, &blockhash);
|
||||
err = s_blake2b_long(out, outlen, blockhash_bytes, ARGON2_BLOCK_SIZE);
|
||||
|
||||
zeromem(blockhash.v, ARGON2_BLOCK_SIZE);
|
||||
zeromem(blockhash_bytes, ARGON2_BLOCK_SIZE);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Fill the entire memory */
|
||||
static void s_fill_memory(argon2_instance *instance)
|
||||
{
|
||||
ulong32 r, s, l;
|
||||
|
||||
for (r = 0; r < instance->passes; ++r) {
|
||||
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
|
||||
for (l = 0; l < instance->lanes; ++l) {
|
||||
argon2_position position;
|
||||
position.pass = r;
|
||||
position.lane = l;
|
||||
position.slice = (unsigned char)s;
|
||||
position.index = 0;
|
||||
s_fill_segment(instance, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Hash a password with Argon2 (RFC 9106)
|
||||
|
||||
@param pwd Password (or message)
|
||||
@param pwdlen Length of password
|
||||
@param salt Salt
|
||||
@param saltlen Length of salt
|
||||
@param secret Optional secret value (may be NULL)
|
||||
@param secretlen Length of secret
|
||||
@param ad Optional associated data (may be NULL)
|
||||
@param adlen Length of associated data
|
||||
@param t_cost Number of passes (iterations), minimum 1
|
||||
@param m_cost Memory size in KiB, minimum 8*parallelism
|
||||
@param parallelism Degree of parallelism (number of lanes), minimum 1
|
||||
@param type ARGON2_D, ARGON2_I, or ARGON2_ID
|
||||
@param out [out] Output tag
|
||||
@param outlen Desired output length (4..2^32-1)
|
||||
@return CRYPT_OK on success
|
||||
*/
|
||||
int argon2_hash(const unsigned char *pwd, unsigned long pwdlen,
|
||||
const unsigned char *salt, unsigned long saltlen,
|
||||
const unsigned char *secret, unsigned long secretlen,
|
||||
const unsigned char *ad, unsigned long adlen,
|
||||
unsigned int t_cost, unsigned int m_cost,
|
||||
unsigned int parallelism,
|
||||
argon2_type type,
|
||||
unsigned char *out, unsigned long outlen)
|
||||
{
|
||||
argon2_instance instance;
|
||||
unsigned char blockhash[ARGON2_PREHASH_SEED_LEN];
|
||||
ulong32 memory_blocks, segment_length;
|
||||
int err;
|
||||
|
||||
LTC_ARGCHK(out != NULL);
|
||||
|
||||
/* Validate inputs */
|
||||
if (outlen < ARGON2_MIN_OUTLEN) return CRYPT_INVALID_ARG;
|
||||
if (pwd == NULL && pwdlen != 0) return CRYPT_INVALID_ARG;
|
||||
if (salt == NULL && saltlen != 0) return CRYPT_INVALID_ARG;
|
||||
if (secret == NULL && secretlen != 0) return CRYPT_INVALID_ARG;
|
||||
if (ad == NULL && adlen != 0) return CRYPT_INVALID_ARG;
|
||||
if (t_cost < 1) return CRYPT_INVALID_ARG;
|
||||
if (parallelism < 1) return CRYPT_INVALID_ARG;
|
||||
if (m_cost < 8 * parallelism) return CRYPT_INVALID_ARG;
|
||||
if (type != ARGON2_D && type != ARGON2_I && type != ARGON2_ID) return CRYPT_INVALID_ARG;
|
||||
|
||||
/* Align memory: ensure memory_blocks is a multiple of 4*parallelism */
|
||||
memory_blocks = (ulong32)m_cost;
|
||||
if (memory_blocks < 2 * ARGON2_SYNC_POINTS * (ulong32)parallelism) {
|
||||
memory_blocks = 2 * ARGON2_SYNC_POINTS * (ulong32)parallelism;
|
||||
}
|
||||
segment_length = memory_blocks / ((ulong32)parallelism * ARGON2_SYNC_POINTS);
|
||||
memory_blocks = segment_length * ((ulong32)parallelism * ARGON2_SYNC_POINTS);
|
||||
|
||||
/* Set up instance */
|
||||
instance.passes = (ulong32)t_cost;
|
||||
instance.memory_blocks = memory_blocks;
|
||||
instance.segment_length = segment_length;
|
||||
instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
|
||||
instance.lanes = (ulong32)parallelism;
|
||||
instance.type = (int)type;
|
||||
instance.memory = NULL;
|
||||
|
||||
/* Allocate memory */
|
||||
{
|
||||
unsigned long alloc_size = (unsigned long)memory_blocks * sizeof(argon2_block);
|
||||
/* overflow check */
|
||||
if (alloc_size / sizeof(argon2_block) != memory_blocks) {
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
instance.memory = (argon2_block *)XMALLOC(alloc_size);
|
||||
if (instance.memory == NULL) {
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initial hash H_0 */
|
||||
err = s_initial_hash(blockhash, pwd, pwdlen, salt, saltlen,
|
||||
secret, secretlen, ad, adlen,
|
||||
(ulong32)t_cost, (ulong32)m_cost,
|
||||
(ulong32)parallelism, (ulong32)outlen,
|
||||
(int)type);
|
||||
if (err != CRYPT_OK) goto cleanup;
|
||||
|
||||
/* Zero the extra 8 bytes after digest */
|
||||
XMEMSET(blockhash + ARGON2_PREHASH_DIGEST_LEN, 0, ARGON2_PREHASH_SEED_LEN - ARGON2_PREHASH_DIGEST_LEN);
|
||||
|
||||
/* Generate first blocks */
|
||||
err = s_fill_first_blocks(blockhash, &instance);
|
||||
if (err != CRYPT_OK) goto cleanup;
|
||||
|
||||
zeromem(blockhash, ARGON2_PREHASH_SEED_LEN);
|
||||
|
||||
/* Fill memory */
|
||||
s_fill_memory(&instance);
|
||||
|
||||
/* Finalize */
|
||||
err = s_finalize(out, outlen, &instance);
|
||||
|
||||
cleanup:
|
||||
if (instance.memory != NULL) {
|
||||
zeromem(instance.memory, (unsigned long)memory_blocks * sizeof(argon2_block));
|
||||
XFREE(instance.memory);
|
||||
}
|
||||
zeromem(blockhash, ARGON2_PREHASH_SEED_LEN);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* LTC_ARGON2 */
|
||||
|
|
@ -451,6 +451,9 @@ const char *crypt_build_settings =
|
|||
#if defined(LTC_BASE16)
|
||||
" BASE16 "
|
||||
#endif
|
||||
#if defined(LTC_ARGON2)
|
||||
" ARGON2 "
|
||||
#endif
|
||||
#if defined(LTC_BCRYPT)
|
||||
" BCRYPT "
|
||||
" " NAME_VALUE(LTC_BCRYPT_DEFAULT_ROUNDS) " "
|
||||
|
|
|
|||
91
tests/argon2_test.c
Normal file
91
tests/argon2_test.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
#include <tomcrypt_test.h>
|
||||
|
||||
#ifdef LTC_ARGON2
|
||||
|
||||
/* RFC 9106 test vectors */
|
||||
|
||||
int argon2_test(void)
|
||||
{
|
||||
static const unsigned char password[32] = {
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
|
||||
};
|
||||
static const unsigned char salt[16] = {
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
|
||||
};
|
||||
static const unsigned char secret[8] = {
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
};
|
||||
static const unsigned char ad[12] = {
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04
|
||||
};
|
||||
|
||||
static const unsigned char expected_argon2d[32] = {
|
||||
0x51, 0x2b, 0x39, 0x1b, 0x6f, 0x11, 0x62, 0x97,
|
||||
0x53, 0x71, 0xd3, 0x09, 0x19, 0x73, 0x42, 0x94,
|
||||
0xf8, 0x68, 0xe3, 0xbe, 0x39, 0x84, 0xf3, 0xc1,
|
||||
0xa1, 0x3a, 0x4d, 0xb9, 0xfa, 0xbe, 0x4a, 0xcb
|
||||
};
|
||||
static const unsigned char expected_argon2i[32] = {
|
||||
0xc8, 0x14, 0xd9, 0xd1, 0xdc, 0x7f, 0x37, 0xaa,
|
||||
0x13, 0xf0, 0xd7, 0x7f, 0x24, 0x94, 0xbd, 0xa1,
|
||||
0xc8, 0xde, 0x6b, 0x01, 0x6d, 0xd3, 0x88, 0xd2,
|
||||
0x99, 0x52, 0xa4, 0xc4, 0x67, 0x2b, 0x6c, 0xe8
|
||||
};
|
||||
static const unsigned char expected_argon2id[32] = {
|
||||
0x0d, 0x64, 0x0d, 0xf5, 0x8d, 0x78, 0x76, 0x6c,
|
||||
0x08, 0xc0, 0x37, 0xa3, 0x4a, 0x8b, 0x53, 0xc9,
|
||||
0xd0, 0x1e, 0xf0, 0x45, 0x2d, 0x75, 0xb6, 0x5e,
|
||||
0xb5, 0x25, 0x20, 0xe9, 0x6b, 0x01, 0xe6, 0x59
|
||||
};
|
||||
|
||||
unsigned char tag[32];
|
||||
|
||||
/* Argon2d */
|
||||
DO(argon2_hash(password, sizeof(password),
|
||||
salt, sizeof(salt),
|
||||
secret, sizeof(secret),
|
||||
ad, sizeof(ad),
|
||||
3, 32, 4,
|
||||
ARGON2_D,
|
||||
tag, sizeof(tag)));
|
||||
COMPARE_TESTVECTOR(tag, sizeof(tag), expected_argon2d, sizeof(expected_argon2d), "Argon2d", 0);
|
||||
|
||||
/* Argon2i */
|
||||
DO(argon2_hash(password, sizeof(password),
|
||||
salt, sizeof(salt),
|
||||
secret, sizeof(secret),
|
||||
ad, sizeof(ad),
|
||||
3, 32, 4,
|
||||
ARGON2_I,
|
||||
tag, sizeof(tag)));
|
||||
COMPARE_TESTVECTOR(tag, sizeof(tag), expected_argon2i, sizeof(expected_argon2i), "Argon2i", 1);
|
||||
|
||||
/* Argon2id */
|
||||
DO(argon2_hash(password, sizeof(password),
|
||||
salt, sizeof(salt),
|
||||
secret, sizeof(secret),
|
||||
ad, sizeof(ad),
|
||||
3, 32, 4,
|
||||
ARGON2_ID,
|
||||
tag, sizeof(tag)));
|
||||
COMPARE_TESTVECTOR(tag, sizeof(tag), expected_argon2id, sizeof(expected_argon2id), "Argon2id", 2);
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int argon2_test(void)
|
||||
{
|
||||
return CRYPT_NOP;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
int misc_test(void)
|
||||
{
|
||||
#ifdef LTC_ARGON2
|
||||
DO(argon2_test());
|
||||
#endif
|
||||
#ifdef LTC_BCRYPT
|
||||
DO(bcrypt_test());
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
set(SOURCES
|
||||
argon2_test.c
|
||||
base16_test.c
|
||||
base32_test.c
|
||||
base64_test.c
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ int padding_test(void);
|
|||
int x25519_test(void);
|
||||
int ed25519_test(void);
|
||||
int ssh_test(void);
|
||||
int argon2_test(void);
|
||||
int bcrypt_test(void);
|
||||
int no_null_termination_check_test(void);
|
||||
int pk_oid_test(void);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue