| #include "os.h" |
| #include <libsec.h> |
| |
| /* |
| * rfc1321 requires that I include this. The code is new. The constants |
| * all come from the rfc (hence the copyright). We trade a table for the |
| * macros in rfc. The total size is a lot less. -- presotto |
| * |
| * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All |
| * rights reserved. |
| * |
| * License to copy and use this software is granted provided that it |
| * is identified as the "RSA Data Security, Inc. MD5 Message-Digest |
| * Algorithm" in all material mentioning or referencing this software |
| * or this function. |
| * |
| * License is also granted to make and use derivative works provided |
| * that such works are identified as "derived from the RSA Data |
| * Security, Inc. MD5 Message-Digest Algorithm" in all material |
| * mentioning or referencing the derived work. |
| * |
| * RSA Data Security, Inc. makes no representations concerning either |
| * the merchantability of this software or the suitability of this |
| * software forany particular purpose. It is provided "as is" |
| * without express or implied warranty of any kind. |
| * These notices must be retained in any copies of any part of this |
| * documentation and/or software. |
| */ |
| |
| static void encode(uchar*, u32int*, ulong); |
| |
| extern void _md5block(uchar*, ulong, u32int*); |
| |
| MD5state* |
| md5(uchar *p, ulong len, uchar *digest, MD5state *s) |
| { |
| u32int x[16]; |
| uchar buf[128]; |
| int i; |
| uchar *e; |
| |
| if(s == nil){ |
| s = malloc(sizeof(*s)); |
| if(s == nil) |
| return nil; |
| memset(s, 0, sizeof(*s)); |
| s->malloced = 1; |
| } |
| |
| if(s->seeded == 0){ |
| /* seed the state, these constants would look nicer big-endian */ |
| s->state[0] = 0x67452301; |
| s->state[1] = 0xefcdab89; |
| s->state[2] = 0x98badcfe; |
| s->state[3] = 0x10325476; |
| s->seeded = 1; |
| } |
| |
| /* fill out the partial 64 byte block from previous calls */ |
| if(s->blen){ |
| i = 64 - s->blen; |
| if(len < i) |
| i = len; |
| memmove(s->buf + s->blen, p, i); |
| len -= i; |
| s->blen += i; |
| p += i; |
| if(s->blen == 64){ |
| _md5block(s->buf, s->blen, s->state); |
| s->len += s->blen; |
| s->blen = 0; |
| } |
| } |
| |
| /* do 64 byte blocks */ |
| i = len & ~0x3f; |
| if(i){ |
| _md5block(p, i, s->state); |
| s->len += i; |
| len -= i; |
| p += i; |
| } |
| |
| /* save the left overs if not last call */ |
| if(digest == 0){ |
| if(len){ |
| memmove(s->buf, p, len); |
| s->blen += len; |
| } |
| return s; |
| } |
| |
| /* |
| * this is the last time through, pad what's left with 0x80, |
| * 0's, and the input count to create a multiple of 64 bytes |
| */ |
| if(s->blen){ |
| p = s->buf; |
| len = s->blen; |
| } else { |
| memmove(buf, p, len); |
| p = buf; |
| } |
| s->len += len; |
| e = p + len; |
| if(len < 56) |
| i = 56 - len; |
| else |
| i = 120 - len; |
| memset(e, 0, i); |
| *e = 0x80; |
| len += i; |
| |
| /* append the count */ |
| x[0] = s->len<<3; |
| x[1] = s->len>>29; |
| encode(p+len, x, 8); |
| |
| /* digest the last part */ |
| _md5block(p, len+8, s->state); |
| s->len += len; |
| |
| /* return result and free state */ |
| encode(digest, s->state, MD5dlen); |
| if(s->malloced == 1) |
| free(s); |
| return nil; |
| } |
| |
| /* |
| * encodes input (u32int) into output (uchar). Assumes len is |
| * a multiple of 4. |
| */ |
| static void |
| encode(uchar *output, u32int *input, ulong len) |
| { |
| u32int x; |
| uchar *e; |
| |
| for(e = output + len; output < e;) { |
| x = *input++; |
| *output++ = x; |
| *output++ = x >> 8; |
| *output++ = x >> 16; |
| *output++ = x >> 24; |
| } |
| } |