]> git.sesse.net Git - bcachefs-tools-debian/blob - c_src/crypto.c
Disable pristine-tar option in gbp.conf, since there is no pristine-tar branch.
[bcachefs-tools-debian] / c_src / 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 <keyutils.h>
14 #include <linux/random.h>
15 #include <sodium/crypto_pwhash_scryptsalsa208sha256.h>
16 #include <uuid/uuid.h>
17
18 #include "libbcachefs/checksum.h"
19 #include "crypto.h"
20
21 char *read_passphrase(const char *prompt)
22 {
23         char *buf = NULL;
24         size_t buflen = 0;
25         ssize_t len;
26
27         if (isatty(STDIN_FILENO)) {
28                 struct termios old, new;
29
30                 fprintf(stderr, "%s", prompt);
31                 fflush(stderr);
32
33                 if (tcgetattr(STDIN_FILENO, &old))
34                         die("error getting terminal attrs");
35
36                 new = old;
37                 new.c_lflag &= ~ECHO;
38                 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &new))
39                         die("error setting terminal attrs");
40
41                 len = getline(&buf, &buflen, stdin);
42
43                 tcsetattr(STDIN_FILENO, TCSAFLUSH, &old);
44                 fprintf(stderr, "\n");
45         } else {
46                 len = getline(&buf, &buflen, stdin);
47         }
48
49         if (len < 0)
50                 die("error reading passphrase");
51         if (len && buf[len - 1] == '\n')
52                 buf[len - 1] = '\0';
53
54         return buf;
55 }
56
57 char *read_passphrase_twice(const char *prompt)
58 {
59         char *pass = read_passphrase(prompt);
60
61         if (!isatty(STDIN_FILENO))
62                 return pass;
63
64         char *pass2 = read_passphrase("Enter same passphrase again: ");
65
66         if (strcmp(pass, pass2)) {
67                 memzero_explicit(pass, strlen(pass));
68                 memzero_explicit(pass2, strlen(pass2));
69                 die("Passphrases do not match");
70         }
71
72         memzero_explicit(pass2, strlen(pass2));
73         free(pass2);
74
75         return pass;
76 }
77
78 struct bch_key derive_passphrase(struct bch_sb_field_crypt *crypt,
79                                  const char *passphrase)
80 {
81         const unsigned char salt[] = "bcache";
82         struct bch_key key;
83         int ret;
84
85         switch (BCH_CRYPT_KDF_TYPE(crypt)) {
86         case BCH_KDF_SCRYPT:
87                 ret = crypto_pwhash_scryptsalsa208sha256_ll(
88                         (void *) passphrase, strlen(passphrase),
89                         salt, sizeof(salt),
90                         1ULL << BCH_KDF_SCRYPT_N(crypt),
91                         1ULL << BCH_KDF_SCRYPT_R(crypt),
92                         1ULL << BCH_KDF_SCRYPT_P(crypt),
93                         (void *) &key, sizeof(key));
94                 if (ret)
95                         die("scrypt error: %i", ret);
96                 break;
97         default:
98                 die("unknown kdf type %llu", BCH_CRYPT_KDF_TYPE(crypt));
99         }
100
101         return key;
102 }
103
104 bool bch2_sb_is_encrypted(struct bch_sb *sb)
105 {
106         struct bch_sb_field_crypt *crypt;
107
108         return (crypt = bch2_sb_field_get(sb, crypt)) &&
109                 bch2_key_is_encrypted(&crypt->key);
110 }
111
112 void bch2_passphrase_check(struct bch_sb *sb, const char *passphrase,
113                            struct bch_key *passphrase_key,
114                            struct bch_encrypted_key *sb_key)
115 {
116         struct bch_sb_field_crypt *crypt = bch2_sb_field_get(sb, crypt);
117         if (!crypt)
118                 die("filesystem is not encrypted");
119
120         *sb_key = crypt->key;
121
122         if (!bch2_key_is_encrypted(sb_key))
123                 die("filesystem does not have encryption key");
124
125         *passphrase_key = derive_passphrase(crypt, passphrase);
126
127         /* Check if the user supplied the correct passphrase: */
128         if (bch2_chacha_encrypt_key(passphrase_key, __bch2_sb_key_nonce(sb),
129                                     sb_key, sizeof(*sb_key)))
130                 die("error encrypting key");
131
132         if (bch2_key_is_encrypted(sb_key))
133                 die("incorrect passphrase");
134 }
135
136 void bch2_add_key(struct bch_sb *sb,
137                   const char *type,
138                   const char *keyring_str,
139                   const char *passphrase)
140 {
141         struct bch_key passphrase_key;
142         struct bch_encrypted_key sb_key;
143         int keyring;
144
145         if (!strcmp(keyring_str, "session"))
146                 keyring = KEY_SPEC_SESSION_KEYRING;
147         else if (!strcmp(keyring_str, "user"))
148                 keyring = KEY_SPEC_USER_KEYRING;
149         else if (!strcmp(keyring_str, "user_session"))
150                 keyring = KEY_SPEC_USER_SESSION_KEYRING;
151         else
152                 die("unknown keyring %s", keyring_str);
153
154         bch2_passphrase_check(sb, passphrase,
155                               &passphrase_key,
156                               &sb_key);
157
158         char uuid[40];
159         uuid_unparse_lower(sb->user_uuid.b, uuid);
160
161         char *description = mprintf("bcachefs:%s", uuid);
162
163         if (add_key(type,
164                     description,
165                     &passphrase_key, sizeof(passphrase_key),
166                     keyring) < 0)
167                 die("add_key error: %m");
168
169         memzero_explicit(description, strlen(description));
170         free(description);
171         memzero_explicit(&passphrase_key, sizeof(passphrase_key));
172         memzero_explicit(&sb_key, sizeof(sb_key));
173 }
174
175 void bch_sb_crypt_init(struct bch_sb *sb,
176                        struct bch_sb_field_crypt *crypt,
177                        const char *passphrase)
178 {
179         crypt->key.magic = BCH_KEY_MAGIC;
180         get_random_bytes(&crypt->key.key, sizeof(crypt->key.key));
181
182         if (passphrase) {
183
184                 SET_BCH_CRYPT_KDF_TYPE(crypt, BCH_KDF_SCRYPT);
185                 SET_BCH_KDF_SCRYPT_N(crypt, ilog2(16384));
186                 SET_BCH_KDF_SCRYPT_R(crypt, ilog2(8));
187                 SET_BCH_KDF_SCRYPT_P(crypt, ilog2(16));
188
189                 struct bch_key passphrase_key = derive_passphrase(crypt, passphrase);
190
191                 assert(!bch2_key_is_encrypted(&crypt->key));
192
193                 if (bch2_chacha_encrypt_key(&passphrase_key, __bch2_sb_key_nonce(sb),
194                                            &crypt->key, sizeof(crypt->key)))
195                         die("error encrypting key");
196
197                 assert(bch2_key_is_encrypted(&crypt->key));
198
199                 memzero_explicit(&passphrase_key, sizeof(passphrase_key));
200         }
201 }