summaryrefslogtreecommitdiff
path: root/cipher/scrypt.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2013-04-05 12:23:41 +0200
committerWerner Koch <wk@gnupg.org>2013-04-05 12:24:06 +0200
commitf23a068bcb6ec9788710698578d8be0a2a006dbc (patch)
tree16640fd3ce5f8fd358752ce4ed57667f0519ea0d /cipher/scrypt.c
parent855b1a8f81b5a3b5b31d0c3c303675425f58a5af (diff)
downloadlibgcrypt-f23a068bcb6ec9788710698578d8be0a2a006dbc.tar.gz
Add test case for SCRYPT and rework the code.
* tests/t-kdf.c (check_scrypt): New. (main): Call new test. * configure.ac: Support disabling of the scrypt algorithm. Make KDF enabling similar to the other algorithm classes. Disable scrypt if we don't have a 64 bit type. * cipher/memxor.c, cipher/memxor.h: Remove. * cipher/scrypt.h: Remove. * cipher/kdf-internal.h: New. * cipher/Makefile.am: Remove files. Add new file. Move scrypt.c to EXTRA_libcipher_la_SOURCES. (GCRYPT_MODULES): Add GCRYPT_KDFS. * src/gcrypt.h.in (GCRY_KDF_SCRYPT): Change value. * cipher/kdf.c (pkdf2): Rename to _gcry_kdf_pkdf2. (_gcry_kdf_pkdf2): Don't bail out for SALTLEN==0. (gcry_kdf_derive): Allow for a passwordlen of zero for scrypt. Check for SALTLEN > 0 for GCRY_KDF_PBKDF2. Pass algo to _gcry_kdf_scrypt. (gcry_kdf_derive) [!USE_SCRYPT]: Return an error. * cipher/scrypt.c: Replace memxor.h by bufhelp.h. Replace scrypt.h by kdf-internal.h. Enable code only if HAVE_U64_TYPEDEF is defined. Replace C99 types uint64_t, uint32_t, and uint8_t by libgcrypt types. (_SALSA20_INPUT_LENGTH): Remove underscore from identifier. (_scryptBlockMix): Replace memxor by buf_xor. (_gcry_kdf_scrypt): Use gcry_malloc and gcry_free. Check for integer overflow. Add hack to support blocksize of 1 for tests. Return errors from calls to _gcry_kdf_pkdf2. * cipher/kdf.c (openpgp_s2k): Make static. -- This patch prepares the addition of more KDF functions, brings the code into Libgcrypt shape, adds a test case and makes the code more robust. For example, scrypt would have fail silently if Libgcrypt was not build with SHA256 support. Also fixed symbol naming for systems without a visibility support. Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'cipher/scrypt.c')
-rw-r--r--cipher/scrypt.c276
1 files changed, 169 insertions, 107 deletions
diff --git a/cipher/scrypt.c b/cipher/scrypt.c
index 45ab4b31..06196d62 100644
--- a/cipher/scrypt.c
+++ b/cipher/scrypt.c
@@ -1,6 +1,22 @@
/* scrypt.c - Scrypt password-based key derivation function.
+ * Copyright (C) 2012 Simon Josefsson
+ * Copyright (C) 2013 Christian Grothoff
+ * 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 <http://www.gnu.org/licenses/>.
*/
/* Adapted from the nettle, low-level cryptographics library for
@@ -30,39 +46,40 @@
#include <string.h>
#include "g10lib.h"
-#include "scrypt.h"
-#include "memxor.h"
-
+#include "kdf-internal.h"
+#include "bufhelp.h"
+/* We really need a 64 bit type for this code. */
+#ifdef HAVE_U64_TYPEDEF
-#define _SALSA20_INPUT_LENGTH 16
+#define SALSA20_INPUT_LENGTH 16
#define ROTL32(n,x) (((x)<<(n)) | ((x)>>(32-(n))))
/* Reads a 64-bit integer, in network, big-endian, byte order */
#define READ_UINT64(p) \
-( (((uint64_t) (p)[0]) << 56) \
- | (((uint64_t) (p)[1]) << 48) \
- | (((uint64_t) (p)[2]) << 40) \
- | (((uint64_t) (p)[3]) << 32) \
- | (((uint64_t) (p)[4]) << 24) \
- | (((uint64_t) (p)[5]) << 16) \
- | (((uint64_t) (p)[6]) << 8) \
- | ((uint64_t) (p)[7]))
+( (((u64) (p)[0]) << 56) \
+ | (((u64) (p)[1]) << 48) \
+ | (((u64) (p)[2]) << 40) \
+ | (((u64) (p)[3]) << 32) \
+ | (((u64) (p)[4]) << 24) \
+ | (((u64) (p)[5]) << 16) \
+ | (((u64) (p)[6]) << 8) \
+ | ((u64) (p)[7]))
/* And the other, little-endian, byteorder */
#define LE_READ_UINT64(p) \
-( (((uint64_t) (p)[7]) << 56) \
- | (((uint64_t) (p)[6]) << 48) \
- | (((uint64_t) (p)[5]) << 40) \
- | (((uint64_t) (p)[4]) << 32) \
- | (((uint64_t) (p)[3]) << 24) \
- | (((uint64_t) (p)[2]) << 16) \
- | (((uint64_t) (p)[1]) << 8) \
- | ((uint64_t) (p)[0]))
+( (((u64) (p)[7]) << 56) \
+ | (((u64) (p)[6]) << 48) \
+ | (((u64) (p)[5]) << 40) \
+ | (((u64) (p)[4]) << 32) \
+ | (((u64) (p)[3]) << 24) \
+ | (((u64) (p)[2]) << 16) \
+ | (((u64) (p)[1]) << 8) \
+ | ((u64) (p)[0]))
@@ -83,9 +100,9 @@
static void
-_salsa20_core(uint32_t *dst, const uint32_t *src, unsigned rounds)
+_salsa20_core(u32 *dst, const u32 *src, unsigned rounds)
{
- uint32_t x[_SALSA20_INPUT_LENGTH];
+ u32 x[SALSA20_INPUT_LENGTH];
unsigned i;
assert ( (rounds & 1) == 0);
@@ -104,33 +121,36 @@ _salsa20_core(uint32_t *dst, const uint32_t *src, unsigned rounds)
QROUND(x[15], x[12], x[13], x[14]);
}
- for (i = 0; i < _SALSA20_INPUT_LENGTH; i++)
+ for (i = 0; i < SALSA20_INPUT_LENGTH; i++)
{
- uint32_t t = x[i] + src[i];
+ u32 t = x[i] + src[i];
dst[i] = LE_SWAP32 (t);
}
}
static void
-_scryptBlockMix (uint32_t r, uint8_t *B, uint8_t *tmp2)
+_scryptBlockMix (u32 r, unsigned char *B, unsigned char *tmp2)
{
- uint64_t i;
- uint8_t *X = tmp2;
- uint8_t *Y = tmp2 + 64;
+ u64 i;
+ unsigned char *X = tmp2;
+ unsigned char *Y = tmp2 + 64;
#if 0
- for (i = 0; i < 2 * r; i++)
+ if (r == 1)
{
- size_t j;
- printf ("B[%d]: ", i);
- for (j = 0; j < 64; j++)
- {
- if (j % 4 == 0)
- printf (" ");
- printf ("%02x", B[i * 64 + j]);
- }
- printf ("\n");
+ for (i = 0; i < 2 * r; i++)
+ {
+ size_t j;
+ printf ("B[%d] = ", (int)i);
+ for (j = 0; j < 64; j++)
+ {
+ if (j && !(j % 16))
+ printf ("\n ");
+ printf (" %02x", B[i * 64 + j]);
+ }
+ putchar ('\n');
+ }
}
#endif
@@ -141,10 +161,10 @@ _scryptBlockMix (uint32_t r, uint8_t *B, uint8_t *tmp2)
for (i = 0; i <= 2 * r - 1; i++)
{
/* T = X xor B[i] */
- memxor(X, &B[i * 64], 64);
+ buf_xor(X, X, &B[i * 64], 64);
/* X = Salsa (T) */
- _salsa20_core (X, X, 8);
+ _salsa20_core ((u32*)X, (u32*)X, 8);
/* Y[i] = X */
memcpy (&Y[i * 64], X, 64);
@@ -157,38 +177,43 @@ _scryptBlockMix (uint32_t r, uint8_t *B, uint8_t *tmp2)
}
#if 0
- for (i = 0; i < 2 * r; i++)
+ if (r==1)
{
- size_t j;
- printf ("B'[%d]: ", i);
- for (j = 0; j < 64; j++)
- {
- if (j % 4 == 0)
- printf (" ");
- printf ("%02x", B[i * 64 + j]);
- }
- printf ("\n");
+ for (i = 0; i < 2 * r; i++)
+ {
+ size_t j;
+ printf ("B'[%d] =", (int)i);
+ for (j = 0; j < 64; j++)
+ {
+ if (j && !(j % 16))
+ printf ("\n ");
+ printf (" %02x", B[i * 64 + j]);
+ }
+ putchar ('\n');
+ }
}
#endif
}
static void
-_scryptROMix (uint32_t r, uint8_t *B, uint64_t N,
- uint8_t *tmp1, uint8_t *tmp2)
+_scryptROMix (u32 r, unsigned char *B, u64 N,
+ unsigned char *tmp1, unsigned char *tmp2)
{
- uint8_t *X = B, *T = B;
- uint64_t i;
+ unsigned char *X = B, *T = B;
+ u64 i;
#if 0
- printf ("B: ");
- for (i = 0; i < 128 * r; i++)
+ if (r == 1)
{
- size_t j;
- if (i % 4 == 0)
- printf (" ");
- printf ("%02x", B[i]);
+ printf ("B = ");
+ for (i = 0; i < 128 * r; i++)
+ {
+ if (i && !(i % 16))
+ printf ("\n ");
+ printf (" %02x", B[i]);
+ }
+ putchar ('\n');
}
- printf ("\n");
#endif
/* for i = 0 to N - 1 do */
@@ -204,81 +229,118 @@ _scryptROMix (uint32_t r, uint8_t *B, uint64_t N,
/* for i = 0 to N - 1 do */
for (i = 0; i <= N - 1; i++)
{
- uint64_t j;
+ u64 j;
/* j = Integerify (X) mod N */
j = LE_READ_UINT64 (&X[128 * r - 64]) % N;
/* T = X xor V[j] */
- memxor (T, &tmp1[j * 128 * r], 128 * r);
+ buf_xor (T, T, &tmp1[j * 128 * r], 128 * r);
/* X = scryptBlockMix (T) */
_scryptBlockMix (r, T, tmp2);
}
#if 0
- printf ("B': ");
- for (i = 0; i < 128 * r; i++)
+ if (r == 1)
{
- size_t j;
- if (i % 4 == 0)
- printf (" ");
- printf ("%02x", B[i]);
+ printf ("B' =");
+ for (i = 0; i < 128 * r; i++)
+ {
+ if (i && !(i % 16))
+ printf ("\n ");
+ printf (" %02x", B[i]);
+ }
+ putchar ('\n');
}
- printf ("\n");
#endif
}
/**
*/
gcry_err_code_t
-scrypt (const uint8_t * passwd, size_t passwdlen,
- int subalgo,
- const uint8_t * salt, size_t saltlen,
- unsigned long iterations,
- size_t dkLen, uint8_t * DK)
+_gcry_kdf_scrypt (const unsigned char *passwd, size_t passwdlen,
+ int algo, int subalgo,
+ const unsigned char *salt, size_t saltlen,
+ unsigned long iterations,
+ size_t dkLen, unsigned char *DK)
{
- /* XXX sanity-check parameters */
- uint64_t N = subalgo; /* CPU/memory cost paramter */
- uint32_t r = 8; /* block size, should be sane enough */
- uint32_t p = iterations; /* parallelization parameter */
-
- uint32_t i;
- uint8_t *B;
- uint8_t *tmp1;
- uint8_t *tmp2;
-
+ u64 N = subalgo; /* CPU/memory cost paramter. */
+ u32 r; /* Block size. */
+ u32 p = iterations; /* Parallelization parameter. */
+
+ gpg_err_code_t ec;
+ u32 i;
+ unsigned char *B = NULL;
+ unsigned char *tmp1 = NULL;
+ unsigned char *tmp2 = NULL;
+ size_t r128;
+ size_t nbytes;
+
+ if (subalgo < 1 || !iterations)
+ return GPG_ERR_INV_VALUE;
+
+ if (algo == GCRY_KDF_SCRYPT)
+ r = 8;
+ else if (algo == 41) /* Hack to allow the use of all test vectors. */
+ r = 1;
+ else
+ return GPG_ERR_UNKNOWN_ALGORITHM;
+
+ r128 = r * 128;
+ if (r128 / 128 != r)
+ return GPG_ERR_ENOMEM;
- B = malloc (p * 128 * r);
- if (B == NULL)
+ nbytes = p * r128;
+ if (r128 && nbytes / r128 != p)
return GPG_ERR_ENOMEM;
- tmp1 = malloc (N * 128 * r);
- if (tmp1 == NULL)
- {
- free (B);
+ nbytes = N * r128;
+ if (r128 && nbytes / r128 != N)
return GPG_ERR_ENOMEM;
- }
- tmp2 = malloc (64 + 128 * r);
- if (tmp2 == NULL)
- {
- free (B);
- free (tmp1);
+ nbytes = 64 + r128;
+ if (nbytes < r128)
return GPG_ERR_ENOMEM;
- }
- pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, salt, saltlen, 1 /* iterations */, p * 128 * r, B);
+ B = gcry_malloc (p * r128);
+ if (!B)
+ {
+ ec = gpg_err_code_from_syserror ();
+ goto leave;
+ }
- for (i = 0; i < p; i++)
- _scryptROMix (r, &B[i * 128 * r], N, tmp1, tmp2);
+ tmp1 = gcry_malloc (N * r128);
+ if (!tmp1)
+ {
+ ec = gpg_err_code_from_syserror ();
+ goto leave;
+ }
+
+ tmp2 = gcry_malloc (64 + r128);
+ if (!tmp2)
+ {
+ ec = gpg_err_code_from_syserror ();
+ goto leave;
+ }
- for (i = 0; i < p; i++)
- pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, B, p * 128 * r, 1 /* iterations */, dkLen, DK);
+ ec = _gcry_kdf_pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, salt, saltlen,
+ 1 /* iterations */, p * r128, B);
- free (tmp2);
- free (tmp1);
- free (B);
+ for (i = 0; !ec && i < p; i++)
+ _scryptROMix (r, &B[i * r128], N, tmp1, tmp2);
- return 0;
+ for (i = 0; !ec && i < p; i++)
+ ec = _gcry_kdf_pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, B, p * r128,
+ 1 /* iterations */, dkLen, DK);
+
+ leave:
+ gcry_free (tmp2);
+ gcry_free (tmp1);
+ gcry_free (B);
+
+ return ec;
}
+
+
+#endif /* HAVE_U64_TYPEDEF */