LCOV - code coverage report
Current view: top level - src - scram.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 58 0
Test Date: 2024-08-20 10:03:45 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /* SPDX-License-Identifier: MIT OR GPL-3.0-only */
       2              : /* scram.c
       3              :  * strophe XMPP client library
       4              :  *
       5              :  * SCRAM-SHA1 helper functions according to RFC5802
       6              :  * HMAC-SHA1 implementation according to RFC2104
       7              :  *
       8              :  * Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com>
       9              :  *
      10              :  *  This software is provided AS-IS with no warranty, either express
      11              :  *  or implied.
      12              :  *
      13              :  *  This program is dual licensed under the MIT or GPLv3 licenses.
      14              :  */
      15              : 
      16              : /** @file
      17              :  *  SCRAM-SHA1 helper functions.
      18              :  */
      19              : 
      20              : #include <assert.h>
      21              : #include <string.h>
      22              : 
      23              : #include "common.h"
      24              : #include "sha1.h"
      25              : #include "sha256.h"
      26              : #include "sha512.h"
      27              : #include "ostypes.h"
      28              : 
      29              : #include "scram.h"
      30              : 
      31              : #define HMAC_BLOCK_SIZE_MAX 128
      32              : 
      33              : static const uint8_t ipad = 0x36;
      34              : static const uint8_t opad = 0x5C;
      35              : 
      36              : const struct hash_alg scram_sha1 = {
      37              :     "SCRAM-SHA-1",
      38              :     SASL_MASK_SCRAMSHA1,
      39              :     SHA1_DIGEST_SIZE,
      40              :     (void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
      41              :     (void (*)(void *))crypto_SHA1_Init,
      42              :     (void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
      43              :     (void (*)(void *, uint8_t *))crypto_SHA1_Final};
      44              : 
      45              : const struct hash_alg scram_sha1_plus = {
      46              :     "SCRAM-SHA-1-PLUS",
      47              :     SASL_MASK_SCRAMSHA1_PLUS,
      48              :     SHA1_DIGEST_SIZE,
      49              :     (void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
      50              :     (void (*)(void *))crypto_SHA1_Init,
      51              :     (void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
      52              :     (void (*)(void *, uint8_t *))crypto_SHA1_Final};
      53              : 
      54              : const struct hash_alg scram_sha256 = {
      55              :     "SCRAM-SHA-256",
      56              :     SASL_MASK_SCRAMSHA256,
      57              :     SHA256_DIGEST_SIZE,
      58              :     (void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
      59              :     (void (*)(void *))sha256_init,
      60              :     (void (*)(void *, const uint8_t *, size_t))sha256_process,
      61              :     (void (*)(void *, uint8_t *))sha256_done};
      62              : 
      63              : const struct hash_alg scram_sha256_plus = {
      64              :     "SCRAM-SHA-256-PLUS",
      65              :     SASL_MASK_SCRAMSHA256_PLUS,
      66              :     SHA256_DIGEST_SIZE,
      67              :     (void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
      68              :     (void (*)(void *))sha256_init,
      69              :     (void (*)(void *, const uint8_t *, size_t))sha256_process,
      70              :     (void (*)(void *, uint8_t *))sha256_done};
      71              : 
      72              : const struct hash_alg scram_sha512 = {
      73              :     "SCRAM-SHA-512",
      74              :     SASL_MASK_SCRAMSHA512,
      75              :     SHA512_DIGEST_SIZE,
      76              :     (void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
      77              :     (void (*)(void *))sha512_init,
      78              :     (void (*)(void *, const uint8_t *, size_t))sha512_process,
      79              :     (void (*)(void *, uint8_t *))sha512_done};
      80              : 
      81              : /* The order of this list defines the order in which the SCRAM algorithms are
      82              :  * tried if the server supports them.
      83              :  * Their order is derived from
      84              :  * https://datatracker.ietf.org/doc/html/draft-ietf-kitten-password-storage
      85              :  */
      86              : const struct hash_alg *scram_algs[] = {
      87              :     /* *1 */
      88              :     &scram_sha256_plus,
      89              :     /* *1 */
      90              :     &scram_sha1_plus,
      91              :     /* *1 */
      92              :     &scram_sha512,
      93              :     /* *1 */
      94              :     &scram_sha256,
      95              :     /* *1 */
      96              :     &scram_sha1,
      97              : };
      98              : /* *1 - I want to use clang-format here, but by default it will put multiple
      99              :  * elements per line if there's no comment. Currently clang-format also doesn't
     100              :  * have an option to enforce it to behave like that, besides by putting comments
     101              :  * between each element (or I couldn't find a way to do it). In order to prevent
     102              :  * clang-format from re-formatting the array I added the comments above and
     103              :  * wrote this lengthy description.
     104              :  */
     105              : const size_t scram_algs_num = sizeof(scram_algs) / sizeof(scram_algs[0]);
     106              : 
     107              : union common_hash_ctx {
     108              :     SHA1_CTX sha1;
     109              :     sha256_context sha256;
     110              :     sha512_context sha512;
     111              : };
     112              : 
     113            0 : static void crypto_HMAC(const struct hash_alg *alg,
     114              :                         const uint8_t *key,
     115              :                         size_t key_len,
     116              :                         const uint8_t *text,
     117              :                         size_t len,
     118              :                         uint8_t *digest)
     119              : {
     120            0 :     uint8_t key_pad[HMAC_BLOCK_SIZE_MAX];
     121            0 :     uint8_t key_ipad[HMAC_BLOCK_SIZE_MAX];
     122            0 :     uint8_t key_opad[HMAC_BLOCK_SIZE_MAX];
     123            0 :     uint8_t sha_digest[SCRAM_DIGEST_SIZE];
     124            0 :     size_t blocksize;
     125            0 :     size_t i;
     126            0 :     union common_hash_ctx ctx;
     127              : 
     128            0 :     assert(alg->digest_size <= HMAC_BLOCK_SIZE_MAX);
     129            0 :     blocksize = alg->digest_size < 48 ? 64 : 128;
     130              : 
     131            0 :     memset(key_pad, 0, blocksize);
     132            0 :     if (key_len <= blocksize) {
     133            0 :         memcpy(key_pad, key, key_len);
     134              :     } else {
     135              :         /* according to RFC2104 */
     136            0 :         alg->hash(key, key_len, key_pad);
     137              :     }
     138              : 
     139            0 :     for (i = 0; i < blocksize; i++) {
     140            0 :         key_ipad[i] = key_pad[i] ^ ipad;
     141            0 :         key_opad[i] = key_pad[i] ^ opad;
     142              :     }
     143              : 
     144            0 :     alg->init((void *)&ctx);
     145            0 :     alg->update((void *)&ctx, key_ipad, blocksize);
     146            0 :     alg->update((void *)&ctx, text, len);
     147            0 :     alg->final((void *)&ctx, sha_digest);
     148              : 
     149            0 :     alg->init((void *)&ctx);
     150            0 :     alg->update((void *)&ctx, key_opad, blocksize);
     151            0 :     alg->update((void *)&ctx, sha_digest, alg->digest_size);
     152            0 :     alg->final((void *)&ctx, digest);
     153            0 : }
     154              : 
     155            0 : static void SCRAM_Hi(const struct hash_alg *alg,
     156              :                      const uint8_t *text,
     157              :                      size_t len,
     158              :                      const uint8_t *salt,
     159              :                      size_t salt_len,
     160              :                      uint32_t i,
     161              :                      uint8_t *digest)
     162              : {
     163            0 :     size_t k;
     164            0 :     uint32_t j;
     165            0 :     uint8_t tmp[128];
     166              : 
     167            0 :     static uint8_t int1[] = {0x0, 0x0, 0x0, 0x1};
     168              : 
     169              :     /* assume salt + INT(1) isn't longer than sizeof(tmp) */
     170            0 :     assert(salt_len <= sizeof(tmp) - sizeof(int1));
     171              : 
     172            0 :     memset(digest, 0, alg->digest_size);
     173            0 :     if (i == 0) {
     174            0 :         return;
     175              :     }
     176              : 
     177            0 :     memcpy(tmp, salt, salt_len);
     178            0 :     memcpy(&tmp[salt_len], int1, sizeof(int1));
     179              : 
     180              :     /* 'text' for Hi is a 'key' for HMAC */
     181            0 :     crypto_HMAC(alg, text, len, tmp, salt_len + sizeof(int1), digest);
     182            0 :     memcpy(tmp, digest, alg->digest_size);
     183              : 
     184            0 :     for (j = 1; j < i; j++) {
     185            0 :         crypto_HMAC(alg, text, len, tmp, alg->digest_size, tmp);
     186            0 :         for (k = 0; k < alg->digest_size; k++) {
     187            0 :             digest[k] ^= tmp[k];
     188              :         }
     189              :     }
     190              : }
     191              : 
     192            0 : void SCRAM_ClientKey(const struct hash_alg *alg,
     193              :                      const uint8_t *password,
     194              :                      size_t len,
     195              :                      const uint8_t *salt,
     196              :                      size_t salt_len,
     197              :                      uint32_t i,
     198              :                      uint8_t *key)
     199              : {
     200            0 :     uint8_t salted[SCRAM_DIGEST_SIZE];
     201              : 
     202              :     /* XXX: Normalize(password) is omitted */
     203              : 
     204            0 :     SCRAM_Hi(alg, password, len, salt, salt_len, i, salted);
     205            0 :     crypto_HMAC(alg, salted, alg->digest_size, (uint8_t *)"Client Key",
     206              :                 strlen("Client Key"), key);
     207            0 : }
     208              : 
     209            0 : void SCRAM_ClientSignature(const struct hash_alg *alg,
     210              :                            const uint8_t *ClientKey,
     211              :                            const uint8_t *AuthMessage,
     212              :                            size_t len,
     213              :                            uint8_t *sign)
     214              : {
     215            0 :     uint8_t stored[SCRAM_DIGEST_SIZE];
     216              : 
     217            0 :     alg->hash(ClientKey, alg->digest_size, stored);
     218            0 :     crypto_HMAC(alg, stored, alg->digest_size, AuthMessage, len, sign);
     219            0 : }
     220              : 
     221            0 : void SCRAM_ClientProof(const struct hash_alg *alg,
     222              :                        const uint8_t *ClientKey,
     223              :                        const uint8_t *ClientSignature,
     224              :                        uint8_t *proof)
     225              : {
     226            0 :     size_t i;
     227            0 :     for (i = 0; i < alg->digest_size; i++) {
     228            0 :         proof[i] = ClientKey[i] ^ ClientSignature[i];
     229              :     }
     230            0 : }
        

Generated by: LCOV version 2.0-1