LCOV - code coverage report
Current view: top level - port - cpl_sha256.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 164 227 72.2 %
Date: 2025-09-10 17:48:50 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /* CPL_SHA256* functions derived from
       2             :  * http://code.google.com/p/ulib/source/browse/trunk/src/base/sha256sum.c?r=39
       3             :  */
       4             : 
       5             : /* The MIT License
       6             : 
       7             :    Copyright (C) 2011 Zilong Tan (tzlloch@gmail.com)
       8             :    Copyright (C) 2015 Even Rouault <even.rouault at spatialys.com>
       9             : 
      10             :    Permission is hereby granted, free of charge, to any person obtaining
      11             :    a copy of this software and associated documentation files (the
      12             :    "Software"), to deal in the Software without restriction, including
      13             :    without limitation the rights to use, copy, modify, merge, publish,
      14             :    distribute, sublicense, and/or sell copies of the Software, and to
      15             :    permit persons to whom the Software is furnished to do so, subject to
      16             :    the following conditions:
      17             : 
      18             :    The above copyright notice and this permission notice shall be
      19             :    included in all copies or substantial portions of the Software.
      20             : 
      21             :    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      22             :    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      23             :    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      24             :    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
      25             :    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
      26             :    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
      27             :    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      28             :    SOFTWARE.
      29             : */
      30             : 
      31             : /*
      32             :  *  Original code (for SHA256 computation only) is derived from the author:
      33             :  *  Allan Saddi
      34             :  */
      35             : 
      36             : #include <string.h>
      37             : #include "cpl_conv.h"
      38             : #include "cpl_error.h"
      39             : #include "cpl_sha256.h"
      40             : #include "cpl_string.h"
      41             : 
      42             : #define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
      43             : #define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
      44             : 
      45             : #define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
      46             : #define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
      47             : #define SIGMA0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22))
      48             : #define SIGMA1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25))
      49             : #define sigma0(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ ((x) >> 3))
      50             : #define sigma1(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ ((x) >> 10))
      51             : 
      52             : #define DO_ROUND()                                                             \
      53             :     {                                                                          \
      54             :         GUInt32 t1 = h + SIGMA1(e) + Ch(e, f, g) + *(Kp++) + *(W++);           \
      55             :         GUInt32 t2 = SIGMA0(a) + Maj(a, b, c);                                 \
      56             :         h = g;                                                                 \
      57             :         g = f;                                                                 \
      58             :         f = e;                                                                 \
      59             :         e = d + t1;                                                            \
      60             :         d = c;                                                                 \
      61             :         c = b;                                                                 \
      62             :         b = a;                                                                 \
      63             :         a = t1 + t2;                                                           \
      64             :     }
      65             : 
      66             : constexpr GUInt32 K[64] = {
      67             :     0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU,
      68             :     0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0xd807aa98U, 0x12835b01U,
      69             :     0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U,
      70             :     0xc19bf174U, 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU,
      71             :     0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, 0x983e5152U,
      72             :     0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U,
      73             :     0x06ca6351U, 0x14292967U, 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU,
      74             :     0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U,
      75             :     0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U,
      76             :     0xd6990624U, 0xf40e3585U, 0x106aa070U, 0x19a4c116U, 0x1e376c08U,
      77             :     0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU,
      78             :     0x682e6ff3U, 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U,
      79             :     0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U};
      80             : 
      81             : #ifdef WORDS_BIGENDIAN
      82             : 
      83             : #define BYTESWAP(x) (x)
      84             : #define BYTESWAP64(x) (x)
      85             : 
      86             : #else  // WORDS_BIGENDIAN
      87             : 
      88             : #define BYTESWAP(x)                                                            \
      89             :     ((ROTR((x), 8) & 0xff00ff00U) | (ROTL((x), 8) & 0x00ff00ffU))
      90             : #define BYTESWAP64(x) _byteswap64(x)
      91             : 
      92        4649 : static inline GUInt64 _byteswap64(GUInt64 x)
      93             : {
      94        4649 :     GUInt32 a = static_cast<GUInt32>(x >> 32);
      95        4649 :     GUInt32 b = static_cast<GUInt32>(x);
      96        4649 :     return (static_cast<GUInt64>(BYTESWAP(b)) << 32) |
      97        4649 :            static_cast<GUInt64>(BYTESWAP(a));
      98             : }
      99             : 
     100             : #endif /* !(WORDS_BIGENDIAN) */
     101             : 
     102             : constexpr GByte padding[64] = {
     103             :     0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     104             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     105             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     106             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     107             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     108             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
     109             : 
     110        4649 : void CPL_SHA256Init(CPL_SHA256Context *sc)
     111             : {
     112        4649 :     sc->totalLength = 0;
     113        4649 :     sc->hash[0] = 0x6a09e667U;
     114        4649 :     sc->hash[1] = 0xbb67ae85U;
     115        4649 :     sc->hash[2] = 0x3c6ef372U;
     116        4649 :     sc->hash[3] = 0xa54ff53aU;
     117        4649 :     sc->hash[4] = 0x510e527fU;
     118        4649 :     sc->hash[5] = 0x9b05688cU;
     119        4649 :     sc->hash[6] = 0x1f83d9abU;
     120        4649 :     sc->hash[7] = 0x5be0cd19U;
     121        4649 :     sc->bufferLength = 0U;
     122        4649 : }
     123             : 
     124       28869 : static GUInt32 burnStack(int size)
     125             : {
     126             :     GByte buf[128];
     127       28869 :     GUInt32 ret = 0;
     128             : 
     129       28869 :     memset(buf, static_cast<GByte>(size & 0xff), sizeof(buf));
     130     3722580 :     for (size_t i = 0; i < sizeof(buf); i++)
     131     3693710 :         ret += ret * buf[i];
     132       28869 :     size -= static_cast<int>(sizeof(buf));
     133       28869 :     if (size > 0)
     134       19246 :         ret += burnStack(size);
     135       28869 :     return ret;
     136             : }
     137             : 
     138             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
     139      114834 : static void CPL_SHA256Guts(CPL_SHA256Context *sc, const GUInt32 *cbuf)
     140             : {
     141      114834 :     GUInt32 buf[64] = {};
     142             : 
     143      114834 :     GUInt32 *W = buf;
     144             : 
     145     1952170 :     for (int i = 15; i >= 0; i--)
     146             :     {
     147     1837340 :         *(W++) = BYTESWAP(*cbuf);
     148     1837340 :         cbuf++;
     149             :     }
     150             : 
     151      114834 :     GUInt32 *W16 = &buf[0];
     152      114834 :     GUInt32 *W15 = &buf[1];
     153      114834 :     GUInt32 *W7 = &buf[9];
     154      114834 :     GUInt32 *W2 = &buf[14];
     155             : 
     156     5626720 :     for (int i = 47; i >= 0; i--)
     157             :     {
     158     5511890 :         *(W++) = sigma1(*W2) + *(W7++) + sigma0(*W15) + *(W16++);
     159     5511890 :         W2++;
     160     5511890 :         W15++;
     161             :     }
     162             : 
     163      114834 :     GUInt32 a = sc->hash[0];
     164      114834 :     GUInt32 b = sc->hash[1];
     165      114834 :     GUInt32 c = sc->hash[2];
     166      114834 :     GUInt32 d = sc->hash[3];
     167      114834 :     GUInt32 e = sc->hash[4];
     168      114834 :     GUInt32 f = sc->hash[5];
     169      114834 :     GUInt32 g = sc->hash[6];
     170      114834 :     GUInt32 h = sc->hash[7];
     171             : 
     172      114834 :     const GUInt32 *Kp = K;
     173      114834 :     W = buf;
     174             : 
     175             : #ifndef CPL_SHA256_UNROLL
     176             : #define CPL_SHA256_UNROLL 1
     177             : #endif /* !CPL_SHA256_UNROLL */
     178             : 
     179             : #if CPL_SHA256_UNROLL == 1
     180     7464010 :     for (int i = 63; i >= 0; i--)
     181     7349180 :         DO_ROUND();
     182             : #elif CPL_SHA256_UNROLL == 2
     183             :     for (int i = 31; i >= 0; i--)
     184             :     {
     185             :         DO_ROUND();
     186             :         DO_ROUND();
     187             :     }
     188             : #elif CPL_SHA256_UNROLL == 4
     189             :     for (int i = 15; i >= 0; i--)
     190             :     {
     191             :         DO_ROUND();
     192             :         DO_ROUND();
     193             :         DO_ROUND();
     194             :         DO_ROUND();
     195             :     }
     196             : #elif CPL_SHA256_UNROLL == 8
     197             :     for (int i = 7; i >= 0; i--)
     198             :     {
     199             :         DO_ROUND();
     200             :         DO_ROUND();
     201             :         DO_ROUND();
     202             :         DO_ROUND();
     203             :         DO_ROUND();
     204             :         DO_ROUND();
     205             :         DO_ROUND();
     206             :         DO_ROUND();
     207             :     }
     208             : #elif CPL_SHA256_UNROLL == 16
     209             :     for (int i = 3; i >= 0; i--)
     210             :     {
     211             :         DO_ROUND();
     212             :         DO_ROUND();
     213             :         DO_ROUND();
     214             :         DO_ROUND();
     215             :         DO_ROUND();
     216             :         DO_ROUND();
     217             :         DO_ROUND();
     218             :         DO_ROUND();
     219             :         DO_ROUND();
     220             :         DO_ROUND();
     221             :         DO_ROUND();
     222             :         DO_ROUND();
     223             :         DO_ROUND();
     224             :         DO_ROUND();
     225             :         DO_ROUND();
     226             :         DO_ROUND();
     227             :     }
     228             : #elif CPL_SHA256_UNROLL == 32
     229             :     for (int i = 1; i >= 0; i--)
     230             :     {
     231             :         DO_ROUND();
     232             :         DO_ROUND();
     233             :         DO_ROUND();
     234             :         DO_ROUND();
     235             :         DO_ROUND();
     236             :         DO_ROUND();
     237             :         DO_ROUND();
     238             :         DO_ROUND();
     239             :         DO_ROUND();
     240             :         DO_ROUND();
     241             :         DO_ROUND();
     242             :         DO_ROUND();
     243             :         DO_ROUND();
     244             :         DO_ROUND();
     245             :         DO_ROUND();
     246             :         DO_ROUND();
     247             :         DO_ROUND();
     248             :         DO_ROUND();
     249             :         DO_ROUND();
     250             :         DO_ROUND();
     251             :         DO_ROUND();
     252             :         DO_ROUND();
     253             :         DO_ROUND();
     254             :         DO_ROUND();
     255             :         DO_ROUND();
     256             :         DO_ROUND();
     257             :         DO_ROUND();
     258             :         DO_ROUND();
     259             :         DO_ROUND();
     260             :         DO_ROUND();
     261             :         DO_ROUND();
     262             :         DO_ROUND();
     263             :     }
     264             : #elif CPL_SHA256_UNROLL == 64
     265             :     DO_ROUND();
     266             :     DO_ROUND();
     267             :     DO_ROUND();
     268             :     DO_ROUND();
     269             :     DO_ROUND();
     270             :     DO_ROUND();
     271             :     DO_ROUND();
     272             :     DO_ROUND();
     273             :     DO_ROUND();
     274             :     DO_ROUND();
     275             :     DO_ROUND();
     276             :     DO_ROUND();
     277             :     DO_ROUND();
     278             :     DO_ROUND();
     279             :     DO_ROUND();
     280             :     DO_ROUND();
     281             :     DO_ROUND();
     282             :     DO_ROUND();
     283             :     DO_ROUND();
     284             :     DO_ROUND();
     285             :     DO_ROUND();
     286             :     DO_ROUND();
     287             :     DO_ROUND();
     288             :     DO_ROUND();
     289             :     DO_ROUND();
     290             :     DO_ROUND();
     291             :     DO_ROUND();
     292             :     DO_ROUND();
     293             :     DO_ROUND();
     294             :     DO_ROUND();
     295             :     DO_ROUND();
     296             :     DO_ROUND();
     297             :     DO_ROUND();
     298             :     DO_ROUND();
     299             :     DO_ROUND();
     300             :     DO_ROUND();
     301             :     DO_ROUND();
     302             :     DO_ROUND();
     303             :     DO_ROUND();
     304             :     DO_ROUND();
     305             :     DO_ROUND();
     306             :     DO_ROUND();
     307             :     DO_ROUND();
     308             :     DO_ROUND();
     309             :     DO_ROUND();
     310             :     DO_ROUND();
     311             :     DO_ROUND();
     312             :     DO_ROUND();
     313             :     DO_ROUND();
     314             :     DO_ROUND();
     315             :     DO_ROUND();
     316             :     DO_ROUND();
     317             :     DO_ROUND();
     318             :     DO_ROUND();
     319             :     DO_ROUND();
     320             :     DO_ROUND();
     321             :     DO_ROUND();
     322             :     DO_ROUND();
     323             :     DO_ROUND();
     324             :     DO_ROUND();
     325             :     DO_ROUND();
     326             :     DO_ROUND();
     327             :     DO_ROUND();
     328             :     DO_ROUND();
     329             : #else
     330             : #error "CPL_SHA256_UNROLL must be 1, 2, 4, 8, 16, 32, or 64!"
     331             : #endif
     332             : 
     333      114834 :     sc->hash[0] += a;
     334      114834 :     sc->hash[1] += b;
     335      114834 :     sc->hash[2] += c;
     336      114834 :     sc->hash[3] += d;
     337      114834 :     sc->hash[4] += e;
     338      114834 :     sc->hash[5] += f;
     339      114834 :     sc->hash[6] += g;
     340      114834 :     sc->hash[7] += h;
     341      114834 : }
     342             : 
     343       17909 : void CPL_SHA256Update(CPL_SHA256Context *sc, const void *data, size_t len)
     344             : {
     345       17909 :     int needBurn = 0;
     346             : 
     347       17909 :     if (sc->bufferLength)
     348             :     {
     349        9108 :         const GUInt32 bufferBytesLeft = 64U - sc->bufferLength;
     350             : 
     351        9108 :         GUInt32 bytesToCopy = bufferBytesLeft;
     352        9108 :         if (bytesToCopy > len)
     353        4358 :             bytesToCopy = static_cast<GUInt32>(len);
     354             : 
     355        9108 :         memcpy(&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
     356             : 
     357        9108 :         sc->totalLength += bytesToCopy * 8U;
     358             : 
     359        9108 :         sc->bufferLength += bytesToCopy;
     360        9108 :         data = static_cast<const GByte *>(data) + bytesToCopy;
     361        9108 :         len -= bytesToCopy;
     362             : 
     363        9108 :         if (sc->bufferLength == 64U)
     364             :         {
     365        4750 :             CPL_SHA256Guts(sc, sc->buffer.words);
     366        4750 :             needBurn = 1;
     367        4750 :             sc->bufferLength = 0U;
     368             :         }
     369             :     }
     370             : 
     371      127993 :     while (len > 63U)
     372             :     {
     373      110084 :         sc->totalLength += 512U;
     374             : 
     375      110084 :         CPL_SHA256Guts(sc, static_cast<const GUInt32 *>(data));
     376      110084 :         needBurn = 1;
     377             : 
     378      110084 :         data = static_cast<const GByte *>(data) + 64U;
     379      110084 :         len -= 64U;
     380             :     }
     381             : 
     382       17909 :     if (len)
     383             :     {
     384        4750 :         memcpy(&sc->buffer.bytes[sc->bufferLength], data, len);
     385             : 
     386        4750 :         sc->totalLength += static_cast<GUInt32>(len) * 8U;
     387             : 
     388        4750 :         sc->bufferLength += static_cast<GUInt32>(len);
     389             :     }
     390             : 
     391       17909 :     if (needBurn)
     392             :     {
     393             :         // Clean stack state of CPL_SHA256Guts()
     394             : 
     395             :         // We add dummy side effects to avoid burnStack() to be
     396             :         // optimized away (#6157).
     397             :         static GUInt32 accumulator = 0;
     398       19245 :         accumulator += burnStack(
     399             :             static_cast<int>(sizeof(GUInt32[74]) + sizeof(GUInt32 *[6]) +
     400        9622 :                              sizeof(int) + ((len % 2) ? sizeof(int) : 0)));
     401        9623 :         if (accumulator == 0xDEADBEEF)
     402           0 :             fprintf(stderr, "%s", ""); /*ok*/
     403             :     }
     404       17910 : }
     405             : 
     406        4649 : void CPL_SHA256Final(CPL_SHA256Context *sc, GByte hash[CPL_SHA256_HASH_SIZE])
     407             : {
     408        4649 :     GUInt32 bytesToPad = 120U - sc->bufferLength;
     409        4649 :     if (bytesToPad > 64U)
     410        4561 :         bytesToPad -= 64U;
     411             : 
     412        4649 :     const GUInt64 lengthPad = BYTESWAP64(sc->totalLength);
     413             : 
     414        4649 :     CPL_SHA256Update(sc, padding, bytesToPad);
     415        4649 :     CPL_SHA256Update(sc, &lengthPad, 8U);
     416             : 
     417        4649 :     if (hash)
     418             :     {
     419       41841 :         for (int i = 0; i < CPL_SHA256_HASH_WORDS; i++)
     420             :         {
     421       37192 :             *reinterpret_cast<GUInt32 *>(hash) = BYTESWAP(sc->hash[i]);
     422       37192 :             hash += 4;
     423             :         }
     424             :     }
     425        4649 : }
     426             : 
     427         687 : void CPL_SHA256(const void *data, size_t len, GByte hash[CPL_SHA256_HASH_SIZE])
     428             : {
     429             :     CPL_SHA256Context sSHA256Ctxt;
     430         687 :     CPL_SHA256Init(&sSHA256Ctxt);
     431         687 :     CPL_SHA256Update(&sSHA256Ctxt, data, len);
     432         686 :     CPL_SHA256Final(&sSHA256Ctxt, hash);
     433         687 :     memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt));
     434         687 : }
     435             : 
     436             : #define CPL_HMAC_SHA256_BLOCKSIZE 64U
     437             : 
     438             : // See
     439             : // https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Implementation
     440        1905 : void CPL_HMAC_SHA256(const void *pKey, size_t nKeyLen, const void *pabyMessage,
     441             :                      size_t nMessageLen, GByte abyDigest[CPL_SHA256_HASH_SIZE])
     442             : {
     443        1905 :     GByte abyPad[CPL_HMAC_SHA256_BLOCKSIZE] = {};
     444        1905 :     if (nKeyLen > CPL_HMAC_SHA256_BLOCKSIZE)
     445             :     {
     446           1 :         CPL_SHA256(pKey, nKeyLen, abyPad);
     447             :     }
     448             :     else
     449             :     {
     450        1904 :         memcpy(abyPad, pKey, nKeyLen);
     451             :     }
     452             : 
     453             :     // Compute ipad.
     454      123825 :     for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++)
     455      121920 :         abyPad[i] = 0x36 ^ abyPad[i];
     456             : 
     457             :     CPL_SHA256Context sSHA256Ctxt;
     458        1905 :     CPL_SHA256Init(&sSHA256Ctxt);
     459        1905 :     CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE);
     460        1905 :     CPL_SHA256Update(&sSHA256Ctxt, pabyMessage, nMessageLen);
     461        1905 :     CPL_SHA256Final(&sSHA256Ctxt, abyDigest);
     462             : 
     463             :     // Compute opad.
     464      123825 :     for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++)
     465      121920 :         abyPad[i] = (0x36 ^ 0x5C) ^ abyPad[i];
     466             : 
     467        1905 :     CPL_SHA256Init(&sSHA256Ctxt);
     468        1905 :     CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE);
     469        1905 :     CPL_SHA256Update(&sSHA256Ctxt, abyDigest, CPL_SHA256_HASH_SIZE);
     470        1905 :     CPL_SHA256Final(&sSHA256Ctxt, abyDigest);
     471             : 
     472        1905 :     memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt));
     473        1905 :     memset(abyPad, 0, CPL_HMAC_SHA256_BLOCKSIZE);
     474        1905 : }
     475             : 
     476             : #ifdef HAVE_CRYPTOPP
     477             : 
     478             : /* Begin of crypto++ headers */
     479             : #ifdef _MSC_VER
     480             : #pragma warning(push)
     481             : #pragma warning(disable : 4189)
     482             : #pragma warning(disable : 4512)
     483             : #pragma warning(disable : 4244)
     484             : #endif
     485             : 
     486             : #ifdef __GNUC__
     487             : #pragma GCC diagnostic push
     488             : #pragma GCC diagnostic ignored "-Weffc++"
     489             : #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
     490             : #pragma GCC diagnostic ignored "-Wold-style-cast"
     491             : #pragma GCC diagnostic ignored "-Wshadow"
     492             : #endif
     493             : 
     494             : #ifdef USE_ONLY_CRYPTODLL_ALG
     495             : #include "cryptopp/dll.h"
     496             : #else
     497             : #include "cryptopp/rsa.h"
     498             : #include "cryptopp/queue.h"
     499             : #endif
     500             : 
     501             : #include "cryptopp/base64.h"
     502             : #include "cryptopp/osrng.h"
     503             : 
     504             : // Fix compatibility with Crypto++
     505             : #if CRYPTOPP_VERSION >= 600
     506             : typedef CryptoPP::byte cryptopp_byte;
     507             : #else
     508             : typedef byte cryptopp_byte;
     509             : #endif
     510             : 
     511             : #ifdef __GNUC__
     512             : #pragma GCC diagnostic pop
     513             : #endif
     514             : 
     515             : #ifdef _MSC_VER
     516             : #pragma warning(pop)
     517             : #endif
     518             : 
     519             : #endif  // HAVE_CRYPTOPP
     520             : 
     521             : #ifdef HAVE_OPENSSL_CRYPTO
     522             : 
     523             : #if defined(__GNUC__)
     524             : #pragma GCC diagnostic push
     525             : #pragma GCC diagnostic ignored "-Wold-style-cast"
     526             : #ifdef HAVE_WFLAG_CAST_FUNCTION_TYPE
     527             : #pragma GCC diagnostic ignored "-Wcast-function-type"
     528             : #endif
     529             : #endif
     530             : 
     531             : #include <openssl/bio.h>
     532             : #include <openssl/evp.h>
     533             : #include <openssl/pem.h>
     534             : 
     535             : #if defined(__GNUC__)
     536             : #pragma GCC diagnostic pop
     537             : #endif
     538             : 
     539             : #endif
     540             : 
     541             : /************************************************************************/
     542             : /*                  CPLOpenSSLNullPassphraseCallback()                  */
     543             : /************************************************************************/
     544             : 
     545             : #if defined(HAVE_OPENSSL_CRYPTO)
     546           0 : static int CPLOpenSSLNullPassphraseCallback(char * /*buf*/, int /*size*/,
     547             :                                             int /*rwflag*/, void * /*u*/)
     548             : {
     549           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     550             :              "A passphrase was required for this private key, "
     551             :              "but this is not supported");
     552           0 :     return 0;
     553             : }
     554             : 
     555             : #endif
     556             : 
     557             : /************************************************************************/
     558             : /*                         CPL_RSA_SHA256_Sign()                        */
     559             : /************************************************************************/
     560             : 
     561           7 : GByte *CPL_RSA_SHA256_Sign(const char *pszPrivateKey, const void *pabyData,
     562             :                            unsigned int nDataLen, unsigned int *pnSignatureLen)
     563             : {
     564           7 :     *pnSignatureLen = 0;
     565             : 
     566             : #ifdef HAVE_CRYPTOPP
     567           7 :     if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "CRYPTOPP"),
     568             :               "CRYPTOPP"))
     569             :     {
     570             :         // See https://www.cryptopp.com/wiki/RSA_Cryptography
     571             :         // https://www.cryptopp.com/wiki/RSA_Signature_Schemes#RSA_Signature_Scheme_.28PKCS_v1.5.29
     572             :         // https://www.cryptopp.com/wiki/Keys_and_Formats#PEM_Encoded_Keys
     573             : 
     574          14 :         CPLString osRSAPrivKey(pszPrivateKey);
     575           7 :         static std::string HEADER = "-----BEGIN PRIVATE KEY-----";
     576           7 :         static std::string HEADER_RSA = "-----BEGIN RSA PRIVATE KEY-----";
     577             :         static std::string HEADER_ENCRYPTED =
     578           7 :             "-----BEGIN ENCRYPTED PRIVATE KEY-----";
     579           7 :         static std::string FOOTER = "-----END PRIVATE KEY-----";
     580             : 
     581             :         size_t pos1, pos2;
     582           7 :         pos1 = osRSAPrivKey.find(HEADER);
     583           7 :         if (pos1 == std::string::npos)
     584             :         {
     585           0 :             if (osRSAPrivKey.find(HEADER_RSA) != std::string::npos)
     586             :             {
     587           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     588             :                          "'Traditional' PEM header found, whereas PKCS#8 is "
     589             :                          "expected. You can use for example "
     590             :                          "'openssl pkcs8 -topk8 -inform pem -in file.key "
     591             :                          "-outform pem -nocrypt -out file.pem' to generate "
     592             :                          "a compatible PEM file");
     593             :             }
     594           0 :             else if (osRSAPrivKey.find(HEADER_ENCRYPTED) != std::string::npos)
     595             :             {
     596           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     597             :                          "Encrypted PEM header found. Only PKCS#8 unencrypted "
     598             :                          "private keys are supported");
     599             :             }
     600             :             else
     601             :             {
     602           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "PEM header not found");
     603             :             }
     604           0 :             return nullptr;
     605             :         }
     606             : 
     607           7 :         pos2 = osRSAPrivKey.find(FOOTER, pos1 + 1);
     608           7 :         if (pos2 == std::string::npos)
     609             :         {
     610           0 :             CPLError(CE_Failure, CPLE_AppDefined, "PEM footer not found");
     611           0 :             return nullptr;
     612             :         }
     613             : 
     614             :         // Strip header and footer to get the base64-only portion
     615           7 :         pos1 = pos1 + HEADER.size();
     616          14 :         std::string osKeyB64 = osRSAPrivKey.substr(pos1, pos2 - pos1);
     617             : 
     618             :         // Base64 decode, place in a ByteQueue
     619          14 :         CryptoPP::ByteQueue queue;
     620          14 :         CryptoPP::Base64Decoder decoder;
     621             : 
     622           7 :         decoder.Attach(new CryptoPP::Redirector(queue));
     623           7 :         decoder.Put(reinterpret_cast<const cryptopp_byte *>(osKeyB64.data()),
     624             :                     osKeyB64.length());
     625           7 :         decoder.MessageEnd();
     626             : 
     627          14 :         CryptoPP::RSA::PrivateKey rsaPrivate;
     628             :         try
     629             :         {
     630           7 :             rsaPrivate.BERDecode(queue);
     631             :         }
     632           0 :         catch (const std::exception &e)
     633             :         {
     634           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     635           0 :                      "Exception while decoding private key: %s", e.what());
     636           0 :             return nullptr;
     637             :         }
     638             : 
     639             :         // Check that we have consumed all bytes.
     640           7 :         if (!queue.IsEmpty())
     641             :         {
     642           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     643             :                      "Invalid private key: extraneous trailing bytes");
     644           0 :             return nullptr;
     645             :         }
     646             : 
     647          14 :         CryptoPP::AutoSeededRandomPool prng;
     648           7 :         bool valid = rsaPrivate.Validate(prng, 3);
     649           7 :         if (!valid)
     650             :         {
     651           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     652             :                      "Invalid private key: validation failed");
     653           0 :             return nullptr;
     654             :         }
     655             : 
     656          14 :         std::string signature;
     657             :         try
     658             :         {
     659             :             typedef CryptoPP::RSASS<CryptoPP::PKCS1v15,
     660             :                                     CryptoPP::SHA256>::Signer
     661             :                 RSASSA_PKCS1v15_SHA256_Signer;
     662          14 :             RSASSA_PKCS1v15_SHA256_Signer signer(rsaPrivate);
     663             : 
     664          14 :             std::string message;
     665           7 :             message.assign(static_cast<const char *>(pabyData), nDataLen);
     666             : 
     667             :             CryptoPP::StringSource stringSource(
     668             :                 message, true,
     669             :                 new CryptoPP::SignerFilter(
     670           7 :                     prng, signer, new CryptoPP::StringSink(signature)));
     671             :         }
     672           0 :         catch (const std::exception &e)
     673             :         {
     674           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Exception while signing: %s",
     675           0 :                      e.what());
     676           0 :             return nullptr;
     677             :         }
     678             : 
     679           7 :         *pnSignatureLen = static_cast<unsigned int>(signature.size());
     680             :         GByte *pabySignature =
     681           7 :             static_cast<GByte *>(CPLMalloc(signature.size()));
     682           7 :         memcpy(pabySignature, signature.c_str(), signature.size());
     683           7 :         return pabySignature;
     684             :     }
     685             : #endif
     686             : 
     687             : #if defined(HAVE_OPENSSL_CRYPTO)
     688           0 :     if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "OPENSSL"), "OPENSSL"))
     689             :     {
     690           0 :         const EVP_MD *digest = EVP_sha256();
     691           0 :         if (digest == nullptr)
     692             :         {
     693           0 :             CPLError(CE_Failure, CPLE_AppDefined, "EVP_sha256() failed");
     694           0 :             return nullptr;
     695             :         }
     696             : 
     697             :         // Old versions expect a void*, newer a const void*
     698           0 :         BIO *bio = BIO_new_mem_buf(
     699             :             const_cast<void *>(static_cast<const void *>(pszPrivateKey)),
     700           0 :             static_cast<int>(strlen(pszPrivateKey)));
     701           0 :         if (bio == nullptr)
     702             :         {
     703           0 :             CPLError(CE_Failure, CPLE_AppDefined, "BIO_new_mem_buf() failed");
     704           0 :             return nullptr;
     705             :         }
     706           0 :         EVP_PKEY *pkey = PEM_read_bio_PrivateKey(
     707             :             bio, nullptr, CPLOpenSSLNullPassphraseCallback, nullptr);
     708           0 :         BIO_free(bio);
     709           0 :         if (pkey == nullptr)
     710             :         {
     711           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     712             :                      "PEM_read_bio_PrivateKey() failed");
     713           0 :             return nullptr;
     714             :         }
     715           0 :         EVP_MD_CTX *md_ctx = EVP_MD_CTX_create();
     716           0 :         CPLAssert(md_ctx != nullptr);
     717           0 :         int ret = EVP_SignInit(md_ctx, digest);
     718           0 :         CPLAssert(ret == 1);
     719           0 :         ret = EVP_SignUpdate(md_ctx, pabyData, nDataLen);
     720           0 :         CPLAssert(ret == 1);
     721           0 :         const int nPKeyLength = EVP_PKEY_size(pkey);
     722           0 :         CPLAssert(nPKeyLength > 0);
     723           0 :         GByte *abyBuffer = static_cast<GByte *>(CPLMalloc(nPKeyLength));
     724           0 :         ret = EVP_SignFinal(md_ctx, abyBuffer, pnSignatureLen, pkey);
     725           0 :         if (ret != 1)
     726             :         {
     727           0 :             CPLError(CE_Failure, CPLE_AppDefined, "EVP_SignFinal() failed");
     728           0 :             EVP_MD_CTX_destroy(md_ctx);
     729           0 :             EVP_PKEY_free(pkey);
     730           0 :             CPLFree(abyBuffer);
     731           0 :             return nullptr;
     732             :         }
     733             : 
     734           0 :         EVP_MD_CTX_destroy(md_ctx);
     735           0 :         EVP_PKEY_free(pkey);
     736           0 :         return abyBuffer;
     737             :     }
     738             : #endif
     739             : 
     740           0 :     CPL_IGNORE_RET_VAL(pszPrivateKey);
     741           0 :     CPL_IGNORE_RET_VAL(pabyData);
     742           0 :     CPL_IGNORE_RET_VAL(nDataLen);
     743             : 
     744           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     745             :              "CPLRSASHA256Sign() not implemented: "
     746             :              "GDAL must be built against libcrypto++ or libcrypto (openssl)");
     747           0 :     return nullptr;
     748             : }

Generated by: LCOV version 1.14