Add HMAC and PBKDF2
This commit is contained in:
parent
37f7911f01
commit
6e7d9194d1
6 changed files with 302 additions and 8 deletions
|
@ -624,4 +624,9 @@ crypto_mod_SOURCES = lib/crypto.c
|
|||
crypto_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
crypto_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
||||
pkglib_MODULES += pbkdf2.mod
|
||||
pbkdf2_mod_SOURCES = lib/pbkdf2.c
|
||||
pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
||||
include $(srcdir)/conf/gcry.mk
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
#*
|
||||
#* GRUB -- GRand Unified Bootloader
|
||||
#* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
#*
|
||||
#* GRUB is free software: you can redistribute it and/or modify
|
||||
#* it under the terms of the GNU General Public License as published by
|
||||
#* the Free Software Foundation, either version 3 of the License, or
|
||||
#* (at your option) any later version.
|
||||
#*
|
||||
#* GRUB 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 General Public License for more details.
|
||||
#*
|
||||
#* You should have received a copy of the GNU General Public License
|
||||
#* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
#*
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
@ -26,9 +44,12 @@ conf = open (os.path.join (outdir, "conf", "gcry.rmk"), "w")
|
|||
conf.write ("# -*- makefile -*-\n\n")
|
||||
chlog = ""
|
||||
|
||||
mdblocksizes = {"_gcry_digest_spec_crc32" : 1,
|
||||
"_gcry_digest_spec_crc32_rfc1510" : 1,
|
||||
"_gcry_digest_spec_crc24_rfc2440" : 1,
|
||||
# Strictly speaking CRC32/CRC24 work on bytes so this value should be 1
|
||||
# But libgcrypt uses 64. Let's keep the value for compatibility. Since
|
||||
# noone uses CRC24/CRC32 for HMAC this is no problem
|
||||
mdblocksizes = {"_gcry_digest_spec_crc32" : 64,
|
||||
"_gcry_digest_spec_crc32_rfc1510" : 64,
|
||||
"_gcry_digest_spec_crc24_rfc2440" : 64,
|
||||
"_gcry_digest_spec_md4" : 64,
|
||||
"_gcry_digest_spec_md5" : 64,
|
||||
"_gcry_digest_spec_rmd160" : 64,
|
||||
|
|
|
@ -64,7 +64,7 @@ typedef union {
|
|||
static inline void
|
||||
grub_assert_real (const char *file, int line, int cond)
|
||||
{
|
||||
if (cond)
|
||||
if (!cond)
|
||||
grub_fatal ("Assertion failed at %s:%d\n", file, line);
|
||||
}
|
||||
|
||||
|
|
|
@ -166,11 +166,15 @@ typedef struct gcry_md_spec
|
|||
struct gcry_md_spec *next;
|
||||
} gcry_md_spec_t;
|
||||
|
||||
typedef struct grub_crypto_cipher_handle
|
||||
struct grub_crypto_cipher_handle
|
||||
{
|
||||
const struct gcry_cipher_spec *cipher;
|
||||
char ctx[0];
|
||||
} *grub_crypto_cipher_handle_t;
|
||||
};
|
||||
|
||||
typedef struct grub_crypto_cipher_handle *grub_crypto_cipher_handle_t;
|
||||
|
||||
struct grub_crypto_hmac_handle;
|
||||
|
||||
const gcry_cipher_spec_t *
|
||||
grub_crypto_lookup_cipher_by_name (const char *name);
|
||||
|
@ -213,7 +217,7 @@ grub_md_register (gcry_md_spec_t *digest);
|
|||
void
|
||||
grub_md_unregister (gcry_md_spec_t *cipher);
|
||||
void
|
||||
grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in,
|
||||
grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
|
||||
grub_size_t inlen);
|
||||
const gcry_md_spec_t *
|
||||
grub_crypto_lookup_md_by_name (const char *name);
|
||||
|
@ -223,7 +227,35 @@ grub_crypto_gcry_error (gcry_err_code_t in);
|
|||
|
||||
void grub_burn_stack (grub_size_t size);
|
||||
|
||||
struct grub_crypto_hmac_handle *
|
||||
grub_crypto_hmac_init (const struct gcry_md_spec *md,
|
||||
const void *key, grub_size_t keylen);
|
||||
void
|
||||
grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data,
|
||||
grub_size_t datalen);
|
||||
gcry_err_code_t
|
||||
grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out);
|
||||
|
||||
gcry_err_code_t
|
||||
grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
|
||||
const void *key, grub_size_t keylen,
|
||||
void *data, grub_size_t datalen, void *out);
|
||||
|
||||
extern gcry_md_spec_t _gcry_digest_spec_md5;
|
||||
#define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5)
|
||||
#define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1)
|
||||
|
||||
/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant
|
||||
of digest supplied by MD. Inputs are the password P of length PLEN,
|
||||
the salt S of length SLEN, the iteration counter C (> 0), and the
|
||||
desired derived output length DKLEN. Output buffer is DK which
|
||||
must have room for at least DKLEN octets. The output buffer will
|
||||
be filled with the derived data. */
|
||||
gcry_err_code_t
|
||||
grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
|
||||
const grub_uint8_t *P, grub_size_t Plen,
|
||||
const grub_uint8_t *S, grub_size_t Slen,
|
||||
unsigned int c,
|
||||
grub_uint8_t *DK, grub_size_t dkLen);
|
||||
|
||||
#endif
|
||||
|
|
137
lib/crypto.c
137
lib/crypto.c
|
@ -21,6 +21,13 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
struct grub_crypto_hmac_handle
|
||||
{
|
||||
const struct gcry_md_spec *md;
|
||||
void *ctx;
|
||||
void *opad;
|
||||
};
|
||||
|
||||
static gcry_cipher_spec_t *grub_ciphers = NULL;
|
||||
static gcry_md_spec_t *grub_digests = NULL;
|
||||
|
||||
|
@ -69,7 +76,7 @@ grub_md_unregister (gcry_md_spec_t *cipher)
|
|||
}
|
||||
|
||||
void
|
||||
grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in,
|
||||
grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
|
||||
grub_size_t inlen)
|
||||
{
|
||||
grub_uint8_t ctx[hash->contextsize];
|
||||
|
@ -228,6 +235,134 @@ grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher,
|
|||
return GPG_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Based on gcry/cipher/md.c. */
|
||||
struct grub_crypto_hmac_handle *
|
||||
grub_crypto_hmac_init (const struct gcry_md_spec *md,
|
||||
const void *key, grub_size_t keylen)
|
||||
{
|
||||
grub_uint8_t *helpkey = NULL;
|
||||
grub_uint8_t *ipad = NULL, *opad = NULL;
|
||||
void *ctx = NULL;
|
||||
struct grub_crypto_hmac_handle *ret = NULL;
|
||||
unsigned i;
|
||||
|
||||
if (md->mdlen > md->blocksize)
|
||||
return NULL;
|
||||
|
||||
ctx = grub_malloc (md->contextsize);
|
||||
if (!ctx)
|
||||
goto err;
|
||||
|
||||
if ( keylen > md->blocksize )
|
||||
{
|
||||
helpkey = grub_malloc (md->mdlen);
|
||||
if (!helpkey)
|
||||
goto err;
|
||||
grub_crypto_hash (md, helpkey, key, keylen);
|
||||
|
||||
key = helpkey;
|
||||
keylen = md->mdlen;
|
||||
}
|
||||
|
||||
ipad = grub_zalloc (md->blocksize);
|
||||
if (!ipad)
|
||||
goto err;
|
||||
|
||||
opad = grub_zalloc (md->blocksize);
|
||||
if (!opad)
|
||||
goto err;
|
||||
|
||||
grub_memcpy ( ipad, key, keylen );
|
||||
grub_memcpy ( opad, key, keylen );
|
||||
for (i=0; i < md->blocksize; i++ )
|
||||
{
|
||||
ipad[i] ^= 0x36;
|
||||
opad[i] ^= 0x5c;
|
||||
}
|
||||
grub_free (helpkey);
|
||||
helpkey = NULL;
|
||||
|
||||
md->init (ctx);
|
||||
|
||||
md->write (ctx, ipad, md->blocksize); /* inner pad */
|
||||
grub_memset (ipad, 0, md->blocksize);
|
||||
grub_free (ipad);
|
||||
ipad = NULL;
|
||||
|
||||
ret = grub_malloc (sizeof (*ret));
|
||||
if (!ret)
|
||||
goto err;
|
||||
|
||||
ret->md = md;
|
||||
ret->ctx = ctx;
|
||||
ret->opad = opad;
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
grub_free (helpkey);
|
||||
grub_free (ctx);
|
||||
grub_free (ipad);
|
||||
grub_free (opad);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data,
|
||||
grub_size_t datalen)
|
||||
{
|
||||
hnd->md->write (hnd->ctx, data, datalen);
|
||||
}
|
||||
|
||||
gcry_err_code_t
|
||||
grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out)
|
||||
{
|
||||
grub_uint8_t *p;
|
||||
grub_uint8_t *ctx2;
|
||||
|
||||
ctx2 = grub_malloc (hnd->md->contextsize);
|
||||
if (!ctx2)
|
||||
return GPG_ERR_OUT_OF_MEMORY;
|
||||
|
||||
hnd->md->final (hnd->ctx);
|
||||
hnd->md->read (hnd->ctx);
|
||||
p = hnd->md->read (hnd->ctx);
|
||||
|
||||
hnd->md->init (ctx2);
|
||||
hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize);
|
||||
hnd->md->write (ctx2, p, hnd->md->mdlen);
|
||||
hnd->md->final (ctx2);
|
||||
grub_memset (hnd->opad, 0, hnd->md->blocksize);
|
||||
grub_free (hnd->opad);
|
||||
grub_memset (hnd->ctx, 0, hnd->md->contextsize);
|
||||
grub_free (hnd->ctx);
|
||||
|
||||
grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen);
|
||||
grub_memset (ctx2, 0, hnd->md->contextsize);
|
||||
grub_free (ctx2);
|
||||
|
||||
grub_memset (hnd, 0, sizeof (*hnd));
|
||||
grub_free (hnd);
|
||||
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
gcry_err_code_t
|
||||
grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
|
||||
const void *key, grub_size_t keylen,
|
||||
void *data, grub_size_t datalen, void *out)
|
||||
{
|
||||
struct grub_crypto_hmac_handle *hnd;
|
||||
|
||||
hnd = grub_crypto_hmac_init (md, key, keylen);
|
||||
if (!hnd)
|
||||
return GPG_ERR_OUT_OF_MEMORY;
|
||||
|
||||
grub_crypto_hmac_write (hnd, data, datalen);
|
||||
return grub_crypto_hmac_fini (hnd, out);
|
||||
}
|
||||
|
||||
|
||||
grub_err_t
|
||||
grub_crypto_gcry_error (gcry_err_code_t in)
|
||||
{
|
||||
|
|
101
lib/pbkdf2.c
Normal file
101
lib/pbkdf2.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* gc-pbkdf2-sha1.c --- Password-Based Key Derivation Function a'la PKCS#5
|
||||
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Written by Simon Josefsson. */
|
||||
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant
|
||||
of digest supplied by MD. Inputs are the password P of length PLEN,
|
||||
the salt S of length SLEN, the iteration counter C (> 0), and the
|
||||
desired derived output length DKLEN. Output buffer is DK which
|
||||
must have room for at least DKLEN octets. The output buffer will
|
||||
be filled with the derived data. */
|
||||
gcry_err_code_t
|
||||
grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
|
||||
const grub_uint8_t *P, grub_size_t Plen,
|
||||
const grub_uint8_t *S, grub_size_t Slen,
|
||||
unsigned int c,
|
||||
grub_uint8_t *DK, grub_size_t dkLen)
|
||||
{
|
||||
unsigned int hLen = md->mdlen;
|
||||
grub_uint8_t U[md->mdlen];
|
||||
grub_uint8_t T[md->mdlen];
|
||||
unsigned int u;
|
||||
unsigned int l;
|
||||
unsigned int r;
|
||||
unsigned int i;
|
||||
unsigned int k;
|
||||
gcry_err_code_t rc;
|
||||
grub_uint8_t *tmp;
|
||||
grub_size_t tmplen = Slen + 4;
|
||||
|
||||
if (c == 0)
|
||||
return GPG_ERR_INV_ARG;
|
||||
|
||||
if (dkLen == 0)
|
||||
return GPG_ERR_INV_ARG;
|
||||
|
||||
if (dkLen > 4294967295U)
|
||||
return GPG_ERR_INV_ARG;
|
||||
|
||||
l = ((dkLen - 1) / hLen) + 1;
|
||||
r = dkLen - (l - 1) * hLen;
|
||||
|
||||
tmp = grub_malloc (tmplen);
|
||||
if (tmp == NULL)
|
||||
return GPG_ERR_OUT_OF_MEMORY;
|
||||
|
||||
grub_memcpy (tmp, S, Slen);
|
||||
|
||||
for (i = 1; i <= l; i++)
|
||||
{
|
||||
grub_memset (T, 0, hLen);
|
||||
|
||||
for (u = 1; u <= c; u++)
|
||||
{
|
||||
if (u == 1)
|
||||
{
|
||||
tmp[Slen + 0] = (i & 0xff000000) >> 24;
|
||||
tmp[Slen + 1] = (i & 0x00ff0000) >> 16;
|
||||
tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
|
||||
tmp[Slen + 3] = (i & 0x000000ff) >> 0;
|
||||
|
||||
rc = grub_crypto_hmac_buffer (md, P, Plen, tmp, tmplen, U);
|
||||
}
|
||||
else
|
||||
rc = grub_crypto_hmac_buffer (md, P, Plen, U, hLen, U);
|
||||
|
||||
if (rc != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
grub_free (tmp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (k = 0; k < hLen; k++)
|
||||
T[k] ^= U[k];
|
||||
}
|
||||
|
||||
grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
|
||||
}
|
||||
|
||||
grub_free (tmp);
|
||||
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
Loading…
Reference in a new issue