2010-01-07 Vladimir Serbinenko <phcoder@gmail.com>

Merge crypto branch.

	* Makefile.in (pkglib_DATA):  Add crypto.lst.
	(crypto.lst): New target.
	* commands/hashsum.c: New file.
	* commands/password.c (check_password): Use grub_crypto_memcmp.
	* commands/password_pbkdf2.c: New file.
	* commands/xnu_uuid.c: Remove MD5. Use GRUB_MD_MD5.
	* conf/any-emu.rmk (grub_emu_SOURCES): Add lib/crypto.c,
	normal/crypto.c and lib/libgcrypt-grub/cipher/md5.c.
	(grub_emu_CFLAGS): Add -Wno-missing-field-initializers -Wno-error
	-I$(srcdir)/lib/libgcrypt_wrap.
	* conf/common.rmk (normal_mod_SOURCES): Add normal/crypto.c.
	(pkglib_MODULES): Add crypto.mod, hashsum.mod, pbkdf2.mod and
	password_pbkdf2.mod.
	(crypto_mod_SOURCES): New variable.
	(crypto_mod_CFLAGS): Likewise.
	(crypto_mod_LDFLAGS): Likewise.
	(hashsum_mod_SOURCES): New variable.
	(hashsum_mod_CFLAGS): Likewise.
	(hashsum_mod_LDFLAGS): Likewise.
	(pbkdf2_mod_SOURCES): New variable.
	(pbkdf2_mod_CFLAGS): Likewise.
	(pbkdf2_mod_LDFLAGS): Likewise.
	(password_pbkdf2_mod_SOURCES): New variable.
	(password_pbkdf2_mod_CFLAGS): Likewise.
	(password_pbkdf2_mod_LDFLAGS): Likewise.
	(bin_UTILITIES): Add grub-mkpasswd-pbkdf2.
	(grub_mkpasswd_pbkdf2_SOURCES): New variable.
	(grub_mkpasswd_pbkdf2_CFLAGS): Likewise.
	Include conf/gcry.rmk.
	* include/grub/auth.h: Rewritten.
	* include/grub/crypto.h: New file.
	* include/grub/disk.h (grub_disk_dev_id): Add GRUB_DISK_DEVICE_LUKS_ID.
	* include/grub/normal.h (read_crypto_list): New prototype.
	* lib/crypto.c: New file.
	* lib/libgcrypt_wrap/cipher_wrap.h: Likewise.
	* lib/pbkdf2.c: Likewise.
	* normal/auth.c (grub_auth_strcmp): Removed.
	(grub_iswordseparator): Likewise.
	(grub_auth_strword): Likewise.
	(is_authenticated): Use grub_strword.
	(grub_auth_check_authentication): Use grub_strcmp, grub_password_get
	and grub_strword. Pass entered password to authentication callback.
	* normal/crypto.c: New file.
	* normal/main.c: Call read_crypto_list.
	* util/grub-mkpasswd-pbkdf2.c: New file.
	* util/import_gcry.py: Generate crypto.lst. Add hash blocklen.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-01-07 01:13:01 +01:00
commit 607a3701db
21 changed files with 2086 additions and 414 deletions

View File

@ -35,6 +35,7 @@ grub_fstest_init.c
grub_fstest_init.h
grub-install
grub-mk*
grub-pbkdf2
grub-pe2elf
grub-probe
grub_probe_init.c

View File

@ -1,3 +1,54 @@
2010-01-07 Vladimir Serbinenko <phcoder@gmail.com>
Merge crypto branch.
* Makefile.in (pkglib_DATA): Add crypto.lst.
(crypto.lst): New target.
* commands/hashsum.c: New file.
* commands/password.c (check_password): Use grub_crypto_memcmp.
* commands/password_pbkdf2.c: New file.
* commands/xnu_uuid.c: Remove MD5. Use GRUB_MD_MD5.
* conf/any-emu.rmk (grub_emu_SOURCES): Add lib/crypto.c,
normal/crypto.c and lib/libgcrypt-grub/cipher/md5.c.
(grub_emu_CFLAGS): Add -Wno-missing-field-initializers -Wno-error
-I$(srcdir)/lib/libgcrypt_wrap.
* conf/common.rmk (normal_mod_SOURCES): Add normal/crypto.c.
(pkglib_MODULES): Add crypto.mod, hashsum.mod, pbkdf2.mod and
password_pbkdf2.mod.
(crypto_mod_SOURCES): New variable.
(crypto_mod_CFLAGS): Likewise.
(crypto_mod_LDFLAGS): Likewise.
(hashsum_mod_SOURCES): New variable.
(hashsum_mod_CFLAGS): Likewise.
(hashsum_mod_LDFLAGS): Likewise.
(pbkdf2_mod_SOURCES): New variable.
(pbkdf2_mod_CFLAGS): Likewise.
(pbkdf2_mod_LDFLAGS): Likewise.
(password_pbkdf2_mod_SOURCES): New variable.
(password_pbkdf2_mod_CFLAGS): Likewise.
(password_pbkdf2_mod_LDFLAGS): Likewise.
(bin_UTILITIES): Add grub-mkpasswd-pbkdf2.
(grub_mkpasswd_pbkdf2_SOURCES): New variable.
(grub_mkpasswd_pbkdf2_CFLAGS): Likewise.
Include conf/gcry.rmk.
* include/grub/auth.h: Rewritten.
* include/grub/crypto.h: New file.
* include/grub/disk.h (grub_disk_dev_id): Add GRUB_DISK_DEVICE_LUKS_ID.
* include/grub/normal.h (read_crypto_list): New prototype.
* lib/crypto.c: New file.
* lib/libgcrypt_wrap/cipher_wrap.h: Likewise.
* lib/pbkdf2.c: Likewise.
* normal/auth.c (grub_auth_strcmp): Removed.
(grub_iswordseparator): Likewise.
(grub_auth_strword): Likewise.
(is_authenticated): Use grub_strword.
(grub_auth_check_authentication): Use grub_strcmp, grub_password_get
and grub_strword. Pass entered password to authentication callback.
* normal/crypto.c: New file.
* normal/main.c: Call read_crypto_list.
* util/grub-mkpasswd-pbkdf2.c: New file.
* util/import_gcry.py: Generate crypto.lst. Add hash blocklen.
2010-01-06 Vladimir Serbinenko <phcoder@gmail.com>
Fix descent and ascent calculation.

View File

@ -174,7 +174,7 @@ endif
### General targets.
CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA) po/*.mo
pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst
pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst
moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk
cat $(DEFSYMFILES) /dev/null \
| $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \
@ -198,6 +198,9 @@ parttool.lst: $(PARTTOOLFILES)
video.lst: $(VIDEOFILES)
cat $^ /dev/null | sort | uniq > $@
crypto.lst: lib/libgcrypt-grub/cipher/crypto.lst
cp $^ $@
ifneq (true, $(MAKEINFO))
info_INFOS += docs/grub.info
endif

278
commands/hashsum.c Normal file
View File

@ -0,0 +1,278 @@
/*
* 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/>.
*/
#include <grub/dl.h>
#include <grub/extcmd.h>
#include <grub/file.h>
#include <grub/disk.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/crypto.h>
#include <grub/normal.h>
static const struct grub_arg_option options[] = {
{"hash", 'h', 0, "Specify hash to use.", "HASH", ARG_TYPE_STRING},
{"check", 'c', 0, "Check hash list file.", "FILE", ARG_TYPE_STRING},
{"prefix", 'p', 0, "Base directory for hash list.", "DIRECTORY",
ARG_TYPE_STRING},
{"keep-going", 'k', 0, "Don't stop after first error.", 0, 0},
{0, 0, 0, 0, 0, 0}
};
struct { const char *name; const char *hashname; } aliases[] =
{
{"sha256sum", "sha256"},
{"sha512sum", "sha512"},
{"md5sum", "md5"},
};
static inline int
hextoval (char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return -1;
}
static grub_err_t
hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result)
{
grub_uint8_t context[hash->contextsize];
char *readbuf[4096];
grub_memset (context, 0, sizeof (context));
hash->init (context);
while (1)
{
grub_ssize_t r;
r = grub_file_read (file, readbuf, sizeof (readbuf));
if (r < 0)
return grub_errno;
if (r == 0)
break;
hash->write (context, readbuf, r);
}
hash->final (context);
grub_memcpy (result, hash->read (context), hash->mdlen);
return GRUB_ERR_NONE;
}
static grub_err_t
check_list (const gcry_md_spec_t *hash, const char *hashfilename,
const char *prefix, int keep)
{
grub_file_t hashlist, file;
char *buf = NULL;
grub_uint8_t expected[hash->mdlen];
grub_uint8_t actual[hash->mdlen];
grub_err_t err;
unsigned i;
unsigned unread = 0, mismatch = 0;
hashlist = grub_file_open (hashfilename);
if (!hashlist)
return grub_errno;
while (grub_free (buf), (buf = grub_file_getline (hashlist)))
{
const char *p = buf;
for (i = 0; i < hash->mdlen; i++)
{
int high, low;
high = hextoval (*p++);
low = hextoval (*p++);
if (high < 0 || low < 0)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
expected[i] = (high << 4) | low;
}
if (*p++ != ' ' || *p++ != ' ')
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
if (prefix)
{
char *filename;
filename = grub_malloc (grub_strlen (prefix)
+ grub_strlen (p) + 2);
if (!filename)
return grub_errno;
grub_sprintf (filename, "%s/%s", prefix, p);
file = grub_file_open (filename);
grub_free (filename);
}
else
file = grub_file_open (p);
if (!file)
{
grub_file_close (hashlist);
grub_free (buf);
return grub_errno;
}
err = hash_file (file, hash, actual);
grub_file_close (file);
if (err)
{
grub_printf ("%s: READ ERROR\n", p);
if (!keep)
{
grub_file_close (hashlist);
grub_free (buf);
return err;
}
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
unread++;
continue;
}
if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0)
{
grub_printf ("%s: HASH MISMATCH\n", p);
if (!keep)
{
grub_file_close (hashlist);
grub_free (buf);
return grub_error (GRUB_ERR_TEST_FAILURE,
"hash of '%s' mismatches", p);
}
mismatch++;
continue;
}
grub_printf ("%s: OK\n", p);
}
if (mismatch || unread)
return grub_error (GRUB_ERR_TEST_FAILURE,
"%d files couldn't be read and hash "
"of %d files mismatches", unread, mismatch);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_hashsum (struct grub_extcmd *cmd,
int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
const char *hashname = NULL;
const char *prefix = NULL;
const gcry_md_spec_t *hash;
unsigned i;
int keep = state[3].set;
unsigned unread = 0;
for (i = 0; i < ARRAY_SIZE (aliases); i++)
if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0)
hashname = aliases[i].hashname;
if (state[0].set)
hashname = state[0].arg;
if (!hashname)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified");
hash = grub_crypto_lookup_md_by_name (hashname);
if (!hash)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash");
if (state[2].set)
prefix = state[2].arg;
if (state[1].set)
{
if (argc != 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"--check is incompatible with file list");
return check_list (hash, state[1].arg, prefix, keep);
}
for (i = 0; i < (unsigned) argc; i++)
{
grub_uint8_t result[hash->mdlen];
grub_file_t file;
grub_err_t err;
unsigned j;
file = grub_file_open (args[i]);
if (!file)
{
if (!keep)
return grub_errno;
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
unread++;
continue;
}
err = hash_file (file, hash, result);
grub_file_close (file);
if (err)
{
if (!keep)
return err;
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
unread++;
continue;
}
for (j = 0; j < hash->mdlen; j++)
grub_printf ("%02x", result[j]);
grub_printf (" %s\n", args[i]);
}
if (unread)
return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read.",
unread);
return GRUB_ERR_NONE;
}
static grub_extcmd_t cmd, cmd_md5, cmd_sha256, cmd_sha512;
GRUB_MOD_INIT(hashsum)
{
cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum,
GRUB_COMMAND_FLAG_BOTH,
"hashsum -h HASH [-c FILE [-p PREFIX]] "
"[FILE1 [FILE2 ...]]",
"Compute or check hash checksum.",
options);
cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum,
GRUB_COMMAND_FLAG_BOTH,
"md5sum [-c FILE [-p PREFIX]] "
"[FILE1 [FILE2 ...]]",
"Compute or check hash checksum.",
options);
cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum,
GRUB_COMMAND_FLAG_BOTH,
"sha256sum [-c FILE [-p PREFIX]] "
"[FILE1 [FILE2 ...]]",
"Compute or check hash checksum.",
options);
cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum,
GRUB_COMMAND_FLAG_BOTH,
"sha512sum [-c FILE [-p PREFIX]] "
"[FILE1 [FILE2 ...]]",
"Compute or check hash checksum.",
options);
}
GRUB_MOD_FINI(hashsum)
{
grub_unregister_extcmd (cmd);
grub_unregister_extcmd (cmd_md5);
grub_unregister_extcmd (cmd_sha256);
grub_unregister_extcmd (cmd_sha512);
}

View File

@ -17,6 +17,7 @@
*/
#include <grub/auth.h>
#include <grub/crypto.h>
#include <grub/list.h>
#include <grub/mm.h>
#include <grub/misc.h>
@ -28,17 +29,10 @@
static grub_dl_t my_mod;
static grub_err_t
check_password (const char *user,
check_password (const char *user, const char *entered,
void *password)
{
char entered[1024];
grub_memset (entered, 0, sizeof (entered));
if (!GRUB_GET_PASSWORD (entered, sizeof (entered) - 1))
return GRUB_ACCESS_DENIED;
if (grub_auth_strcmp (entered, password) != 0)
if (grub_crypto_memcmp (entered, password, GRUB_AUTH_MAX_PASSLEN) != 0)
return GRUB_ACCESS_DENIED;
grub_auth_authenticate (user);
@ -52,13 +46,18 @@ grub_cmd_password (grub_command_t cmd __attribute__ ((unused)),
{
grub_err_t err;
char *pass;
int copylen;
if (argc != 2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments expected");
pass = grub_strdup (args[1]);
pass = grub_zalloc (GRUB_AUTH_MAX_PASSLEN);
if (!pass)
return grub_errno;
copylen = grub_strlen (args[1]);
if (copylen >= GRUB_AUTH_MAX_PASSLEN)
copylen = GRUB_AUTH_MAX_PASSLEN - 1;
grub_memcpy (pass, args[1], copylen);
err = grub_auth_register_authentication (args[0], check_password, pass);
if (err)

196
commands/password_pbkdf2.c Normal file
View File

@ -0,0 +1,196 @@
/*
* 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/>.
*/
#include <grub/auth.h>
#include <grub/crypto.h>
#include <grub/list.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/normal.h>
#include <grub/dl.h>
static grub_dl_t my_mod;
struct pbkdf2_password
{
grub_uint8_t *salt;
grub_size_t saltlen;
unsigned int c;
grub_uint8_t *expected;
grub_size_t buflen;
};
static grub_err_t
check_password (const char *user, const char *entered, void *pin)
{
grub_uint8_t *buf;
struct pbkdf2_password *pass = pin;
gcry_err_code_t err;
buf = grub_malloc (pass->buflen);
if (!buf)
return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY);
err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) entered,
grub_strlen (entered),
pass->salt, pass->saltlen, pass->c,
buf, pass->buflen);
if (err)
{
grub_free (buf);
return grub_crypto_gcry_error (err);
}
if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0)
return GRUB_ACCESS_DENIED;
grub_auth_authenticate (user);
return GRUB_ERR_NONE;
}
static inline int
hex2val (char hex)
{
if ('0' <= hex && hex <= '9')
return hex - '0';
if ('a' <= hex && hex <= 'f')
return hex - 'a' + 10;
if ('A' <= hex && hex <= 'F')
return hex - 'A' + 10;
return -1;
}
static grub_err_t
grub_cmd_password (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
{
grub_err_t err;
char *ptr, *ptr2;
grub_uint8_t *ptro;
struct pbkdf2_password *pass;
if (argc != 2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected.");
if (grub_memcmp (args[1], "grub.pbkdf2.sha512.",
sizeof ("grub.pbkdf2.sha512.") - 1) != 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
ptr = args[1] + sizeof ("grub.pbkdf2.sha512.") - 1;
pass = grub_malloc (sizeof (*pass));
if (!pass)
return grub_errno;
pass->c = grub_strtoul (ptr, &ptr, 0);
if (*ptr != '.')
{
grub_free (pass);
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
}
ptr++;
ptr2 = grub_strchr (ptr, '.');
if (!ptr2 || ((ptr2 - ptr) & 1) || grub_strlen (ptr2 + 1) & 1)
{
grub_free (pass);
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
}
pass->saltlen = (ptr2 - ptr) >> 1;
pass->buflen = grub_strlen (ptr2 + 1) >> 1;
ptro = pass->salt = grub_malloc (pass->saltlen);
if (!ptro)
{
grub_free (pass);
return grub_errno;
}
while (ptr < ptr2)
{
int hex1, hex2;
hex1 = hex2val (*ptr);
ptr++;
hex2 = hex2val (*ptr);
ptr++;
if (hex1 < 0 || hex2 < 0)
{
grub_free (pass->salt);
grub_free (pass);
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"Incorrect PBKDF2 password.");
}
*ptro = (hex1 << 4) | hex2;
ptro++;
}
ptro = pass->expected = grub_malloc (pass->buflen);
if (!ptro)
{
grub_free (pass->salt);
grub_free (pass);
return grub_errno;
}
ptr = ptr2 + 1;
ptr2 += grub_strlen (ptr2);
while (ptr < ptr2)
{
int hex1, hex2;
hex1 = hex2val (*ptr);
ptr++;
hex2 = hex2val (*ptr);
ptr++;
if (hex1 < 0 || hex2 < 0)
{
grub_free (pass->expected);
grub_free (pass->salt);
grub_free (pass);
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"Incorrect PBKDF2 password.");
}
*ptro = (hex1 << 4) | hex2;
ptro++;
}
err = grub_auth_register_authentication (args[0], check_password, pass);
if (err)
{
grub_free (pass);
return err;
}
grub_dl_ref (my_mod);
return GRUB_ERR_NONE;
}
static grub_command_t cmd;
GRUB_MOD_INIT(password_pbkdf2)
{
my_mod = mod;
cmd = grub_register_command ("password_pbkdf2", grub_cmd_password,
"password_pbkdf2 USER PBKDF2_PASSWORD",
"Set user password (PBKDF2). ");
}
GRUB_MOD_FINI(password_pbkdf2)
{
grub_unregister_command (cmd);
}

View File

@ -32,12 +32,7 @@
#include <grub/env.h>
#include <grub/command.h>
#include <grub/i18n.h>
struct tohash
{
grub_uint8_t prefix[16];
grub_uint64_t serial;
} __attribute__ ((packed));
#include <grub/crypto.h>
/* This prefix is used by xnu and boot-132 to hash
together with volume serial. */
@ -45,311 +40,27 @@ static grub_uint8_t hash_prefix[16]
= {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6,
0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};
#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) )
typedef struct {
grub_uint32_t A,B,C,D; /* chaining variables */
grub_uint32_t nblocks;
grub_uint8_t buf[64];
int count;
} MD5_CONTEXT;
static void
md5_init( void *context )
{
MD5_CONTEXT *ctx = context;
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->nblocks = 0;
ctx->count = 0;
}
/* These are the four functions used in the four steps of the MD5 algorithm
and defined in the RFC 1321. The first function is a little bit optimized
(as found in Colin Plumbs public domain implementation). */
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
#define FF(b, c, d) (d ^ (b & (c ^ d)))
#define FG(b, c, d) FF (d, b, c)
#define FH(b, c, d) (b ^ c ^ d)
#define FI(b, c, d) (c ^ (b | ~d))
/****************
* transform n*64 grub_uint8_ts
*/
static void
transform ( MD5_CONTEXT *ctx, const unsigned char *data )
{
grub_uint32_t correct_words[16];
register grub_uint32_t A = ctx->A;
register grub_uint32_t B = ctx->B;
register grub_uint32_t C = ctx->C;
register grub_uint32_t D = ctx->D;
grub_uint32_t *cwp = correct_words;
#ifdef GRUB_CPU_WORDS_BIGENDIAN
{
int i;
const grub_uint32_t *p = (const grub_uint32_t *) data;
for (i = 0; i < 16; i++)
correct_words[i] = grub_le_to_cpu32 (p[i]);
}
#else
grub_memcpy (correct_words, data, 64);
#endif
#define OP(a, b, c, d, s, T) \
do \
{ \
a += FF (b, c, d) + (*cwp++) + T; \
a = rol(a, s); \
a += b; \
} \
while (0)
/* Before we start, one word about the strange constants.
They are defined in RFC 1321 as
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
*/
/* Round 1. */
OP (A, B, C, D, 7, 0xd76aa478);
OP (D, A, B, C, 12, 0xe8c7b756);
OP (C, D, A, B, 17, 0x242070db);
OP (B, C, D, A, 22, 0xc1bdceee);
OP (A, B, C, D, 7, 0xf57c0faf);
OP (D, A, B, C, 12, 0x4787c62a);
OP (C, D, A, B, 17, 0xa8304613);
OP (B, C, D, A, 22, 0xfd469501);
OP (A, B, C, D, 7, 0x698098d8);
OP (D, A, B, C, 12, 0x8b44f7af);
OP (C, D, A, B, 17, 0xffff5bb1);
OP (B, C, D, A, 22, 0x895cd7be);
OP (A, B, C, D, 7, 0x6b901122);
OP (D, A, B, C, 12, 0xfd987193);
OP (C, D, A, B, 17, 0xa679438e);
OP (B, C, D, A, 22, 0x49b40821);
#undef OP
#define OP(f, a, b, c, d, k, s, T) \
do \
{ \
a += f (b, c, d) + correct_words[k] + T; \
a = rol(a, s); \
a += b; \
} \
while (0)
/* Round 2. */
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
OP (FG, D, A, B, C, 10, 9, 0x02441453);
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
/* Round 3. */
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
/* Round 4. */
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
/* Put checksum in context given as argument. */
ctx->A += A;
ctx->B += B;
ctx->C += C;
ctx->D += D;
}
/* The routine updates the message-digest context to
* account for the presence of each of the characters inBuf[0..inLen-1]
* in the message whose digest is being computed.
*/
static void
md5_write( void *context, const void *inbuf_arg , grub_size_t inlen)
{
const unsigned char *inbuf = inbuf_arg;
MD5_CONTEXT *hd = context;
if( hd->count == 64 ) /* flush the buffer */
{
transform( hd, hd->buf );
// _gcry_burn_stack (80+6*sizeof(void*));
hd->count = 0;
hd->nblocks++;
}
if( !inbuf )
return;
if( hd->count )
{
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
md5_write( hd, NULL, 0 );
if( !inlen )
return;
}
// _gcry_burn_stack (80+6*sizeof(void*));
while( inlen >= 64 )
{
transform( hd, inbuf );
hd->count = 0;
hd->nblocks++;
inlen -= 64;
inbuf += 64;
}
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
}
/* The routine final terminates the message-digest computation and
* ends with the desired message digest in mdContext->digest[0...15].
* The handle is prepared for a new MD5 cycle.
* Returns 16 grub_uint8_ts representing the digest.
*/
static void
md5_final( void *context)
{
MD5_CONTEXT *hd = context;
grub_uint32_t t, msb, lsb;
grub_uint32_t *p;
md5_write(hd, NULL, 0); /* flush */;
t = hd->nblocks;
/* multiply by 64 to make a grub_uint8_t count */
lsb = t << 6;
msb = t >> 26;
/* add the count */
t = lsb;
if( (lsb += hd->count) < t )
msb++;
/* multiply by 8 to make a bit count */
t = lsb;
lsb <<= 3;
msb <<= 3;
msb |= t >> 29;
if( hd->count < 56 ) /* enough room */
{
hd->buf[hd->count++] = 0x80; /* pad */
while( hd->count < 56 )
hd->buf[hd->count++] = 0; /* pad */
}
else /* need one extra block */
{
hd->buf[hd->count++] = 0x80; /* pad character */
while( hd->count < 64 )
hd->buf[hd->count++] = 0;
md5_write(hd, NULL, 0); /* flush */;
grub_memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
}
/* append the 64 bit count */
hd->buf[56] = lsb ;
hd->buf[57] = lsb >> 8;
hd->buf[58] = lsb >> 16;
hd->buf[59] = lsb >> 24;
hd->buf[60] = msb ;
hd->buf[61] = msb >> 8;
hd->buf[62] = msb >> 16;
hd->buf[63] = msb >> 24;
transform( hd, hd->buf );
// _gcry_burn_stack (80+6*sizeof(void*));
p = (grub_uint32_t *) hd->buf;
#define X(a) do { *p = grub_le_to_cpu32 (hd->a); p++; } while (0)
X(A);
X(B);
X(C);
X(D);
#undef X
}
/**
* GRUB2 Crypto Interface
* Written by Michael Gorven
*/
static grub_err_t
md5 (const char *in, grub_size_t insize, char *out)
{
MD5_CONTEXT hd;
md5_init (&hd);
md5_write (&hd, in, insize);
md5_final (&hd);
grub_memcpy (out, hd.buf, 16);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
{
struct tohash hashme;
grub_uint8_t xnu_uuid[16];
grub_uint64_t serial;
grub_uint8_t *xnu_uuid;
char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")];
char *ptr;
grub_uint8_t ctx[GRUB_MD_MD5->contextsize];
if (argc < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required");
hashme.serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16));
grub_memcpy (hashme.prefix, hash_prefix, sizeof (hashme.prefix));
serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16));
GRUB_MD_MD5->init (&ctx);
GRUB_MD_MD5->write (&ctx, hash_prefix, sizeof (hash_prefix));
GRUB_MD_MD5->write (&ctx, &serial, sizeof (serial));
GRUB_MD_MD5->final (&ctx);
xnu_uuid = GRUB_MD_MD5->read (&ctx);
md5 ((char *) &hashme, sizeof (hashme), (char *) xnu_uuid);
grub_sprintf (uuid_string,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
(unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1],

View File

@ -26,10 +26,10 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \
kern/partition.c kern/reader.c kern/term.c \
kern/rescue_reader.c kern/rescue_parser.c \
lib/arg.c normal/cmdline.c normal/datetime.c normal/misc.c \
normal/handler.c normal/auth.c normal/autofs.c \
normal/handler.c normal/auth.c lib/crypto.c normal/autofs.c \
normal/completion.c normal/main.c normal/color.c \
normal/menu.c normal/menu_entry.c normal/menu_viewer.c \
normal/menu_text.c \
normal/menu_text.c normal/crypto.c \
script/main.c script/execute.c script/function.c \
script/lexer.c script/script.c grub_script.tab.c \
partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \
@ -47,7 +47,10 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \
disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \
disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \
commands/parttool.c parttool/msdospart.c \
lib/libgcrypt-grub/cipher/md5.c \
grub_emu_init.c gnulib/progname.c
grub_emu_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap
ifeq ($(target_cpu), i386)
grub_emu_SOURCES += commands/i386/cpuid.c

View File

@ -550,7 +550,7 @@ normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \
normal/auth.c normal/autofs.c normal/handler.c \
normal/color.c normal/completion.c normal/datetime.c normal/menu.c \
normal/menu_entry.c normal/menu_text.c normal/menu_viewer.c \
normal/misc.c
normal/misc.c normal/crypto.c
normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
@ -650,3 +650,30 @@ pkglib_MODULES += charset.mod
charset_mod_SOURCES = lib/charset.c
charset_mod_CFLAGS = $(COMMON_CFLAGS)
charset_mod_LDFLAGS = $(COMMON_LDFLAGS)
pkglib_MODULES += crypto.mod
crypto_mod_SOURCES = lib/crypto.c
crypto_mod_CFLAGS = $(COMMON_CFLAGS)
crypto_mod_LDFLAGS = $(COMMON_LDFLAGS)
pkglib_MODULES += hashsum.mod
hashsum_mod_SOURCES = commands/hashsum.c
hashsum_mod_CFLAGS = $(COMMON_CFLAGS)
hashsum_mod_LDFLAGS = $(COMMON_LDFLAGS)
pkglib_MODULES += pbkdf2.mod
pbkdf2_mod_SOURCES = lib/pbkdf2.c
pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS)
pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For password_pbkdf2.mod.
pkglib_MODULES += password_pbkdf2.mod
password_pbkdf2_mod_SOURCES = commands/password_pbkdf2.c
password_pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS)
password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS)
bin_UTILITIES += grub-mkpasswd-pbkdf2
grub_mkpasswd_pbkdf2_SOURCES = gnulib/progname.c util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c
grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap -DGRUB_MKPASSWD=1
include $(srcdir)/conf/gcry.mk

View File

@ -15,24 +15,15 @@
* 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_AURH_HEADER
#ifndef GRUB_AUTH_HEADER
#define GRUB_AUTH_HEADER 1
#include <grub/err.h>
#include <grub/i18n.h>
#include <grub/crypto.h>
/* Macros for indistinguishibility. */
#define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "access denied")
#define GRUB_GET_PASSWORD(string, len) grub_cmdline_get (N_("Enter password:"), \
string, len, \
'*', 0, 0)
#define GRUB_AUTH_MAX_PASSLEN 1024
/* Like strcmp but untimeable. Accepts NULL as second argument. */
int grub_auth_strcmp (const char *user_input, const char *template);
/* Like strcmp but untimeable and ignores commas in needle. */
int grub_auth_strword (const char *haystack, const char *needle);
typedef grub_err_t (*grub_auth_callback_t) (const char*, void *);
typedef grub_err_t (*grub_auth_callback_t) (const char *, const char *, void *);
grub_err_t grub_auth_register_authentication (const char *user,
grub_auth_callback_t callback,

275
include/grub/crypto.h Normal file
View File

@ -0,0 +1,275 @@
/*
* 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/>.
*/
/* Contains elements based on gcrypt-module.h and gcrypt.h.in.
If it's changed please update this file. */
#ifndef GRUB_CRYPTO_HEADER
#define GRUB_CRYPTO_HEADER 1
#include <grub/symbol.h>
#include <grub/types.h>
#include <grub/err.h>
typedef enum
{
GPG_ERR_NO_ERROR,
GPG_ERR_BAD_MPI,
GPG_ERR_BAD_SECKEY,
GPG_ERR_BAD_SIGNATURE,
GPG_ERR_CIPHER_ALGO,
GPG_ERR_CONFLICT,
GPG_ERR_DECRYPT_FAILED,
GPG_ERR_DIGEST_ALGO,
GPG_ERR_GENERAL,
GPG_ERR_INTERNAL,
GPG_ERR_INV_ARG,
GPG_ERR_INV_CIPHER_MODE,
GPG_ERR_INV_FLAG,
GPG_ERR_INV_KEYLEN,
GPG_ERR_INV_OBJ,
GPG_ERR_INV_OP,
GPG_ERR_INV_SEXP,
GPG_ERR_INV_VALUE,
GPG_ERR_MISSING_VALUE,
GPG_ERR_NO_ENCRYPTION_SCHEME,
GPG_ERR_NO_OBJ,
GPG_ERR_NO_PRIME,
GPG_ERR_NO_SIGNATURE_SCHEME,
GPG_ERR_NOT_FOUND,
GPG_ERR_NOT_IMPLEMENTED,
GPG_ERR_NOT_SUPPORTED,
GPG_ERROR_CFLAGS,
GPG_ERR_PUBKEY_ALGO,
GPG_ERR_SELFTEST_FAILED,
GPG_ERR_TOO_SHORT,
GPG_ERR_UNSUPPORTED,
GPG_ERR_WEAK_KEY,
GPG_ERR_WRONG_KEY_USAGE,
GPG_ERR_WRONG_PUBKEY_ALGO,
GPG_ERR_OUT_OF_MEMORY
} gcry_err_code_t;
#define gpg_err_code_t gcry_err_code_t
#define gpg_error_t gcry_err_code_t
enum gcry_cipher_modes
{
GCRY_CIPHER_MODE_NONE = 0, /* Not yet specified. */
GCRY_CIPHER_MODE_ECB = 1, /* Electronic codebook. */
GCRY_CIPHER_MODE_CFB = 2, /* Cipher feedback. */
GCRY_CIPHER_MODE_CBC = 3, /* Cipher block chaining. */
GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */
GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */
GCRY_CIPHER_MODE_CTR = 6 /* Counter. */
};
/* Type for the cipher_setkey function. */
typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c,
const unsigned char *key,
unsigned keylen);
/* Type for the cipher_encrypt function. */
typedef void (*gcry_cipher_encrypt_t) (void *c,
unsigned char *outbuf,
const unsigned char *inbuf);
/* Type for the cipher_decrypt function. */
typedef void (*gcry_cipher_decrypt_t) (void *c,
unsigned char *outbuf,
const unsigned char *inbuf);
/* Type for the cipher_stencrypt function. */
typedef void (*gcry_cipher_stencrypt_t) (void *c,
unsigned char *outbuf,
const unsigned char *inbuf,
unsigned int n);
/* Type for the cipher_stdecrypt function. */
typedef void (*gcry_cipher_stdecrypt_t) (void *c,
unsigned char *outbuf,
const unsigned char *inbuf,
unsigned int n);
typedef struct gcry_cipher_oid_spec
{
const char *oid;
int mode;
} gcry_cipher_oid_spec_t;
/* Module specification structure for ciphers. */
typedef struct gcry_cipher_spec
{
const char *name;
const char **aliases;
gcry_cipher_oid_spec_t *oids;
grub_size_t blocksize;
grub_size_t keylen;
grub_size_t contextsize;
gcry_cipher_setkey_t setkey;
gcry_cipher_encrypt_t encrypt;
gcry_cipher_decrypt_t decrypt;
gcry_cipher_stencrypt_t stencrypt;
gcry_cipher_stdecrypt_t stdecrypt;
struct gcry_cipher_spec *next;
} gcry_cipher_spec_t;
/* Type for the md_init function. */
typedef void (*gcry_md_init_t) (void *c);
/* Type for the md_write function. */
typedef void (*gcry_md_write_t) (void *c, const void *buf, grub_size_t nbytes);
/* Type for the md_final function. */
typedef void (*gcry_md_final_t) (void *c);
/* Type for the md_read function. */
typedef unsigned char *(*gcry_md_read_t) (void *c);
typedef struct gcry_md_oid_spec
{
const char *oidstring;
} gcry_md_oid_spec_t;
/* Module specification structure for message digests. */
typedef struct gcry_md_spec
{
const char *name;
unsigned char *asnoid;
int asnlen;
gcry_md_oid_spec_t *oids;
grub_size_t mdlen;
gcry_md_init_t init;
gcry_md_write_t write;
gcry_md_final_t final;
gcry_md_read_t read;
grub_size_t contextsize; /* allocate this amount of context */
/* Block size, needed for HMAC. */
grub_size_t blocksize;
struct gcry_md_spec *next;
} gcry_md_spec_t;
struct grub_crypto_cipher_handle
{
const struct gcry_cipher_spec *cipher;
char ctx[0];
};
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);
grub_crypto_cipher_handle_t
grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher);
gcry_err_code_t
grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher,
const unsigned char *key,
unsigned keylen);
void
grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher);
void
grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size);
gcry_err_code_t
grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
void *out, void *in, grub_size_t size);
gcry_err_code_t
grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
void *out, void *in, grub_size_t size);
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);
gcry_err_code_t
grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher,
void *out, void *in, grub_size_t size,
void *iv);
void
grub_cipher_register (gcry_cipher_spec_t *cipher);
void
grub_cipher_unregister (gcry_cipher_spec_t *cipher);
void
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, const void *in,
grub_size_t inlen);
const gcry_md_spec_t *
grub_crypto_lookup_md_by_name (const char *name);
grub_err_t
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;
extern gcry_md_spec_t _gcry_digest_spec_sha1;
extern gcry_md_spec_t _gcry_digest_spec_sha256;
extern gcry_md_spec_t _gcry_digest_spec_sha512;
#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)
#define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256)
#define GRUB_MD_SHA512 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha512)
/* 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);
int
grub_crypto_memcmp (const void *a, const void *b, grub_size_t n);
int
grub_password_get (char buf[], unsigned buf_size);
/* For indistinguishibility. */
#define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "Access denied.")
extern void (*grub_crypto_autoload_hook) (const char *name);
#endif

View File

@ -42,6 +42,7 @@ enum grub_disk_dev_id
GRUB_DISK_DEVICE_PXE_ID,
GRUB_DISK_DEVICE_SCSI_ID,
GRUB_DISK_DEVICE_FILE_ID,
GRUB_DISK_DEVICE_LUKS_ID
};
struct grub_disk;

View File

@ -95,6 +95,8 @@ void read_command_list (void);
/* Defined in `autofs.c'. */
void read_fs_list (void);
void read_crypto_list (void);
#ifdef GRUB_UTIL
void grub_normal_init (void);

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

@ -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

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;
}

View File

@ -36,58 +36,6 @@ struct grub_auth_user
struct grub_auth_user *users = NULL;
int
grub_auth_strcmp (const char *s1, const char *s2)
{
int ret;
grub_uint64_t end;
end = grub_get_time_ms () + 100;
ret = grub_strcmp (s1, s2);
/* This prevents an attacker from deriving information about the
password from the time it took to execute this function. */
while (grub_get_time_ms () < end);
return ret;
}
static int
grub_iswordseparator (int c)
{
return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
}
int
grub_auth_strword (const char *haystack, const char *needle)
{
const char *n_pos = needle;
int found = 0;
while (grub_iswordseparator (*haystack))
haystack++;
while (*haystack)
{
int ok = 1;
/* Crawl both the needle and the haystack word we're on. */
while(*haystack && !grub_iswordseparator (*haystack))
{
if (*haystack == *n_pos && ok)
n_pos++;
else
ok = 0;
haystack++;
}
if (ok)
found = 1;
}
return found;
}
grub_err_t
grub_auth_register_authentication (const char *user,
grub_auth_callback_t callback,
@ -194,8 +142,8 @@ is_authenticated (const char *userlist)
return 0;
name = ((struct grub_auth_user *) item)->name;
return (userlist && grub_auth_strword (userlist, name))
|| grub_auth_strword (superusers, name);
return (userlist && grub_strword (userlist, name))
|| grub_strword (superusers, name);
}
superusers = grub_env_get ("superusers");
@ -213,11 +161,12 @@ grub_auth_check_authentication (const char *userlist)
struct grub_auth_user *cur = NULL;
grub_err_t err;
static unsigned long punishment_delay = 1;
char entered[GRUB_AUTH_MAX_PASSLEN];
auto int hook (grub_list_t item);
int hook (grub_list_t item)
{
if (grub_auth_strcmp (login, ((struct grub_auth_user *) item)->name) == 0)
if (grub_strcmp (login, ((struct grub_auth_user *) item)->name) == 0)
cur = (struct grub_auth_user *) item;
return 0;
}
@ -242,22 +191,17 @@ grub_auth_check_authentication (const char *userlist)
0, 0, 0))
goto access_denied;
grub_printf ("Enter password: ");
if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
goto access_denied;
grub_list_iterate (GRUB_AS_LIST (users), hook);
if (!cur || ! cur->callback)
{
grub_list_iterate (GRUB_AS_LIST (users), hook_any);
goto access_denied;
/* No users present at all. */
if (!cur)
goto access_denied;
/* Display any of available authentication schemes. */
err = cur->callback (login, 0);
goto access_denied;
}
err = cur->callback (login, cur->arg);
err = cur->callback (login, entered, cur->arg);
if (is_authenticated (userlist))
{
punishment_delay = 1;

153
normal/crypto.c Normal file
View File

@ -0,0 +1,153 @@
/* crypto.c - support crypto autoload */
/*
* 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/>.
*/
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/crypto.h>
#include <grub/normal.h>
struct load_spec
{
struct load_spec *next;
char *name;
char *modname;
};
struct load_spec *crypto_specs = NULL;
static void
grub_crypto_autoload (const char *name)
{
struct load_spec *cur;
grub_dl_t mod;
for (cur = crypto_specs; cur; cur = cur->next)
if (grub_strcasecmp (name, cur->name) == 0)
{
mod = grub_dl_load (cur->modname);
if (mod)
grub_dl_ref (mod);
grub_errno = GRUB_ERR_NONE;
}
}
static void
grub_crypto_spec_free (void)
{
struct load_spec *cur, *next;
for (cur = crypto_specs; cur; cur = next)
{
next = cur->next;
grub_free (cur->name);
grub_free (cur->modname);
grub_free (cur);
}
crypto_specs = NULL;
}
/* Read the file crypto.lst for auto-loading. */
void
read_crypto_list (void)
{
const char *prefix;
char *filename;
grub_file_t file;
char *buf = NULL;
prefix = grub_env_get ("prefix");
if (!prefix)
{
grub_errno = GRUB_ERR_NONE;
return;
}
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/crypto.lst"));
if (!filename)
{
grub_errno = GRUB_ERR_NONE;
return;
}
grub_sprintf (filename, "%s/crypto.lst", prefix);
file = grub_file_open (filename);
if (!file)
{
grub_errno = GRUB_ERR_NONE;
return;
}
/* Override previous commands.lst. */
grub_crypto_spec_free ();
for (;; grub_free (buf))
{
char *p, *name;
struct load_spec *cur;
buf = grub_file_getline (file);
if (! buf)
break;
name = buf;
p = grub_strchr (name, ':');
if (! p)
continue;
*p = '\0';
while (*++p == ' ')
;
cur = grub_malloc (sizeof (*cur));
if (!cur)
{
grub_errno = GRUB_ERR_NONE;
continue;
}
cur->name = grub_strdup (name);
if (! name)
{
grub_errno = GRUB_ERR_NONE;
grub_free (cur);
continue;
}
cur->modname = grub_strdup (p);
if (! cur->modname)
{
grub_errno = GRUB_ERR_NONE;
grub_free (cur);
grub_free (cur->name);
continue;
}
cur->next = crypto_specs;
crypto_specs = cur;
}
grub_file_close (file);
grub_errno = GRUB_ERR_NONE;
grub_crypto_autoload_hook = grub_crypto_autoload;
}

View File

@ -428,6 +428,7 @@ grub_normal_execute (const char *config, int nested, int batch)
read_command_list ();
read_fs_list ();
read_handler_list ();
read_crypto_list ();
grub_command_execute ("parser.grub", 0, 0);
reader_nested = nested;

342
util/grub-mkpasswd-pbkdf2.c Normal file
View File

@ -0,0 +1,342 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1992-1999,2001,2003,2004,2005,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/types.h>
#include <grub/crypto.h>
#include <grub/util/misc.h>
#include <grub/i18n.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <termios.h>
#include "progname.h"
/* Few functions to make crypto happy. */
void *
grub_memmove (void *dest, const void *src, grub_size_t n)
{
return memmove (dest, src, n);
}
void *
grub_memset (void *s, int c, grub_size_t n)
{
return memset (s, c, n);
}
int
grub_vprintf (const char *fmt, va_list args)
{
return vprintf (fmt, args);
}
int
grub_vsprintf (char *str, const char *fmt, va_list args)
{
return vsprintf (str, fmt, args);
}
void
grub_abort (void)
{
abort ();
}
static struct option options[] =
{
{"iteration_count", required_argument, 0, 'c'},
{"buflen", required_argument, 0, 'l'},
{"saltlen", required_argument, 0, 's'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
};
static void
usage (int status)
{
if (status)
fprintf (stderr, "Try ``grub-scrypt --help'' for more information.\n");
else
printf ("\
Usage: grub-scrypt [OPTIONS]\n\
\nOptions:\n\
-c number, --iteration-count=number Number of PBKDF2 iterations\n\
-l number, --buflen=number Length of generated hash\n\
-s number, --salt=number Length of salt\n\
\n\
Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
exit (status);
}
static void
hexify (char *hex, grub_uint8_t *bin, grub_size_t n)
{
while (n--)
{
if (((*bin & 0xf0) >> 4) < 10)
*hex = ((*bin & 0xf0) >> 4) + '0';
else
*hex = ((*bin & 0xf0) >> 4) + 'A' - 10;
hex++;
if ((*bin & 0xf) < 10)
*hex = (*bin & 0xf) + '0';
else
*hex = (*bin & 0xf) + 'A' - 10;
hex++;
bin++;
}
*hex = 0;
}
int
main (int argc, char *argv[])
{
unsigned int c = 10000, buflen = 64, saltlen = 64;
char *pass1, *pass2;
char *bufhex, *salthex;
gcry_err_code_t gcry_err;
grub_uint8_t *buf, *salt;
ssize_t nr;
FILE *in, *out;
struct termios s, t;
int tty_changed;
set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
/* Check for options. */
while (1)
{
int c = getopt_long (argc, argv, "c:l:s:hvV", options, 0);
if (c == -1)
break;
switch (c)
{
case 'c':
c = strtoul (optarg, NULL, 0);
break;
case 'l':
buflen = strtoul (optarg, NULL, 0);
break;
case 's':
saltlen = strtoul (optarg, NULL, 0);
break;
case 'h':
usage (0);
return 0;
case 'V':
printf ("%s (%s) %s\n", program_name,
PACKAGE_NAME, PACKAGE_VERSION);
return 0;
default:
usage (1);
return 1;
}
}
bufhex = malloc (buflen * 2 + 1);
if (!bufhex)
grub_util_error ("Out of memory");
buf = malloc (buflen);
if (!buf)
{
free (bufhex);
grub_util_error ("Out of memory");
}
salt = malloc (saltlen);
if (!salt)
{
free (bufhex);
free (buf);
grub_util_error ("Out of memory");
}
salthex = malloc (saltlen * 2 + 1);
if (!salthex)
{
free (salt);
free (bufhex);
free (buf);
grub_util_error ("Out of memory");
}
/* Disable echoing. Based on glibc. */
in = fopen ("/dev/tty", "w+c");
if (in == NULL)
{
in = stdin;
out = stderr;
}
else
out = in;
if (tcgetattr (fileno (in), &t) == 0)
{
/* Save the old one. */
s = t;
/* Tricky, tricky. */
t.c_lflag &= ~(ECHO|ISIG);
tty_changed = (tcsetattr (fileno (in), TCSAFLUSH, &t) == 0);
}
else
tty_changed = 0;
printf ("Enter password: ");
pass1 = NULL;
{
grub_size_t n;
nr = getline (&pass1, &n, stdin);
}
if (nr < 0 || !pass1)
{
free (buf);
free (bufhex);
free (salthex);
free (salt);
/* Restore the original setting. */
if (tty_changed)
(void) tcsetattr (fileno (in), TCSAFLUSH, &s);
grub_util_error ("Failure to read password");
}
if (nr >= 1 && pass1[nr-1] == '\n')
pass1[nr-1] = 0;
printf ("\nReenter password: ");
pass2 = NULL;
{
grub_size_t n;
nr = getline (&pass2, &n, stdin);
}
/* Restore the original setting. */
if (tty_changed)
(void) tcsetattr (fileno (in), TCSAFLUSH, &s);
printf ("\n");
if (nr < 0 || !pass2)
{
memset (pass1, 0, strlen (pass1));
free (pass1);
free (buf);
free (bufhex);
free (salthex);
free (salt);
grub_util_error ("Failure to read password");
}
if (nr >= 1 && pass2[nr-1] == '\n')
pass2[nr-1] = 0;
if (strcmp (pass1, pass2) != 0)
{
memset (pass1, 0, strlen (pass1));
memset (pass2, 0, strlen (pass2));
free (pass1);
free (pass2);
free (buf);
free (bufhex);
free (salthex);
free (salt);
grub_util_error ("Passwords don't match");
}
memset (pass2, 0, strlen (pass2));
free (pass2);
#if ! defined (__linux__) && ! defined (__FreeBSD__)
printf ("WARNING: your random generator isn't known to be secure\n");
#endif
{
FILE *f;
size_t rd;
f = fopen ("/dev/random", "rb");
if (!f)
{
memset (pass1, 0, strlen (pass1));
free (pass1);
free (buf);
free (bufhex);
free (salthex);
free (salt);
fclose (f);
grub_util_error ("Couldn't retrieve random data for salt");
}
rd = fread (salt, 1, saltlen, f);
if (rd != saltlen)
{
fclose (f);
memset (pass1, 0, strlen (pass1));
free (pass1);
free (buf);
free (bufhex);
free (salthex);
free (salt);
fclose (f);
grub_util_error ("Couldn't retrieve random data for salt");
}
fclose (f);
}
gcry_err = grub_crypto_pbkdf2 (GRUB_MD_SHA512,
(grub_uint8_t *) pass1, strlen (pass1),
salt, saltlen,
c, buf, buflen);
memset (pass1, 0, strlen (pass1));
free (pass1);
if (gcry_err)
{
memset (buf, 0, buflen);
memset (bufhex, 0, 2 * buflen);
free (buf);
free (bufhex);
memset (salt, 0, saltlen);
memset (salthex, 0, 2 * saltlen);
free (salt);
free (salthex);
grub_util_error ("Cryptographic error number %d", gcry_err);
}
hexify (bufhex, buf, buflen);
hexify (salthex, salt, saltlen);
printf ("Your PBKDF2 is grub.pbkdf2.sha512.%d.%s.%s\n", c, salthex, bufhex);
memset (buf, 0, buflen);
memset (bufhex, 0, 2 * buflen);
free (buf);
free (bufhex);
memset (salt, 0, saltlen);
memset (salthex, 0, 2 * saltlen);
free (salt);
free (salthex);
return 0;
}

View File

@ -61,12 +61,30 @@ mdblocksizes = {"_gcry_digest_spec_crc32" : 64,
"_gcry_digest_spec_tiger" : 64,
"_gcry_digest_spec_whirlpool" : 64}
cryptolist = open (os.path.join (cipher_dir_out, "crypto.lst"), "w")
# rijndael is the only cipher using aliases. So no need for mangling, just
# hardcode it
cryptolist.write ("RIJNDAEL: gcry_rijndael\n");
cryptolist.write ("RIJNDAEL192: gcry_rijndael\n");
cryptolist.write ("RIJNDAEL256: gcry_rijndael\n");
cryptolist.write ("AES128: gcry_rijndael\n");
cryptolist.write ("AES-128: gcry_rijndael\n");
cryptolist.write ("AES-192: gcry_rijndael\n");
cryptolist.write ("AES-256: gcry_rijndael\n");
for cipher_file in cipher_files:
infile = os.path.join (cipher_dir_in, cipher_file)
outfile = os.path.join (cipher_dir_out, cipher_file)
if cipher_file == "ChangeLog":
continue
chlognew = " * %s" % cipher_file
if re.match ("(Manifest|Makefile\.am|ac\.c|cipher\.c|hash-common\.c|hmac-tests\.c|md\.c|pubkey\.c)$", cipher_file):
chlog = "%s%s: Removed\n" % (chlog, chlognew)
continue
# Autogenerated files. Not even worth mentionning in ChangeLog
if re.match ("Makefile\.in$", cipher_file):
continue
nch = False
if re.match (".*\.[ch]$", cipher_file):
isc = re.match (".*\.c$", cipher_file)
@ -80,8 +98,21 @@ for cipher_file in cipher_files:
skip = False
skip2 = False
ismd = False
iscryptostart = False
iscomma = False
isglue = False
skip_statement = False
if isc:
modname = cipher_file [0:len(cipher_file) - 2]
if re.match (".*-glue$", modname):
modname = modname.replace ("-glue", "")
isglue = True
modname = "gcry_%s" % modname
for line in f:
if skip_statement:
if not re.search (";", line) is None:
skip_statement = False
continue
if skip:
if line[0] == "}":
skip = False
@ -90,6 +121,12 @@ for cipher_file in cipher_files:
if not re.search (" *};", line) is None:
skip2 = False
continue
if iscryptostart:
s = re.search (" *\"([A-Z0-9_a-z]*)\"", line)
if not s is None:
sg = s.groups()[0]
cryptolist.write (("%s: %s\n") % (sg, modname))
iscryptostart = False
if ismd:
if not re.search (" *};", line) is None:
if not mdblocksizes.has_key (mdname):
@ -100,10 +137,22 @@ for cipher_file in cipher_files:
fw.write (" .blocksize = %s\n" % mdblocksizes [mdname])
ismd = False
iscomma = not re.search (",$", line) is None
# Used only for selftests.
m = re.match ("(static byte|static unsigned char) (weak_keys_chksum)\[[0-9]*\] =", line)
if not m is None:
skip = True
fname = m.groups ()[1]
chmsg = "(%s): Removed." % fname
if nch:
chlognew = "%s\n %s" % (chlognew, chmsg)
else:
chlognew = "%s %s" % (chlognew, chmsg)
nch = True
continue
if hold:
hold = False
# We're optimising for size.
if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer)", line) is None:
if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer|tripledes_set2keys|do_tripledes_set_extra_info)", line) is None:
skip = True
fname = re.match ("[a-zA-Z0-9_]*", line).group ()
chmsg = "(%s): Removed." % fname
@ -127,16 +176,20 @@ for cipher_file in cipher_files:
continue
m = re.match ("gcry_cipher_spec_t", line)
if isc and not m is None:
assert (not iscryptostart)
ciphername = line [len ("gcry_cipher_spec_t"):].strip ()
ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group ()
ciphernames.append (ciphername)
iscryptostart = True
m = re.match ("gcry_md_spec_t", line)
if isc and not m is None:
assert (not ismd)
assert (not iscryptostart)
mdname = line [len ("gcry_md_spec_t"):].strip ()
mdname = re.match("[a-zA-Z0-9_]*",mdname).group ()
mdnames.append (mdname)
ismd = True
iscryptostart = True
m = re.match ("static const char \*selftest.*;$", line)
if not m is None:
fname = line[len ("static const char \*"):]
@ -148,11 +201,18 @@ for cipher_file in cipher_files:
chlognew = "%s %s" % (chlognew, chmsg)
nch = True
continue
m = re.match ("(static const char( |)\*|static gpg_err_code_t|void)$", line)
m = re.match ("(static const char( |)\*|static gpg_err_code_t|void|static int|static gcry_err_code_t)$", line)
if not m is None:
hold = True
holdline = line
continue
m = re.match ("static int tripledes_set2keys \(.*\);", line)
if not m is None:
continue
m = re.match ("static int tripledes_set2keys \(", line)
if not m is None:
skip_statement = True
continue
m = re.match ("cipher_extra_spec_t", line)
if isc and not m is None:
skip2 = True
@ -179,14 +239,11 @@ for cipher_file in cipher_files:
continue
fw.write (line)
if len (ciphernames) > 0 or len (mdnames) > 0:
modname = cipher_file [0:len(cipher_file) - 2]
if re.match (".*-glue$", modname):
modfiles = "libgcrypt-grub/cipher/%s libgcrypt-grub/cipher/%s" \
if isglue:
modfiles = "lib/libgcrypt-grub/cipher/%s lib/libgcrypt-grub/cipher/%s" \
% (cipher_file, cipher_file.replace ("-glue.c", ".c"))
modname = modname.replace ("-glue", "")
else:
modfiles = "libgcrypt-grub/cipher/%s" % cipher_file
modname = "gcry_%s" % modname
modfiles = "lib/libgcrypt-grub/cipher/%s" % cipher_file
chmsg = "(GRUB_MOD_INIT(%s)): New function\n" % modname
if nch:
chlognew = "%s\n %s" % (chlognew, chmsg)
@ -220,7 +277,7 @@ for cipher_file in cipher_files:
conf.write ("pkglib_MODULES += %s.mod\n" % modname)
conf.write ("%s_mod_SOURCES = %s\n" %\
(modname, modfiles))
conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error\n" % modname)
conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap\n" % modname)
conf.write ("%s_mod_LDFLAGS = $(COMMON_LDFLAGS)\n\n" % modname)
elif isc and cipher_file != "camellia.c":
print ("WARNING: C file isn't a module: %s" % cipher_file)
@ -229,26 +286,22 @@ for cipher_file in cipher_files:
if nch:
chlog = "%s%s\n" % (chlog, chlognew)
continue
if re.match ("(Manifest|Makefile\.am)$", cipher_file):
chlog = "%s%sRemoved\n" % (chlog, chlognew)
continue
# Autogenerated files. Not even worth mentionning in ChangeLog
if re.match ("Makefile\.in$", cipher_file):
chlog = "%s%sRemoved\n" % (chlog, chlognew)
continue
chlog = "%s%sSkipped unknown file\n" % (chlog, chlognew)
print ("WARNING: unknown file %s" % cipher_file)
cryptolist.close ()
chlog = "%s * crypto.lst: New file.\n" % chlog
outfile = os.path.join (cipher_dir_out, "types.h")
fw=open (outfile, "w")
fw.write ("#include <grub/types.h>\n")
fw.write ("#include <grub/cipher_wrap.h>\n")
fw.write ("#include <cipher_wrap.h>\n")
chlog = "%s * types.h: New file.\n" % chlog
fw.close ()
outfile = os.path.join (cipher_dir_out, "memory.h")
fw=open (outfile, "w")
fw.write ("#include <grub/cipher_wrap.h>\n")
fw.write ("#include <cipher_wrap.h>\n")
chlog = "%s * memory.h: New file.\n" % chlog
fw.close ()
@ -256,13 +309,13 @@ fw.close ()
outfile = os.path.join (cipher_dir_out, "cipher.h")
fw=open (outfile, "w")
fw.write ("#include <grub/crypto.h>\n")
fw.write ("#include <grub/cipher_wrap.h>\n")
fw.write ("#include <cipher_wrap.h>\n")
chlog = "%s * cipher.h: Likewise.\n" % chlog
fw.close ()
outfile = os.path.join (cipher_dir_out, "g10lib.h")
fw=open (outfile, "w")
fw.write ("#include <grub/cipher_wrap.h>\n")
fw.write ("#include <cipher_wrap.h>\n")
chlog = "%s * g10lib.h: Likewise.\n" % chlog
fw.close ()