1N/A/* md5.c - an implementation of the MD5 algorithm and MD5 crypt */
1N/A/*
1N/A * GRUB -- GRand Unified Bootloader
1N/A * Copyright (C) 2000, 2001 Free Software Foundation, Inc.
1N/A *
1N/A * This program is free software; you can redistribute it and/or modify
1N/A * it under the terms of the GNU General Public License as published by
1N/A * the Free Software Foundation; either version 2 of the License, or
1N/A * (at your option) any later version.
1N/A *
1N/A * This program is distributed in the hope that it will be useful,
1N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A * GNU General Public License for more details.
1N/A *
1N/A * You should have received a copy of the GNU General Public License
1N/A * along with this program; if not, write to the Free Software
1N/A * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1N/A */
1N/A
1N/A/* See RFC 1321 for a description of the MD5 algorithm.
1N/A */
1N/A
1N/A#include <md5.h>
1N/A#ifndef TEST
1N/A# include <shared.h>
1N/A#endif
1N/A
1N/A#ifdef TEST
1N/A# include <string.h>
1N/A# define USE_MD5_PASSWORDS
1N/A# define USE_MD5
1N/A#endif
1N/A
1N/A#ifdef USE_MD5_PASSWORDS
1N/A# define USE_MD5
1N/A#endif
1N/A
1N/A#ifdef USE_MD5
1N/A
1N/A#define cpu_to_le32(x) (x)
1N/A#define le32_to_cpu(x) cpu_to_le32(x)
1N/Atypedef unsigned int UINT4;
1N/A
1N/A/* F, G, H and I are basic MD5 functions.
1N/A */
1N/A#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
1N/A#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
1N/A#define H(x, y, z) ((x) ^ (y) ^ (z))
1N/A#define I(x, y, z) ((y) ^ ((x) | (~z)))
1N/A
1N/A/* ROTATE_LEFT rotates x left n bits.
1N/A */
1N/A#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x >> (32 - (n)))))
1N/A
1N/Astatic UINT4 initstate[4] =
1N/A{
1N/A 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
1N/A};
1N/A
1N/Astatic char s1[4] = { 7, 12, 17, 22 };
1N/Astatic char s2[4] = { 5, 9, 14, 20 };
1N/Astatic char s3[4] = { 4, 11, 16, 23 };
1N/Astatic char s4[4] = { 6, 10, 15, 21 };
1N/A
1N/Astatic UINT4 T[64] =
1N/A{
1N/A 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
1N/A 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
1N/A 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
1N/A 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
1N/A 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
1N/A 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
1N/A 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
1N/A 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
1N/A 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
1N/A 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
1N/A 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
1N/A 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
1N/A 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
1N/A 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
1N/A 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
1N/A 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
1N/A};
1N/A
1N/Astatic const char *b64t =
1N/A"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1N/A
1N/Astatic UINT4 state[4];
1N/Astatic unsigned int length;
1N/Astatic unsigned char buffer[64];
1N/A
1N/Astatic void
1N/Amd5_transform (const unsigned char block[64])
1N/A{
1N/A int i, j;
1N/A UINT4 a,b,c,d,tmp;
1N/A const UINT4 *x = (UINT4 *) block;
1N/A
1N/A a = state[0];
1N/A b = state[1];
1N/A c = state[2];
1N/A d = state[3];
1N/A
1N/A /* Round 1 */
1N/A for (i = 0; i < 16; i++)
1N/A {
1N/A tmp = a + F (b, c, d) + le32_to_cpu (x[i]) + T[i];
1N/A tmp = ROTATE_LEFT (tmp, s1[i & 3]);
1N/A tmp += b;
1N/A a = d; d = c; c = b; b = tmp;
1N/A }
1N/A /* Round 2 */
1N/A for (i = 0, j = 1; i < 16; i++, j += 5)
1N/A {
1N/A tmp = a + G (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+16];
1N/A tmp = ROTATE_LEFT (tmp, s2[i & 3]);
1N/A tmp += b;
1N/A a = d; d = c; c = b; b = tmp;
1N/A }
1N/A /* Round 3 */
1N/A for (i = 0, j = 5; i < 16; i++, j += 3)
1N/A {
1N/A tmp = a + H (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+32];
1N/A tmp = ROTATE_LEFT (tmp, s3[i & 3]);
1N/A tmp += b;
1N/A a = d; d = c; c = b; b = tmp;
1N/A }
1N/A /* Round 4 */
1N/A for (i = 0, j = 0; i < 16; i++, j += 7)
1N/A {
1N/A tmp = a + I (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+48];
1N/A tmp = ROTATE_LEFT (tmp, s4[i & 3]);
1N/A tmp += b;
1N/A a = d; d = c; c = b; b = tmp;
1N/A }
1N/A
1N/A state[0] += a;
1N/A state[1] += b;
1N/A state[2] += c;
1N/A state[3] += d;
1N/A}
1N/A
1N/Astatic void
1N/Amd5_init(void)
1N/A{
1N/A memcpy ((char *) state, (char *) initstate, sizeof (initstate));
1N/A length = 0;
1N/A}
1N/A
1N/Astatic void
1N/Amd5_update (const char *input, int inputlen)
1N/A{
1N/A int buflen = length & 63;
1N/A length += inputlen;
1N/A if (buflen + inputlen < 64)
1N/A {
1N/A memcpy (buffer + buflen, input, inputlen);
1N/A buflen += inputlen;
1N/A return;
1N/A }
1N/A
1N/A memcpy (buffer + buflen, input, 64 - buflen);
1N/A md5_transform (buffer);
1N/A input += 64 - buflen;
1N/A inputlen -= 64 - buflen;
1N/A while (inputlen >= 64)
1N/A {
1N/A md5_transform (input);
1N/A input += 64;
1N/A inputlen -= 64;
1N/A }
1N/A memcpy (buffer, input, inputlen);
1N/A buflen = inputlen;
1N/A}
1N/A
1N/Astatic unsigned char *
1N/Amd5_final()
1N/A{
1N/A int i, buflen = length & 63;
1N/A
1N/A buffer[buflen++] = 0x80;
1N/A memset (buffer+buflen, 0, 64 - buflen);
1N/A if (buflen > 56)
1N/A {
1N/A md5_transform (buffer);
1N/A memset (buffer, 0, 64);
1N/A buflen = 0;
1N/A }
1N/A
1N/A *(UINT4 *) (buffer + 56) = cpu_to_le32 (8 * length);
1N/A *(UINT4 *) (buffer + 60) = 0;
1N/A md5_transform (buffer);
1N/A
1N/A for (i = 0; i < 4; i++)
1N/A state[i] = cpu_to_le32 (state[i]);
1N/A return (unsigned char *) state;
1N/A}
1N/A
1N/A#ifdef USE_MD5_PASSWORDS
1N/A/* If CHECK is true, check a password for correctness. Returns 0
1N/A if password was correct, and a value != 0 for error, similarly
1N/A to strcmp.
1N/A If CHECK is false, crypt KEY and save the result in CRYPTED.
1N/A CRYPTED must have a salt. */
1N/Aint
1N/Amd5_password (const char *key, char *crypted, int check)
1N/A{
1N/A int keylen = strlen (key);
1N/A char *salt = crypted + 3; /* skip $1$ header */
1N/A char *p;
1N/A int saltlen;
1N/A int i, n;
1N/A unsigned char alt_result[16];
1N/A unsigned char *digest;
1N/A
1N/A if (check)
1N/A {
1N/A /* If our crypted password isn't 3 chars, then it can't be md5
1N/A crypted. So, they don't match. */
1N/A if (strlen(crypted) <= 3)
1N/A return 1;
1N/A
1N/A saltlen = strstr (salt, "$") - salt;
1N/A }
1N/A else
1N/A {
1N/A char *end = strstr (salt, "$");
1N/A if (end && end - salt < 8)
1N/A saltlen = end - salt;
1N/A else
1N/A saltlen = 8;
1N/A
1N/A salt[saltlen] = '$';
1N/A }
1N/A
1N/A md5_init ();
1N/A md5_update (key, keylen);
1N/A md5_update (salt, saltlen);
1N/A md5_update (key, keylen);
1N/A digest = md5_final ();
1N/A memcpy (alt_result, digest, 16);
1N/A
1N/A memcpy ((char *) state, (char *) initstate, sizeof (initstate));
1N/A length = 0;
1N/A md5_update (key, keylen);
1N/A md5_update (crypted, 3 + saltlen); /* include the $1$ header */
1N/A for (i = keylen; i > 16; i -= 16)
1N/A md5_update (alt_result, 16);
1N/A md5_update (alt_result, i);
1N/A
1N/A for (i = keylen; i > 0; i >>= 1)
1N/A md5_update (key + ((i & 1) ? keylen : 0), 1);
1N/A digest = md5_final ();
1N/A
1N/A for (i = 0; i < 1000; i++)
1N/A {
1N/A memcpy (alt_result, digest, 16);
1N/A
1N/A memcpy ((char *) state, (char *) initstate, sizeof (initstate));
1N/A length = 0;
1N/A if ((i & 1) != 0)
1N/A md5_update (key, keylen);
1N/A else
1N/A md5_update (alt_result, 16);
1N/A
1N/A if (i % 3 != 0)
1N/A md5_update (salt, saltlen);
1N/A
1N/A if (i % 7 != 0)
1N/A md5_update (key, keylen);
1N/A
1N/A if ((i & 1) != 0)
1N/A md5_update (alt_result, 16);
1N/A else
1N/A md5_update (key, keylen);
1N/A digest = md5_final ();
1N/A }
1N/A
1N/A p = salt + saltlen + 1;
1N/A for (i = 0; i < 5; i++)
1N/A {
1N/A unsigned int w =
1N/A digest[i == 4 ? 5 : 12+i] | (digest[6+i] << 8) | (digest[i] << 16);
1N/A for (n = 4; n-- > 0;)
1N/A {
1N/A if (check)
1N/A {
1N/A if (*p++ != b64t[w & 0x3f])
1N/A return 1;
1N/A }
1N/A else
1N/A {
1N/A *p++ = b64t[w & 0x3f];
1N/A }
1N/A
1N/A w >>= 6;
1N/A }
1N/A }
1N/A {
1N/A unsigned int w = digest[11];
1N/A for (n = 2; n-- > 0;)
1N/A {
1N/A if (check)
1N/A {
1N/A if (*p++ != b64t[w & 0x3f])
1N/A return 1;
1N/A }
1N/A else
1N/A {
1N/A *p++ = b64t[w & 0x3f];
1N/A }
1N/A
1N/A w >>= 6;
1N/A }
1N/A }
1N/A
1N/A if (! check)
1N/A *p = '\0';
1N/A
1N/A return *p;
1N/A}
1N/A#endif
1N/A
1N/A#ifdef TEST
1N/Astatic char *
1N/Amd5 (const char *input)
1N/A{
1N/A memcpy ((char *) state, (char *) initstate, sizeof (initstate));
1N/A length = 0;
1N/A md5_update (input, strlen (input));
1N/A return md5_final ();
1N/A}
1N/A
1N/Astatic void
1N/Atest (char *buffer, char *expected)
1N/A{
1N/A char result[16 * 3 +1];
1N/A unsigned char* digest = md5 (buffer);
1N/A int i;
1N/A
1N/A for (i=0; i < 16; i++)
1N/A sprintf (result+2*i, "%02x", digest[i]);
1N/A
1N/A if (strcmp (result, expected))
1N/A printf ("MD5(%s) failed: %s\n", buffer, result);
1N/A else
1N/A printf ("MD5(%s) OK\n", buffer);
1N/A}
1N/A
1N/Aint
1N/Amain (void)
1N/A{
1N/A test ("", "d41d8cd98f00b204e9800998ecf8427e");
1N/A test ("a", "0cc175b9c0f1b6a831c399e269772661");
1N/A test ("abc", "900150983cd24fb0d6963f7d28e17f72");
1N/A test ("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
1N/A test ("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
1N/A test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
1N/A "d174ab98d277d9f5a5611c2c9f419d9f");
1N/A test ("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
1N/A "57edf4a22be3c955ac49da2e2107b67a");
1N/A test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz3456",
1N/A "6831fa90115bb9a54fbcd4f9fee0b5c4");
1N/A test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz345",
1N/A "bc40505cc94a43b7ff3e2ac027325233");
1N/A test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567",
1N/A "fa94b73a6f072a0239b52acacfbcf9fa");
1N/A test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz345678901234",
1N/A "bd201eae17f29568927414fa326f1267");
1N/A test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567890123",
1N/A "80063db1e6b70a2e91eac903f0e46b85");
1N/A
1N/A if (check_md5_password ("Hello world!",
1N/A "$1$saltstri$YMyguxXMBpd2TEZ.vS/3q1"))
1N/A printf ("Password differs\n");
1N/A else
1N/A printf ("Password OK\n");
1N/A return 0;
1N/A}
1N/A#endif
1N/A
1N/A#endif