1 /*
2 * This code implements the MD5 message-digest algorithm.
3 * The algorithm is due to Ron Rivest.  This code was
4 * written by Colin Plumb in 1993, no copyright is claimed.
5 * This code is in the public domain; do with it what you wish.
6 *
7 * Equivalent code is available from RSA Data Security, Inc.
8 * This code has been tested against that, and is equivalent,
9 * except that you don't need to include two pages of legalese
10 * with every copy.
11 *
12 * To compute the message digest of a chunk of bytes, declare an
13 * MD5Context structure, pass it to MD5Init, call MD5Update as
14 * needed on buffers full of bytes, and then call MD5Final, which
15 * will fill a supplied 16-byte array with the digest.
16 */
17 
18 /* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
19 not require an integer type which is exactly 32 bits.  This work
20 draws on the changes for the same purpose by Tatu Ylonen
21 <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
22 that code, there is no copyright issue.  I hereby disclaim
23 copyright in any changes I have made; this code remains in the
24 public domain.  */
25 
26 /* Note regarding cvs_* namespace: this avoids potential conflicts
27 with libraries such as some versions of Kerberos.  No particular
28 need to worry about whether the system supplies an MD5 library, as
29 this file is only about 3k of object code.  */
30 
31 /* Modified by E. Rouault, to fix :
32    warning: argument to 'sizeof' in 'memset' call is the same expression as
33    the destination; did you mean to dereference it? [-Wsizeof-pointer-memaccess]
34         memset(ctx, 0, sizeof(ctx)); */   /* In case it is sensitive */
35 /* at the end of cvs_MD5Final */
36 
37 #include "cpl_md5.h"
38 
39 #include "cpl_string.h"
40 
41 CPL_CVSID("$Id: cpl_md5.cpp 3798cbe48457b7127606931896549f26507469db 2021-04-09 15:04:16 +0200 Even Rouault $")
42 
getu32(const unsigned char * addr)43 static GUInt32 getu32( const unsigned char *addr )
44 {
45     return
46         ((((static_cast<GUInt32>(addr[3]) << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0];
47 }
48 
putu32(GUInt32 data,unsigned char * addr)49 static void putu32( GUInt32 data, unsigned char *addr )
50 {
51     addr[0] = static_cast<unsigned char>(data & 0xff);
52     addr[1] = static_cast<unsigned char>((data >> 8) & 0xff);
53     addr[2] = static_cast<unsigned char>((data >> 16) & 0xff);
54     addr[3] = static_cast<unsigned char>((data >> 24) & 0xff);
55 }
56 
57 /*
58 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
59 * initialization constants.
60 */
CPLMD5Init(struct CPLMD5Context * context)61 void CPLMD5Init( struct CPLMD5Context *context )
62 {
63     context->buf[0] = 0x67452301;
64     context->buf[1] = 0xefcdab89;
65     context->buf[2] = 0x98badcfe;
66     context->buf[3] = 0x10325476;
67 
68     context->bits[0] = 0;
69     context->bits[1] = 0;
70 }
71 
72 /*
73 * Update context to reflect the concatenation of another buffer full
74 * of bytes.
75 */
CPLMD5Update(struct CPLMD5Context * context,const void * buf,size_t len)76 void CPLMD5Update( struct CPLMD5Context *context, const void *buf,
77                    size_t len )
78 {
79     const GByte* pabyBuf = static_cast<const GByte*>(buf);
80     while( len > 0xffffffffU )
81     {
82         CPLMD5Update(context, pabyBuf, 0xffffffffU);
83         pabyBuf += 0xffffffffU;
84         len -= 0xffffffffU;
85     }
86 
87     // Update bitcount
88     GUInt32 t = context->bits[0];
89     if ((context->bits[0] = (t + (static_cast<GUInt32>(len) << 3)) & 0xffffffff) < t)
90         context->bits[1]++;  /* Carry from low to high */
91     context->bits[1] += static_cast<GUInt32>(len >> 29);
92 
93     t = (t >> 3) & 0x3f;  /* Bytes already in shsInfo->data */
94 
95     /* Handle any leading odd-sized chunks */
96 
97     if( t )
98     {
99         unsigned char *p = context->in + t;
100 
101         t = 64 - t;
102         if( len < t )
103         {
104             memcpy(p, pabyBuf, len);
105             return;
106         }
107         memcpy(p, pabyBuf, t);
108         CPLMD5Transform(context->buf, context->in);
109         pabyBuf += t;
110         len -= t;
111     }
112 
113     /* Process data in 64-byte chunks */
114 
115     while( len >= 64 )
116     {
117         memcpy(context->in, pabyBuf, 64);
118         CPLMD5Transform(context->buf, context->in);
119         pabyBuf += 64;
120         len -= 64;
121     }
122 
123     /* Handle any remaining bytes of data. */
124 
125     memcpy(context->in, pabyBuf, len);
126 }
127 
128 /*
129 * Final wrapup - pad to 64-byte boundary with the bit pattern
130 * 1 0* (64-bit count of bits processed, MSB-first)
131 */
CPLMD5Final(unsigned char digest[16],struct CPLMD5Context * context)132 void CPLMD5Final( unsigned char digest[16], struct CPLMD5Context *context )
133 {
134     /* Compute number of bytes mod 64 */
135     unsigned count = static_cast<unsigned>((context->bits[0] >> 3) & 0x3F);
136 
137     /* Set the first char of padding to 0x80.  This is safe since there is
138     always at least one byte free */
139     unsigned char *p = context->in + count;
140     *p++ = 0x80;
141 
142     /* Bytes of padding needed to make 64 bytes */
143     count = 64 - 1 - count;
144 
145     /* Pad out to 56 mod 64 */
146     if (count < 8) {
147         /* Two lots of padding:  Pad the first block to 64 bytes */
148         memset(p, 0, count);
149         CPLMD5Transform(context->buf, context->in);
150 
151         /* Now fill the next block with 56 bytes */
152         memset(context->in, 0, 56);
153     } else {
154         /* Pad block to 56 bytes */
155         memset(p, 0, count-8);
156     }
157 
158     /* Append length in bits and transform */
159     putu32(context->bits[0], context->in + 56);
160     putu32(context->bits[1], context->in + 60);
161 
162     CPLMD5Transform (context->buf, context->in);
163     putu32(context->buf[0], digest);
164     putu32(context->buf[1], digest + 4);
165     putu32(context->buf[2], digest + 8);
166     putu32(context->buf[3], digest + 12);
167     memset(context, 0, sizeof(*context));  /* In case it is sensitive */
168 }
169 
170 #ifndef ASM_MD5
171 
172 /* The four core functions - F1 is optimized somewhat */
173 
174 /* #define F1(x, y, z) (x & y | ~x & z) */
175 #define F1(x, y, z) (z ^ (x & (y ^ z)))
176 #define F2(x, y, z) F1(z, x, y)
177 #define F3(x, y, z) (x ^ y ^ z)
178 #define F4(x, y, z) (y ^ (x | ~z))
179 
180 /* This is the central step in the MD5 algorithm. */
181 #define MD5STEP(f, w, x, y, z, data, s) \
182     ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
183 
184 /*
185 * The core of the MD5 algorithm, this alters an existing MD5 hash to
186 * reflect the addition of 16 longwords of new data.  MD5Update blocks
187 * the data and converts bytes into longwords for this routine.
188 */
189 CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
CPLMD5Transform(GUInt32 buf[4],const unsigned char inraw[64])190 void CPLMD5Transform( GUInt32 buf[4], const unsigned char inraw[64] )
191 {
192     GUInt32 in[16];
193     for( int i = 0; i < 16; ++i )
194         in[i] = getu32(inraw + 4 * i);
195 
196     GUInt32 a = buf[0];
197     GUInt32 b = buf[1];
198     GUInt32 c = buf[2];
199     GUInt32 d = buf[3];
200 
201     MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
202     MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
203     MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
204     MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
205     MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
206     MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
207     MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
208     MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
209     MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
210     MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
211     MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
212     MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
213     MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
214     MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
215     MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
216     MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
217 
218     MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
219     MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
220     MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
221     MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
222     MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
223     MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
224     MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
225     MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
226     MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
227     MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
228     MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
229     MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
230     MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
231     MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
232     MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
233     MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
234 
235     MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
236     MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
237     MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
238     MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
239     MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
240     MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
241     MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
242     MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
243     MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
244     MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
245     MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
246     MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
247     MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
248     MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
249     MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
250     MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
251 
252     MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
253     MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
254     MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
255     MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
256     MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
257     MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
258     MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
259     MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
260     MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
261     MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
262     MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
263     MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
264     MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
265     MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
266     MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
267     MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
268 
269     buf[0] += a;
270     buf[1] += b;
271     buf[2] += c;
272     buf[3] += d;
273 }
274 #endif
275 
276 /**
277  * @brief CPLMD5String Transform string to MD5 hash
278  * @param pszText Text to transform
279  * @return MD5 hash string
280  */
CPLMD5String(const char * pszText)281 const char *CPLMD5String( const char *pszText )
282 {
283     struct CPLMD5Context context;
284     CPLMD5Init(&context);
285     CPLMD5Update(&context, pszText, strlen(pszText));
286     unsigned char hash[16];
287     CPLMD5Final(hash, &context);
288 
289     constexpr char tohex[] = "0123456789abcdef";
290     char hhash[33];
291     for (int i = 0; i < 16; ++i)
292     {
293         hhash[i * 2] = tohex[(hash[i] >> 4) & 0xf];
294         hhash[i * 2 + 1] = tohex[hash[i] & 0xf];
295     }
296     hhash[32] = '\0';
297     return CPLSPrintf( "%s", hhash );
298 }
299