diff --git a/cipher/kdf.c b/cipher/kdf.c index 8b78ee16..3a027c53 100644 --- a/cipher/kdf.c +++ b/cipher/kdf.c @@ -1,1347 +1,1339 @@ /* kdf.c - Key Derivation Functions * Copyright (C) 1998, 2008, 2011 Free Software Foundation, Inc. * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser general Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include #include #include #include #include #include "g10lib.h" #include "cipher.h" #include "kdf-internal.h" /* Transform a passphrase into a suitable key of length KEYSIZE and store this key in the caller provided buffer KEYBUFFER. The caller must provide an HASHALGO, a valid ALGO and depending on that algo a SALT of 8 bytes and the number of ITERATIONS. Code taken from gnupg/agent/protect.c:hash_passphrase. */ static gpg_err_code_t openpgp_s2k (const void *passphrase, size_t passphraselen, int algo, int hashalgo, const void *salt, size_t saltlen, unsigned long iterations, size_t keysize, void *keybuffer) { gpg_err_code_t ec; gcry_md_hd_t md; char *key = keybuffer; int pass, i; int used = 0; int secmode; if ((algo == GCRY_KDF_SALTED_S2K || algo == GCRY_KDF_ITERSALTED_S2K) && (!salt || saltlen != 8)) return GPG_ERR_INV_VALUE; secmode = _gcry_is_secure (passphrase) || _gcry_is_secure (keybuffer); ec = _gcry_md_open (&md, hashalgo, secmode? GCRY_MD_FLAG_SECURE : 0); if (ec) return ec; for (pass=0; used < keysize; pass++) { if (pass) { _gcry_md_reset (md); for (i=0; i < pass; i++) /* Preset the hash context. */ _gcry_md_putc (md, 0); } if (algo == GCRY_KDF_SALTED_S2K || algo == GCRY_KDF_ITERSALTED_S2K) { int len2 = passphraselen + 8; unsigned long count = len2; if (algo == GCRY_KDF_ITERSALTED_S2K) { count = iterations; if (count < len2) count = len2; } while (count > len2) { _gcry_md_write (md, salt, saltlen); _gcry_md_write (md, passphrase, passphraselen); count -= len2; } if (count < saltlen) _gcry_md_write (md, salt, count); else { _gcry_md_write (md, salt, saltlen); count -= saltlen; _gcry_md_write (md, passphrase, count); } } else _gcry_md_write (md, passphrase, passphraselen); _gcry_md_final (md); i = _gcry_md_get_algo_dlen (hashalgo); if (i > keysize - used) i = keysize - used; memcpy (key+used, _gcry_md_read (md, hashalgo), i); used += i; } _gcry_md_close (md); return 0; } /* Transform a passphrase into a suitable key of length KEYSIZE and store this key in the caller provided buffer KEYBUFFER. The caller must provide PRFALGO which indicates the pseudorandom function to use: This shall be the algorithms id of a hash algorithm; it is used in HMAC mode. SALT is a salt of length SALTLEN and ITERATIONS gives the number of iterations. */ gpg_err_code_t _gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen, int hashalgo, const void *salt, size_t saltlen, unsigned long iterations, size_t keysize, void *keybuffer) { gpg_err_code_t ec; gcry_md_hd_t md; int secmode; unsigned long dklen = keysize; char *dk = keybuffer; unsigned int hlen; /* Output length of the digest function. */ unsigned int l; /* Rounded up number of blocks. */ unsigned int r; /* Number of octets in the last block. */ char *sbuf; /* Malloced buffer to concatenate salt and iter as well as space to hold TBUF and UBUF. */ char *tbuf; /* Buffer for T; ptr into SBUF, size is HLEN. */ char *ubuf; /* Buffer for U; ptr into SBUF, size is HLEN. */ unsigned int lidx; /* Current block number. */ unsigned long iter; /* Current iteration number. */ unsigned int i; /* We allow for a saltlen of 0 here to support scrypt. It is not clear whether rfc2898 allows for this this, thus we do a test on saltlen > 0 only in gcry_kdf_derive. */ if (!salt || !iterations || !dklen) return GPG_ERR_INV_VALUE; hlen = _gcry_md_get_algo_dlen (hashalgo); if (!hlen) return GPG_ERR_DIGEST_ALGO; secmode = _gcry_is_secure (passphrase) || _gcry_is_secure (keybuffer); /* Step 1 */ /* If dkLen > (2^32 - 1) * hLen, output "derived key too long" and * stop. We use a stronger inequality but only if our type can hold * a larger value. */ #if SIZEOF_UNSIGNED_LONG > 4 if (dklen > 0xffffffffU) return GPG_ERR_INV_VALUE; #endif /* Step 2 */ l = ((dklen - 1)/ hlen) + 1; r = dklen - (l - 1) * hlen; /* Setup buffers and prepare a hash context. */ sbuf = (secmode ? xtrymalloc_secure (saltlen + 4 + hlen + hlen) : xtrymalloc (saltlen + 4 + hlen + hlen)); if (!sbuf) return gpg_err_code_from_syserror (); tbuf = sbuf + saltlen + 4; ubuf = tbuf + hlen; ec = _gcry_md_open (&md, hashalgo, (GCRY_MD_FLAG_HMAC | (secmode?GCRY_MD_FLAG_SECURE:0))); if (ec) { xfree (sbuf); return ec; } ec = _gcry_md_setkey (md, passphrase, passphraselen); if (ec) { _gcry_md_close (md); xfree (sbuf); return ec; } /* Step 3 and 4. */ memcpy (sbuf, salt, saltlen); for (lidx = 1; lidx <= l; lidx++) { for (iter = 0; iter < iterations; iter++) { _gcry_md_reset (md); if (!iter) /* Compute U_1: */ { sbuf[saltlen] = (lidx >> 24); sbuf[saltlen + 1] = (lidx >> 16); sbuf[saltlen + 2] = (lidx >> 8); sbuf[saltlen + 3] = lidx; _gcry_md_write (md, sbuf, saltlen + 4); memcpy (ubuf, _gcry_md_read (md, 0), hlen); memcpy (tbuf, ubuf, hlen); } else /* Compute U_(2..c): */ { _gcry_md_write (md, ubuf, hlen); memcpy (ubuf, _gcry_md_read (md, 0), hlen); for (i=0; i < hlen; i++) tbuf[i] ^= ubuf[i]; } } if (lidx == l) /* Last block. */ memcpy (dk, tbuf, r); else { memcpy (dk, tbuf, hlen); dk += hlen; } } _gcry_md_close (md); xfree (sbuf); return 0; } /* Derive a key from a passphrase. KEYSIZE gives the requested size of the keys in octets. KEYBUFFER is a caller provided buffer filled on success with the derived key. The input passphrase is taken from (PASSPHRASE,PASSPHRASELEN) which is an arbitrary memory buffer. ALGO specifies the KDF algorithm to use; these are the constants GCRY_KDF_*. SUBALGO specifies an algorithm used internally by the KDF algorithms; this is usually a hash algorithm but certain KDF algorithm may use it differently. {SALT,SALTLEN} is a salt as needed by most KDF algorithms. ITERATIONS is a positive integer parameter to most KDFs. 0 is returned on success, or an error code on failure. */ gpg_err_code_t _gcry_kdf_derive (const void *passphrase, size_t passphraselen, int algo, int subalgo, const void *salt, size_t saltlen, unsigned long iterations, size_t keysize, void *keybuffer) { gpg_err_code_t ec; if (!passphrase) { ec = GPG_ERR_INV_DATA; goto leave; } if (!keybuffer || !keysize) { ec = GPG_ERR_INV_VALUE; goto leave; } switch (algo) { case GCRY_KDF_SIMPLE_S2K: case GCRY_KDF_SALTED_S2K: case GCRY_KDF_ITERSALTED_S2K: if (!passphraselen) ec = GPG_ERR_INV_DATA; else ec = openpgp_s2k (passphrase, passphraselen, algo, subalgo, salt, saltlen, iterations, keysize, keybuffer); break; case GCRY_KDF_PBKDF1: ec = GPG_ERR_UNSUPPORTED_ALGORITHM; break; case GCRY_KDF_PBKDF2: if (!saltlen) ec = GPG_ERR_INV_VALUE; else ec = _gcry_kdf_pkdf2 (passphrase, passphraselen, subalgo, salt, saltlen, iterations, keysize, keybuffer); break; case 41: case GCRY_KDF_SCRYPT: #if USE_SCRYPT ec = _gcry_kdf_scrypt (passphrase, passphraselen, algo, subalgo, salt, saltlen, iterations, keysize, keybuffer); #else ec = GPG_ERR_UNSUPPORTED_ALGORITHM; #endif /*USE_SCRYPT*/ break; default: ec = GPG_ERR_UNKNOWN_ALGORITHM; break; } leave: return ec; } #include "bufhelp.h" typedef struct argon2_context *argon2_ctx_t; /* Per thread data for Argon2. */ struct argon2_thread_data { argon2_ctx_t a; union { void *user_data; gpg_err_code_t ec; } u; unsigned int pass; unsigned int slice; unsigned int lane; }; /* Argon2 context */ struct argon2_context { int algo; int hash_type; unsigned int outlen; unsigned int n_threads; const unsigned char *password; size_t passwordlen; const unsigned char *salt; size_t saltlen; const unsigned char *key; size_t keylen; const unsigned char *ad; size_t adlen; unsigned int m_cost; unsigned int passes; unsigned int memory_blocks; unsigned int segment_length; unsigned int lane_length; unsigned int lanes; unsigned int step; unsigned int r; unsigned int s; unsigned int l; unsigned int t; gcry_md_hd_t hd; u64 *block; struct argon2_thread_data *thread_data; unsigned char out[1]; /* In future, we may use flexible array member. */ }; enum argon2_iterator_step { ARGON2_ITERATOR_STEP0, ARGON2_ITERATOR_STEP1, ARGON2_ITERATOR_STEP2, ARGON2_ITERATOR_STEP3, ARGON2_ITERATOR_STEP4 }; #define ARGON2_VERSION 0x13 #define ARGON2_WORDS_IN_BLOCK (1024/8) static void xor_block (u64 *dst, const u64 *src) { int i; for (i = 0; i < ARGON2_WORDS_IN_BLOCK; i++) dst[i] ^= src[i]; } static void hash (gcry_md_hd_t hd, const void *input, unsigned int inputlen, void *output, unsigned int outputlen) { unsigned char buf[4]; const unsigned char *digest; _gcry_md_reset (hd); - if (outputlen < 64) + if (outputlen <= 64) { buf_put_le32 (buf, outputlen); _gcry_md_write (hd, buf, 4); _gcry_md_write (hd, input, inputlen); digest = _gcry_md_read (hd, GCRY_MD_BLAKE2B_512); memcpy (output, digest, outputlen); } - else if (outputlen == 64) - { - buf_put_le32 (buf, outputlen); - _gcry_md_write (hd, buf, 4); - _gcry_md_write (hd, input, inputlen); - digest = _gcry_md_read (hd, GCRY_MD_BLAKE2B_512); - memcpy (output, digest, 64); - } else { int i, r; unsigned int remained; unsigned char d[64]; i = 0; r = (outputlen-1)/32; buf_put_le32 (buf, outputlen); _gcry_md_write (hd, buf, 4); _gcry_md_write (hd, input, inputlen); while (1) { digest = _gcry_md_read (hd, GCRY_MD_BLAKE2B_512); memcpy (d, digest, 64); memcpy ((unsigned char *)output+i*32, d, 32); if (++i >= r) break; _gcry_md_reset (hd); _gcry_md_write (hd, d, 64); } remained = outputlen - 32*r; if (remained) memcpy ((unsigned char *)output+r*32, d+32, remained); } } static void argon2_fill_first_blocks (argon2_ctx_t a) { unsigned char h0_01_i[72]; const unsigned char *digest; unsigned char buf[4]; int i; /* Generate H0. */ buf_put_le32 (buf, a->lanes); _gcry_md_write (a->hd, buf, 4); buf_put_le32 (buf, a->outlen); _gcry_md_write (a->hd, buf, 4); buf_put_le32 (buf, a->m_cost); _gcry_md_write (a->hd, buf, 4); buf_put_le32 (buf, a->passes); _gcry_md_write (a->hd, buf, 4); buf_put_le32 (buf, ARGON2_VERSION); _gcry_md_write (a->hd, buf, 4); buf_put_le32 (buf, a->hash_type); _gcry_md_write (a->hd, buf, 4); buf_put_le32 (buf, a->passwordlen); _gcry_md_write (a->hd, buf, 4); _gcry_md_write (a->hd, a->password, a->passwordlen); buf_put_le32 (buf, a->saltlen); _gcry_md_write (a->hd, buf, 4); _gcry_md_write (a->hd, a->salt, a->saltlen); buf_put_le32 (buf, a->keylen); _gcry_md_write (a->hd, buf, 4); if (a->key) _gcry_md_write (a->hd, a->key, a->keylen); buf_put_le32 (buf, a->adlen); _gcry_md_write (a->hd, buf, 4); if (a->ad) _gcry_md_write (a->hd, a->ad, a->adlen); digest = _gcry_md_read (a->hd, GCRY_MD_BLAKE2B_512); memcpy (h0_01_i, digest, 64); for (i = 0; i < a->lanes; i++) { memset (h0_01_i+64, 0, 4); buf_put_le32 (h0_01_i+64+4, i); hash (a->hd, h0_01_i, 72, &a->block[i*a->lane_length*ARGON2_WORDS_IN_BLOCK], 1024); buf_put_le32 (h0_01_i+64, 1); hash (a->hd, h0_01_i, 72, &a->block[(i*a->lane_length+1)*ARGON2_WORDS_IN_BLOCK], 1024); } } static gpg_err_code_t argon2_init (argon2_ctx_t a, unsigned int parallelism, unsigned int m_cost, unsigned int t_cost) { gpg_err_code_t ec = 0; unsigned int memory_blocks; unsigned int segment_length; gcry_md_hd_t hd; void *block; struct argon2_thread_data *thread_data; memory_blocks = m_cost; if (memory_blocks < 8 * parallelism) memory_blocks = 8 * parallelism; segment_length = memory_blocks / (parallelism * 4); memory_blocks = segment_length * parallelism * 4; a->passes = t_cost; a->memory_blocks = memory_blocks; a->segment_length = segment_length; a->lane_length = segment_length * 4; a->lanes = parallelism; a->r = a->s = a->l = a->t = 0; a->step = ARGON2_ITERATOR_STEP0; a->hd = NULL; a->block = NULL; a->thread_data = NULL; ec = _gcry_md_open (&hd, GCRY_MD_BLAKE2B_512, 0); if (ec) return ec; block = xtrymalloc (1024 * memory_blocks); if (!block) { ec = gpg_err_code_from_errno (errno); _gcry_md_close (hd); return ec; } memset (block, 0, 1024 * memory_blocks); thread_data = xtrymalloc (a->n_threads * sizeof (struct argon2_thread_data)); if (!thread_data) { ec = gpg_err_code_from_errno (errno); xfree (block); _gcry_md_close (hd); return ec; } memset (thread_data, 0, a->n_threads * sizeof (struct argon2_thread_data)); a->hd = hd; a->block = block; a->thread_data = thread_data; return 0; } static gpg_err_code_t argon2_ctl (argon2_ctx_t a, int cmd, void *buffer, size_t buflen) { gpg_err_code_t ec = GPG_ERR_NOT_IMPLEMENTED; (void)a; (void)cmd; (void)buffer; (void)buflen; return ec; } static gpg_err_code_t argon2_iterator (argon2_ctx_t a, int *action_p, struct gcry_kdf_pt_head **t_p) { switch (a->step) { case ARGON2_ITERATOR_STEP0: argon2_fill_first_blocks (a); /* continue */ *action_p = 3; *t_p = NULL; a->step = ARGON2_ITERATOR_STEP1; return 0; case ARGON2_ITERATOR_STEP1: for (a->r = 0; a->r < a->passes; a->r++) for (a->s = 0; a->s < 4; a->s++) { struct argon2_thread_data *thread_data; for (a->l = 0; a->l < a->lanes; a->l++) { if (a->l >= a->n_threads) { /* Join a thread. */ thread_data = &a->thread_data[a->t]; *action_p = 2; *t_p = (struct gcry_kdf_pt_head *)thread_data; a->step = ARGON2_ITERATOR_STEP2; return 0; case ARGON2_ITERATOR_STEP2: thread_data = &a->thread_data[a->t]; if (thread_data->u.ec) return thread_data->u.ec; } /* Create a thread. */ thread_data = &a->thread_data[a->t]; thread_data->a = a; thread_data->u.user_data = NULL; thread_data->pass = a->r; thread_data->slice = a->s; thread_data->lane = a->l; *action_p = 1; *t_p = (struct gcry_kdf_pt_head *)thread_data; a->step = ARGON2_ITERATOR_STEP3; return 0; case ARGON2_ITERATOR_STEP3: a->t = (a->t + 1) % a->n_threads; } for (a->l = a->lanes - a->n_threads; a->l < a->lanes; a->l++) { thread_data = &a->thread_data[a->t]; /* Join a thread. */ *action_p = 2; *t_p = (struct gcry_kdf_pt_head *)thread_data; a->step = ARGON2_ITERATOR_STEP4; return 0; case ARGON2_ITERATOR_STEP4: thread_data = &a->thread_data[a->t]; if (thread_data->u.ec) return thread_data->u.ec; a->t = (a->t + 1) % a->n_threads; } } } *action_p = 0; *t_p = NULL; a->step = ARGON2_ITERATOR_STEP0; return 0; } static void argon2_pseudo_rand_gen (argon2_ctx_t a, const struct argon2_thread_data *t, u32 *random_index) { (void)a; (void)t; (void)random_index; } static u64 fBlaMka (u64 x, u64 y) { const u64 m = U64_C(0xFFFFFFFF); return x + y + 2 * (x & m) * (y & m); } static u64 rotr64 (uint64_t w, unsigned int c) { return (w >> c) | (w << (64 - c)); } #define G(a, b, c, d) \ do { \ a = fBlaMka(a, b); \ d = rotr64(d ^ a, 32); \ c = fBlaMka(c, d); \ b = rotr64(b ^ c, 24); \ a = fBlaMka(a, b); \ d = rotr64(d ^ a, 16); \ c = fBlaMka(c, d); \ b = rotr64(b ^ c, 63); \ } while ((void)0, 0) #define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \ v12, v13, v14, v15) \ do { \ G(v0, v4, v8, v12); \ G(v1, v5, v9, v13); \ G(v2, v6, v10, v14); \ G(v3, v7, v11, v15); \ G(v0, v5, v10, v15); \ G(v1, v6, v11, v12); \ G(v2, v7, v8, v13); \ G(v3, v4, v9, v14); \ } while ((void)0, 0) static void fill_block (const u64 *prev_block, const u64 *ref_block, u64 *curr_block, int with_xor) { u64 block_r[ARGON2_WORDS_IN_BLOCK]; u64 block_tmp[ARGON2_WORDS_IN_BLOCK]; int i; memcpy (block_r, ref_block, 1024); xor_block (block_r, prev_block); memcpy (block_tmp, block_r, 1024); if (with_xor) xor_block (block_tmp, curr_block); for (i = 0; i < 8; ++i) BLAKE2_ROUND_NOMSG (block_r[16 * i], block_r[16 * i + 1], block_r[16 * i + 2], block_r[16 * i + 3], block_r[16 * i + 4], block_r[16 * i + 5], block_r[16 * i + 6], block_r[16 * i + 7], block_r[16 * i + 8], block_r[16 * i + 9], block_r[16 * i + 10], block_r[16 * i + 11], block_r[16 * i + 12], block_r[16 * i + 13], block_r[16 * i + 14], block_r[16 * i + 15]); for (i = 0; i < 8; i++) BLAKE2_ROUND_NOMSG (block_r[2 * i], block_r[2 * i + 1], block_r[2 * i + 16], block_r[2 * i + 17], block_r[2 * i + 32], block_r[2 * i + 33], block_r[2 * i + 48], block_r[2 * i + 49], block_r[2 * i + 64], block_r[2 * i + 65], block_r[2 * i + 80], block_r[2 * i + 81], block_r[2 * i + 96], block_r[2 * i + 97], block_r[2 * i + 112], block_r[2 * i + 113]); memcpy (curr_block, block_tmp, 1024); xor_block (curr_block, block_r); } static u32 index_alpha (argon2_ctx_t a, const struct argon2_thread_data *t, int segment_index, u32 random, int same_lane) { u32 reference_area_size; u64 relative_position; u32 start_position; if (t->pass == 0) { if (t->slice == 0) reference_area_size = segment_index - 1; else { if (same_lane) reference_area_size = t->slice * a->segment_length + segment_index - 1; else reference_area_size = t->slice * a->segment_length + ((segment_index == 0) ? -1 : 0); } } else { if (same_lane) reference_area_size = a->lane_length - a->segment_length + segment_index - 1; else reference_area_size = a->lane_length - a->segment_length + ((segment_index == 0) ? -1 : 0); } relative_position = (random * (u64)random) >> 32; relative_position = reference_area_size - 1 - ((reference_area_size * relative_position) >> 32); if (t->pass == 0) start_position = 0; else start_position = (t->slice == 4 - 1) ? 0 : (t->slice + 1) * a->segment_length; return (start_position + relative_position) % a->lane_length; } static gpg_err_code_t argon2_compute_segment (argon2_ctx_t a, const struct argon2_thread_data *t) { gpg_err_code_t ec = 0; u32 *random_index = NULL; int i; int prev_offset, curr_offset; u32 ref_index, ref_lane; if (a->hash_type == GCRY_KDF_ARGON2I || (a->hash_type == GCRY_KDF_ARGON2ID && t->pass == 0 && t->slice < 2)) { random_index = xtrymalloc (2*sizeof (u32)*a->segment_length); if (!random_index) return gpg_err_code_from_errno (errno); argon2_pseudo_rand_gen (a, t, random_index); } if (t->pass == 0 && t->slice == 0) i = 2; else i = 0; curr_offset = t->lane * a->lane_length + t->slice * a->segment_length + i; if ((curr_offset % a->lane_length)) prev_offset = curr_offset - 1; else prev_offset = curr_offset + a->lane_length - 1; for (; i < a->segment_length; i++, curr_offset++, prev_offset++) { void *pseudo_rand; u64 *ref_block, *curr_block; if ((curr_offset % a->lane_length) == 1) prev_offset = curr_offset - 1; if (random_index) { /* not yet implemented */ pseudo_rand = &a->block[prev_offset*ARGON2_WORDS_IN_BLOCK]; } else pseudo_rand = &a->block[prev_offset*ARGON2_WORDS_IN_BLOCK]; if (t->pass == 0 && t->slice == 0) ref_lane = t->lane; else ref_lane = buf_get_le32 ((unsigned char *)pseudo_rand+4) % a->lanes; ref_index = index_alpha (a, t, i, buf_get_le32 (pseudo_rand), ref_lane == t->lane); ref_block = &a->block[(a->lane_length * ref_lane + ref_index)* ARGON2_WORDS_IN_BLOCK]; curr_block = &a->block[curr_offset * ARGON2_WORDS_IN_BLOCK]; fill_block (&a->block[prev_offset * ARGON2_WORDS_IN_BLOCK], ref_block, curr_block, t->pass != 0); } xfree (random_index); return ec; } static gpg_err_code_t argon2_final (argon2_ctx_t a, size_t resultlen, void *result) { int i; if (resultlen != a->outlen) return GPG_ERR_INV_VALUE; memset (a->block, 0, 1024); for (i = 0; i < a->lanes; i++) { u64 *last_block; last_block = &a->block[(a->lane_length * i + (a->lane_length - 1)) * ARGON2_WORDS_IN_BLOCK]; xor_block (a->block, last_block); } hash (a->hd, a->block, 1024, result, a->outlen); return 0; } static void argon2_close (argon2_ctx_t a) { size_t n; n = offsetof (struct argon2_context, out) + a->outlen; if (a->hd) _gcry_md_close (a->hd); if (a->block) { wipememory (a->block, 1024 * a->memory_blocks); xfree (a->block); } if (a->thread_data) xfree (a->thread_data); wipememory (a, n); xfree (a); } static gpg_err_code_t argon2_open (gcry_kdf_hd_t *hd, int subalgo, const unsigned long *param, unsigned int paramlen, const void *password, size_t passwordlen, const void *salt, size_t saltlen, const void *key, size_t keylen, const void *ad, size_t adlen) { int hash_type; unsigned int taglen; unsigned int t_cost; unsigned int m_cost; unsigned int parallelism = 1; unsigned int n_threads = 1; argon2_ctx_t a; gpg_err_code_t ec; size_t n; if (subalgo != GCRY_KDF_ARGON2D && subalgo != GCRY_KDF_ARGON2I && subalgo != GCRY_KDF_ARGON2ID) return GPG_ERR_INV_VALUE; else hash_type = subalgo; /* param : [ tag_length, t_cost, m_cost, parallelism, n_threads ] */ if (paramlen < 3 || paramlen > 5) return GPG_ERR_INV_VALUE; else { taglen = (unsigned int)param[0]; t_cost = (unsigned int)param[1]; m_cost = (unsigned int)param[2]; if (paramlen >= 4) parallelism = (unsigned int)param[3]; if (paramlen == 5) { n_threads = (unsigned int)param[4]; if (n_threads > parallelism) n_threads = parallelism; } if (!(taglen == 64 || taglen == 48 || taglen % 32 == 0 || taglen % 32 == 20)) /* * FIXME: To support arbitrary taglen, we need to expose * internal API of Blake2b. */ return GPG_ERR_NOT_IMPLEMENTED; } n = offsetof (struct argon2_context, out) + taglen; a = xtrymalloc (n); if (!a) return gpg_err_code_from_errno (errno); a->algo = GCRY_KDF_ARGON2; a->hash_type = hash_type; a->outlen = taglen; a->n_threads = n_threads; a->password = password; a->passwordlen = passwordlen; a->salt = salt; a->saltlen = saltlen; a->key = key; a->keylen = keylen; a->ad = ad; a->adlen = adlen; a->m_cost = m_cost; a->block = NULL; a->thread_data = NULL; ec = argon2_init (a, parallelism, m_cost, t_cost); if (ec) { xfree (a); return ec; } *hd = (void *)a; return 0; } static gpg_err_code_t balloon_open (gcry_kdf_hd_t *hd, int subalgo, const unsigned long *param, unsigned int paramlen, const void *passphrase, size_t passphraselen, const void *salt, size_t saltlen) { /* * It should have space_cost and time_cost. * Optionally, for parallelised version, it has parallelism. */ if (paramlen != 2 && paramlen != 3) return GPG_ERR_INV_VALUE; (void)param; (void)subalgo; (void)passphrase; (void)passphraselen; (void)salt; (void)saltlen; *hd = NULL; return GPG_ERR_NOT_IMPLEMENTED; } struct gcry_kdf_handle { int algo; /* And algo specific parts come. */ }; gpg_err_code_t _gcry_kdf_open (gcry_kdf_hd_t *hd, int algo, int subalgo, const unsigned long *param, unsigned int paramlen, const void *passphrase, size_t passphraselen, const void *salt, size_t saltlen, const void *key, size_t keylen, const void *ad, size_t adlen) { gpg_err_code_t ec; switch (algo) { case GCRY_KDF_ARGON2: if (!passphraselen || !saltlen) ec = GPG_ERR_INV_VALUE; else ec = argon2_open (hd, subalgo, param, paramlen, passphrase, passphraselen, salt, saltlen, key, keylen, ad, adlen); break; case GCRY_KDF_BALLOON: if (!passphraselen || !saltlen) ec = GPG_ERR_INV_VALUE; else { (void)key; (void)keylen; (void)ad; (void)adlen; ec = balloon_open (hd, subalgo, param, paramlen, passphrase, passphraselen, salt, saltlen); } break; default: ec = GPG_ERR_UNKNOWN_ALGORITHM; break; } return ec; } gpg_err_code_t _gcry_kdf_ctl (gcry_kdf_hd_t h, int cmd, void *buffer, size_t buflen) { gpg_err_code_t ec; switch (h->algo) { case GCRY_KDF_ARGON2: ec = argon2_ctl ((argon2_ctx_t)h, cmd, buffer, buflen); break; default: ec = GPG_ERR_UNKNOWN_ALGORITHM; break; } return ec; } gpg_err_code_t _gcry_kdf_iterator (gcry_kdf_hd_t h, int *action_p, struct gcry_kdf_pt_head **t_p) { gpg_err_code_t ec; switch (h->algo) { case GCRY_KDF_ARGON2: ec = argon2_iterator ((argon2_ctx_t)h, action_p, t_p); break; default: ec = GPG_ERR_UNKNOWN_ALGORITHM; break; } return ec; } gpg_err_code_t _gcry_kdf_compute_segment (gcry_kdf_hd_t h, const struct gcry_kdf_pt_head *t) { gpg_err_code_t ec; switch (h->algo) { case GCRY_KDF_ARGON2: ec = argon2_compute_segment ((argon2_ctx_t)h, (const struct argon2_thread_data *)t); break; default: ec = GPG_ERR_UNKNOWN_ALGORITHM; break; } return ec; } gpg_err_code_t _gcry_kdf_final (gcry_kdf_hd_t h, size_t resultlen, void *result) { gpg_err_code_t ec; switch (h->algo) { case GCRY_KDF_ARGON2: ec = argon2_final ((argon2_ctx_t)h, resultlen, result); break; default: ec = GPG_ERR_UNKNOWN_ALGORITHM; break; } return ec; } void _gcry_kdf_close (gcry_kdf_hd_t h) { switch (h->algo) { case GCRY_KDF_ARGON2: argon2_close ((argon2_ctx_t)h); break; default: break; } } /* Check one KDF call with ALGO and HASH_ALGO using the regular KDF * API. (passphrase,passphraselen) is the password to be derived, * (salt,saltlen) the salt for the key derivation, * iterations is the number of the kdf iterations, * and (expect,expectlen) the expected result. Returns NULL on * success or a string describing the failure. */ static const char * check_one (int algo, int hash_algo, const void *passphrase, size_t passphraselen, const void *salt, size_t saltlen, unsigned long iterations, const void *expect, size_t expectlen) { unsigned char key[512]; /* hardcoded to avoid allocation */ size_t keysize = expectlen; /* Skip test with shoter passphrase in FIPS mode. */ if (fips_mode () && passphraselen < 14) return NULL; if (keysize > sizeof(key)) return "invalid tests data"; if (_gcry_kdf_derive (passphrase, passphraselen, algo, hash_algo, salt, saltlen, iterations, keysize, key)) return "gcry_kdf_derive failed"; if (memcmp (key, expect, expectlen)) return "does not match"; return NULL; } static gpg_err_code_t selftest_pbkdf2 (int extended, selftest_report_func_t report) { static const struct { const char *desc; const char *p; /* Passphrase. */ size_t plen; /* Length of P. */ const char *salt; size_t saltlen; int hashalgo; unsigned long c; /* Iterations. */ int dklen; /* Requested key length. */ const char *dk; /* Derived key. */ int disabled; } tv[] = { #if USE_SHA1 #define NUM_TEST_VECTORS 9 /* SHA1 test vectors are from RFC-6070. */ { "Basic PBKDF2 SHA1 #1", "password", 8, "salt", 4, GCRY_MD_SHA1, 1, 20, "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9" "\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6" }, { "Basic PBKDF2 SHA1 #2", "password", 8, "salt", 4, GCRY_MD_SHA1, 2, 20, "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e" "\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57" }, { "Basic PBKDF2 SHA1 #3", "password", 8, "salt", 4, GCRY_MD_SHA1, 4096, 20, "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad" "\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1" }, { "Basic PBKDF2 SHA1 #4", "password", 8, "salt", 4, GCRY_MD_SHA1, 16777216, 20, "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94" "\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", 1 /* This test takes too long. */ }, { "Basic PBKDF2 SHA1 #5", "passwordPASSWORDpassword", 24, "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, GCRY_MD_SHA1, 4096, 25, "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8" "\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96" "\x4c\xf2\xf0\x70\x38" }, { "Basic PBKDF2 SHA1 #6", "pass\0word", 9, "sa\0lt", 5, GCRY_MD_SHA1, 4096, 16, "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37" "\xd7\xf0\x34\x25\xe0\xc3" }, { /* empty password test, not in RFC-6070 */ "Basic PBKDF2 SHA1 #7", "", 0, "salt", 4, GCRY_MD_SHA1, 2, 20, "\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2" "\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97" }, #else #define NUM_TEST_VECTORS 2 #endif { "Basic PBKDF2 SHA256", "password", 8, "salt", 4, GCRY_MD_SHA256, 2, 32, "\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9\x28\xf0\x6d\xd0" "\x2a\x30\x3f\x8e\xf3\xc2\x51\xdf\xd6\xe2\xd8\x5a\x95\x47\x4c\x43" }, { "Extended PBKDF2 SHA256", "passwordPASSWORDpassword", 24, "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, GCRY_MD_SHA256, 4096, 40, "\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11\x6e\x84\xcf" "\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c\x4e\x2a\x1f\xb8\xdd\x53\xe1" "\xc6\x35\x51\x8c\x7d\xac\x47\xe9" }, { NULL } }; const char *what; const char *errtxt; int tvidx; for (tvidx=0; tv[tvidx].desc; tvidx++) { what = tv[tvidx].desc; if (tv[tvidx].disabled) continue; errtxt = check_one (GCRY_KDF_PBKDF2, tv[tvidx].hashalgo, tv[tvidx].p, tv[tvidx].plen, tv[tvidx].salt, tv[tvidx].saltlen, tv[tvidx].c, tv[tvidx].dk, tv[tvidx].dklen); if (errtxt) goto failed; if (tvidx >= NUM_TEST_VECTORS - 1 && !extended) break; } return 0; /* Succeeded. */ failed: if (report) report ("kdf", GCRY_KDF_PBKDF2, what, errtxt); return GPG_ERR_SELFTEST_FAILED; } /* Run the selftests for KDF with KDF algorithm ALGO with optional reporting function REPORT. */ gpg_error_t _gcry_kdf_selftest (int algo, int extended, selftest_report_func_t report) { gcry_err_code_t ec = 0; if (algo == GCRY_KDF_PBKDF2) ec = selftest_pbkdf2 (extended, report); else { ec = GPG_ERR_UNSUPPORTED_ALGORITHM; if (report) report ("kdf", algo, "module", "algorithm not available"); } return gpg_error (ec); }