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 : }
|