merge mainline into asprintf

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-01-20 07:36:17 +01:00
commit 2d49abe9e7
342 changed files with 14569 additions and 4699 deletions

View file

@ -24,6 +24,8 @@
last byte used in SRC. */
#include <grub/charset.h>
#include <grub/mm.h>
#include <grub/misc.h>
grub_ssize_t
grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
@ -114,3 +116,154 @@ grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
*srcend = src;
return p - dest;
}
/* Convert UCS-4 to UTF-8. */
char *
grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size)
{
grub_size_t remaining;
grub_uint32_t *ptr;
grub_size_t cnt = 0;
grub_uint8_t *ret, *dest;
remaining = size;
ptr = src;
while (remaining--)
{
grub_uint32_t code = *ptr++;
if (code <= 0x007F)
cnt++;
else if (code <= 0x07FF)
cnt += 2;
else if ((code >= 0xDC00 && code <= 0xDFFF)
|| (code >= 0xD800 && code <= 0xDBFF))
/* No surrogates in UCS-4... */
cnt++;
else
cnt += 3;
}
cnt++;
ret = grub_malloc (cnt);
if (!ret)
return 0;
dest = ret;
remaining = size;
ptr = src;
while (remaining--)
{
grub_uint32_t code = *ptr++;
if (code <= 0x007F)
*dest++ = code;
else if (code <= 0x07FF)
{
*dest++ = (code >> 6) | 0xC0;
*dest++ = (code & 0x3F) | 0x80;
}
else if ((code >= 0xDC00 && code <= 0xDFFF)
|| (code >= 0xD800 && code <= 0xDBFF))
{
/* No surrogates in UCS-4... */
*dest++ = '?';
}
else
{
*dest++ = (code >> 12) | 0xE0;
*dest++ = ((code >> 6) & 0x3F) | 0x80;
*dest++ = (code & 0x3F) | 0x80;
}
}
*dest = 0;
return (char *) ret;
}
int
grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize)
{
grub_uint32_t code = 0;
int count = 0;
while (srcsize)
{
grub_uint32_t c = *src++;
if (srcsize != (grub_size_t)-1)
srcsize--;
if (count)
{
if ((c & 0xc0) != 0x80)
{
/* invalid */
return 0;
}
else
{
code <<= 6;
code |= (c & 0x3f);
count--;
}
}
else
{
if (c == 0)
break;
if ((c & 0x80) == 0x00)
code = c;
else if ((c & 0xe0) == 0xc0)
{
count = 1;
code = c & 0x1f;
}
else if ((c & 0xf0) == 0xe0)
{
count = 2;
code = c & 0x0f;
}
else if ((c & 0xf8) == 0xf0)
{
count = 3;
code = c & 0x07;
}
else if ((c & 0xfc) == 0xf8)
{
count = 4;
code = c & 0x03;
}
else if ((c & 0xfe) == 0xfc)
{
count = 5;
code = c & 0x01;
}
else
return 0;
}
}
return 1;
}
int
grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
grub_uint32_t **last_position)
{
grub_size_t msg_len = grub_strlen (msg);
*unicode_msg = grub_malloc (grub_strlen (msg) * sizeof (grub_uint32_t));
if (!*unicode_msg)
{
grub_printf ("utf8_to_ucs4 ERROR1: %s", msg);
return -1;
}
msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len,
(grub_uint8_t *) msg, -1, 0);
*last_position = *unicode_msg + msg_len;
return msg_len;
}

View file

@ -1,7 +1,7 @@
/* kern/i386/datetime.c - x86 CMOS datetime function.
/* kern/cmos_datetime.c - CMOS datetime function.
*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
* Copyright (C) 2008,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
@ -18,7 +18,7 @@
*/
#include <grub/datetime.h>
#include <grub/i386/cmos.h>
#include <grub/cmos.h>
grub_err_t
grub_get_datetime (struct grub_datetime *datetime)

453
lib/crypto.c Normal file
View file

@ -0,0 +1,453 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
* 2007, 2008, 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/>.
*/
#include <grub/crypto.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/term.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;
void (*grub_crypto_autoload_hook) (const char *name) = NULL;
/* Based on libgcrypt-1.4.4/src/misc.c. */
void
grub_burn_stack (grub_size_t size)
{
char buf[64];
grub_memset (buf, 0, sizeof (buf));
if (size > sizeof (buf))
grub_burn_stack (size - sizeof (buf));
}
void
grub_cipher_register (gcry_cipher_spec_t *cipher)
{
cipher->next = grub_ciphers;
grub_ciphers = cipher;
}
void
grub_cipher_unregister (gcry_cipher_spec_t *cipher)
{
gcry_cipher_spec_t **ciph;
for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next))
if (*ciph == cipher)
{
*ciph = (*ciph)->next;
break;
}
}
void
grub_md_register (gcry_md_spec_t *digest)
{
digest->next = grub_digests;
grub_digests = digest;
}
void
grub_md_unregister (gcry_md_spec_t *cipher)
{
gcry_md_spec_t **ciph;
for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next))
if (*ciph == cipher)
{
*ciph = (*ciph)->next;
break;
}
}
void
grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
grub_size_t inlen)
{
grub_uint8_t ctx[hash->contextsize];
hash->init (&ctx);
hash->write (&ctx, in, inlen);
hash->final (&ctx);
grub_memcpy (out, hash->read (&ctx), hash->mdlen);
}
const gcry_md_spec_t *
grub_crypto_lookup_md_by_name (const char *name)
{
const gcry_md_spec_t *md;
int first = 1;
while (1)
{
for (md = grub_digests; md; md = md->next)
if (grub_strcasecmp (name, md->name) == 0)
return md;
if (grub_crypto_autoload_hook && first)
grub_crypto_autoload_hook (name);
else
return NULL;
first = 0;
}
}
const gcry_cipher_spec_t *
grub_crypto_lookup_cipher_by_name (const char *name)
{
const gcry_cipher_spec_t *ciph;
int first = 1;
while (1)
{
for (ciph = grub_ciphers; ciph; ciph = ciph->next)
{
const char **alias;
if (grub_strcasecmp (name, ciph->name) == 0)
return ciph;
if (!ciph->aliases)
continue;
for (alias = ciph->aliases; *alias; alias++)
if (grub_strcasecmp (name, *alias) == 0)
return ciph;
}
if (grub_crypto_autoload_hook && first)
grub_crypto_autoload_hook (name);
else
return NULL;
first = 0;
}
}
grub_crypto_cipher_handle_t
grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher)
{
grub_crypto_cipher_handle_t ret;
ret = grub_malloc (sizeof (*ret) + cipher->contextsize);
if (!ret)
return NULL;
ret->cipher = cipher;
return ret;
}
gcry_err_code_t
grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher,
const unsigned char *key,
unsigned keylen)
{
return cipher->cipher->setkey (cipher->ctx, key, keylen);
}
void
grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher)
{
grub_free (cipher);
}
void
grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size)
{
const grub_uint8_t *in1ptr = in1, *in2ptr = in2;
grub_uint8_t *outptr = out;
while (size--)
{
*outptr = *in1ptr ^ *in2ptr;
in1ptr++;
in2ptr++;
outptr++;
}
}
gcry_err_code_t
grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
void *out, void *in, grub_size_t size)
{
grub_uint8_t *inptr, *outptr, *end;
if (!cipher->cipher->decrypt)
return GPG_ERR_NOT_SUPPORTED;
if (size % cipher->cipher->blocksize != 0)
return GPG_ERR_INV_ARG;
end = (grub_uint8_t *) in + size;
for (inptr = in, outptr = out; inptr < end;
inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
return GPG_ERR_NO_ERROR;
}
gcry_err_code_t
grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
void *out, void *in, grub_size_t size)
{
grub_uint8_t *inptr, *outptr, *end;
if (!cipher->cipher->encrypt)
return GPG_ERR_NOT_SUPPORTED;
if (size % cipher->cipher->blocksize != 0)
return GPG_ERR_INV_ARG;
end = (grub_uint8_t *) in + size;
for (inptr = in, outptr = out; inptr < end;
inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
cipher->cipher->encrypt (cipher->ctx, outptr, inptr);
return GPG_ERR_NO_ERROR;
}
gcry_err_code_t
grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher,
void *out, void *in, grub_size_t size,
void *iv_in)
{
grub_uint8_t *inptr, *outptr, *end;
void *iv;
if (!cipher->cipher->decrypt)
return GPG_ERR_NOT_SUPPORTED;
if (size % cipher->cipher->blocksize != 0)
return GPG_ERR_INV_ARG;
end = (grub_uint8_t *) in + size;
iv = iv_in;
for (inptr = in, outptr = out; inptr < end;
inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
{
grub_crypto_xor (outptr, inptr, iv, cipher->cipher->blocksize);
cipher->cipher->encrypt (cipher->ctx, outptr, outptr);
iv = outptr;
}
grub_memcpy (iv_in, iv, cipher->cipher->blocksize);
return GPG_ERR_NO_ERROR;
}
gcry_err_code_t
grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher,
void *out, void *in, grub_size_t size,
void *iv)
{
grub_uint8_t *inptr, *outptr, *end;
grub_uint8_t ivt[cipher->cipher->blocksize];
if (!cipher->cipher->decrypt)
return GPG_ERR_NOT_SUPPORTED;
if (size % cipher->cipher->blocksize != 0)
return GPG_ERR_INV_ARG;
end = (grub_uint8_t *) in + size;
for (inptr = in, outptr = out; inptr < end;
inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
{
grub_memcpy (ivt, inptr, cipher->cipher->blocksize);
cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize);
grub_memcpy (iv, ivt, cipher->cipher->blocksize);
}
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)
{
if (in == GPG_ERR_NO_ERROR)
return GRUB_ERR_NONE;
return GRUB_ACCESS_DENIED;
}
int
grub_crypto_memcmp (const void *a, const void *b, grub_size_t n)
{
register grub_size_t counter = 0;
const grub_uint8_t *pa, *pb;
for (pa = a, pb = b; n; pa++, pb++, n--)
{
if (*pa != *pb)
counter++;
}
return !!counter;
}
#ifndef GRUB_MKPASSWD
int
grub_password_get (char buf[], unsigned buf_size)
{
unsigned cur_len = 0;
int key;
while (1)
{
key = GRUB_TERM_ASCII_CHAR (grub_getkey ());
if (key == '\n' || key == '\r')
break;
if (key == '\e')
{
cur_len = 0;
break;
}
if (key == '\b')
{
cur_len--;
continue;
}
if (!grub_isprint (key))
continue;
if (cur_len + 2 < buf_size)
buf[cur_len++] = key;
}
grub_memset (buf + cur_len, 0, buf_size - cur_len);
grub_putchar ('\n');
grub_refresh ();
return (key != '\e');
}
#endif

View file

@ -1,7 +1,7 @@
/* hexdump.c - hexdump function */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
* Copyright (C) 2008,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

View file

@ -0,0 +1,86 @@
/*
* 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/>.
*/
#ifndef GRUB_GCRY_WRAP_HEADER
#define GRUB_GCRY_WRAP_HEADER 1
#include <grub/types.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/dl.h>
#include <grub/crypto.h>
#define __GNU_LIBRARY__
#define DIM ARRAY_SIZE
typedef grub_uint64_t u64;
typedef grub_uint32_t u32;
typedef grub_uint16_t u16;
typedef grub_uint8_t byte;
typedef grub_size_t size_t;
#define U64_C(c) (c ## ULL)
#define _gcry_burn_stack grub_burn_stack
#define log_error(fmt, args...) grub_dprintf ("crypto", fmt, ## args)
#define PUBKEY_FLAG_NO_BLINDING (1 << 0)
#define CIPHER_INFO_NO_WEAK_KEY 1
#define HAVE_U64_TYPEDEF 1
typedef union {
int a;
short b;
char c[1];
long d;
#ifdef HAVE_U64_TYPEDEF
u64 e;
#endif
float f;
double g;
} PROPERLY_ALIGNED_TYPE;
#define gcry_assert(x) grub_assert_real(__FILE__, __LINE__, x)
static inline void
grub_assert_real (const char *file, int line, int cond)
{
if (!cond)
grub_fatal ("Assertion failed at %s:%d\n", file, line);
}
/* Selftests are in separate modules. */
static inline char *
selftest (void)
{
return NULL;
}
static inline int
fips_mode (void)
{
return 0;
}
#define memset grub_memset
#endif

View file

@ -36,7 +36,7 @@ extern grub_uint8_t grub_relocator32_backward_start;
extern grub_uint8_t grub_relocator32_backward_end;
#define REGW_SIZEOF (2 * sizeof (grub_uint32_t))
#define JUMP_SIZEOF (sizeof (grub_uint32_t))
#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t))
#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator32_##x##_end \
- &grub_relocator32_##x##_start)
@ -64,6 +64,9 @@ write_jump (int regn, void **target)
/* j $r. */
*(grub_uint32_t *) *target = (regn<<21) | 0x8;
*target = ((grub_uint32_t *) *target) + 1;
/* nop. */
*(grub_uint32_t *) *target = 0;
*target = ((grub_uint32_t *) *target) + 1;
}
static void

View file

@ -21,8 +21,8 @@
.p2align 4 /* force 16-byte alignment */
VARIABLE (grub_relocator32_forward_start)
move $12, $9
move $13, $10
move $a0, $9
move $a1, $10
copycont1:
lb $11,0($8)
@ -32,31 +32,13 @@ copycont1:
addiu $10, $10, 0xffff
bne $10, $0, copycont1
move $9, $12
move $10, $13
cachecont1a:
cache 1,0($12)
addiu $12, $12, 0x1
addiu $13, $13, 0xffff
bne $13, $0, cachecont1a
sync
move $12, $9
move $13, $10
cachecont1b:
cache 0,0($12)
addiu $12, $12, 0x1
addiu $13, $13, 0xffff
bne $13, $0, cachecont1b
sync
#include "../../kern/mips/cache_flush.S"
VARIABLE (grub_relocator32_forward_end)
VARIABLE (grub_relocator32_backward_start)
move $12, $9
move $13, $10
move $a0, $9
move $a1, $10
addu $9, $9, $10
addu $8, $8, $10
@ -71,23 +53,6 @@ copycont2:
addiu $10, 0xffff
bne $10, $0, copycont2
move $9, $12
move $10, $13
cachecont2a:
cache 1,0($12)
addiu $12, $12, 0x1
addiu $13, $13, 0xffff
bne $13, $0, cachecont2a
#include "../../kern/mips/cache_flush.S"
sync
move $12, $9
move $13, $10
cachecont2b:
cache 0,0($12)
addiu $12, $12, 0x1
addiu $13, $13, 0xffff
bne $13, $0, cachecont2b
sync
VARIABLE (grub_relocator32_backward_end)

65
lib/mips/setjmp.S Normal file
View file

@ -0,0 +1,65 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2007,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/>.
*/
#include <grub/symbol.h>
.file "setjmp.S"
.text
/*
* int grub_setjmp (grub_jmp_buf env)
*/
FUNCTION(grub_setjmp)
sw $s0, 0($a0)
sw $s1, 4($a0)
sw $s2, 8($a0)
sw $s3, 12($a0)
sw $s4, 16($a0)
sw $s5, 20($a0)
sw $s6, 24($a0)
sw $s7, 28($a0)
sw $s8, 32($a0)
sw $gp, 36($a0)
sw $sp, 40($a0)
sw $ra, 44($a0)
move $v0, $zero
move $v1, $zero
jr $ra
/*
* int grub_longjmp (grub_jmp_buf env, int val)
*/
FUNCTION(grub_longjmp)
lw $s0, 0($a0)
lw $s1, 4($a0)
lw $s2, 8($a0)
lw $s3, 12($a0)
lw $s4, 16($a0)
lw $s5, 20($a0)
lw $s6, 24($a0)
lw $s7, 28($a0)
lw $s8, 32($a0)
lw $gp, 36($a0)
lw $sp, 40($a0)
lw $ra, 44($a0)
move $v0, $a1
bne $v0, $zero, 1f
addiu $v0, $v0, 1
1:
move $v1, $zero
jr $ra

102
lib/pbkdf2.c Normal file
View file

@ -0,0 +1,102 @@
/* 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. */
/* Imported from gnulib. */
#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;
}