]> git.sesse.net Git - bcachefs-tools-debian/blob - crypto.c
Encryption support
[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 bcache_disk_key *disk_key,
60                       struct bcache_key *key)
61 {
62         int ret;
63
64         ret = crypto_stream_chacha20_xor((void *) disk_key,
65                                          (void *) disk_key, sizeof(*disk_key),
66                                          (void *) &bch_master_key_nonce,
67                                          (void *) key);
68         if (ret)
69                 die("chacha20 error: %i", ret);
70 }
71
72 void disk_key_init(struct bcache_disk_key *disk_key)
73 {
74         ssize_t ret;
75
76         memcpy(&disk_key->header, bch_key_header, sizeof(bch_key_header));
77 #if 0
78         ret = getrandom(disk_key->key, sizeof(disk_key->key), GRND_RANDOM);
79         if (ret != sizeof(disk_key->key))
80                 die("error getting random bytes for key");
81 #else
82         int fd = open("/dev/random", O_RDONLY|O_NONBLOCK);
83         if (fd < 0)
84                 die("error opening /dev/random");
85
86         size_t n = 0;
87         struct timespec start;
88         bool printed = false;
89
90         clock_gettime(CLOCK_MONOTONIC, &start);
91
92         while (n < sizeof(disk_key->key)) {
93                 struct timeval timeout = { 1, 0 };
94                 fd_set set;
95
96                 FD_ZERO(&set);
97                 FD_SET(fd, &set);
98
99                 if (select(fd + 1, &set, NULL, NULL, &timeout) < 0)
100                         die("select error");
101
102                 ret = read(fd,
103                            (void *) disk_key->key + n,
104                            sizeof(disk_key->key) - n);
105                 if (ret == -1 && errno != EINTR && errno != EAGAIN)
106                         die("error reading from /dev/random");
107                 if (ret > 0)
108                         n += ret;
109
110                 struct timespec now;
111                 clock_gettime(CLOCK_MONOTONIC, &now);
112
113                 now.tv_sec      -= start.tv_sec;
114                 now.tv_nsec     -= start.tv_nsec;
115
116                 while (now.tv_nsec < 0) {
117                         long nsec_per_sec = 1000 * 1000 * 1000;
118                         long sec = now.tv_nsec / nsec_per_sec - 1;
119                         now.tv_nsec     -= sec * nsec_per_sec;
120                         now.tv_sec      += sec;
121                 }
122
123                 if (!printed && now.tv_sec >= 3) {
124                         printf("Reading from /dev/random is taking a long time...\n)");
125                         printed = true;
126                 }
127         }
128         close(fd);
129 #endif
130 }