123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /* kdf.c - Key Derivation Functions
- * Copyright (C) 1998, 2011 Free Software Foundation, Inc.
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
- #include <config.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include "g10lib.h"
- #include "cipher.h"
- #include "ath.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. */
- 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 = gpg_err_code (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
- 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 int 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;
- if (!salt || !saltlen || !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);
- /* We ignore step 1 from pksc5v2.1 which demands a check that dklen
- is not larger that 0xffffffff * hlen. */
- /* Step 2 */
- l = ((dklen - 1)/ hlen) + 1;
- r = dklen - (l - 1) * hlen;
- /* Setup buffers and prepare a hash context. */
- sbuf = (secmode
- ? gcry_malloc_secure (saltlen + 4 + hlen + hlen)
- : gcry_malloc (saltlen + 4 + hlen + hlen));
- if (!sbuf)
- return gpg_err_code_from_syserror ();
- tbuf = sbuf + saltlen + 4;
- ubuf = tbuf + hlen;
- ec = gpg_err_code (gcry_md_open (&md, hashalgo,
- (GCRY_MD_FLAG_HMAC
- | (secmode?GCRY_MD_FLAG_SECURE:0))));
- if (ec)
- {
- gcry_free (sbuf);
- return ec;
- }
- /* Step 3 and 4. */
- memcpy (sbuf, salt, saltlen);
- for (lidx = 1; lidx <= l; lidx++)
- {
- for (iter = 0; iter < iterations; iter++)
- {
- ec = gpg_err_code (gcry_md_setkey (md, passphrase, passphraselen));
- if (ec)
- {
- gcry_md_close (md);
- gcry_free (sbuf);
- return ec;
- }
- 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);
- gcry_free (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_error_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 || (!passphraselen && algo != GCRY_KDF_PBKDF2))
- {
- 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:
- 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:
- ec = pkdf2 (passphrase, passphraselen, subalgo,
- salt, saltlen, iterations, keysize, keybuffer);
- break;
- default:
- ec = GPG_ERR_UNKNOWN_ALGORITHM;
- break;
- }
- leave:
- return gpg_error (ec);
- }
|