add a new command, md5crypt.
This commit is contained in:
parent
06adfc82ff
commit
4928cfdad2
7 changed files with 234 additions and 86 deletions
21
ChangeLog
21
ChangeLog
|
@ -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>
|
||||
|
||||
* docs/user-ref.texi: Fixed several typos and some inappropriate
|
||||
|
|
1
NEWS
1
NEWS
|
@ -11,6 +11,7 @@ New in 1.0 - XXXX-XX-XX:
|
|||
is given. This command can now also be used to protect specific menu
|
||||
items with their own passwords.
|
||||
* New command, "displayapm".
|
||||
* New command, "md5crypt".
|
||||
|
||||
New in 0.5.96 - 2000-10-04:
|
||||
* New commands, "reboot" and "halt".
|
||||
|
|
|
@ -984,8 +984,22 @@ password --md5 PASSWORD
|
|||
|
||||
If this is specified, GRUB disallows any interactive control, until you
|
||||
press the key @key{p} and enter @samp{PASSWORD}. The option
|
||||
@option{--md5} tells GRUB that @samp{PASSWORD} is in md5 format. If it
|
||||
is omitted grub assumes the @samp{PASSWORD} is in clear text.
|
||||
@option{--md5} tells GRUB that @samp{PASSWORD} is in MD5 format. If it
|
||||
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
|
||||
this example:
|
||||
|
|
|
@ -2370,6 +2370,67 @@ static struct builtin builtin_map =
|
|||
" 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 */
|
||||
static int
|
||||
|
@ -4118,6 +4179,9 @@ struct builtin *builtin_table[] =
|
|||
&builtin_lock,
|
||||
&builtin_makeactive,
|
||||
&builtin_map,
|
||||
#ifdef USE_MD5_PASSWORDS
|
||||
&builtin_md5crypt,
|
||||
#endif /* USE_MD5_PASSWORDS */
|
||||
&builtin_module,
|
||||
&builtin_modulenounzip,
|
||||
&builtin_partnew,
|
||||
|
|
|
@ -1282,17 +1282,20 @@ nul_terminate (char *str)
|
|||
char *
|
||||
grub_strstr (const char *s1, const char *s2)
|
||||
{
|
||||
const char *ptr, *tmp;
|
||||
|
||||
while (*s1)
|
||||
{
|
||||
const char *ptr, *tmp;
|
||||
|
||||
ptr = s1;
|
||||
tmp = s2;
|
||||
|
||||
while (*s1 && *s1++ == *tmp++);
|
||||
while (*tmp && *ptr == *tmp)
|
||||
ptr++, tmp++;
|
||||
|
||||
if (tmp > s2 && !*(tmp - 1))
|
||||
return (char *) ptr;
|
||||
if (tmp > s2 && ! *tmp)
|
||||
return (char *) s1;
|
||||
|
||||
s1++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
169
stage2/md5.c
169
stage2/md5.c
|
@ -23,17 +23,17 @@
|
|||
|
||||
#include <md5.h>
|
||||
#ifndef TEST
|
||||
#include <shared.h>
|
||||
# include <shared.h>
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
#include <string.h>
|
||||
#define USE_MD5_PASSWORDS
|
||||
#define USE_MD5
|
||||
# include <string.h>
|
||||
# define USE_MD5_PASSWORDS
|
||||
# define USE_MD5
|
||||
#endif
|
||||
|
||||
#ifdef USE_MD5_PASSWORDS
|
||||
#define USE_MD5
|
||||
# define USE_MD5
|
||||
#endif
|
||||
|
||||
#ifdef USE_MD5
|
||||
|
@ -53,7 +53,8 @@ typedef unsigned int UINT4;
|
|||
*/
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x >> (32 - (n)))))
|
||||
|
||||
static UINT4 initstate[4] = {
|
||||
static UINT4 initstate[4] =
|
||||
{
|
||||
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 s4[4] = { 6, 10, 15, 21 };
|
||||
|
||||
static UINT4 T[64] = {
|
||||
static UINT4 T[64] =
|
||||
{
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
|
@ -88,11 +90,12 @@ static UINT4 state[4];
|
|||
static unsigned int length;
|
||||
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;
|
||||
UINT4 a,b,c,d,tmp;
|
||||
const UINT4 *x = (UINT4*) block;
|
||||
const UINT4 *x = (UINT4 *) block;
|
||||
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
|
@ -102,7 +105,7 @@ static void md5_transform (const unsigned char block[64])
|
|||
/* Round 1 */
|
||||
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 += b;
|
||||
a = d; d = c; c = b; b = tmp;
|
||||
|
@ -110,7 +113,7 @@ static void md5_transform (const unsigned char block[64])
|
|||
/* Round 2 */
|
||||
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 += b;
|
||||
a = d; d = c; c = b; b = tmp;
|
||||
|
@ -118,7 +121,7 @@ static void md5_transform (const unsigned char block[64])
|
|||
/* Round 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 += b;
|
||||
a = d; d = c; c = b; b = tmp;
|
||||
|
@ -126,7 +129,7 @@ static void md5_transform (const unsigned char block[64])
|
|||
/* Round 4 */
|
||||
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 += b;
|
||||
a = d; d = c; c = b; b = tmp;
|
||||
|
@ -138,22 +141,26 @@ static void md5_transform (const unsigned char block[64])
|
|||
state[3] += d;
|
||||
}
|
||||
|
||||
void md5_init() {
|
||||
memcpy ((char *)state, (char *)initstate, sizeof (initstate));
|
||||
static void
|
||||
md5_init(void)
|
||||
{
|
||||
memcpy ((char *) state, (char *) initstate, sizeof (initstate));
|
||||
length = 0;
|
||||
}
|
||||
|
||||
void md5_update(const char *input, int inputlen) {
|
||||
static void
|
||||
md5_update (const char *input, int inputlen)
|
||||
{
|
||||
int buflen = length & 63;
|
||||
length += inputlen;
|
||||
if (buflen + inputlen < 64)
|
||||
{
|
||||
memcpy(buffer + buflen, input, inputlen);
|
||||
memcpy (buffer + buflen, input, inputlen);
|
||||
buflen += inputlen;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(buffer + buflen, input, 64 - buflen);
|
||||
memcpy (buffer + buflen, input, 64 - buflen);
|
||||
md5_transform (buffer);
|
||||
input += 64 - buflen;
|
||||
inputlen -= 64 - buflen;
|
||||
|
@ -163,11 +170,12 @@ void md5_update(const char *input, int inputlen) {
|
|||
input += 64;
|
||||
inputlen -= 64;
|
||||
}
|
||||
memcpy(buffer, input, inputlen);
|
||||
memcpy (buffer, input, inputlen);
|
||||
buflen = inputlen;
|
||||
}
|
||||
|
||||
unsigned char* md5_final()
|
||||
static unsigned char *
|
||||
md5_final()
|
||||
{
|
||||
int i, buflen = length & 63;
|
||||
|
||||
|
@ -180,68 +188,86 @@ unsigned char* md5_final()
|
|||
buflen = 0;
|
||||
}
|
||||
|
||||
*(UINT4 *) (buffer + 56) = cpu_to_le32(8*length);
|
||||
*(UINT4 *) (buffer + 56) = cpu_to_le32 (8 * length);
|
||||
*(UINT4 *) (buffer + 60) = 0;
|
||||
md5_transform (buffer);
|
||||
|
||||
for (i=0; i < 4; i++)
|
||||
for (i = 0; i < 4; i++)
|
||||
state[i] = cpu_to_le32 (state[i]);
|
||||
return (unsigned char*) state;
|
||||
return (unsigned char *) state;
|
||||
}
|
||||
|
||||
#ifdef USE_MD5_PASSWORDS
|
||||
/* Check a password for correctness. Returns 0 if password was
|
||||
correct, and a value != 0 for error, similarly to strcmp. */
|
||||
int check_md5_password (const char* key, const char* crypted) {
|
||||
int keylen = strlen(key);
|
||||
/* If CHECK is true, check a password for correctness. Returns 0
|
||||
if password was correct, and a value != 0 for error, similarly
|
||||
to strcmp.
|
||||
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 *p;
|
||||
int saltlen = strstr(salt, "$") - salt;
|
||||
int i,n;
|
||||
int saltlen;
|
||||
int i, n;
|
||||
unsigned char alt_result[16];
|
||||
unsigned char *digest;
|
||||
|
||||
md5_init();
|
||||
md5_update(key, keylen);
|
||||
md5_update(salt, saltlen);
|
||||
md5_update(key, keylen);
|
||||
digest = md5_final();
|
||||
memcpy(alt_result, digest, 16);
|
||||
if (check)
|
||||
saltlen = strstr (salt, "$") - salt;
|
||||
else
|
||||
{
|
||||
char *end = strstr (salt, "$");
|
||||
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;
|
||||
md5_update(key, keylen);
|
||||
md5_update(crypted, 3 + saltlen); /* include the $1$ header */
|
||||
md5_update (key, keylen);
|
||||
md5_update (crypted, 3 + saltlen); /* include the $1$ header */
|
||||
for (i = keylen; i > 16; i -= 16)
|
||||
md5_update(alt_result, 16);
|
||||
md5_update(alt_result, i);
|
||||
md5_update (alt_result, 16);
|
||||
md5_update (alt_result, i);
|
||||
|
||||
for (i = keylen; i > 0; i >>= 1)
|
||||
md5_update(key + ((i & 1) ? keylen : 0), 1);
|
||||
digest = md5_final();
|
||||
md5_update (key + ((i & 1) ? keylen : 0), 1);
|
||||
digest = md5_final ();
|
||||
|
||||
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;
|
||||
if ((i & 1) != 0)
|
||||
md5_update(key, keylen);
|
||||
md5_update (key, keylen);
|
||||
else
|
||||
md5_update(alt_result, 16);
|
||||
md5_update (alt_result, 16);
|
||||
|
||||
if (i % 3 != 0)
|
||||
md5_update(salt, saltlen);
|
||||
md5_update (salt, saltlen);
|
||||
|
||||
if (i % 7 != 0)
|
||||
md5_update(key, keylen);
|
||||
md5_update (key, keylen);
|
||||
|
||||
if ((i & 1) != 0)
|
||||
md5_update(alt_result, 16);
|
||||
md5_update (alt_result, 16);
|
||||
else
|
||||
md5_update(key, keylen);
|
||||
digest = md5_final();
|
||||
md5_update (key, keylen);
|
||||
digest = md5_final ();
|
||||
}
|
||||
|
||||
p = salt + saltlen + 1;
|
||||
|
@ -250,35 +276,57 @@ int check_md5_password (const char* key, const char* crypted) {
|
|||
unsigned int w =
|
||||
digest[i == 4 ? 5 : 12+i] | (digest[6+i] << 8) | (digest[i] << 16);
|
||||
for (n = 4; n-- > 0;)
|
||||
{
|
||||
if (check)
|
||||
{
|
||||
if (*p++ != b64t[w & 0x3f])
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = b64t[w & 0x3f];
|
||||
}
|
||||
|
||||
w >>= 6;
|
||||
}
|
||||
}
|
||||
{
|
||||
unsigned int w = digest[11];
|
||||
for (n = 2; n-- > 0;)
|
||||
{
|
||||
if (check)
|
||||
{
|
||||
if (*p++ != b64t[w & 0x3f])
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = b64t[w & 0x3f];
|
||||
}
|
||||
|
||||
w >>= 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (! check)
|
||||
*p = '\0';
|
||||
|
||||
return *p;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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;
|
||||
md5_update(input, strlen (input));
|
||||
return md5_final();
|
||||
md5_update (input, strlen (input));
|
||||
return md5_final ();
|
||||
}
|
||||
|
||||
static void test (char *buffer, char *expected)
|
||||
static void
|
||||
test (char *buffer, char *expected)
|
||||
{
|
||||
char result[16 * 3 +1];
|
||||
unsigned char* digest = md5 (buffer);
|
||||
|
@ -293,7 +341,8 @@ static void test (char *buffer, char *expected)
|
|||
printf ("MD5(%s) OK\n", buffer);
|
||||
}
|
||||
|
||||
int main ()
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
test ("", "d41d8cd98f00b204e9800998ecf8427e");
|
||||
test ("a", "0cc175b9c0f1b6a831c399e269772661");
|
||||
|
@ -315,11 +364,11 @@ int main ()
|
|||
test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567890123",
|
||||
"80063db1e6b70a2e91eac903f0e46b85");
|
||||
|
||||
if (check_md5_password("Hello world!",
|
||||
if (check_md5_password ("Hello world!",
|
||||
"$1$saltstri$YMyguxXMBpd2TEZ.vS/3q1"))
|
||||
printf("Password differs\n");
|
||||
printf ("Password differs\n");
|
||||
else
|
||||
printf("Password OK\n");
|
||||
printf ("Password OK\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
22
stage2/md5.h
22
stage2/md5.h
|
@ -18,17 +18,13 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* Initialize the buffers to compute a new md5 checksum. This will
|
||||
destroy any previously calculated md5 sum. */
|
||||
extern void md5_init(void);
|
||||
/* If CHECK is true, check a password for correctness. Returns 0
|
||||
if password was correct, and a value != 0 for error, similarly
|
||||
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. */
|
||||
extern void md5_update(const char *input, int inputlen);
|
||||
|
||||
/* 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);
|
||||
/* For convenience. */
|
||||
#define check_md5_password(key,crypted) md5_password((key), (crypted), 1)
|
||||
#define make_md5_password(key,crypted) md5_password((key), (crypted), 0)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue