|
| 1 | +#include "md5.h" |
| 2 | + |
| 3 | +static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, |
| 4 | + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, |
| 5 | + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, |
| 6 | + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; |
| 7 | + |
| 8 | +static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, |
| 9 | + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, |
| 10 | + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, |
| 11 | + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, |
| 12 | + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, |
| 13 | + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, |
| 14 | + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, |
| 15 | + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, |
| 16 | + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, |
| 17 | + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, |
| 18 | + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, |
| 19 | + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, |
| 20 | + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, |
| 21 | + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, |
| 22 | + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, |
| 23 | + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; |
| 24 | + |
| 25 | +/* |
| 26 | + * Padding used to make the size (in bits) of the input congruent to 448 mod 512 |
| 27 | + */ |
| 28 | +static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 29 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 30 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 31 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 32 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 33 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 34 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 35 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 36 | + |
| 37 | +uint32_t MD5::rotateLeft(uint32_t x, uint32_t n) |
| 38 | +{ |
| 39 | + return (x << n) | (x >> (32 - n)); |
| 40 | +} |
| 41 | + |
| 42 | +void MD5::Init(MD5Context *ctx){ |
| 43 | + ctx->size = (uint64_t)0; |
| 44 | + |
| 45 | + ctx->buffer[0] = (uint32_t)A; |
| 46 | + ctx->buffer[1] = (uint32_t)B; |
| 47 | + ctx->buffer[2] = (uint32_t)C; |
| 48 | + ctx->buffer[3] = (uint32_t)D; |
| 49 | +} |
| 50 | + |
| 51 | +/* |
| 52 | + * Add some amount of input to the context |
| 53 | + * |
| 54 | + * If the input fills out a block of 512 bits, apply the algorithm (md5Step) |
| 55 | + * and save the result in the buffer. Also updates the overall size. |
| 56 | + */ |
| 57 | +void MD5::Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len){ |
| 58 | + uint32_t input[16]; |
| 59 | + unsigned int offset = ctx->size % 64; |
| 60 | + ctx->size += (uint64_t)input_len; |
| 61 | + |
| 62 | + // Copy each byte in input_buffer into the next space in our context input |
| 63 | + for(unsigned int i = 0; i < input_len; ++i){ |
| 64 | + ctx->input[offset++] = (uint8_t)*(input_buffer + i); |
| 65 | + |
| 66 | + // If we've filled our context input, copy it into our local array input |
| 67 | + // then reset the offset to 0 and fill in a new buffer. |
| 68 | + // Every time we fill out a chunk, we run it through the algorithm |
| 69 | + // to enable some back and forth between cpu and i/o |
| 70 | + if(offset % 64 == 0){ |
| 71 | + for(unsigned int j = 0; j < 16; ++j){ |
| 72 | + // Convert to little-endian |
| 73 | + // The local variable `input` our 512-bit chunk separated into 32-bit words |
| 74 | + // we can use in calculations |
| 75 | + input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 | |
| 76 | + (uint32_t)(ctx->input[(j * 4) + 2]) << 16 | |
| 77 | + (uint32_t)(ctx->input[(j * 4) + 1]) << 8 | |
| 78 | + (uint32_t)(ctx->input[(j * 4)]); |
| 79 | + } |
| 80 | + Step(ctx->buffer, input); |
| 81 | + offset = 0; |
| 82 | + } |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +/* |
| 87 | + * Pad the current input to get to 448 bytes, append the size in bits to the very end, |
| 88 | + * and save the result of the final iteration into digest. |
| 89 | + */ |
| 90 | +void MD5::Finalize(MD5Context *ctx){ |
| 91 | + uint32_t input[16]; |
| 92 | + unsigned int offset = ctx->size % 64; |
| 93 | + unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset; |
| 94 | + |
| 95 | + // Fill in the padding and undo the changes to size that resulted from the update |
| 96 | + Update(ctx, PADDING, padding_length); |
| 97 | + ctx->size -= (uint64_t)padding_length; |
| 98 | + |
| 99 | + // Do a final update (internal to this function) |
| 100 | + // Last two 32-bit words are the two halves of the size (converted from bytes to bits) |
| 101 | + for(unsigned int j = 0; j < 14; ++j){ |
| 102 | + input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 | |
| 103 | + (uint32_t)(ctx->input[(j * 4) + 2]) << 16 | |
| 104 | + (uint32_t)(ctx->input[(j * 4) + 1]) << 8 | |
| 105 | + (uint32_t)(ctx->input[(j * 4)]); |
| 106 | + } |
| 107 | + input[14] = (uint32_t)(ctx->size * 8); |
| 108 | + input[15] = (uint32_t)((ctx->size * 8) >> 32); |
| 109 | + |
| 110 | + Step(ctx->buffer, input); |
| 111 | + |
| 112 | + // Move the result into digest (convert from little-endian) |
| 113 | + for(unsigned int i = 0; i < 4; ++i){ |
| 114 | + ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF)); |
| 115 | + ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8); |
| 116 | + ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16); |
| 117 | + ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24); |
| 118 | + } |
| 119 | +} |
| 120 | + |
| 121 | +/* |
| 122 | + * Step on 512 bits of input with the main MD5 algorithm. |
| 123 | + */ |
| 124 | +void MD5::Step(uint32_t *buffer, uint32_t *input){ |
| 125 | + uint32_t AA = buffer[0]; |
| 126 | + uint32_t BB = buffer[1]; |
| 127 | + uint32_t CC = buffer[2]; |
| 128 | + uint32_t DD = buffer[3]; |
| 129 | + |
| 130 | + uint32_t E; |
| 131 | + |
| 132 | + unsigned int j; |
| 133 | + |
| 134 | + for(unsigned int i = 0; i < 64; ++i){ |
| 135 | + switch(i / 16){ |
| 136 | + case 0: |
| 137 | + E = F(BB, CC, DD); |
| 138 | + j = i; |
| 139 | + break; |
| 140 | + case 1: |
| 141 | + E = G(BB, CC, DD); |
| 142 | + j = ((i * 5) + 1) % 16; |
| 143 | + break; |
| 144 | + case 2: |
| 145 | + E = H(BB, CC, DD); |
| 146 | + j = ((i * 3) + 5) % 16; |
| 147 | + break; |
| 148 | + default: |
| 149 | + E = I(BB, CC, DD); |
| 150 | + j = (i * 7) % 16; |
| 151 | + break; |
| 152 | + } |
| 153 | + |
| 154 | + uint32_t temp = DD; |
| 155 | + DD = CC; |
| 156 | + CC = BB; |
| 157 | + BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]); |
| 158 | + AA = temp; |
| 159 | + } |
| 160 | + |
| 161 | + buffer[0] += AA; |
| 162 | + buffer[1] += BB; |
| 163 | + buffer[2] += CC; |
| 164 | + buffer[3] += DD; |
| 165 | +} |
0 commit comments