add a new command, md5crypt.

This commit is contained in:
okuji 2000-10-21 00:13:55 +00:00
parent 06adfc82ff
commit 4928cfdad2
7 changed files with 234 additions and 86 deletions

View file

@ -1,3 +1,24 @@
2000-10-21 OKUJI Yoshinori <okuji@gnu.org>
* stage2/md5.c (check_md5_password): Removed.
(md5_password): New function. Mostly copied from
check_md5_password.
(md5_init): Made static.
(md5_update): Likewise.
(md5_final): Likewise.
* stage2/md5.h (check_md5_password): Changed to just a macro.
(md5_password): Declared.
(make_md5_password): New macro.
* stage2/char_io.c [!STAGE1_5] (grub_strstr): Rewriten, because
it was too buggy.
* stage2/builtins.c [USE_MD5_PASSWORDS] (md5crypt_func): New
function.
[USE_MD5_PASSWORDS] (builtin_md5crypt): New variable.
(builtin_table) [USE_MD5_PASSWORDS]: Added a pointer to
BUILTIN_MD5CRYPT.
* docs/tutorial.texi (Security): Added a paragraph about
md5crypt.
2000-10-21 OKUJI Yoshinori <okuji@gnu.org> 2000-10-21 OKUJI Yoshinori <okuji@gnu.org>
* docs/user-ref.texi: Fixed several typos and some inappropriate * docs/user-ref.texi: Fixed several typos and some inappropriate

1
NEWS
View file

@ -11,6 +11,7 @@ New in 1.0 - XXXX-XX-XX:
is given. This command can now also be used to protect specific menu is given. This command can now also be used to protect specific menu
items with their own passwords. items with their own passwords.
* New command, "displayapm". * New command, "displayapm".
* New command, "md5crypt".
New in 0.5.96 - 2000-10-04: New in 0.5.96 - 2000-10-04:
* New commands, "reboot" and "halt". * New commands, "reboot" and "halt".

View file

@ -984,8 +984,22 @@ password --md5 PASSWORD
If this is specified, GRUB disallows any interactive control, until you If this is specified, GRUB disallows any interactive control, until you
press the key @key{p} and enter @samp{PASSWORD}. The option press the key @key{p} and enter @samp{PASSWORD}. The option
@option{--md5} tells GRUB that @samp{PASSWORD} is in md5 format. If it @option{--md5} tells GRUB that @samp{PASSWORD} is in MD5 format. If it
is omitted grub assumes the @samp{PASSWORD} is in clear text. is omitted, GRUB assumes the @samp{PASSWORD} is in clear text.
You can encrypt your password with the command @command{md5crypt}. For
example, run the grub shell (@pxref{Invoking the grub shell}), and enter
your password:
@example
@group
grub> md5crypt
Password: **********
Encrypted: $1$U$JK7xFegdxWH6VuppCUSIb.
@end group
@end example
Then, cut and paste the encrypted password to your configuration file.
Also, you can specify an optional argument to @command{password}. See Also, you can specify an optional argument to @command{password}. See
this example: this example:

View file

@ -2370,6 +2370,67 @@ static struct builtin builtin_map =
" OS resides at a non-first drive." " OS resides at a non-first drive."
}; };
#ifdef USE_MD5_PASSWORDS
/* md5crypt */
static int
md5crypt_func (char *arg, int flags)
{
char crypted[36];
char key[32];
int saltlen;
int i;
const char *const seedchars =
"./0123456789ABCDEFGHIJKLMNOPQRST"
"UVWXYZabcdefghijklmnopqrstuvwxyz";
/* First create a salt. */
/* The magical prefix. */
grub_memset (crypted, 0, sizeof (crypted));
grub_memmove (crypted, "$1$", 3);
/* Create the length of a salt. */
saltlen = currticks ();
saltlen &= 7;
saltlen++;
/* Generate a salt. */
for (i = 0; i < saltlen; i++)
{
/* FIXME: This should be more random. */
crypted[3 + i] = seedchars[(currticks () >> i) & 0x3f];
}
/* A salt must be terminated with `$', if it is less than 8 chars. */
if (saltlen != 8)
crypted[3 + i] = '$';
#ifdef DEBUG_MD5CRYPT
grub_printf ("salt = %s\n", crypted);
#endif
/* Get a password. */
grub_memset (key, 0, sizeof (key));
get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
/* Crypt the key. */
make_md5_password (key, crypted);
grub_printf ("Encrypted: %s\n", crypted);
return 0;
}
static struct builtin builtin_md5crypt =
{
"md5crypt",
md5crypt_func,
BUILTIN_CMDLINE,
"md5crypt",
"Generate a password in MD5 format."
};
#endif /* USE_MD5_PASSWORDS */
/* module */ /* module */
static int static int
@ -4118,6 +4179,9 @@ struct builtin *builtin_table[] =
&builtin_lock, &builtin_lock,
&builtin_makeactive, &builtin_makeactive,
&builtin_map, &builtin_map,
#ifdef USE_MD5_PASSWORDS
&builtin_md5crypt,
#endif /* USE_MD5_PASSWORDS */
&builtin_module, &builtin_module,
&builtin_modulenounzip, &builtin_modulenounzip,
&builtin_partnew, &builtin_partnew,

View file

@ -1282,17 +1282,20 @@ nul_terminate (char *str)
char * char *
grub_strstr (const char *s1, const char *s2) grub_strstr (const char *s1, const char *s2)
{ {
const char *ptr, *tmp;
while (*s1) while (*s1)
{ {
const char *ptr, *tmp;
ptr = s1; ptr = s1;
tmp = s2; tmp = s2;
while (*s1 && *s1++ == *tmp++); while (*tmp && *ptr == *tmp)
ptr++, tmp++;
if (tmp > s2 && !*(tmp - 1)) if (tmp > s2 && ! *tmp)
return (char *) ptr; return (char *) s1;
s1++;
} }
return 0; return 0;

View file

@ -23,17 +23,17 @@
#include <md5.h> #include <md5.h>
#ifndef TEST #ifndef TEST
#include <shared.h> # include <shared.h>
#endif #endif
#ifdef TEST #ifdef TEST
#include <string.h> # include <string.h>
#define USE_MD5_PASSWORDS # define USE_MD5_PASSWORDS
#define USE_MD5 # define USE_MD5
#endif #endif
#ifdef USE_MD5_PASSWORDS #ifdef USE_MD5_PASSWORDS
#define USE_MD5 # define USE_MD5
#endif #endif
#ifdef USE_MD5 #ifdef USE_MD5
@ -53,7 +53,8 @@ typedef unsigned int UINT4;
*/ */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x >> (32 - (n))))) #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x >> (32 - (n)))))
static UINT4 initstate[4] = { static UINT4 initstate[4] =
{
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
}; };
@ -62,7 +63,8 @@ static char s2[4] = { 5, 9, 14, 20 };
static char s3[4] = { 4, 11, 16, 23 }; static char s3[4] = { 4, 11, 16, 23 };
static char s4[4] = { 6, 10, 15, 21 }; static char s4[4] = { 6, 10, 15, 21 };
static UINT4 T[64] = { static UINT4 T[64] =
{
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
@ -88,11 +90,12 @@ static UINT4 state[4];
static unsigned int length; static unsigned int length;
static unsigned char buffer[64]; static unsigned char buffer[64];
static void md5_transform (const unsigned char block[64]) static void
md5_transform (const unsigned char block[64])
{ {
int i, j; int i, j;
UINT4 a,b,c,d,tmp; UINT4 a,b,c,d,tmp;
const UINT4 *x = (UINT4*) block; const UINT4 *x = (UINT4 *) block;
a = state[0]; a = state[0];
b = state[1]; b = state[1];
@ -102,7 +105,7 @@ static void md5_transform (const unsigned char block[64])
/* Round 1 */ /* Round 1 */
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
{ {
tmp = a + F(b, c, d) + le32_to_cpu(x[i]) + T[i]; tmp = a + F (b, c, d) + le32_to_cpu (x[i]) + T[i];
tmp = ROTATE_LEFT (tmp, s1[i & 3]); tmp = ROTATE_LEFT (tmp, s1[i & 3]);
tmp += b; tmp += b;
a = d; d = c; c = b; b = tmp; a = d; d = c; c = b; b = tmp;
@ -110,7 +113,7 @@ static void md5_transform (const unsigned char block[64])
/* Round 2 */ /* Round 2 */
for (i = 0, j = 1; i < 16; i++, j += 5) for (i = 0, j = 1; i < 16; i++, j += 5)
{ {
tmp = a + G(b, c, d) + le32_to_cpu(x[j & 15]) + T[i+16]; tmp = a + G (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+16];
tmp = ROTATE_LEFT (tmp, s2[i & 3]); tmp = ROTATE_LEFT (tmp, s2[i & 3]);
tmp += b; tmp += b;
a = d; d = c; c = b; b = tmp; a = d; d = c; c = b; b = tmp;
@ -118,7 +121,7 @@ static void md5_transform (const unsigned char block[64])
/* Round 3 */ /* Round 3 */
for (i = 0, j = 5; i < 16; i++, j += 3) for (i = 0, j = 5; i < 16; i++, j += 3)
{ {
tmp = a + H(b, c, d) + le32_to_cpu(x[j & 15]) + T[i+32]; tmp = a + H (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+32];
tmp = ROTATE_LEFT (tmp, s3[i & 3]); tmp = ROTATE_LEFT (tmp, s3[i & 3]);
tmp += b; tmp += b;
a = d; d = c; c = b; b = tmp; a = d; d = c; c = b; b = tmp;
@ -126,7 +129,7 @@ static void md5_transform (const unsigned char block[64])
/* Round 4 */ /* Round 4 */
for (i = 0, j = 0; i < 16; i++, j += 7) for (i = 0, j = 0; i < 16; i++, j += 7)
{ {
tmp = a + I(b, c, d) + le32_to_cpu(x[j & 15]) + T[i+48]; tmp = a + I (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+48];
tmp = ROTATE_LEFT (tmp, s4[i & 3]); tmp = ROTATE_LEFT (tmp, s4[i & 3]);
tmp += b; tmp += b;
a = d; d = c; c = b; b = tmp; a = d; d = c; c = b; b = tmp;
@ -138,22 +141,26 @@ static void md5_transform (const unsigned char block[64])
state[3] += d; state[3] += d;
} }
void md5_init() { static void
memcpy ((char *)state, (char *)initstate, sizeof (initstate)); md5_init(void)
{
memcpy ((char *) state, (char *) initstate, sizeof (initstate));
length = 0; length = 0;
} }
void md5_update(const char *input, int inputlen) { static void
md5_update (const char *input, int inputlen)
{
int buflen = length & 63; int buflen = length & 63;
length += inputlen; length += inputlen;
if (buflen + inputlen < 64) if (buflen + inputlen < 64)
{ {
memcpy(buffer + buflen, input, inputlen); memcpy (buffer + buflen, input, inputlen);
buflen += inputlen; buflen += inputlen;
return; return;
} }
memcpy(buffer + buflen, input, 64 - buflen); memcpy (buffer + buflen, input, 64 - buflen);
md5_transform (buffer); md5_transform (buffer);
input += 64 - buflen; input += 64 - buflen;
inputlen -= 64 - buflen; inputlen -= 64 - buflen;
@ -163,11 +170,12 @@ void md5_update(const char *input, int inputlen) {
input += 64; input += 64;
inputlen -= 64; inputlen -= 64;
} }
memcpy(buffer, input, inputlen); memcpy (buffer, input, inputlen);
buflen = inputlen; buflen = inputlen;
} }
unsigned char* md5_final() static unsigned char *
md5_final()
{ {
int i, buflen = length & 63; int i, buflen = length & 63;
@ -180,68 +188,86 @@ unsigned char* md5_final()
buflen = 0; buflen = 0;
} }
*(UINT4 *) (buffer + 56) = cpu_to_le32(8*length); *(UINT4 *) (buffer + 56) = cpu_to_le32 (8 * length);
*(UINT4 *) (buffer + 60) = 0; *(UINT4 *) (buffer + 60) = 0;
md5_transform (buffer); md5_transform (buffer);
for (i=0; i < 4; i++) for (i = 0; i < 4; i++)
state[i] = cpu_to_le32 (state[i]); state[i] = cpu_to_le32 (state[i]);
return (unsigned char*) state; return (unsigned char *) state;
} }
#ifdef USE_MD5_PASSWORDS #ifdef USE_MD5_PASSWORDS
/* Check a password for correctness. Returns 0 if password was /* If CHECK is true, check a password for correctness. Returns 0
correct, and a value != 0 for error, similarly to strcmp. */ if password was correct, and a value != 0 for error, similarly
int check_md5_password (const char* key, const char* crypted) { to strcmp.
int keylen = strlen(key); If CHECK is false, crypt KEY and save the result in CRYPTED.
CRYPTED must have a salt. */
int
md5_password (const char *key, char *crypted, int check)
{
int keylen = strlen (key);
char *salt = crypted + 3; /* skip $1$ header */ char *salt = crypted + 3; /* skip $1$ header */
char *p; char *p;
int saltlen = strstr(salt, "$") - salt; int saltlen;
int i,n; int i, n;
unsigned char alt_result[16]; unsigned char alt_result[16];
unsigned char *digest; unsigned char *digest;
md5_init(); if (check)
md5_update(key, keylen); saltlen = strstr (salt, "$") - salt;
md5_update(salt, saltlen); else
md5_update(key, keylen); {
digest = md5_final(); char *end = strstr (salt, "$");
memcpy(alt_result, digest, 16); if (end && end - salt < 8)
saltlen = end - salt;
else
saltlen = 8;
memcpy ((char *)state, (char *)initstate, sizeof (initstate)); salt[saltlen] = '$';
}
md5_init ();
md5_update (key, keylen);
md5_update (salt, saltlen);
md5_update (key, keylen);
digest = md5_final ();
memcpy (alt_result, digest, 16);
memcpy ((char *) state, (char *) initstate, sizeof (initstate));
length = 0; length = 0;
md5_update(key, keylen); md5_update (key, keylen);
md5_update(crypted, 3 + saltlen); /* include the $1$ header */ md5_update (crypted, 3 + saltlen); /* include the $1$ header */
for (i = keylen; i > 16; i -= 16) for (i = keylen; i > 16; i -= 16)
md5_update(alt_result, 16); md5_update (alt_result, 16);
md5_update(alt_result, i); md5_update (alt_result, i);
for (i = keylen; i > 0; i >>= 1) for (i = keylen; i > 0; i >>= 1)
md5_update(key + ((i & 1) ? keylen : 0), 1); md5_update (key + ((i & 1) ? keylen : 0), 1);
digest = md5_final(); digest = md5_final ();
for (i = 0; i < 1000; i++) for (i = 0; i < 1000; i++)
{ {
memcpy(alt_result, digest, 16); memcpy (alt_result, digest, 16);
memcpy ((char *)state, (char *)initstate, sizeof (initstate)); memcpy ((char *) state, (char *) initstate, sizeof (initstate));
length = 0; length = 0;
if ((i & 1) != 0) if ((i & 1) != 0)
md5_update(key, keylen); md5_update (key, keylen);
else else
md5_update(alt_result, 16); md5_update (alt_result, 16);
if (i % 3 != 0) if (i % 3 != 0)
md5_update(salt, saltlen); md5_update (salt, saltlen);
if (i % 7 != 0) if (i % 7 != 0)
md5_update(key, keylen); md5_update (key, keylen);
if ((i & 1) != 0) if ((i & 1) != 0)
md5_update(alt_result, 16); md5_update (alt_result, 16);
else else
md5_update(key, keylen); md5_update (key, keylen);
digest = md5_final(); digest = md5_final ();
} }
p = salt + saltlen + 1; p = salt + saltlen + 1;
@ -250,35 +276,57 @@ int check_md5_password (const char* key, const char* crypted) {
unsigned int w = unsigned int w =
digest[i == 4 ? 5 : 12+i] | (digest[6+i] << 8) | (digest[i] << 16); digest[i == 4 ? 5 : 12+i] | (digest[6+i] << 8) | (digest[i] << 16);
for (n = 4; n-- > 0;) for (n = 4; n-- > 0;)
{
if (check)
{ {
if (*p++ != b64t[w & 0x3f]) if (*p++ != b64t[w & 0x3f])
return 1; return 1;
}
else
{
*p++ = b64t[w & 0x3f];
}
w >>= 6; w >>= 6;
} }
} }
{ {
unsigned int w = digest[11]; unsigned int w = digest[11];
for (n = 2; n-- > 0;) for (n = 2; n-- > 0;)
{
if (check)
{ {
if (*p++ != b64t[w & 0x3f]) if (*p++ != b64t[w & 0x3f])
return 1; return 1;
}
else
{
*p++ = b64t[w & 0x3f];
}
w >>= 6; w >>= 6;
} }
} }
if (! check)
*p = '\0';
return *p; return *p;
} }
#endif #endif
#ifdef TEST #ifdef TEST
static char* md5 (const char* input) static char *
md5 (const char *input)
{ {
memcpy ((char *)state, (char *)initstate, sizeof (initstate)); memcpy ((char *) state, (char *) initstate, sizeof (initstate));
length = 0; length = 0;
md5_update(input, strlen (input)); md5_update (input, strlen (input));
return md5_final(); return md5_final ();
} }
static void test (char *buffer, char *expected) static void
test (char *buffer, char *expected)
{ {
char result[16 * 3 +1]; char result[16 * 3 +1];
unsigned char* digest = md5 (buffer); unsigned char* digest = md5 (buffer);
@ -293,7 +341,8 @@ static void test (char *buffer, char *expected)
printf ("MD5(%s) OK\n", buffer); printf ("MD5(%s) OK\n", buffer);
} }
int main () int
main (void)
{ {
test ("", "d41d8cd98f00b204e9800998ecf8427e"); test ("", "d41d8cd98f00b204e9800998ecf8427e");
test ("a", "0cc175b9c0f1b6a831c399e269772661"); test ("a", "0cc175b9c0f1b6a831c399e269772661");
@ -315,11 +364,11 @@ int main ()
test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567890123", test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567890123",
"80063db1e6b70a2e91eac903f0e46b85"); "80063db1e6b70a2e91eac903f0e46b85");
if (check_md5_password("Hello world!", if (check_md5_password ("Hello world!",
"$1$saltstri$YMyguxXMBpd2TEZ.vS/3q1")) "$1$saltstri$YMyguxXMBpd2TEZ.vS/3q1"))
printf("Password differs\n"); printf ("Password differs\n");
else else
printf("Password OK\n"); printf ("Password OK\n");
return 0; return 0;
} }
#endif #endif

View file

@ -18,17 +18,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* Initialize the buffers to compute a new md5 checksum. This will /* If CHECK is true, check a password for correctness. Returns 0
destroy any previously calculated md5 sum. */ if password was correct, and a value != 0 for error, similarly
extern void md5_init(void); to strcmp.
If CHECK is false, crypt KEY and save the result in CRYPTED.
CRYPTED must have a salt. */
extern int md5_password (const char *key, char *crypted, int check);
/* Digestify the given input. This may be called multiple times. */ /* For convenience. */
extern void md5_update(const char *input, int inputlen); #define check_md5_password(key,crypted) md5_password((key), (crypted), 1)
#define make_md5_password(key,crypted) md5_password((key), (crypted), 0)
/* Calculate the 16 byte md5 check sum. The result will be valid until
the next md5_init(). */
extern unsigned char* md5_final(void);
/* Check a md5 password for validity. Returns 0 if password was
correct, and a value != 0 for error, similarly to strcmp. */
extern int check_md5_password (const char* key, const char* crypted);