]> git.sesse.net Git - bcachefs-tools-debian/blob - crypto.c
Add upstream files
[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 <keyutils.h>
14 #include <linux/random.h>
15 #include <libscrypt.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 = libscrypt_scrypt((void *) passphrase, strlen(passphrase),
88                                        salt, sizeof(salt),
89                                        1ULL << BCH_KDF_SCRYPT_N(crypt),
90                                        1ULL << BCH_KDF_SCRYPT_R(crypt),
91                                        1ULL << BCH_KDF_SCRYPT_P(crypt),
92                                        (void *) &key, sizeof(key));
93                 if (ret)
94                         die("scrypt error: %i", ret);
95                 break;
96         default:
97                 die("unknown kdf type %llu", BCH_CRYPT_KDF_TYPE(crypt));
98         }
99
100         return key;
101 }
102
103 bool bch2_sb_is_encrypted(struct bch_sb *sb)
104 {
105         struct bch_sb_field_crypt *crypt;
106
107         return (crypt = bch2_sb_get_crypt(sb)) &&
108                 bch2_key_is_encrypted(&crypt->key);
109 }
110
111 void bch2_passphrase_check(struct bch_sb *sb, const char *passphrase,
112                            struct bch_key *passphrase_key,
113                            struct bch_encrypted_key *sb_key)
114 {
115         struct bch_sb_field_crypt *crypt = bch2_sb_get_crypt(sb);
116         if (!crypt)
117                 die("filesystem is not encrypted");
118
119         *sb_key = crypt->key;
120
121         if (!bch2_key_is_encrypted(sb_key))
122                 die("filesystem does not have encryption key");
123
124         *passphrase_key = derive_passphrase(crypt, passphrase);
125
126         /* Check if the user supplied the correct passphrase: */
127         if (bch2_chacha_encrypt_key(passphrase_key, __bch2_sb_key_nonce(sb),
128                                     sb_key, sizeof(*sb_key)))
129                 die("error encrypting key");
130
131         if (bch2_key_is_encrypted(sb_key))
132                 die("incorrect passphrase");
133 }
134
135 void bch2_add_key(struct bch_sb *sb, const char *passphrase)
136 {
137         struct bch_key passphrase_key;
138         struct bch_encrypted_key sb_key;
139
140         bch2_passphrase_check(sb, passphrase,
141                               &passphrase_key,
142                               &sb_key);
143
144         char uuid[40];
145         uuid_unparse_lower(sb->user_uuid.b, uuid);
146
147         char *description = mprintf("bcachefs:%s", uuid);
148
149         if (add_key("logon", description,
150                     &passphrase_key, sizeof(passphrase_key),
151                     KEY_SPEC_USER_KEYRING) < 0 ||
152             add_key("user", description,
153                     &passphrase_key, sizeof(passphrase_key),
154                     KEY_SPEC_USER_KEYRING) < 0)
155                 die("add_key error: %m");
156
157         memzero_explicit(description, strlen(description));
158         free(description);
159         memzero_explicit(&passphrase_key, sizeof(passphrase_key));
160         memzero_explicit(&sb_key, sizeof(sb_key));
161 }
162
163 void bch_sb_crypt_init(struct bch_sb *sb,
164                        struct bch_sb_field_crypt *crypt,
165                        const char *passphrase)
166 {
167         crypt->key.magic = BCH_KEY_MAGIC;
168         get_random_bytes(&crypt->key.key, sizeof(crypt->key.key));
169
170         if (passphrase) {
171
172                 SET_BCH_CRYPT_KDF_TYPE(crypt, BCH_KDF_SCRYPT);
173                 SET_BCH_KDF_SCRYPT_N(crypt, ilog2(SCRYPT_N));
174                 SET_BCH_KDF_SCRYPT_R(crypt, ilog2(SCRYPT_r));
175                 SET_BCH_KDF_SCRYPT_P(crypt, ilog2(SCRYPT_p));
176
177                 struct bch_key passphrase_key = derive_passphrase(crypt, passphrase);
178
179                 assert(!bch2_key_is_encrypted(&crypt->key));
180
181                 if (bch2_chacha_encrypt_key(&passphrase_key, __bch2_sb_key_nonce(sb),
182                                            &crypt->key, sizeof(crypt->key)))
183                         die("error encrypting key");
184
185                 assert(bch2_key_is_encrypted(&crypt->key));
186
187                 memzero_explicit(&passphrase_key, sizeof(passphrase_key));
188         }
189 }