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: 2024-04-28 23:18:46 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        4206 : static inline GUInt64 _byteswap64(GUInt64 x)
      93             : {
      94        4206 :     GUInt32 a = static_cast<GUInt32>(x >> 32);
      95        4206 :     GUInt32 b = static_cast<GUInt32>(x);
      96        4206 :     return (static_cast<GUInt64>(BYTESWAP(b)) << 32) |
      97        4206 :            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        4206 : void CPL_SHA256Init(CPL_SHA256Context *sc)
     111             : {
     112        4206 :     sc->totalLength = 0;
     113        4206 :     sc->hash[0] = 0x6a09e667U;
     114        4206 :     sc->hash[1] = 0xbb67ae85U;
     115        4206 :     sc->hash[2] = 0x3c6ef372U;
     116        4206 :     sc->hash[3] = 0xa54ff53aU;
     117        4206 :     sc->hash[4] = 0x510e527fU;
     118        4206 :     sc->hash[5] = 0x9b05688cU;
     119        4206 :     sc->hash[6] = 0x1f83d9abU;
     120        4206 :     sc->hash[7] = 0x5be0cd19U;
     121        4206 :     sc->bufferLength = 0U;
     122        4206 : }
     123             : 
     124       26178 : static GUInt32 burnStack(int size)
     125             : {
     126             :     GByte buf[128];
     127       26178 :     GUInt32 ret = 0;
     128             : 
     129       26178 :     memset(buf, static_cast<GByte>(size & 0xff), sizeof(buf));
     130     3376810 :     for (size_t i = 0; i < sizeof(buf); i++)
     131     3350640 :         ret += ret * buf[i];
     132       26178 :     size -= static_cast<int>(sizeof(buf));
     133       26178 :     if (size > 0)
     134       17452 :         ret += burnStack(size);
     135       26178 :     return ret;
     136             : }
     137             : 
     138             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
     139      228084 : static void CPL_SHA256Guts(CPL_SHA256Context *sc, const GUInt32 *cbuf)
     140             : {
     141      228084 :     GUInt32 buf[64] = {};
     142             : 
     143      228084 :     GUInt32 *W = buf;
     144             : 
     145     3877430 :     for (int i = 15; i >= 0; i--)
     146             :     {
     147     3649340 :         *(W++) = BYTESWAP(*cbuf);
     148     3649340 :         cbuf++;
     149             :     }
     150             : 
     151      228084 :     GUInt32 *W16 = &buf[0];
     152      228084 :     GUInt32 *W15 = &buf[1];
     153      228084 :     GUInt32 *W7 = &buf[9];
     154      228084 :     GUInt32 *W2 = &buf[14];
     155             : 
     156    11176100 :     for (int i = 47; i >= 0; i--)
     157             :     {
     158    10948000 :         *(W++) = sigma1(*W2) + *(W7++) + sigma0(*W15) + *(W16++);
     159    10948000 :         W2++;
     160    10948000 :         W15++;
     161             :     }
     162             : 
     163      228084 :     GUInt32 a = sc->hash[0];
     164      228084 :     GUInt32 b = sc->hash[1];
     165      228084 :     GUInt32 c = sc->hash[2];
     166      228084 :     GUInt32 d = sc->hash[3];
     167      228084 :     GUInt32 e = sc->hash[4];
     168      228084 :     GUInt32 f = sc->hash[5];
     169      228084 :     GUInt32 g = sc->hash[6];
     170      228084 :     GUInt32 h = sc->hash[7];
     171             : 
     172      228084 :     const GUInt32 *Kp = K;
     173      228084 :     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    14825500 :     for (int i = 63; i >= 0; i--)
     181    14597400 :         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      228084 :     sc->hash[0] += a;
     334      228084 :     sc->hash[1] += b;
     335      228084 :     sc->hash[2] += c;
     336      228084 :     sc->hash[3] += d;
     337      228084 :     sc->hash[4] += e;
     338      228084 :     sc->hash[5] += f;
     339      228084 :     sc->hash[6] += g;
     340      228084 :     sc->hash[7] += h;
     341      228084 : }
     342             : 
     343       16207 : void CPL_SHA256Update(CPL_SHA256Context *sc, const void *data, size_t len)
     344             : {
     345       16207 :     int needBurn = 0;
     346             : 
     347       16207 :     if (sc->bufferLength)
     348             :     {
     349        8236 :         const GUInt32 bufferBytesLeft = 64U - sc->bufferLength;
     350             : 
     351        8236 :         GUInt32 bytesToCopy = bufferBytesLeft;
     352        8236 :         if (bytesToCopy > len)
     353        3936 :             bytesToCopy = static_cast<GUInt32>(len);
     354             : 
     355        8236 :         memcpy(&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
     356             : 
     357        8236 :         sc->totalLength += bytesToCopy * 8U;
     358             : 
     359        8236 :         sc->bufferLength += bytesToCopy;
     360        8236 :         data = static_cast<const GByte *>(data) + bytesToCopy;
     361        8236 :         len -= bytesToCopy;
     362             : 
     363        8236 :         if (sc->bufferLength == 64U)
     364             :         {
     365        4300 :             CPL_SHA256Guts(sc, sc->buffer.words);
     366        4300 :             needBurn = 1;
     367        4300 :             sc->bufferLength = 0U;
     368             :         }
     369             :     }
     370             : 
     371      239991 :     while (len > 63U)
     372             :     {
     373      223784 :         sc->totalLength += 512U;
     374             : 
     375      223784 :         CPL_SHA256Guts(sc, static_cast<const GUInt32 *>(data));
     376      223784 :         needBurn = 1;
     377             : 
     378      223784 :         data = static_cast<const GByte *>(data) + 64U;
     379      223784 :         len -= 64U;
     380             :     }
     381             : 
     382       16207 :     if (len)
     383             :     {
     384        4300 :         memcpy(&sc->buffer.bytes[sc->bufferLength], data, len);
     385             : 
     386        4300 :         sc->totalLength += static_cast<GUInt32>(len) * 8U;
     387             : 
     388        4300 :         sc->bufferLength += static_cast<GUInt32>(len);
     389             :     }
     390             : 
     391       16207 :     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       17452 :         accumulator += burnStack(
     399             :             static_cast<int>(sizeof(GUInt32[74]) + sizeof(GUInt32 *[6]) +
     400        8726 :                              sizeof(int) + ((len % 2) ? sizeof(int) : 0)));
     401        8726 :         if (accumulator == 0xDEADBEEF)
     402           0 :             fprintf(stderr, "%s", ""); /*ok*/
     403             :     }
     404       16207 : }
     405             : 
     406        4206 : void CPL_SHA256Final(CPL_SHA256Context *sc, GByte hash[CPL_SHA256_HASH_SIZE])
     407             : {
     408        4206 :     GUInt32 bytesToPad = 120U - sc->bufferLength;
     409        4206 :     if (bytesToPad > 64U)
     410        4124 :         bytesToPad -= 64U;
     411             : 
     412        4206 :     const GUInt64 lengthPad = BYTESWAP64(sc->totalLength);
     413             : 
     414        4206 :     CPL_SHA256Update(sc, padding, bytesToPad);
     415        4206 :     CPL_SHA256Update(sc, &lengthPad, 8U);
     416             : 
     417        4206 :     if (hash)
     418             :     {
     419       37854 :         for (int i = 0; i < CPL_SHA256_HASH_WORDS; i++)
     420             :         {
     421       33648 :             *reinterpret_cast<GUInt32 *>(hash) = BYTESWAP(sc->hash[i]);
     422       33648 :             hash += 4;
     423             :         }
     424             :     }
     425        4206 : }
     426             : 
     427         617 : void CPL_SHA256(const void *data, size_t len, GByte hash[CPL_SHA256_HASH_SIZE])
     428             : {
     429             :     CPL_SHA256Context sSHA256Ctxt;
     430         617 :     CPL_SHA256Init(&sSHA256Ctxt);
     431         617 :     CPL_SHA256Update(&sSHA256Ctxt, data, len);
     432         617 :     CPL_SHA256Final(&sSHA256Ctxt, hash);
     433         617 :     memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt));
     434         617 : }
     435             : 
     436             : #define CPL_HMAC_SHA256_BLOCKSIZE 64U
     437             : 
     438             : // See
     439             : // https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Implementation
     440        1722 : 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        1722 :     GByte abyPad[CPL_HMAC_SHA256_BLOCKSIZE] = {};
     444        1722 :     if (nKeyLen > CPL_HMAC_SHA256_BLOCKSIZE)
     445             :     {
     446           1 :         CPL_SHA256(pKey, nKeyLen, abyPad);
     447             :     }
     448             :     else
     449             :     {
     450        1721 :         memcpy(abyPad, pKey, nKeyLen);
     451             :     }
     452             : 
     453             :     // Compute ipad.
     454      111930 :     for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++)
     455      110208 :         abyPad[i] = 0x36 ^ abyPad[i];
     456             : 
     457             :     CPL_SHA256Context sSHA256Ctxt;
     458        1722 :     CPL_SHA256Init(&sSHA256Ctxt);
     459        1722 :     CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE);
     460        1722 :     CPL_SHA256Update(&sSHA256Ctxt, pabyMessage, nMessageLen);
     461        1722 :     CPL_SHA256Final(&sSHA256Ctxt, abyDigest);
     462             : 
     463             :     // Compute opad.
     464      111930 :     for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++)
     465      110208 :         abyPad[i] = (0x36 ^ 0x5C) ^ abyPad[i];
     466             : 
     467        1722 :     CPL_SHA256Init(&sSHA256Ctxt);
     468        1722 :     CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE);
     469        1722 :     CPL_SHA256Update(&sSHA256Ctxt, abyDigest, CPL_SHA256_HASH_SIZE);
     470        1722 :     CPL_SHA256Final(&sSHA256Ctxt, abyDigest);
     471             : 
     472        1722 :     memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt));
     473        1722 :     memset(abyPad, 0, CPL_HMAC_SHA256_BLOCKSIZE);
     474        1722 : }
     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             : #endif
     527             : 
     528             : #include <openssl/bio.h>
     529             : #include <openssl/evp.h>
     530             : #include <openssl/pem.h>
     531             : 
     532             : #if defined(__GNUC__)
     533             : #pragma GCC diagnostic pop
     534             : #endif
     535             : 
     536             : #endif
     537             : 
     538             : /************************************************************************/
     539             : /*                  CPLOpenSSLNullPassphraseCallback()                  */
     540             : /************************************************************************/
     541             : 
     542             : #if defined(HAVE_OPENSSL_CRYPTO)
     543           0 : static int CPLOpenSSLNullPassphraseCallback(char * /*buf*/, int /*size*/,
     544             :                                             int /*rwflag*/, void * /*u*/)
     545             : {
     546           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     547             :              "A passphrase was required for this private key, "
     548             :              "but this is not supported");
     549           0 :     return 0;
     550             : }
     551             : 
     552             : #endif
     553             : 
     554             : /************************************************************************/
     555             : /*                         CPL_RSA_SHA256_Sign()                        */
     556             : /************************************************************************/
     557             : 
     558           6 : GByte *CPL_RSA_SHA256_Sign(const char *pszPrivateKey, const void *pabyData,
     559             :                            unsigned int nDataLen, unsigned int *pnSignatureLen)
     560             : {
     561           6 :     *pnSignatureLen = 0;
     562             : 
     563             : #ifdef HAVE_CRYPTOPP
     564           6 :     if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "CRYPTOPP"),
     565             :               "CRYPTOPP"))
     566             :     {
     567             :         // See https://www.cryptopp.com/wiki/RSA_Cryptography
     568             :         // https://www.cryptopp.com/wiki/RSA_Signature_Schemes#RSA_Signature_Scheme_.28PKCS_v1.5.29
     569             :         // https://www.cryptopp.com/wiki/Keys_and_Formats#PEM_Encoded_Keys
     570             : 
     571          12 :         CPLString osRSAPrivKey(pszPrivateKey);
     572           6 :         static std::string HEADER = "-----BEGIN PRIVATE KEY-----";
     573           6 :         static std::string HEADER_RSA = "-----BEGIN RSA PRIVATE KEY-----";
     574             :         static std::string HEADER_ENCRYPTED =
     575           6 :             "-----BEGIN ENCRYPTED PRIVATE KEY-----";
     576           6 :         static std::string FOOTER = "-----END PRIVATE KEY-----";
     577             : 
     578             :         size_t pos1, pos2;
     579           6 :         pos1 = osRSAPrivKey.find(HEADER);
     580           6 :         if (pos1 == std::string::npos)
     581             :         {
     582           0 :             if (osRSAPrivKey.find(HEADER_RSA) != std::string::npos)
     583             :             {
     584           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     585             :                          "'Traditional' PEM header found, whereas PKCS#8 is "
     586             :                          "expected. You can use for example "
     587             :                          "'openssl pkcs8 -topk8 -inform pem -in file.key "
     588             :                          "-outform pem -nocrypt -out file.pem' to generate "
     589             :                          "a compatible PEM file");
     590             :             }
     591           0 :             else if (osRSAPrivKey.find(HEADER_ENCRYPTED) != std::string::npos)
     592             :             {
     593           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     594             :                          "Encrypted PEM header found. Only PKCS#8 unencrypted "
     595             :                          "private keys are supported");
     596             :             }
     597             :             else
     598             :             {
     599           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "PEM header not found");
     600             :             }
     601           0 :             return nullptr;
     602             :         }
     603             : 
     604           6 :         pos2 = osRSAPrivKey.find(FOOTER, pos1 + 1);
     605           6 :         if (pos2 == std::string::npos)
     606             :         {
     607           0 :             CPLError(CE_Failure, CPLE_AppDefined, "PEM footer not found");
     608           0 :             return nullptr;
     609             :         }
     610             : 
     611             :         // Strip header and footer to get the base64-only portion
     612           6 :         pos1 = pos1 + HEADER.size();
     613          12 :         std::string osKeyB64 = osRSAPrivKey.substr(pos1, pos2 - pos1);
     614             : 
     615             :         // Base64 decode, place in a ByteQueue
     616          12 :         CryptoPP::ByteQueue queue;
     617          12 :         CryptoPP::Base64Decoder decoder;
     618             : 
     619           6 :         decoder.Attach(new CryptoPP::Redirector(queue));
     620           6 :         decoder.Put(reinterpret_cast<const cryptopp_byte *>(osKeyB64.data()),
     621             :                     osKeyB64.length());
     622           6 :         decoder.MessageEnd();
     623             : 
     624          12 :         CryptoPP::RSA::PrivateKey rsaPrivate;
     625             :         try
     626             :         {
     627           6 :             rsaPrivate.BERDecode(queue);
     628             :         }
     629           0 :         catch (const std::exception &e)
     630             :         {
     631           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     632           0 :                      "Exception while decoding private key: %s", e.what());
     633           0 :             return nullptr;
     634             :         }
     635             : 
     636             :         // Check that we have consumed all bytes.
     637           6 :         if (!queue.IsEmpty())
     638             :         {
     639           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     640             :                      "Invalid private key: extraneous trailing bytes");
     641           0 :             return nullptr;
     642             :         }
     643             : 
     644          12 :         CryptoPP::AutoSeededRandomPool prng;
     645           6 :         bool valid = rsaPrivate.Validate(prng, 3);
     646           6 :         if (!valid)
     647             :         {
     648           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     649             :                      "Invalid private key: validation failed");
     650           0 :             return nullptr;
     651             :         }
     652             : 
     653          12 :         std::string signature;
     654             :         try
     655             :         {
     656             :             typedef CryptoPP::RSASS<CryptoPP::PKCS1v15,
     657             :                                     CryptoPP::SHA256>::Signer
     658             :                 RSASSA_PKCS1v15_SHA256_Signer;
     659          12 :             RSASSA_PKCS1v15_SHA256_Signer signer(rsaPrivate);
     660             : 
     661          12 :             std::string message;
     662           6 :             message.assign(static_cast<const char *>(pabyData), nDataLen);
     663             : 
     664             :             CryptoPP::StringSource stringSource(
     665             :                 message, true,
     666             :                 new CryptoPP::SignerFilter(
     667           6 :                     prng, signer, new CryptoPP::StringSink(signature)));
     668             :         }
     669           0 :         catch (const std::exception &e)
     670             :         {
     671           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Exception while signing: %s",
     672           0 :                      e.what());
     673           0 :             return nullptr;
     674             :         }
     675             : 
     676           6 :         *pnSignatureLen = static_cast<unsigned int>(signature.size());
     677             :         GByte *pabySignature =
     678           6 :             static_cast<GByte *>(CPLMalloc(signature.size()));
     679           6 :         memcpy(pabySignature, signature.c_str(), signature.size());
     680           6 :         return pabySignature;
     681             :     }
     682             : #endif
     683             : 
     684             : #if defined(HAVE_OPENSSL_CRYPTO)
     685           0 :     if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "OPENSSL"), "OPENSSL"))
     686             :     {
     687           0 :         const EVP_MD *digest = EVP_sha256();
     688           0 :         if (digest == nullptr)
     689             :         {
     690           0 :             CPLError(CE_Failure, CPLE_AppDefined, "EVP_sha256() failed");
     691           0 :             return nullptr;
     692             :         }
     693             : 
     694             :         // Old versions expect a void*, newer a const void*
     695           0 :         BIO *bio = BIO_new_mem_buf(
     696             :             const_cast<void *>(static_cast<const void *>(pszPrivateKey)),
     697           0 :             static_cast<int>(strlen(pszPrivateKey)));
     698           0 :         if (bio == nullptr)
     699             :         {
     700           0 :             CPLError(CE_Failure, CPLE_AppDefined, "BIO_new_mem_buf() failed");
     701           0 :             return nullptr;
     702             :         }
     703           0 :         EVP_PKEY *pkey = PEM_read_bio_PrivateKey(
     704             :             bio, nullptr, CPLOpenSSLNullPassphraseCallback, nullptr);
     705           0 :         BIO_free(bio);
     706           0 :         if (pkey == nullptr)
     707             :         {
     708           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     709             :                      "PEM_read_bio_PrivateKey() failed");
     710           0 :             return nullptr;
     711             :         }
     712           0 :         EVP_MD_CTX *md_ctx = EVP_MD_CTX_create();
     713           0 :         CPLAssert(md_ctx != nullptr);
     714           0 :         int ret = EVP_SignInit(md_ctx, digest);
     715           0 :         CPLAssert(ret == 1);
     716           0 :         ret = EVP_SignUpdate(md_ctx, pabyData, nDataLen);
     717           0 :         CPLAssert(ret == 1);
     718           0 :         const int nPKeyLength = EVP_PKEY_size(pkey);
     719           0 :         CPLAssert(nPKeyLength > 0);
     720           0 :         GByte *abyBuffer = static_cast<GByte *>(CPLMalloc(nPKeyLength));
     721           0 :         ret = EVP_SignFinal(md_ctx, abyBuffer, pnSignatureLen, pkey);
     722           0 :         if (ret != 1)
     723             :         {
     724           0 :             CPLError(CE_Failure, CPLE_AppDefined, "EVP_SignFinal() failed");
     725           0 :             EVP_MD_CTX_destroy(md_ctx);
     726           0 :             EVP_PKEY_free(pkey);
     727           0 :             CPLFree(abyBuffer);
     728           0 :             return nullptr;
     729             :         }
     730             : 
     731           0 :         EVP_MD_CTX_destroy(md_ctx);
     732           0 :         EVP_PKEY_free(pkey);
     733           0 :         return abyBuffer;
     734             :     }
     735             : #endif
     736             : 
     737           0 :     CPL_IGNORE_RET_VAL(pszPrivateKey);
     738           0 :     CPL_IGNORE_RET_VAL(pabyData);
     739           0 :     CPL_IGNORE_RET_VAL(nDataLen);
     740             : 
     741           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     742             :              "CPLRSASHA256Sign() not implemented: "
     743             :              "GDAL must be built against libcrypto++ or libcrypto (openssl)");
     744           0 :     return nullptr;
     745             : }

Generated by: LCOV version 1.14