LCOV - code coverage report
Current view: top level - port - cpl_md5.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 148 152 97.4 %
Date: 2025-07-09 17:50:03 Functions: 7 7 100.0 %

          Line data    Source code
       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     2081740 : static GUInt32 getu32(const unsigned char *addr)
      42             : {
      43     2081740 :     return ((((static_cast<GUInt32>(addr[3]) << 8) | addr[2]) << 8) | addr[1])
      44     2081740 :                << 8 |
      45     2081740 :            addr[0];
      46             : }
      47             : 
      48      339576 : static void putu32(GUInt32 data, unsigned char *addr)
      49             : {
      50      339576 :     addr[0] = static_cast<unsigned char>(data & 0xff);
      51      339576 :     addr[1] = static_cast<unsigned char>((data >> 8) & 0xff);
      52      339576 :     addr[2] = static_cast<unsigned char>((data >> 16) & 0xff);
      53      339576 :     addr[3] = static_cast<unsigned char>((data >> 24) & 0xff);
      54      339576 : }
      55             : 
      56             : /*
      57             :  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
      58             :  * initialization constants.
      59             :  */
      60       56596 : void CPLMD5Init(struct CPLMD5Context *context)
      61             : {
      62       56596 :     context->buf[0] = 0x67452301;
      63       56596 :     context->buf[1] = 0xefcdab89;
      64       56596 :     context->buf[2] = 0x98badcfe;
      65       56596 :     context->buf[3] = 0x10325476;
      66             : 
      67       56596 :     context->bits[0] = 0;
      68       56596 :     context->bits[1] = 0;
      69       56596 : }
      70             : 
      71             : /*
      72             :  * Update context to reflect the concatenation of another buffer full
      73             :  * of bytes.
      74             :  */
      75       56883 : void CPLMD5Update(struct CPLMD5Context *context, const void *buf, size_t len)
      76             : {
      77       56883 :     const GByte *pabyBuf = static_cast<const GByte *>(buf);
      78       56883 :     while (len > 0xffffffffU)
      79             :     {
      80           0 :         CPLMD5Update(context, pabyBuf, 0xffffffffU);
      81           0 :         pabyBuf += 0xffffffffU;
      82           0 :         len -= 0xffffffffU;
      83             :     }
      84             : 
      85             :     // Update bitcount
      86       56883 :     GUInt32 t = context->bits[0];
      87             :     // Clear top 3 bits before left shifting to avoid Coverity Scan warning
      88             :     // about 0xffffffffU overflowing during the shift.
      89       56883 :     const GUInt32 lenShifted = static_cast<GUInt32>(len & 0x1fffffffU) << 3U;
      90       56883 :     context->bits[0] = (t + lenShifted) & 0xffffffff;
      91       56883 :     if (context->bits[0] < t)
      92           0 :         context->bits[1]++; /* Carry from low to high */
      93       56883 :     context->bits[1] += static_cast<GUInt32>(len >> 29);
      94             : 
      95       56883 :     t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
      96             : 
      97             :     /* Handle any leading odd-sized chunks */
      98             : 
      99       56883 :     if (t)
     100             :     {
     101         287 :         unsigned char *p = context->in + t;
     102             : 
     103         287 :         t = 64 - t;
     104         287 :         if (len < t)
     105             :         {
     106          24 :             memcpy(p, pabyBuf, len);
     107          24 :             return;
     108             :         }
     109         263 :         memcpy(p, pabyBuf, t);
     110         263 :         CPLMD5Transform(context->buf, context->in);
     111         263 :         pabyBuf += t;
     112         263 :         len -= t;
     113             :     }
     114             : 
     115             :     /* Process data in 64-byte chunks */
     116             : 
     117      126976 :     while (len >= 64)
     118             :     {
     119       70117 :         memcpy(context->in, pabyBuf, 64);
     120       70117 :         CPLMD5Transform(context->buf, context->in);
     121       70117 :         pabyBuf += 64;
     122       70117 :         len -= 64;
     123             :     }
     124             : 
     125             :     /* Handle any remaining bytes of data. */
     126             : 
     127       56859 :     memcpy(context->in, pabyBuf, len);
     128             : }
     129             : 
     130             : /*
     131             :  * Final wrapup - pad to 64-byte boundary with the bit pattern
     132             :  * 1 0* (64-bit count of bits processed, MSB-first)
     133             :  */
     134       56596 : void CPLMD5Final(unsigned char digest[16], struct CPLMD5Context *context)
     135             : {
     136             :     /* Compute number of bytes mod 64 */
     137       56596 :     unsigned count = static_cast<unsigned>((context->bits[0] >> 3) & 0x3F);
     138             : 
     139             :     /* Set the first char of padding to 0x80.  This is safe since there is
     140             :     always at least one byte free */
     141       56596 :     unsigned char *p = context->in + count;
     142       56596 :     *p++ = 0x80;
     143             : 
     144             :     /* Bytes of padding needed to make 64 bytes */
     145       56596 :     count = 64 - 1 - count;
     146             : 
     147             :     /* Pad out to 56 mod 64 */
     148       56596 :     if (count < 8)
     149             :     {
     150             :         /* Two lots of padding:  Pad the first block to 64 bytes */
     151        3133 :         memset(p, 0, count);
     152        3133 :         CPLMD5Transform(context->buf, context->in);
     153             : 
     154             :         /* Now fill the next block with 56 bytes */
     155        3133 :         memset(context->in, 0, 56);
     156             :     }
     157             :     else
     158             :     {
     159             :         /* Pad block to 56 bytes */
     160       53463 :         memset(p, 0, count - 8);
     161             :     }
     162             : 
     163             :     /* Append length in bits and transform */
     164       56596 :     putu32(context->bits[0], context->in + 56);
     165       56596 :     putu32(context->bits[1], context->in + 60);
     166             : 
     167       56596 :     CPLMD5Transform(context->buf, context->in);
     168       56596 :     putu32(context->buf[0], digest);
     169       56596 :     putu32(context->buf[1], digest + 4);
     170       56596 :     putu32(context->buf[2], digest + 8);
     171       56596 :     putu32(context->buf[3], digest + 12);
     172       56596 :     memset(context, 0, sizeof(*context)); /* In case it is sensitive */
     173       56596 : }
     174             : 
     175             : #ifndef ASM_MD5
     176             : 
     177             : /* The four core functions - F1 is optimized somewhat */
     178             : 
     179             : /* #define F1(x, y, z) (x & y | ~x & z) */
     180             : #define F1(x, y, z) (z ^ (x & (y ^ z)))
     181             : #define F2(x, y, z) F1(z, x, y)
     182             : #define F3(x, y, z) (x ^ y ^ z)
     183             : #define F4(x, y, z) (y ^ (x | ~z))
     184             : 
     185             : /* This is the central step in the MD5 algorithm. */
     186             : #define MD5STEP(f, w, x, y, z, data, s)                                        \
     187             :     (w += f(x, y, z) + data, w &= 0xffffffff, w = w << s | w >> (32 - s),      \
     188             :      w += x)
     189             : 
     190             : /*
     191             :  * The core of the MD5 algorithm, this alters an existing MD5 hash to
     192             :  * reflect the addition of 16 longwords of new data.  MD5Update blocks
     193             :  * the data and converts bytes into longwords for this routine.
     194             :  */
     195             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
     196      130109 : void CPLMD5Transform(GUInt32 buf[4], const unsigned char inraw[64])
     197             : {
     198             :     GUInt32 in[16];
     199     2211850 :     for (int i = 0; i < 16; ++i)
     200     2081740 :         in[i] = getu32(inraw + 4 * i);
     201             : 
     202      130109 :     GUInt32 a = buf[0];
     203      130109 :     GUInt32 b = buf[1];
     204      130109 :     GUInt32 c = buf[2];
     205      130109 :     GUInt32 d = buf[3];
     206             : 
     207      130109 :     MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
     208      130109 :     MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
     209      130109 :     MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
     210      130109 :     MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
     211      130109 :     MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
     212      130109 :     MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
     213      130109 :     MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
     214      130109 :     MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
     215      130109 :     MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
     216      130109 :     MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
     217      130109 :     MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
     218      130109 :     MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
     219      130109 :     MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
     220      130109 :     MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
     221      130109 :     MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
     222      130109 :     MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
     223             : 
     224      130109 :     MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
     225      130109 :     MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
     226      130109 :     MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
     227      130109 :     MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
     228      130109 :     MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
     229      130109 :     MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
     230      130109 :     MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
     231      130109 :     MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
     232      130109 :     MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
     233      130109 :     MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
     234      130109 :     MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
     235      130109 :     MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
     236      130109 :     MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
     237      130109 :     MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
     238      130109 :     MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
     239      130109 :     MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
     240             : 
     241      130109 :     MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
     242      130109 :     MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
     243      130109 :     MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
     244      130109 :     MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
     245      130109 :     MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
     246      130109 :     MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
     247      130109 :     MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
     248      130109 :     MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
     249      130109 :     MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
     250      130109 :     MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
     251      130109 :     MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
     252      130109 :     MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
     253      130109 :     MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
     254      130109 :     MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
     255      130109 :     MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
     256      130109 :     MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
     257             : 
     258      130109 :     MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
     259      130109 :     MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
     260      130109 :     MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
     261      130109 :     MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
     262      130109 :     MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
     263      130109 :     MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
     264      130109 :     MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
     265      130109 :     MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
     266      130109 :     MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
     267      130109 :     MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
     268      130109 :     MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
     269      130109 :     MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
     270      130109 :     MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
     271      130109 :     MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
     272      130109 :     MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
     273      130109 :     MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
     274             : 
     275      130109 :     buf[0] += a;
     276      130109 :     buf[1] += b;
     277      130109 :     buf[2] += c;
     278      130109 :     buf[3] += d;
     279      130109 : }
     280             : #endif
     281             : 
     282             : /**
     283             :  * @brief CPLMD5String Transform string to MD5 hash
     284             :  * @param pszText Text to transform
     285             :  * @return MD5 hash string
     286             :  */
     287       55892 : const char *CPLMD5String(const char *pszText)
     288             : {
     289             :     struct CPLMD5Context context;
     290       55892 :     CPLMD5Init(&context);
     291       55892 :     CPLMD5Update(&context, pszText, strlen(pszText));
     292             :     unsigned char hash[16];
     293       55892 :     CPLMD5Final(hash, &context);
     294             : 
     295       55892 :     constexpr char tohex[] = "0123456789abcdef";
     296             :     char hhash[33];
     297      950164 :     for (int i = 0; i < 16; ++i)
     298             :     {
     299      894272 :         hhash[i * 2] = tohex[(hash[i] >> 4) & 0xf];
     300      894272 :         hhash[i * 2 + 1] = tohex[hash[i] & 0xf];
     301             :     }
     302       55892 :     hhash[32] = '\0';
     303      111784 :     return CPLSPrintf("%s", hhash);
     304             : }

Generated by: LCOV version 1.14