LCOV - code coverage report
Current view: top level - src - scram.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 58 0.0 %
Date: 2024-02-24 14:12:49 Functions: 0 5 0.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 1.14