LCOV - code coverage report
Current view: top level - src/random - deterministic.c (source / functions) Hit Total Coverage
Test: passgen-test.info Lines: 69 73 94.5 %
Date: 2024-09-13 06:04:46 Functions: 6 6 100.0 %

          Line data    Source code
       1             : #include "passgen/assert.h"
       2             : #include "passgen/config.h"
       3             : #include "passgen/monocypher.h"
       4             : #include "passgen/random.h"
       5             : #include <stdlib.h>
       6             : #include <string.h>
       7             : 
       8             : #define CHACHA20_BLOCK_SIZE 64
       9             : #define CHACHA20_KEY_SIZE   32
      10             : #define MIN(x, y)           (x) < (y) ? (x) : (y)
      11             : 
      12             : typedef struct {
      13             :     uint8_t key[CHACHA20_KEY_SIZE];
      14             :     uint8_t iv[8];
      15             :     size_t offset;
      16             : } passgen_random_chacha20_context;
      17             : 
      18             : static size_t
      19           1 : passgen_random_chacha20_read_short(void *context_raw, void *dest, size_t size) {
      20           1 :     passgen_assert(size < CHACHA20_BLOCK_SIZE);
      21           1 :     passgen_random_chacha20_context *context = context_raw;
      22             :     uint8_t block[CHACHA20_BLOCK_SIZE];
      23           1 :     passgen_chacha20_djb(
      24             :         block,
      25             :         NULL,
      26             :         CHACHA20_BLOCK_SIZE,
      27           1 :         context->key,
      28           1 :         context->iv,
      29           1 :         context->offset / CHACHA20_BLOCK_SIZE);
      30             : 
      31           1 :     memcpy(dest, &block[context->offset % CHACHA20_BLOCK_SIZE], size);
      32           1 :     context->offset += size;
      33           1 :     return size;
      34             : }
      35             : 
      36             : static size_t
      37           6 : passgen_random_chacha20_read(void *context_raw, void *dest, size_t size) {
      38           6 :     passgen_random_chacha20_context *context = context_raw;
      39           6 :     memset(dest, 0, size);
      40             : 
      41           6 :     size_t offset_bytes = context->offset % CHACHA20_BLOCK_SIZE;
      42           6 :     size_t written = 0;
      43           6 :     if(offset_bytes) {
      44           1 :         size_t short_bytes = MIN(CHACHA20_BLOCK_SIZE - offset_bytes, size);
      45           1 :         passgen_random_chacha20_read_short(context_raw, dest, short_bytes);
      46           1 :         written += short_bytes;
      47             :     }
      48             : 
      49           6 :     size_t remaining = size - written;
      50           6 :     passgen_chacha20_djb(
      51           6 :         dest + written,
      52             :         NULL,
      53             :         remaining,
      54           6 :         context->key,
      55           6 :         context->iv,
      56           6 :         context->offset / CHACHA20_BLOCK_SIZE);
      57           6 :     context->offset += remaining;
      58             : 
      59           6 :     return size;
      60             : }
      61             : 
      62           4 : static void passgen_random_chacha20_close(void *context_raw) {
      63           4 :     passgen_random_chacha20_context *context = context_raw;
      64           4 :     PASSGEN_CLEAR(context);
      65           4 :     free(context);
      66           4 : }
      67             : 
      68           4 : passgen_random *passgen_random_chacha20_open(
      69             :     passgen_random *random,
      70             :     const uint8_t key[CHACHA20_KEY_SIZE],
      71             :     const uint8_t iv[8]) {
      72           4 :     if(!random) {
      73           0 :         random = malloc(sizeof(passgen_random));
      74           0 :         if(!random) return NULL;
      75             :     }
      76             : 
      77             :     passgen_random_chacha20_context *data =
      78           4 :         malloc(sizeof(passgen_random_chacha20_context));
      79           4 :     if(!data) {
      80           0 :         return NULL;
      81             :     }
      82             : 
      83           4 :     memset(data, 0, sizeof(*data));
      84           4 :     memcpy(data->key, key, CHACHA20_KEY_SIZE);
      85           4 :     memcpy(data->iv, iv, 8);
      86           4 :     data->offset = 0;
      87             : 
      88           4 :     random->context = data;
      89           4 :     random->close = passgen_random_chacha20_close;
      90           4 :     random->read = passgen_random_chacha20_read;
      91             : 
      92           4 :     passgen_random_reload(random);
      93             : 
      94           4 :     return random;
      95             : }
      96             : 
      97           2 : void passgen_random_chacha20_seek(passgen_random *random, size_t position) {
      98             :     // make sure this really is a chacha20 randomness source
      99           2 :     passgen_assert(random->read == passgen_random_chacha20_read);
     100           2 :     passgen_assert(random->close == passgen_random_chacha20_close);
     101             : 
     102             :     // reset offset
     103           2 :     passgen_random_chacha20_context *data = random->context;
     104           2 :     data->offset = position;
     105             : 
     106             :     // reload random data buffer
     107           2 :     passgen_random_reload(random);
     108           2 : }
     109             : 
     110             : const passgen_argon2_config PASSGEN_ARGON2_CONFIG_DEFAULT = {
     111             :     .algorithm = CRYPTO_ARGON2_ID,
     112             :     .nb_blocks = 8,
     113             :     .nb_passes = 8,
     114             :     .nb_lanes = 1,
     115             : };
     116             : 
     117           1 : passgen_random *passgen_random_chacha20_argon2_open(
     118             :     passgen_random *random,
     119             :     const uint8_t *passphrase,
     120             :     const uint8_t *domain,
     121             :     const uint8_t *token,
     122           1 :     passgen_argon2_config *config_ptr) {
     123           1 :     const uint8_t *salt = "passgen";
     124           1 :     passgen_argon2_inputs inputs = {
     125             :         .pass = passphrase,
     126           1 :         .pass_size = strlen(passphrase),
     127             :         .salt = salt,
     128           1 :         .salt_size = strlen(salt),
     129             :     };
     130             : 
     131           2 :     passgen_argon2_extras extras = {
     132             :         .key = domain,
     133           1 :         .key_size = domain ? strlen(domain) : 0,
     134             :         .ad = token,
     135           1 :         .ad_size = token ? strlen(token) : 0,
     136             :     };
     137             : 
     138           1 :     passgen_argon2_config config = PASSGEN_ARGON2_CONFIG_DEFAULT;
     139           1 :     if(config_ptr) {
     140           0 :         config = *config_ptr;
     141             :     }
     142             : 
     143           1 :     size_t hash_size = CHACHA20_KEY_SIZE;
     144           1 :     uint8_t hash[hash_size];
     145           1 :     void *work_area = malloc(1024 * config.nb_blocks);
     146           1 :     passgen_argon2(&hash[0], hash_size, work_area, config, inputs, extras);
     147           1 :     free(work_area);
     148             : 
     149           1 :     return passgen_random_chacha20_open(random, hash, "passgen");
     150             : }

Generated by: LCOV version 1.14