xref: /MusicPlayer2/MusicPlayer2/md5.cpp (revision 4df46f80c2a71e4cf062c2f4a97c6bb43853680a)
1 #include "stdafx.h"
2 /*
3  * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
4  * and modified slightly to be functionally identical but condensed into control structures.
5  */
6 
7 #include "md5.h"
8 
9  /*
10   * Constants defined by the MD5 algorithm
11   */
12 #define A 0x67452301
13 #define B 0xefcdab89
14 #define C 0x98badcfe
15 #define D 0x10325476
16 #define BLOCK_SIZE 64
17 #define DIGEST_LENGTH 16
18 
19 static uint32_t s[] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
20                        5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
21                        4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
22                        6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 };
23 
24 static uint32_t K[] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
25                        0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
26                        0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
27                        0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
28                        0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
29                        0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
30                        0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
31                        0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
32                        0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
33                        0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
34                        0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
35                        0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
36                        0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
37                        0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
38                        0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
39                        0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };
40 
readUint32LE(uint8_t * ptr,size_t pos)41 uint32_t readUint32LE(uint8_t* ptr, size_t pos) {
42     return ((int32_t)ptr[pos + 3] << 24) | ((int32_t)ptr[pos + 2] << 16) | ((int32_t)ptr[pos + 1] << 8) | (int32_t)ptr[pos];
43 }
44 
writeUint32LE(uint32_t value,uint8_t * out,size_t offset=0)45 void writeUint32LE(uint32_t value, uint8_t* out, size_t offset = 0) {
46     out[offset] = value;
47     out[offset + 1] = value >> 8;
48     out[offset + 2] = value >> 16;
49     out[offset + 3] = value >> 24;
50 }
51 
md5Hash(MD5Context * ctx,uint8_t * p,size_t pos,size_t len)52 size_t md5Hash(MD5Context* ctx, uint8_t* p, size_t pos, size_t len) {
53     uint32_t* w = ctx->temp;
54     uint32_t* v = ctx->state;
55     while (len >= 64) {
56         auto a = v[0];
57         auto b = v[1];
58         auto c = v[2];
59         auto d = v[3];
60         for (auto i = 0; i < 16; i++) {
61             size_t j = pos + (size_t)i * 4;
62             w[i] = readUint32LE(p, j);
63         }
64         for (auto i = 0; i < 64; i++) {
65             uint32_t F = 0, g = 0;
66             if (i >= 0 && i <= 15) {
67                 F = d ^ (b & (c ^ d));
68                 g = i;
69             } else if (i >= 16 && i <= 31) {
70                 F = c ^ (d & (b ^ c));
71                 g = (5 * i + 1) % 16;
72             } else if (i >= 32 && i <= 47) {
73                 F = b ^ c ^ d;
74                 g = (3 * i + 5) % 16;
75             } else {
76                 F = c ^ (b | ~d);
77                 g = (7 * i) % 16;
78             }
79             F = F + a + K[i] + w[g];
80             a = d;
81             d = c;
82             c = b;
83             b = b + rotateLeft(F, s[i]);
84         }
85         v[0] = v[0] + a;
86         v[1] = v[1] + b;
87         v[2] = v[2] + c;
88         v[3] = v[3] + d;
89         pos += 64;
90         len -= 64;
91     }
92     return pos;
93 }
94 
95 /*
96  * Initialize a context
97  */
md5Init(MD5Context * ctx)98 void md5Init(MD5Context* ctx) {
99     ctx->bytesHashed = 0;
100     ctx->bufferLength = 0;
101 
102     ctx->state[0] = (uint32_t)A;
103     ctx->state[1] = (uint32_t)B;
104     ctx->state[2] = (uint32_t)C;
105     ctx->state[3] = (uint32_t)D;
106 }
107 
108 /*
109  * Add some amount of input to the context
110  *
111  * If the input fills out a block of 512 bits, apply the algorithm (md5Step)
112  * and save the result in the buffer. Also updates the overall size.
113  */
md5Update(MD5Context * ctx,uint8_t * data,size_t dataLength)114 void md5Update(MD5Context* ctx, uint8_t* data, size_t dataLength) {
115     size_t dataPos = 0;
116     ctx->bytesHashed += dataLength;
117     if (ctx->bufferLength > 0) {
118         while (ctx->bufferLength < BLOCK_SIZE && dataLength > 0) {
119             ctx->buffer[ctx->bufferLength++] = data[dataPos++];
120             dataLength--;
121         }
122         if (ctx->bufferLength == BLOCK_SIZE) {
123             md5Hash(ctx, ctx->buffer, 0, BLOCK_SIZE);
124             ctx->bufferLength = 0;
125         }
126     }
127     if (dataLength >= BLOCK_SIZE) {
128         dataPos = md5Hash(ctx, data, dataPos, dataLength);
129         dataLength %= BLOCK_SIZE;
130     }
131     while (dataLength > 0) {
132         ctx->buffer[ctx->bufferLength++] = data[dataPos++];
133         dataLength--;
134     }
135 }
136 
137 /*
138  * Pad the current input to get to 448 bytes, append the size in bits to the very end,
139  * and save the result of the final iteration into digest.
140  */
md5Finalize(MD5Context * ctx)141 void md5Finalize(MD5Context* ctx) {
142     uint32_t bitLenHi = (ctx->bytesHashed / 0x20000000) | 0;
143     uint32_t bitLenLo = ctx->bytesHashed << 3;
144     size_t padLength = ((ctx->bytesHashed) % 64 < 56) ? 64 : 128;
145     ctx->buffer[ctx->bufferLength] = 0x80;
146     for (size_t i = ctx->bufferLength + 1; i < padLength - 8; i++) {
147         ctx->buffer[i] = 0;
148     }
149     writeUint32LE(bitLenLo, ctx->buffer, padLength - 8);
150     writeUint32LE(bitLenHi, ctx->buffer, padLength - 4);
151     md5Hash(ctx, ctx->buffer, 0, padLength);
152     for (auto i = 0; i < DIGEST_LENGTH / 4; i++) {
153         writeUint32LE(ctx->state[i], ctx->digest, (size_t)i * 4);
154     }
155 }
156 
157 /*
158  * Rotates a 32-bit word left by n bits
159  */
rotateLeft(uint32_t x,uint32_t n)160 uint32_t rotateLeft(uint32_t x, uint32_t n) {
161     return (x << n) | (x >> (32 - n));
162 }
163 
MD5()164 MD5::MD5() {
165     md5Init(&ctx);
166     m_finalized = false;
167 }
168 
Digest()169 std::string MD5::Digest() {
170     if (!m_finalized) {
171         Finalize();
172     }
173     return std::string((char*)ctx.digest, 16);
174 }
175 
Finalize()176 void MD5::Finalize() {
177     md5Finalize(&ctx);
178     m_finalized = true;
179 }
180 
str_hex(std::string input)181 std::string str_hex(std::string input) {
182     if (input.empty()) return "";
183     const char* t = "0123456789abcdef";
184     std::string output;
185     for (auto i = input.begin(); i != input.end(); i++) {
186         unsigned char c = *i;
187         output += t[c / 16];
188         output += t[c % 16];
189     }
190     return output;
191 }
192 
HexDigest()193 std::string MD5::HexDigest() {
194     return str_hex(Digest());
195 }
196 
Update(std::string data)197 void MD5::Update(std::string data) {
198     if (m_finalized) {
199         return;
200     }
201     md5Update(&ctx, (uint8_t*)data.c_str(), data.size());
202 }
203 
Update(std::wstring data,CodeType code,bool * char_cannot_convert)204 void MD5::Update(std::wstring data, CodeType code, bool* char_cannot_convert) {
205     Update(CCommon::UnicodeToStr(data, code, char_cannot_convert));
206 }
207