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