1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2001-2007, Tom St Denis 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* LibTomCrypt, modular cryptographic library -- Tom St Denis 30 * 31 * LibTomCrypt is a library that provides various cryptographic 32 * algorithms in a highly modular and flexible manner. 33 * 34 * The library is free for all purposes without any express 35 * guarantee it works. 36 * 37 * Tom St Denis, tomstdenis@gmail.com, http://libtom.org 38 */ 39 #include "tomcrypt.h" 40 41 42 /** 43 @file md5.c 44 LTC_MD5 hash function by Tom St Denis 45 */ 46 47 #ifdef LTC_MD5 48 49 const struct ltc_hash_descriptor md5_desc = 50 { 51 "md5", 52 3, 53 16, 54 64, 55 56 /* OID */ 57 { 1, 2, 840, 113549, 2, 5, }, 58 6, 59 60 &md5_init, 61 &md5_process, 62 &md5_done, 63 &md5_test, 64 NULL 65 }; 66 67 #define F(x,y,z) (z ^ (x & (y ^ z))) 68 #define G(x,y,z) (y ^ (z & (y ^ x))) 69 #define H(x,y,z) (x^y^z) 70 #define I(x,y,z) (y^(x|(~z))) 71 72 #ifdef LTC_SMALL_CODE 73 74 #define FF(a,b,c,d,M,s,t) \ 75 a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b; 76 77 #define GG(a,b,c,d,M,s,t) \ 78 a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b; 79 80 #define HH(a,b,c,d,M,s,t) \ 81 a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b; 82 83 #define II(a,b,c,d,M,s,t) \ 84 a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b; 85 86 static const unsigned char Worder[64] = { 87 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 88 1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12, 89 5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2, 90 0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9 91 }; 92 93 static const unsigned char Rorder[64] = { 94 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22, 95 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, 96 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23, 97 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21 98 }; 99 100 static const ulong32 Korder[64] = { 101 0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL, 102 0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL, 103 0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL, 104 0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL, 105 0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL, 106 0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL, 107 0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL, 108 0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL 109 }; 110 111 #else 112 113 #define FF(a,b,c,d,M,s,t) \ 114 a = (a + F(b,c,d) + M + t); a = ROLc(a, s) + b; 115 116 #define GG(a,b,c,d,M,s,t) \ 117 a = (a + G(b,c,d) + M + t); a = ROLc(a, s) + b; 118 119 #define HH(a,b,c,d,M,s,t) \ 120 a = (a + H(b,c,d) + M + t); a = ROLc(a, s) + b; 121 122 #define II(a,b,c,d,M,s,t) \ 123 a = (a + I(b,c,d) + M + t); a = ROLc(a, s) + b; 124 125 126 #endif 127 128 #ifdef LTC_CLEAN_STACK 129 static int _md5_compress(hash_state *md, unsigned char *buf) 130 #else 131 static int md5_compress(hash_state *md, unsigned char *buf) 132 #endif 133 { 134 ulong32 i, W[16], a, b, c, d; 135 #ifdef LTC_SMALL_CODE 136 ulong32 t; 137 #endif 138 139 /* copy the state into 512-bits into W[0..15] */ 140 for (i = 0; i < 16; i++) { 141 LOAD32L(W[i], buf + (4*i)); 142 } 143 144 /* copy state */ 145 a = md->md5.state[0]; 146 b = md->md5.state[1]; 147 c = md->md5.state[2]; 148 d = md->md5.state[3]; 149 150 #ifdef LTC_SMALL_CODE 151 for (i = 0; i < 16; ++i) { 152 FF(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]); 153 t = d; d = c; c = b; b = a; a = t; 154 } 155 156 for (; i < 32; ++i) { 157 GG(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]); 158 t = d; d = c; c = b; b = a; a = t; 159 } 160 161 for (; i < 48; ++i) { 162 HH(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]); 163 t = d; d = c; c = b; b = a; a = t; 164 } 165 166 for (; i < 64; ++i) { 167 II(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]); 168 t = d; d = c; c = b; b = a; a = t; 169 } 170 171 #else 172 FF(a,b,c,d,W[0],7,0xd76aa478UL) 173 FF(d,a,b,c,W[1],12,0xe8c7b756UL) 174 FF(c,d,a,b,W[2],17,0x242070dbUL) 175 FF(b,c,d,a,W[3],22,0xc1bdceeeUL) 176 FF(a,b,c,d,W[4],7,0xf57c0fafUL) 177 FF(d,a,b,c,W[5],12,0x4787c62aUL) 178 FF(c,d,a,b,W[6],17,0xa8304613UL) 179 FF(b,c,d,a,W[7],22,0xfd469501UL) 180 FF(a,b,c,d,W[8],7,0x698098d8UL) 181 FF(d,a,b,c,W[9],12,0x8b44f7afUL) 182 FF(c,d,a,b,W[10],17,0xffff5bb1UL) 183 FF(b,c,d,a,W[11],22,0x895cd7beUL) 184 FF(a,b,c,d,W[12],7,0x6b901122UL) 185 FF(d,a,b,c,W[13],12,0xfd987193UL) 186 FF(c,d,a,b,W[14],17,0xa679438eUL) 187 FF(b,c,d,a,W[15],22,0x49b40821UL) 188 GG(a,b,c,d,W[1],5,0xf61e2562UL) 189 GG(d,a,b,c,W[6],9,0xc040b340UL) 190 GG(c,d,a,b,W[11],14,0x265e5a51UL) 191 GG(b,c,d,a,W[0],20,0xe9b6c7aaUL) 192 GG(a,b,c,d,W[5],5,0xd62f105dUL) 193 GG(d,a,b,c,W[10],9,0x02441453UL) 194 GG(c,d,a,b,W[15],14,0xd8a1e681UL) 195 GG(b,c,d,a,W[4],20,0xe7d3fbc8UL) 196 GG(a,b,c,d,W[9],5,0x21e1cde6UL) 197 GG(d,a,b,c,W[14],9,0xc33707d6UL) 198 GG(c,d,a,b,W[3],14,0xf4d50d87UL) 199 GG(b,c,d,a,W[8],20,0x455a14edUL) 200 GG(a,b,c,d,W[13],5,0xa9e3e905UL) 201 GG(d,a,b,c,W[2],9,0xfcefa3f8UL) 202 GG(c,d,a,b,W[7],14,0x676f02d9UL) 203 GG(b,c,d,a,W[12],20,0x8d2a4c8aUL) 204 HH(a,b,c,d,W[5],4,0xfffa3942UL) 205 HH(d,a,b,c,W[8],11,0x8771f681UL) 206 HH(c,d,a,b,W[11],16,0x6d9d6122UL) 207 HH(b,c,d,a,W[14],23,0xfde5380cUL) 208 HH(a,b,c,d,W[1],4,0xa4beea44UL) 209 HH(d,a,b,c,W[4],11,0x4bdecfa9UL) 210 HH(c,d,a,b,W[7],16,0xf6bb4b60UL) 211 HH(b,c,d,a,W[10],23,0xbebfbc70UL) 212 HH(a,b,c,d,W[13],4,0x289b7ec6UL) 213 HH(d,a,b,c,W[0],11,0xeaa127faUL) 214 HH(c,d,a,b,W[3],16,0xd4ef3085UL) 215 HH(b,c,d,a,W[6],23,0x04881d05UL) 216 HH(a,b,c,d,W[9],4,0xd9d4d039UL) 217 HH(d,a,b,c,W[12],11,0xe6db99e5UL) 218 HH(c,d,a,b,W[15],16,0x1fa27cf8UL) 219 HH(b,c,d,a,W[2],23,0xc4ac5665UL) 220 II(a,b,c,d,W[0],6,0xf4292244UL) 221 II(d,a,b,c,W[7],10,0x432aff97UL) 222 II(c,d,a,b,W[14],15,0xab9423a7UL) 223 II(b,c,d,a,W[5],21,0xfc93a039UL) 224 II(a,b,c,d,W[12],6,0x655b59c3UL) 225 II(d,a,b,c,W[3],10,0x8f0ccc92UL) 226 II(c,d,a,b,W[10],15,0xffeff47dUL) 227 II(b,c,d,a,W[1],21,0x85845dd1UL) 228 II(a,b,c,d,W[8],6,0x6fa87e4fUL) 229 II(d,a,b,c,W[15],10,0xfe2ce6e0UL) 230 II(c,d,a,b,W[6],15,0xa3014314UL) 231 II(b,c,d,a,W[13],21,0x4e0811a1UL) 232 II(a,b,c,d,W[4],6,0xf7537e82UL) 233 II(d,a,b,c,W[11],10,0xbd3af235UL) 234 II(c,d,a,b,W[2],15,0x2ad7d2bbUL) 235 II(b,c,d,a,W[9],21,0xeb86d391UL) 236 #endif 237 238 md->md5.state[0] = md->md5.state[0] + a; 239 md->md5.state[1] = md->md5.state[1] + b; 240 md->md5.state[2] = md->md5.state[2] + c; 241 md->md5.state[3] = md->md5.state[3] + d; 242 243 return CRYPT_OK; 244 } 245 246 #ifdef LTC_CLEAN_STACK 247 static int md5_compress(hash_state *md, unsigned char *buf) 248 { 249 int err; 250 err = _md5_compress(md, buf); 251 burn_stack(sizeof(ulong32) * 21); 252 return err; 253 } 254 #endif 255 256 /** 257 Initialize the hash state 258 @param md The hash state you wish to initialize 259 @return CRYPT_OK if successful 260 */ 261 int md5_init(hash_state * md) 262 { 263 LTC_ARGCHK(md != NULL); 264 md->md5.state[0] = 0x67452301UL; 265 md->md5.state[1] = 0xefcdab89UL; 266 md->md5.state[2] = 0x98badcfeUL; 267 md->md5.state[3] = 0x10325476UL; 268 md->md5.curlen = 0; 269 md->md5.length = 0; 270 return CRYPT_OK; 271 } 272 273 /** 274 Process a block of memory though the hash 275 @param md The hash state 276 @param in The data to hash 277 @param inlen The length of the data (octets) 278 @return CRYPT_OK if successful 279 */ 280 HASH_PROCESS(md5_process, md5_compress, md5, 64) 281 282 /** 283 Terminate the hash to get the digest 284 @param md The hash state 285 @param out [out] The destination of the hash (16 bytes) 286 @return CRYPT_OK if successful 287 */ 288 int md5_done(hash_state * md, unsigned char *out) 289 { 290 int i; 291 292 LTC_ARGCHK(md != NULL); 293 LTC_ARGCHK(out != NULL); 294 295 if (md->md5.curlen >= sizeof(md->md5.buf)) { 296 return CRYPT_INVALID_ARG; 297 } 298 299 300 /* increase the length of the message */ 301 md->md5.length += md->md5.curlen * 8; 302 303 /* append the '1' bit */ 304 md->md5.buf[md->md5.curlen++] = (unsigned char)0x80; 305 306 /* if the length is currently above 56 bytes we append zeros 307 * then compress. Then we can fall back to padding zeros and length 308 * encoding like normal. 309 */ 310 if (md->md5.curlen > 56) { 311 while (md->md5.curlen < 64) { 312 md->md5.buf[md->md5.curlen++] = (unsigned char)0; 313 } 314 md5_compress(md, md->md5.buf); 315 md->md5.curlen = 0; 316 } 317 318 /* pad upto 56 bytes of zeroes */ 319 while (md->md5.curlen < 56) { 320 md->md5.buf[md->md5.curlen++] = (unsigned char)0; 321 } 322 323 /* store length */ 324 STORE64L(md->md5.length, md->md5.buf+56); 325 md5_compress(md, md->md5.buf); 326 327 /* copy output */ 328 for (i = 0; i < 4; i++) { 329 STORE32L(md->md5.state[i], out+(4*i)); 330 } 331 #ifdef LTC_CLEAN_STACK 332 zeromem(md, sizeof(hash_state)); 333 #endif 334 return CRYPT_OK; 335 } 336 337 /** 338 Self-test the hash 339 @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled 340 */ 341 int md5_test(void) 342 { 343 #ifndef LTC_TEST 344 return CRYPT_NOP; 345 #else 346 static const struct { 347 const char *msg; 348 unsigned char hash[16]; 349 } tests[] = { 350 { "", 351 { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 352 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } }, 353 { "a", 354 {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 355 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } }, 356 { "abc", 357 { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 358 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } }, 359 { "message digest", 360 { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 361 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } }, 362 { "abcdefghijklmnopqrstuvwxyz", 363 { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 364 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } }, 365 { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 366 { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 367 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } }, 368 { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 369 { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 370 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }, 371 { NULL, { 0 } } 372 }; 373 374 int i; 375 unsigned char tmp[16]; 376 hash_state md; 377 378 for (i = 0; tests[i].msg != NULL; i++) { 379 md5_init(&md); 380 md5_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg)); 381 md5_done(&md, tmp); 382 if (XMEMCMP(tmp, tests[i].hash, 16) != 0) { 383 return CRYPT_FAIL_TESTVECTOR; 384 } 385 } 386 return CRYPT_OK; 387 #endif 388 } 389 390 #endif 391 392 393 394 /* $Source: /cvs/libtom/libtomcrypt/src/hashes/md5.c,v $ */ 395 /* $Revision: 1.10 $ */ 396 /* $Date: 2007/05/12 14:25:28 $ */ 397