quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

sha256.c (15745B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Florin Petriuc, <petriuc.florin@gmail.com>
      9  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
     10  *
     11  * This software is licensed as described in the file COPYING, which
     12  * you should have received as part of this distribution. The terms
     13  * are also available at https://curl.se/docs/copyright.html.
     14  *
     15  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     16  * copies of the Software, and permit persons to whom the Software is
     17  * furnished to do so, under the terms of the COPYING file.
     18  *
     19  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     20  * KIND, either express or implied.
     21  *
     22  * SPDX-License-Identifier: curl
     23  *
     24  ***************************************************************************/
     25 
     26 #include "curl_setup.h"
     27 
     28 #if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \
     29   || defined(USE_LIBSSH2) || defined(USE_SSL)
     30 
     31 #include "curlx/warnless.h"
     32 #include "curl_sha256.h"
     33 #include "curl_hmac.h"
     34 
     35 #ifdef USE_OPENSSL
     36 #include <openssl/evp.h>
     37 #elif defined(USE_GNUTLS)
     38 #include <nettle/sha.h>
     39 #elif defined(USE_MBEDTLS)
     40 #include <mbedtls/version.h>
     41 #if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
     42    (MBEDTLS_VERSION_NUMBER < 0x03000000)
     43   #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
     44 #endif
     45 #include <mbedtls/sha256.h>
     46 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
     47               (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
     48       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
     49               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
     50 #include <CommonCrypto/CommonDigest.h>
     51 #define AN_APPLE_OS
     52 #elif defined(USE_WIN32_CRYPTO)
     53 #include <wincrypt.h>
     54 #endif
     55 
     56 /* The last 3 #include files should be in this order */
     57 #include "curl_printf.h"
     58 #include "curl_memory.h"
     59 #include "memdebug.h"
     60 
     61 /* Please keep the SSL backend-specific #if branches in this order:
     62  *
     63  * 1. USE_OPENSSL
     64  * 2. USE_GNUTLS
     65  * 3. USE_MBEDTLS
     66  * 4. USE_COMMON_CRYPTO
     67  * 5. USE_WIN32_CRYPTO
     68  *
     69  * This ensures that the same SSL branch gets activated throughout this source
     70  * file even if multiple backends are enabled at the same time.
     71  */
     72 
     73 #ifdef USE_OPENSSL
     74 
     75 struct ossl_sha256_ctx {
     76   EVP_MD_CTX *openssl_ctx;
     77 };
     78 typedef struct ossl_sha256_ctx my_sha256_ctx;
     79 
     80 static CURLcode my_sha256_init(void *in)
     81 {
     82   my_sha256_ctx *ctx = (my_sha256_ctx *)in;
     83   ctx->openssl_ctx = EVP_MD_CTX_create();
     84   if(!ctx->openssl_ctx)
     85     return CURLE_OUT_OF_MEMORY;
     86 
     87   if(!EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL)) {
     88     EVP_MD_CTX_destroy(ctx->openssl_ctx);
     89     return CURLE_FAILED_INIT;
     90   }
     91   return CURLE_OK;
     92 }
     93 
     94 static void my_sha256_update(void *in,
     95                              const unsigned char *data,
     96                              unsigned int length)
     97 {
     98   my_sha256_ctx *ctx = (my_sha256_ctx *)in;
     99   EVP_DigestUpdate(ctx->openssl_ctx, data, length);
    100 }
    101 
    102 static void my_sha256_final(unsigned char *digest, void *in)
    103 {
    104   my_sha256_ctx *ctx = (my_sha256_ctx *)in;
    105   EVP_DigestFinal_ex(ctx->openssl_ctx, digest, NULL);
    106   EVP_MD_CTX_destroy(ctx->openssl_ctx);
    107 }
    108 
    109 #elif defined(USE_GNUTLS)
    110 
    111 typedef struct sha256_ctx my_sha256_ctx;
    112 
    113 static CURLcode my_sha256_init(void *ctx)
    114 {
    115   sha256_init(ctx);
    116   return CURLE_OK;
    117 }
    118 
    119 static void my_sha256_update(void *ctx,
    120                              const unsigned char *data,
    121                              unsigned int length)
    122 {
    123   sha256_update(ctx, length, data);
    124 }
    125 
    126 static void my_sha256_final(unsigned char *digest, void *ctx)
    127 {
    128   sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
    129 }
    130 
    131 #elif defined(USE_MBEDTLS)
    132 
    133 typedef mbedtls_sha256_context my_sha256_ctx;
    134 
    135 static CURLcode my_sha256_init(void *ctx)
    136 {
    137 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
    138   (void) mbedtls_sha256_starts(ctx, 0);
    139 #else
    140   (void) mbedtls_sha256_starts_ret(ctx, 0);
    141 #endif
    142   return CURLE_OK;
    143 }
    144 
    145 static void my_sha256_update(void *ctx,
    146                              const unsigned char *data,
    147                              unsigned int length)
    148 {
    149 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
    150   (void) mbedtls_sha256_update(ctx, data, length);
    151 #else
    152   (void) mbedtls_sha256_update_ret(ctx, data, length);
    153 #endif
    154 }
    155 
    156 static void my_sha256_final(unsigned char *digest, void *ctx)
    157 {
    158 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
    159   (void) mbedtls_sha256_finish(ctx, digest);
    160 #else
    161   (void) mbedtls_sha256_finish_ret(ctx, digest);
    162 #endif
    163 }
    164 
    165 #elif defined(AN_APPLE_OS)
    166 typedef CC_SHA256_CTX my_sha256_ctx;
    167 
    168 static CURLcode my_sha256_init(void *ctx)
    169 {
    170   (void) CC_SHA256_Init(ctx);
    171   return CURLE_OK;
    172 }
    173 
    174 static void my_sha256_update(void *ctx,
    175                              const unsigned char *data,
    176                              unsigned int length)
    177 {
    178   (void) CC_SHA256_Update(ctx, data, length);
    179 }
    180 
    181 static void my_sha256_final(unsigned char *digest, void *ctx)
    182 {
    183   (void) CC_SHA256_Final(digest, ctx);
    184 }
    185 
    186 #elif defined(USE_WIN32_CRYPTO)
    187 
    188 struct sha256_ctx {
    189   HCRYPTPROV hCryptProv;
    190   HCRYPTHASH hHash;
    191 };
    192 typedef struct sha256_ctx my_sha256_ctx;
    193 
    194 #if !defined(CALG_SHA_256)
    195 #define CALG_SHA_256 0x0000800c
    196 #endif
    197 
    198 static CURLcode my_sha256_init(void *in)
    199 {
    200   my_sha256_ctx *ctx = (my_sha256_ctx *)in;
    201   if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
    202                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
    203     return CURLE_OUT_OF_MEMORY;
    204 
    205   if(!CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash)) {
    206     CryptReleaseContext(ctx->hCryptProv, 0);
    207     ctx->hCryptProv = 0;
    208     return CURLE_FAILED_INIT;
    209   }
    210 
    211   return CURLE_OK;
    212 }
    213 
    214 static void my_sha256_update(void *in,
    215                              const unsigned char *data,
    216                              unsigned int length)
    217 {
    218   my_sha256_ctx *ctx = (my_sha256_ctx *)in;
    219 #ifdef __MINGW32CE__
    220   CryptHashData(ctx->hHash, (BYTE *)CURL_UNCONST(data), length, 0);
    221 #else
    222   CryptHashData(ctx->hHash, (const BYTE *)data, length, 0);
    223 #endif
    224 }
    225 
    226 static void my_sha256_final(unsigned char *digest, void *in)
    227 {
    228   my_sha256_ctx *ctx = (my_sha256_ctx *)in;
    229   unsigned long length = 0;
    230 
    231   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
    232   if(length == CURL_SHA256_DIGEST_LENGTH)
    233     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
    234 
    235   if(ctx->hHash)
    236     CryptDestroyHash(ctx->hHash);
    237 
    238   if(ctx->hCryptProv)
    239     CryptReleaseContext(ctx->hCryptProv, 0);
    240 }
    241 
    242 #else
    243 
    244 /* When no other crypto library is available we use this code segment */
    245 
    246 /* This is based on SHA256 implementation in LibTomCrypt that was released into
    247  * public domain by Tom St Denis. */
    248 
    249 #define WPA_GET_BE32(a) ((((unsigned long)(a)[0]) << 24) | \
    250                          (((unsigned long)(a)[1]) << 16) | \
    251                          (((unsigned long)(a)[2]) <<  8) | \
    252                           ((unsigned long)(a)[3]))
    253 #define WPA_PUT_BE32(a, val)                                        \
    254 do {                                                                \
    255   (a)[0] = (unsigned char)((((unsigned long) (val)) >> 24) & 0xff); \
    256   (a)[1] = (unsigned char)((((unsigned long) (val)) >> 16) & 0xff); \
    257   (a)[2] = (unsigned char)((((unsigned long) (val)) >> 8) & 0xff);  \
    258   (a)[3] = (unsigned char)(((unsigned long) (val)) & 0xff);         \
    259 } while(0)
    260 
    261 #ifdef HAVE_LONGLONG
    262 #define WPA_PUT_BE64(a, val)                                    \
    263 do {                                                            \
    264   (a)[0] = (unsigned char)(((unsigned long long)(val)) >> 56);  \
    265   (a)[1] = (unsigned char)(((unsigned long long)(val)) >> 48);  \
    266   (a)[2] = (unsigned char)(((unsigned long long)(val)) >> 40);  \
    267   (a)[3] = (unsigned char)(((unsigned long long)(val)) >> 32);  \
    268   (a)[4] = (unsigned char)(((unsigned long long)(val)) >> 24);  \
    269   (a)[5] = (unsigned char)(((unsigned long long)(val)) >> 16);  \
    270   (a)[6] = (unsigned char)(((unsigned long long)(val)) >> 8);   \
    271   (a)[7] = (unsigned char)(((unsigned long long)(val)) & 0xff); \
    272 } while(0)
    273 #else
    274 #define WPA_PUT_BE64(a, val)                                  \
    275 do {                                                          \
    276   (a)[0] = (unsigned char)(((unsigned __int64)(val)) >> 56);  \
    277   (a)[1] = (unsigned char)(((unsigned __int64)(val)) >> 48);  \
    278   (a)[2] = (unsigned char)(((unsigned __int64)(val)) >> 40);  \
    279   (a)[3] = (unsigned char)(((unsigned __int64)(val)) >> 32);  \
    280   (a)[4] = (unsigned char)(((unsigned __int64)(val)) >> 24);  \
    281   (a)[5] = (unsigned char)(((unsigned __int64)(val)) >> 16);  \
    282   (a)[6] = (unsigned char)(((unsigned __int64)(val)) >> 8);   \
    283   (a)[7] = (unsigned char)(((unsigned __int64)(val)) & 0xff); \
    284 } while(0)
    285 #endif
    286 
    287 struct sha256_state {
    288 #ifdef HAVE_LONGLONG
    289   unsigned long long length;
    290 #else
    291   unsigned __int64 length;
    292 #endif
    293   unsigned long state[8], curlen;
    294   unsigned char buf[64];
    295 };
    296 typedef struct sha256_state my_sha256_ctx;
    297 
    298 /* The K array */
    299 static const unsigned long K[64] = {
    300   0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
    301   0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
    302   0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
    303   0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
    304   0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
    305   0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
    306   0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
    307   0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
    308   0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
    309   0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
    310   0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
    311   0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
    312   0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
    313 };
    314 
    315 /* Various logical functions */
    316 #define RORc(x, y) \
    317 (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
    318    ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
    319 #define Sha256_Ch(x,y,z)  (z ^ (x & (y ^ z)))
    320 #define Sha256_Maj(x,y,z) (((x | y) & z) | (x & y))
    321 #define Sha256_S(x, n)    RORc((x), (n))
    322 #define Sha256_R(x, n)    (((x)&0xFFFFFFFFUL)>>(n))
    323 #define Sigma0(x)         (Sha256_S(x, 2) ^ Sha256_S(x, 13) ^ Sha256_S(x, 22))
    324 #define Sigma1(x)         (Sha256_S(x, 6) ^ Sha256_S(x, 11) ^ Sha256_S(x, 25))
    325 #define Gamma0(x)         (Sha256_S(x, 7) ^ Sha256_S(x, 18) ^ Sha256_R(x, 3))
    326 #define Gamma1(x)         (Sha256_S(x, 17) ^ Sha256_S(x, 19) ^ Sha256_R(x, 10))
    327 
    328 /* Compress 512-bits */
    329 static int sha256_compress(struct sha256_state *md,
    330                            const unsigned char *buf)
    331 {
    332   unsigned long S[8], W[64];
    333   int i;
    334 
    335   /* Copy state into S */
    336   for(i = 0; i < 8; i++) {
    337     S[i] = md->state[i];
    338   }
    339   /* copy the state into 512-bits into W[0..15] */
    340   for(i = 0; i < 16; i++)
    341     W[i] = WPA_GET_BE32(buf + (4 * i));
    342   /* fill W[16..63] */
    343   for(i = 16; i < 64; i++) {
    344     W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
    345       W[i - 16];
    346   }
    347 
    348   /* Compress */
    349 #define RND(a,b,c,d,e,f,g,h,i)                                           \
    350   do {                                                                   \
    351     unsigned long t0 = h + Sigma1(e) + Sha256_Ch(e, f, g) + K[i] + W[i]; \
    352     unsigned long t1 = Sigma0(a) + Sha256_Maj(a, b, c);                  \
    353     d += t0;                                                             \
    354     h = t0 + t1;                                                         \
    355   } while(0)
    356 
    357   for(i = 0; i < 64; ++i) {
    358     unsigned long t;
    359     RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
    360     t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
    361     S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
    362   }
    363 
    364   /* Feedback */
    365   for(i = 0; i < 8; i++) {
    366     md->state[i] = md->state[i] + S[i];
    367   }
    368 
    369   return 0;
    370 }
    371 
    372 /* Initialize the hash state */
    373 static CURLcode my_sha256_init(void *in)
    374 {
    375   struct sha256_state *md = (struct sha256_state *)in;
    376   md->curlen = 0;
    377   md->length = 0;
    378   md->state[0] = 0x6A09E667UL;
    379   md->state[1] = 0xBB67AE85UL;
    380   md->state[2] = 0x3C6EF372UL;
    381   md->state[3] = 0xA54FF53AUL;
    382   md->state[4] = 0x510E527FUL;
    383   md->state[5] = 0x9B05688CUL;
    384   md->state[6] = 0x1F83D9ABUL;
    385   md->state[7] = 0x5BE0CD19UL;
    386 
    387   return CURLE_OK;
    388 }
    389 
    390 /*
    391    Process a block of memory though the hash
    392    @param md     The hash state
    393    @param in     The data to hash
    394    @param inlen  The length of the data (octets)
    395 */
    396 static void my_sha256_update(void *ctx,
    397                              const unsigned char *in,
    398                              unsigned int len)
    399 {
    400   unsigned long inlen = len;
    401   unsigned long n;
    402   struct sha256_state *md = (struct sha256_state *)ctx;
    403 #define CURL_SHA256_BLOCK_SIZE 64
    404   if(md->curlen > sizeof(md->buf))
    405     return;
    406   while(inlen > 0) {
    407     if(md->curlen == 0 && inlen >= CURL_SHA256_BLOCK_SIZE) {
    408       if(sha256_compress(md, in) < 0)
    409         return;
    410       md->length += CURL_SHA256_BLOCK_SIZE * 8;
    411       in += CURL_SHA256_BLOCK_SIZE;
    412       inlen -= CURL_SHA256_BLOCK_SIZE;
    413     }
    414     else {
    415       n = CURLMIN(inlen, (CURL_SHA256_BLOCK_SIZE - md->curlen));
    416       memcpy(md->buf + md->curlen, in, n);
    417       md->curlen += n;
    418       in += n;
    419       inlen -= n;
    420       if(md->curlen == CURL_SHA256_BLOCK_SIZE) {
    421         if(sha256_compress(md, md->buf) < 0)
    422           return;
    423         md->length += 8 * CURL_SHA256_BLOCK_SIZE;
    424         md->curlen = 0;
    425       }
    426     }
    427   }
    428 }
    429 
    430 /*
    431    Terminate the hash to get the digest
    432    @param md  The hash state
    433    @param out [out] The destination of the hash (32 bytes)
    434    @return 0 if successful
    435 */
    436 static void my_sha256_final(unsigned char *out, void *ctx)
    437 {
    438   struct sha256_state *md = ctx;
    439   int i;
    440 
    441   if(md->curlen >= sizeof(md->buf))
    442     return;
    443 
    444   /* Increase the length of the message */
    445   md->length += md->curlen * 8;
    446 
    447   /* Append the '1' bit */
    448   md->buf[md->curlen++] = (unsigned char)0x80;
    449 
    450   /* If the length is currently above 56 bytes we append zeros
    451    * then compress. Then we can fall back to padding zeros and length
    452    * encoding like normal.
    453    */
    454   if(md->curlen > 56) {
    455     while(md->curlen < 64) {
    456       md->buf[md->curlen++] = (unsigned char)0;
    457     }
    458     sha256_compress(md, md->buf);
    459     md->curlen = 0;
    460   }
    461 
    462   /* Pad up to 56 bytes of zeroes */
    463   while(md->curlen < 56) {
    464     md->buf[md->curlen++] = (unsigned char)0;
    465   }
    466 
    467   /* Store length */
    468   WPA_PUT_BE64(md->buf + 56, md->length);
    469   sha256_compress(md, md->buf);
    470 
    471   /* Copy output */
    472   for(i = 0; i < 8; i++)
    473     WPA_PUT_BE32(out + (4 * i), md->state[i]);
    474 }
    475 
    476 #endif /* CRYPTO LIBS */
    477 
    478 /*
    479  * Curl_sha256it()
    480  *
    481  * Generates a SHA256 hash for the given input data.
    482  *
    483  * Parameters:
    484  *
    485  * output [in/out] - The output buffer.
    486  * input  [in]     - The input data.
    487  * length [in]     - The input length.
    488  *
    489  * Returns CURLE_OK on success.
    490  */
    491 CURLcode Curl_sha256it(unsigned char *output, const unsigned char *input,
    492                        const size_t length)
    493 {
    494   CURLcode result;
    495   my_sha256_ctx ctx;
    496 
    497   result = my_sha256_init(&ctx);
    498   if(!result) {
    499     my_sha256_update(&ctx, input, curlx_uztoui(length));
    500     my_sha256_final(output, &ctx);
    501   }
    502   return result;
    503 }
    504 
    505 
    506 const struct HMAC_params Curl_HMAC_SHA256 = {
    507   my_sha256_init,        /* Hash initialization function. */
    508   my_sha256_update,      /* Hash update function. */
    509   my_sha256_final,       /* Hash computation end function. */
    510   sizeof(my_sha256_ctx), /* Size of hash context structure. */
    511   64,                    /* Maximum key length. */
    512   32                     /* Result size. */
    513 };
    514 
    515 #endif /* AWS, DIGEST, or libssh2 */