]> git.sesse.net Git - bcachefs-tools-debian/blob - crypto.c
master key nonce
[bcachefs-tools-debian] / crypto.c
1 #include <errno.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <termios.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <time.h>
11 #include <unistd.h>
12
13 #include <linux/random.h>
14 #include <libscrypt.h>
15 #include <sodium/crypto_stream_chacha20.h>
16
17 #include "crypto.h"
18
19 char *read_passphrase(const char *prompt)
20 {
21         struct termios old, new;
22         char *buf = NULL;
23         size_t buflen = 0;
24         ssize_t ret;
25
26         fprintf(stderr, "%s", prompt);
27         fflush(stderr);
28
29         if (tcgetattr(fileno(stdin), &old))
30                 die("error getting terminal attrs");
31
32         new = old;
33         new.c_lflag &= ~ECHO;
34         if (tcsetattr(fileno(stdin), TCSAFLUSH, &new))
35                 die("error setting terminal attrs");
36
37         ret = getline(&buf, &buflen, stdin);
38         if (ret <= 0)
39                 die("error reading passphrase");
40
41         tcsetattr(fileno(stdin), TCSAFLUSH, &old);
42         fprintf(stderr, "\n");
43         return buf;
44 }
45
46 void derive_passphrase(struct bcache_key *key, const char *passphrase)
47 {
48         const unsigned char salt[] = "bcache";
49         int ret;
50
51         ret = libscrypt_scrypt((void *) passphrase, strlen(passphrase),
52                                salt, sizeof(salt),
53                                SCRYPT_N, SCRYPT_r, SCRYPT_p,
54                                (void *) key, sizeof(*key));
55         if (ret)
56                 die("scrypt error: %i", ret);
57 }
58
59 void disk_key_encrypt(struct cache_sb *sb,
60                       struct bcache_disk_key *disk_key,
61                       struct bcache_key *key)
62 {
63         __le32 nonce[2];
64         int ret;
65
66         memcpy(nonce, &sb->set_magic, sizeof(sb->set_magic));
67
68         ret = crypto_stream_chacha20_xor((void *) disk_key,
69                                          (void *) disk_key, sizeof(*disk_key),
70                                          (void *) nonce,
71                                          (void *) key);
72         if (ret)
73                 die("chacha20 error: %i", ret);
74 }
75
76 void disk_key_init(struct bcache_disk_key *disk_key)
77 {
78         ssize_t ret;
79
80         memcpy(&disk_key->header, bch_key_header, sizeof(bch_key_header));
81 #if 0
82         ret = getrandom(disk_key->key, sizeof(disk_key->key), GRND_RANDOM);
83         if (ret != sizeof(disk_key->key))
84                 die("error getting random bytes for key");
85 #else
86         int fd = open("/dev/random", O_RDONLY|O_NONBLOCK);
87         if (fd < 0)
88                 die("error opening /dev/random");
89
90         size_t n = 0;
91         struct timespec start;
92         bool printed = false;
93
94         clock_gettime(CLOCK_MONOTONIC, &start);
95
96         while (n < sizeof(disk_key->key)) {
97                 struct timeval timeout = { 1, 0 };
98                 fd_set set;
99
100                 FD_ZERO(&set);
101                 FD_SET(fd, &set);
102
103                 if (select(fd + 1, &set, NULL, NULL, &timeout) < 0)
104                         die("select error");
105
106                 ret = read(fd,
107                            (void *) disk_key->key + n,
108                            sizeof(disk_key->key) - n);
109                 if (ret == -1 && errno != EINTR && errno != EAGAIN)
110                         die("error reading from /dev/random");
111                 if (ret > 0)
112                         n += ret;
113
114                 struct timespec now;
115                 clock_gettime(CLOCK_MONOTONIC, &now);
116
117                 now.tv_sec      -= start.tv_sec;
118                 now.tv_nsec     -= start.tv_nsec;
119
120                 while (now.tv_nsec < 0) {
121                         long nsec_per_sec = 1000 * 1000 * 1000;
122                         long sec = now.tv_nsec / nsec_per_sec - 1;
123                         now.tv_nsec     -= sec * nsec_per_sec;
124                         now.tv_sec      += sec;
125                 }
126
127                 if (!printed && now.tv_sec >= 3) {
128                         printf("Reading from /dev/random is taking a long time...\n)");
129                         printed = true;
130                 }
131         }
132         close(fd);
133 #endif
134 }