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

          Line data    Source code
       1             : #include "passgen/random.h"
       2             : #include "passgen/assert.h"
       3             : #include "passgen/config.h"
       4             : #include "passgen/util/endian.h"
       5             : #include <stdlib.h>
       6             : #include <string.h>
       7             : 
       8          29 : static bool _strprefix(const char *prefix, const char *string) {
       9          29 :     size_t prefix_len = strlen(prefix);
      10         108 :     for(size_t i = 0; i < prefix_len; i++) {
      11          97 :         if(prefix[i] != string[i]) {
      12          18 :             return false;
      13             :         }
      14             :     }
      15          11 :     return true;
      16             : }
      17             : 
      18       58248 : void passgen_random_reload(passgen_random *random) {
      19       58248 :     passgen_assert(random != NULL);
      20             : 
      21             :     // read random data.
      22             :     size_t bytes =
      23       58248 :         random->read(random->context, &random->buffer, sizeof(random->buffer));
      24             :     (void) bytes;
      25             : 
      26             :     // make sure we've read enough.
      27       58248 :     passgen_assert(bytes == sizeof(random->buffer));
      28             : 
      29             :     // reset position in ring buffer.
      30       58248 :     random->pos = 0;
      31       58248 : }
      32             : 
      33    11753678 : void passgen_random_read(passgen_random *random, void *data, size_t bytes) {
      34    11753678 :     if(bytes <= sizeof(random->buffer)) {
      35             :         // maximum bytes we can have right now
      36    11753677 :         size_t left = sizeof(random->buffer) - random->pos;
      37             : 
      38    11753677 :         if(bytes < left) {
      39             :             // if we have enough, just copy it over.
      40    11695514 :             memcpy(data, &random->buffer[random->pos], bytes);
      41    11695514 :             random->pos += bytes;
      42             :         } else {
      43             :             // if we don't have enough, copy over whatever we have and
      44             :             // reload.
      45       58163 :             memcpy(data, random->buffer, left);
      46       58163 :             passgen_random_reload(random);
      47             : 
      48             :             // if there's more to be read, recurse.
      49       58163 :             if(bytes != left) {
      50           3 :                 passgen_random_read(random, data + left, bytes - left);
      51             :             }
      52             :         }
      53             :     } else {
      54           1 :         size_t ret = random->read(random->context, data, bytes);
      55           1 :         if(ret != bytes) {
      56           0 :             fprintf(
      57             :                 stderr,
      58             :                 "Error reading from randomness source: trying to read %zu "
      59             :                 "bytes but got %zu",
      60             :                 bytes,
      61             :                 ret);
      62           0 :             abort();
      63             :         }
      64             :     }
      65    11753678 : }
      66             : 
      67             : passgen_random *
      68          17 : passgen_random_open_parse(passgen_random *random, const char *desc) {
      69          17 :     if(strcmp("zero", desc) == 0) {
      70           2 :         return passgen_random_zero_open(random);
      71             :     }
      72             : 
      73             :     // check if we should read randomness from this file
      74          15 :     if(_strprefix("file:", desc)) {
      75           5 :         return passgen_random_path_open(random, &desc[5]);
      76             :     }
      77             : 
      78             :     // check if we should use the xorshift PRNG with the given seed
      79          10 :     if(_strprefix("xorshift:", desc)) {
      80           6 :         const char *seed_str = &desc[9];
      81           6 :         if(*seed_str == 0) {
      82           2 :             return NULL;
      83             :         }
      84             : 
      85           4 :         uint64_t seed = atoll(seed_str);
      86           4 :         if(seed == 0) {
      87           2 :             return NULL;
      88             :         }
      89             : 
      90           2 :         return passgen_random_xorshift_open(random, seed);
      91             :     }
      92             : 
      93             :     // check if we should use the system default
      94           4 :     if(0 == strcmp(desc, "system")) {
      95           2 :         return passgen_random_system_open(random);
      96             :     }
      97             : 
      98             : #ifdef PASSGEN_MONOCYPHER
      99             :     // use chacha20 with raw key and IV
     100           2 :     if(_strprefix("chacha20:", desc)) {
     101           0 :         const char *key_ptr = &desc[9];
     102           0 :         const char *key_end = strchr(key_ptr, ':');
     103           0 :         if(!key_end) {
     104           0 :             key_end = key_ptr + strlen(key_ptr);
     105             :         }
     106           0 :         char key[32] = {0};
     107           0 :         memcpy(key, key_ptr, key_end - key_ptr);
     108             : 
     109           0 :         char iv[] = "passgen";
     110             : 
     111           0 :         if(*key_end == ':') {
     112           0 :             const char *iv_ptr = key_end + 1;
     113           0 :             size_t iv_len = strlen(iv_ptr);
     114           0 :             iv_len = iv_len > 8 ? 8 : iv_len;
     115           0 :             memset(iv, 0, 8);
     116           0 :             memcpy(iv, iv_ptr, iv_len);
     117             :         }
     118             : 
     119           0 :         return passgen_random_chacha20_open(random, key, iv);
     120             :     }
     121             : 
     122             :     // use chacha20 with raw key and IV
     123           2 :     if(_strprefix("chacha20-argon2:", desc)) {
     124           0 :         char master_pass[128] = {0};
     125           0 :         char domain[128] = {0};
     126           0 :         char token[128] = {0};
     127             : 
     128           0 :         const char *start = &desc[16];
     129           0 :         const char *end = &desc[16];
     130             : 
     131             : #define PARSE_STRING(name) \
     132             :         if(*end == ':') end++; \
     133             :         if(*end) { \
     134             :             start = end; \
     135             :             end = strchr(start, ':'); \
     136             :             if(!end) { \
     137             :                 end = start + strlen(start); \
     138             :             } \
     139             :             memcpy(name, start, end - start); \
     140             :         }
     141             : 
     142           0 :         PARSE_STRING(master_pass)
     143           0 :         PARSE_STRING(domain)
     144           0 :         PARSE_STRING(token)
     145             : 
     146           0 :         return passgen_random_chacha20_argon2_open(random, master_pass, domain, token, NULL);
     147             :     }
     148             : #endif
     149             : 
     150           2 :     return NULL;
     151             : }
     152             : 
     153          68 : passgen_random *passgen_random_open(passgen_random *random, const char *desc) {
     154          68 :     if(desc) {
     155          17 :         return passgen_random_open_parse(random, desc);
     156             :     }
     157             : 
     158          51 :     return passgen_random_system_open(random);
     159             : }
     160             : 
     161          47 : void passgen_random_close(passgen_random *random) {
     162             :     // close randomness source
     163          47 :     random->close(random->context);
     164             : 
     165             :     // reset members to prevent accidental use-after-free
     166          47 :     PASSGEN_CLEAR(random);
     167          47 : }
     168             : 
     169          12 : void passgen_random_free(passgen_random *random) {
     170          12 :     passgen_random_close(random);
     171          12 :     free(random);
     172          12 : }
     173             : 
     174      643301 : inline uint8_t passgen_random_u8(passgen_random *random) {
     175             :     uint8_t data;
     176      643301 :     passgen_random_read(random, &data, sizeof(data));
     177      643301 :     return data;
     178             : }
     179             : 
     180     2605253 : inline uint16_t passgen_random_u16(passgen_random *random) {
     181             :     uint16_t data;
     182     2605253 :     passgen_random_read(random, &data, sizeof(data));
     183     2605253 :     data = htole16(data);
     184     2605253 :     return data;
     185             : }
     186             : 
     187     3577341 : inline uint32_t passgen_random_u32(passgen_random *random) {
     188             :     uint32_t data;
     189     3577341 :     passgen_random_read(random, &data, sizeof(data));
     190     3577341 :     data = htole32(data);
     191     3577341 :     return data;
     192             : }
     193             : 
     194     4925736 : inline uint64_t passgen_random_u64(passgen_random *random) {
     195             :     uint64_t data;
     196     4925736 :     passgen_random_read(random, &data, sizeof(data));
     197     4925736 :     data = htole64(data);
     198     4925736 :     return data;
     199             : }
     200             : 
     201           6 : inline bool passgen_random_bool(passgen_random *random) {
     202             :     uint8_t data;
     203           6 :     passgen_random_read(random, &data, sizeof(data));
     204           6 :     return (data & 128) == 0;
     205             : }
     206             : 
     207      458343 : inline uint8_t passgen_random_u8_max(passgen_random *random, uint8_t max) {
     208      458343 :     passgen_assert(max);
     209             : 
     210      458343 :     uint8_t mask = max;
     211      458343 :     mask |= mask >> 4;
     212      458343 :     mask |= mask >> 2;
     213      458343 :     mask |= mask >> 1;
     214             : 
     215             :     uint8_t num;
     216             :     do {
     217      640983 :         num = passgen_random_u8(random) & mask;
     218      640983 :     } while(num >= max);
     219             : 
     220      458343 :     return num;
     221             : }
     222             : 
     223     1321984 : inline uint16_t passgen_random_u16_max(passgen_random *random, uint16_t max) {
     224     1321984 :     passgen_assert(max);
     225             : 
     226     1321984 :     uint16_t mask = max;
     227     1321984 :     mask |= mask >> 8;
     228     1321984 :     mask |= mask >> 4;
     229     1321984 :     mask |= mask >> 2;
     230     1321984 :     mask |= mask >> 1;
     231             : 
     232             :     uint16_t num;
     233             : 
     234             :     do {
     235     1654575 :         num = passgen_random_u16(random) & mask;
     236     1654575 :     } while(num >= max);
     237             : 
     238     1321984 :     return num;
     239             : }
     240             : 
     241     1376512 : inline uint32_t passgen_random_u32_max(passgen_random *random, uint32_t max) {
     242     1376512 :     passgen_assert(max);
     243             : 
     244     1376512 :     uint32_t mask = max;
     245     1376512 :     mask |= mask >> 16;
     246     1376512 :     mask |= mask >> 8;
     247     1376512 :     mask |= mask >> 4;
     248     1376512 :     mask |= mask >> 2;
     249     1376512 :     mask |= mask >> 1;
     250             : 
     251             :     uint32_t num;
     252             : 
     253             :     do {
     254     1831542 :         num = passgen_random_u32(random) & mask;
     255     1831542 :     } while(num >= max);
     256             : 
     257     1376512 :     return num;
     258             : }
     259             : 
     260     2256516 : inline uint64_t passgen_random_u64_max(passgen_random *random, uint64_t max) {
     261     2256516 :     passgen_assert(max);
     262             : 
     263     2256516 :     uint64_t mask = max;
     264     2256516 :     mask |= mask >> 32;
     265     2256516 :     mask |= mask >> 16;
     266     2256516 :     mask |= mask >> 8;
     267     2256516 :     mask |= mask >> 4;
     268     2256516 :     mask |= mask >> 2;
     269     2256516 :     mask |= mask >> 1;
     270             : 
     271             :     uint64_t num;
     272             : 
     273             :     do {
     274     2996023 :         num = passgen_random_u64(random) & mask;
     275     2996023 :     } while(num >= max);
     276             : 
     277     2256516 :     return num;
     278             : }

Generated by: LCOV version 1.14