* Print error when getline fails.
* Remove po/cryptsetup-luks.pot, it's autogenerated.
* Return ENOENT for empty keyslots, EINVAL will be used later for other type of error.
+ * Switch PBKDF2 from internal SHA1 to libgcrypt, make hash algorithm not hardcoded to SHA1 here.
2009-07-28 Milan Broz <mbroz@redhat.com>
* Pad luks header to 512 sector size.
/*
* AFsplitter - Anti forensic information splitter
* Copyright 2004, Clemens Fruhwirth <clemens@endorphin.org>
+ * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefor supporting secure data destruction.
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <stdio.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <netinet/in.h>
#include <errno.h>
+#include <gcrypt.h>
#include "sha1.h"
#include "XORblock.h"
#include "random.h"
+static int hash_buf(char *src, char *dst, uint32_t iv, int len, int hash_id)
+{
+ gcry_md_hd_t hd;
+ unsigned char *digest;
+
+ iv = htonl(iv);
+ if (gcry_md_open(&hd, hash_id, 0))
+ return 1;
+ gcry_md_write(hd, (unsigned char *)&iv, sizeof(iv));
+ gcry_md_write(hd, src, len);
+ digest = gcry_md_read(hd, hash_id);
+ memcpy(dst, digest, len);
+ gcry_md_close(hd);
+ return 0;
+}
+
/* diffuse: Information spreading over the whole dataset with
- * the help of sha512.
+ * the help of hash function.
*/
-static void diffuse(unsigned char *src, unsigned char *dst, size_t size)
+static int diffuse(char *src, char *dst, size_t size, int hash_id)
{
- sha1_ctx ctx;
- uint32_t i;
- uint32_t IV; /* host byte order independend hash IV */
-
- unsigned int fullblocks = size / SHA1_DIGEST_SIZE;
- unsigned int padding = size % SHA1_DIGEST_SIZE;
- unsigned char final[SHA1_DIGEST_SIZE];
-
- /* hash block the whole data set with different IVs to produce
- * more than just a single data block
- */
- for (i=0; i < fullblocks; i++) {
- sha1_begin(&ctx);
- IV = htonl(i);
- sha1_hash((const unsigned char *) &IV, sizeof(IV), &ctx);
- sha1_hash(src + SHA1_DIGEST_SIZE * i, SHA1_DIGEST_SIZE, &ctx);
- sha1_end(dst + SHA1_DIGEST_SIZE * i, &ctx);
- }
+ unsigned int digest_size = gcry_md_get_algo_dlen(hash_id);
+ unsigned int i, blocks, padding;
- if(padding) {
- sha1_begin(&ctx);
- IV = htonl(i);
- sha1_hash((const unsigned char *) &IV, sizeof(IV), &ctx);
- sha1_hash(src + SHA1_DIGEST_SIZE * i, padding, &ctx);
- sha1_end(final, &ctx);
- memcpy(dst + SHA1_DIGEST_SIZE * i, final, padding);
- }
+ blocks = size / digest_size;
+ padding = size % digest_size;
+
+ for (i = 0; i < blocks; i++)
+ if(hash_buf(src + digest_size * i,
+ dst + digest_size * i,
+ i, digest_size, hash_id))
+ return 1;
+
+ if(padding)
+ if(hash_buf(src + digest_size * i,
+ dst + digest_size * i,
+ i, padding, hash_id))
+ return 1;
+
+ return 0;
}
/*
* must be supplied to AF_merge to recover information.
*/
-int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers)
+int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash)
{
unsigned int i;
char *bufblock;
int r = -EINVAL;
+ int hash_id;
+
+ if (!(hash_id = gcry_md_map_name(hash)))
+ return -EINVAL;
if((bufblock = calloc(blocksize, 1)) == NULL) return -ENOMEM;
if(r < 0) goto out;
XORblock(dst+(blocksize*i),bufblock,bufblock,blocksize);
- diffuse((unsigned char *) bufblock, (unsigned char *) bufblock, blocksize);
+ if(diffuse(bufblock, bufblock, blocksize, hash_id))
+ goto out;
}
/* the last block is computed */
XORblock(src,bufblock,dst+(i*blocksize),blocksize);
return r;
}
-int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers)
+int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash)
{
unsigned int i;
char *bufblock;
+ int r = -EINVAL;
+ int hash_id;
+
+ if (!(hash_id = gcry_md_map_name(hash)))
+ return -EINVAL;
if((bufblock = calloc(blocksize, 1)) == NULL) return -ENOMEM;
memset(bufblock,0,blocksize);
for(i=0; i<blocknumbers-1; i++) {
XORblock(src+(blocksize*i),bufblock,bufblock,blocksize);
- diffuse((unsigned char *) bufblock, (unsigned char *) bufblock, blocksize);
+ if(diffuse(bufblock, bufblock, blocksize, hash_id))
+ goto out;
}
XORblock(src + blocksize * i, bufblock, dst, blocksize);
-
- free(bufblock);
+ r = 0;
+out:
+ free(bufblock);
return 0;
}
*/
/*
- * AF_split operates on src and produces information splitted data in
+ * AF_split operates on src and produces information splitted data in
* dst. src is assumed to be of the length blocksize. The data stripe
- * dst points to must be captable of storing blocksize*blocknumbers.
+ * dst points to must be captable of storing blocksize*blocknumbers.
* blocknumbers is the data multiplication factor.
*
- * AF_merge does just the opposite: reproduces the information stored in
- * src of the length blocksize*blocknumbers into dst of the length
+ * AF_merge does just the opposite: reproduces the information stored in
+ * src of the length blocksize*blocknumbers into dst of the length
* blocksize.
*
* On error, both functions return -1, 0 otherwise.
- */
+ */
-int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers);
-int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers);
+int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
+int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
#endif
header->keyBytes=mk->keyLength;
r = getRandom(header->mkDigestSalt,LUKS_SALTSIZE);
- if(r < 0) return r;
+ if(r < 0) {
+ set_error( _("Cannot create LUKS header: reading random salt failed."));
+ return r;
+ }
/* Compute master key digest */
header->mkDigestIterations = LUKS_MKD_ITER;
- PBKDF2_HMAC_SHA1(mk->key,mk->keyLength,
- header->mkDigestSalt,LUKS_SALTSIZE,
- header->mkDigestIterations,
- header->mkDigest,LUKS_DIGESTSIZE);
+ r = PBKDF2_HMAC(header->hashSpec,mk->key,mk->keyLength,
+ header->mkDigestSalt,LUKS_SALTSIZE,
+ header->mkDigestIterations,
+ header->mkDigest,LUKS_DIGESTSIZE);
+ if(r < 0) {
+ set_error( _("Cannot create LUKS header: header digest failed (using hash %s)."), header->hashSpec);
+ return r;
+ }
currentSector = round_up_modulo(LUKS_PHDR_SIZE, alignSectors);
for(i = 0; i < LUKS_NUMKEYS; ++i) {
// assert((mk->keyLength % TWOFISH_BLOCKSIZE) == 0); FIXME
- PBKDF2_HMAC_SHA1(password,passwordLen,
- hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
- hdr->keyblock[keyIndex].passwordIterations,
- derivedKey, hdr->keyBytes);
+ r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
+ hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
+ hdr->keyblock[keyIndex].passwordIterations,
+ derivedKey, hdr->keyBytes);
+ if(r < 0) return r;
+
/*
* AF splitting, the masterkey stored in mk->key is splitted to AfMK
*/
AFEKSize = hdr->keyblock[keyIndex].stripes*mk->keyLength;
AfKey = (char *)malloc(AFEKSize);
if(AfKey == NULL) return -ENOMEM;
-
- r = AF_split(mk->key,AfKey,mk->keyLength,hdr->keyblock[keyIndex].stripes);
+
+ r = AF_split(mk->key,AfKey,mk->keyLength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
if(r < 0) goto out;
/* Encryption via dm */
AFEKSize = hdr->keyblock[keyIndex].stripes*mk->keyLength;
AfKey = (char *)malloc(AFEKSize);
if(AfKey == NULL) return -ENOMEM;
-
- PBKDF2_HMAC_SHA1(password,passwordLen,
- hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
- hdr->keyblock[keyIndex].passwordIterations,
- derivedKey, hdr->keyBytes);
+
+ r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
+ hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
+ hdr->keyblock[keyIndex].passwordIterations,
+ derivedKey, hdr->keyBytes);
+ if(r < 0) goto out;
r = LUKS_decrypt_from_storage(AfKey,
AFEKSize,
device,
hdr->keyblock[keyIndex].keyMaterialOffset,
backend);
- if(r < 0) {
- if(!get_error())
- set_error("Failed to read from key storage");
- goto out;
- }
+ if(r < 0) goto out;
+
+ r = AF_merge(AfKey,mk->key,mk->keyLength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
+ if(r < 0) goto out;
- r = AF_merge(AfKey,mk->key,mk->keyLength,hdr->keyblock[keyIndex].stripes);
+ r = PBKDF2_HMAC(hdr->hashSpec,mk->key,mk->keyLength,
+ hdr->mkDigestSalt,LUKS_SALTSIZE,
+ hdr->mkDigestIterations,
+ checkHashBuf,LUKS_DIGESTSIZE);
if(r < 0) goto out;
-
- PBKDF2_HMAC_SHA1(mk->key,mk->keyLength,
- hdr->mkDigestSalt,LUKS_SALTSIZE,
- hdr->mkDigestIterations,
- checkHashBuf,LUKS_DIGESTSIZE);
r = (memcmp(checkHashBuf,hdr->mkDigest, LUKS_DIGESTSIZE) == 0)?0:-EPERM;
out:
free(AfKey);
+
+ if( r < 0 && !get_error())
+ set_error("Failed to read from key storage.");
+
return r;
}
int LUKS_benchmarkt_iterations()
{
- return PBKDF2_performance_check()/2;
+ unsigned int count;
+ char *hash = "sha1";
+
+ if (PBKDF2_performance_check(hash, &count) < 0) {
+ set_error(_("Not compatible options (using hash algorithm %s)."), hash);
+ return -EINVAL;
+ }
+
+ return count/2;
}
int LUKS_device_ready(const char *device, int mode)
-/*
- * Copyright 2004 Clemens Fruhwirth <clemens@endorphin.org>
- * Implementation of PBKDF2-HMAC-SHA1 according to RFC 2898.
+/* Implementation of Password-Based Cryptography as per PKCS#5
+ * Copyright (C) 2002,2003 Simon Josefsson
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * LUKS code
+ * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
+ * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
+ * This file 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.
*
- * This program is distributed in the hope that it will be useful,
+ * This file 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 Library General Public License for more details.
+ * 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 file; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-
+
#include <netinet/in.h>
#include <errno.h>
#include <signal.h>
+#include <alloca.h>
#include <sys/time.h>
+#include <gcrypt.h>
-#include "hmac_sha1.h"
-#include "XORblock.h"
-#include <assert.h>
+static volatile unsigned int __PBKDF2_global_j = 0;
+static volatile unsigned int __PBKDF2_performance = 0;
-static unsigned int *__PBKDF2_global_j;
-static unsigned int __PBKDF2_performance=0;
+static int init_crypto(void)
+{
+ if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
+ if (!gcry_check_version (GCRYPT_VERSION))
+ return -ENOSYS;
+ gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+ gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
+ gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ }
-void PBKDF2_HMAC_SHA1(const char *password, size_t passwordLen,
- const char *salt, size_t saltLen, unsigned int iterations,
- char *dKey, size_t dKeyLen)
+ return 0;
+}
+
+/*
+ * 5.2 PBKDF2
+ *
+ * PBKDF2 applies a pseudorandom function (see Appendix B.1 for an
+ * example) to derive keys. The length of the derived key is essentially
+ * unbounded. (However, the maximum effective search space for the
+ * derived key may be limited by the structure of the underlying
+ * pseudorandom function. See Appendix B.1 for further discussion.)
+ * PBKDF2 is recommended for new applications.
+ *
+ * PBKDF2 (P, S, c, dkLen)
+ *
+ * Options: PRF underlying pseudorandom function (hLen
+ * denotes the length in octets of the
+ * pseudorandom function output)
+ *
+ * Input: P password, an octet string (ASCII or UTF-8)
+ * S salt, an octet string
+ * c iteration count, a positive integer
+ * dkLen intended length in octets of the derived
+ * key, a positive integer, at most
+ * (2^32 - 1) * hLen
+ *
+ * Output: DK derived key, a dkLen-octet string
+ */
+
+#define MAX_PRF_BLOCK_LEN 80
+
+static int pkcs5_pbkdf2(const char *hash,
+ const char *P, size_t Plen,
+ const char *S, size_t Slen,
+ unsigned int c, unsigned int dkLen,
+ char *DK, int perfcheck)
{
- uint32_t i=1;
- unsigned int j;
- /* U_n is the buffer for U_n values */
- unsigned char U_n[SHA1_DIGEST_SIZE];
- /* F_buf is the XOR buffer for F function */
- char F_buf[SHA1_DIGEST_SIZE];
- hmac_ctx templateCtx;
-
- /* We need a global pointer for signal handlers */
- __PBKDF2_global_j = &j;
-
- /* Make a template context initialized with password as key */
- hmac_sha_begin(&templateCtx);
- hmac_sha_key((unsigned char *) password,passwordLen,&templateCtx);
-
-#define HMAC_REINIT(__ctx) memcpy(&__ctx,&templateCtx,sizeof(__ctx))
-
- /* The first hash iteration is done different, therefor
- we reduce iterations to conveniently use it as a loop
- counter */
- assert(iterations != 0);
- iterations--;
-
- while(dKeyLen > 0) {
- hmac_ctx ctx;
- uint32_t iNetworkOrdered;
- unsigned int blocksize = dKeyLen<SHA1_DIGEST_SIZE?dKeyLen:SHA1_DIGEST_SIZE;
-
- j=iterations;
- HMAC_REINIT(ctx);
- // U_1 hashing
- hmac_sha_data((unsigned char *) salt,saltLen,&ctx);
- iNetworkOrdered = htonl(i);
- hmac_sha_data((unsigned char *)&iNetworkOrdered, sizeof(uint32_t), &ctx);
- hmac_sha_end(U_n, SHA1_DIGEST_SIZE, &ctx);
- memcpy(F_buf, U_n, SHA1_DIGEST_SIZE);
-
- // U_n hashing
- while(j--) {
- HMAC_REINIT(ctx);
- hmac_sha_data(U_n,SHA1_DIGEST_SIZE, &ctx);
- hmac_sha_end(U_n,SHA1_DIGEST_SIZE, &ctx);
- XORblock(F_buf,(char*) U_n,F_buf,SHA1_DIGEST_SIZE);
+ gcry_md_hd_t prf;
+ gcry_error_t err;
+ char U[MAX_PRF_BLOCK_LEN];
+ char T[MAX_PRF_BLOCK_LEN];
+ int PRF;
+ unsigned int u;
+ unsigned int hLen;
+ unsigned int l;
+ unsigned int r;
+ int rc;
+ unsigned char *p;
+ int i;
+ int k;
+
+ if (init_crypto())
+ return -ENOSYS;
+
+ PRF = gcry_md_map_name(hash);
+ if (PRF == 0)
+ return -EINVAL;
+
+ hLen = gcry_md_get_algo_dlen(PRF);
+ if (hLen == 0 || hLen > MAX_PRF_BLOCK_LEN)
+ return -EINVAL;
+
+ if (c == 0)
+ return -EINVAL;
+
+ if (dkLen == 0)
+ return -EINVAL;
+
+ /*
+ *
+ * Steps:
+ *
+ * 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
+ * stop.
+ */
+
+ if (dkLen > 4294967295U)
+ return -EINVAL;
+
+ /*
+ * 2. Let l be the number of hLen-octet blocks in the derived key,
+ * rounding up, and let r be the number of octets in the last
+ * block:
+ *
+ * l = CEIL (dkLen / hLen) ,
+ * r = dkLen - (l - 1) * hLen .
+ *
+ * Here, CEIL (x) is the "ceiling" function, i.e. the smallest
+ * integer greater than, or equal to, x.
+ */
+
+ l = dkLen / hLen;
+ if (dkLen % hLen)
+ l++;
+ r = dkLen - (l - 1) * hLen;
+
+ /*
+ * 3. For each block of the derived key apply the function F defined
+ * below to the password P, the salt S, the iteration count c, and
+ * the block index to compute the block:
+ *
+ * T_1 = F (P, S, c, 1) ,
+ * T_2 = F (P, S, c, 2) ,
+ * ...
+ * T_l = F (P, S, c, l) ,
+ *
+ * where the function F is defined as the exclusive-or sum of the
+ * first c iterates of the underlying pseudorandom function PRF
+ * applied to the password P and the concatenation of the salt S
+ * and the block index i:
+ *
+ * F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
+ *
+ * where
+ *
+ * U_1 = PRF (P, S || INT (i)) ,
+ * U_2 = PRF (P, U_1) ,
+ * ...
+ * U_c = PRF (P, U_{c-1}) .
+ *
+ * Here, INT (i) is a four-octet encoding of the integer i, most
+ * significant octet first.
+ *
+ * 4. Concatenate the blocks and extract the first dkLen octets to
+ * produce a derived key DK:
+ *
+ * DK = T_1 || T_2 || ... || T_l<0..r-1>
+ *
+ * 5. Output the derived key DK.
+ *
+ * Note. The construction of the function F follows a "belt-and-
+ * suspenders" approach. The iterates U_i are computed recursively to
+ * remove a degree of parallelism from an opponent; they are exclusive-
+ * ored together to reduce concerns about the recursion degenerating
+ * into a small set of values.
+ *
+ */
+
+ err = gcry_md_open(&prf, PRF, GCRY_MD_FLAG_HMAC);
+ if (err)
+ return -EINVAL;
+
+ for (i = 1; (uint) i <= l; i++) {
+ memset(T, 0, hLen);
+
+ for (u = 1; u <= c ; u++) {
+ gcry_md_reset(prf);
+
+ rc = gcry_md_setkey(prf, P, Plen);
+ if (rc)
+ return -EINVAL;
+
+ if (u == 1) {
+ char *tmp;
+ size_t tmplen = Slen + 4;
+
+ tmp = alloca(tmplen);
+ if (tmp == NULL)
+ return -ENOMEM;
+
+ memcpy(tmp, S, Slen);
+ tmp[Slen + 0] = (i & 0xff000000) >> 24;
+ tmp[Slen + 1] = (i & 0x00ff0000) >> 16;
+ tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
+ tmp[Slen + 3] = (i & 0x000000ff) >> 0;
+
+ gcry_md_write(prf, tmp, tmplen);
+ } else {
+ gcry_md_write(prf, U, hLen);
+ }
+
+ p = gcry_md_read(prf, PRF);
+ if (p == NULL)
+ return -EINVAL;
+
+ memcpy(U, p, hLen);
+
+ for (k = 0; (uint) k < hLen; k++)
+ T[k] ^= U[k];
+
+ if (perfcheck && __PBKDF2_performance)
+ goto out;
+
+ if (perfcheck)
+ __PBKDF2_global_j--;
}
- memcpy(dKey,F_buf,blocksize);
- dKey+=blocksize; dKeyLen-=blocksize; i++;
+
+ memcpy(DK + (i - 1) * hLen, T, (uint) i == l ? r : hLen);
}
-#undef HMAC_REINIT
+out:
+ gcry_md_close(prf);
+
+ return 0;
+}
+
+int PBKDF2_HMAC(const char *hash,
+ const char *password, size_t passwordLen,
+ const char *salt, size_t saltLen, unsigned int iterations,
+ char *dKey, size_t dKeyLen)
+{
+ return pkcs5_pbkdf2(hash, password, passwordLen, salt, saltLen,
+ iterations, (unsigned int)dKeyLen, dKey, 0);
+}
+
+int PBKDF2_HMAC_ready(const char *hash)
+{
+ int hash_id = gcry_md_map_name(hash);
+
+ if (!hash_id)
+ return -EINVAL;
+
+ /* Used hash must have at least 160 bits */
+ if (gcry_md_get_algo_dlen(hash_id) < 20)
+ return -EINVAL;
+
+ return 1;
}
static void sigvtalarm(int foo)
{
- __PBKDF2_performance = ~(0U) - *__PBKDF2_global_j;
- *__PBKDF2_global_j = 0;
+ __PBKDF2_performance = ~(0U) - __PBKDF2_global_j;
+ __PBKDF2_global_j = 0;
}
-unsigned int PBKDF2_performance_check()
+/* This code benchmarks PBKDF2 and returns iterations/second using wth specified hash */
+int PBKDF2_performance_check(const char *hash, unsigned int *iter)
{
- /* This code benchmarks PBKDF2 and returns
- iterations/second per SHA1_DIGEST_SIZE */
-
+ int r;
char buf;
struct itimerval it;
- if(__PBKDF2_performance != 0) return __PBKDF2_performance;
+ if(__PBKDF2_performance != 0) {
+ *iter = __PBKDF2_performance;
+ return 0;
+ }
+
+ if (!PBKDF2_HMAC_ready(hash))
+ return -EINVAL;
signal(SIGVTALRM,sigvtalarm);
it.it_interval.tv_usec = 0;
it.it_value.tv_usec = 0;
it.it_value.tv_sec = 1;
if (setitimer (ITIMER_VIRTUAL, &it, NULL) < 0)
- return 0;
+ return -EINVAL;
+
+ r = pkcs5_pbkdf2(hash, "foo", 3, "bar", 3, ~(0U), 1, &buf, 1);
+
+ __PBKDF2_global_j = 0;
- PBKDF2_HMAC_SHA1("foo", 3,
- "bar", 3, ~(0U),
- &buf, 1);
-
- return __PBKDF2_performance;
+ *iter = __PBKDF2_performance;
+ return r;
}
/* */
-void PBKDF2_HMAC_SHA1(const char *password, size_t passwordLen,
- const char *salt, size_t saltLen, unsigned int iterations,
- char *dKey, size_t dKeyLen);
+int PBKDF2_HMAC(const char *hash,
+ const char *password, size_t passwordLen,
+ const char *salt, size_t saltLen, unsigned int iterations,
+ char *dKey, size_t dKeyLen);
-unsigned int PBKDF2_performance_check();
+
+int PBKDF2_performance_check(const char *hash, unsigned int *iter);
+int PBKDF2_HMAC_ready(const char *hash);
#endif