]> git.sesse.net Git - bcachefs-tools-debian/blob - crypto.c
0e18b36ff81aa6e4f535cea29c8bc6ba52df3db1
[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 void bch2_passphrase_check(struct bch_sb *sb, const char *passphrase,
104                            struct bch_key *passphrase_key,
105                            struct bch_encrypted_key *sb_key)
106 {
107         struct bch_sb_field_crypt *crypt = bch2_sb_get_crypt(sb);
108         if (!crypt)
109                 die("filesystem is not encrypted");
110
111         *sb_key = crypt->key;
112
113         if (!bch2_key_is_encrypted(sb_key))
114                 die("filesystem does not have encryption key");
115
116         *passphrase_key = derive_passphrase(crypt, passphrase);
117
118         /* Check if the user supplied the correct passphrase: */
119         if (bch2_chacha_encrypt_key(passphrase_key, __bch2_sb_key_nonce(sb),
120                                     sb_key, sizeof(*sb_key)))
121                 die("error encrypting key");
122
123         if (bch2_key_is_encrypted(sb_key))
124                 die("incorrect passphrase");
125 }
126
127 void bch2_add_key(struct bch_sb *sb, const char *passphrase)
128 {
129         struct bch_key passphrase_key;
130         struct bch_encrypted_key sb_key;
131
132         bch2_passphrase_check(sb, passphrase,
133                               &passphrase_key,
134                               &sb_key);
135
136         char uuid[40];
137         uuid_unparse_lower(sb->user_uuid.b, uuid);
138
139         char *description = mprintf("bcachefs:%s", uuid);
140
141         if (add_key("logon", description,
142                     &passphrase_key, sizeof(passphrase_key),
143                     KEY_SPEC_USER_KEYRING) < 0 ||
144             add_key("user", description,
145                     &passphrase_key, sizeof(passphrase_key),
146                     KEY_SPEC_USER_KEYRING) < 0)
147                 die("add_key error: %m");
148
149         memzero_explicit(description, strlen(description));
150         free(description);
151         memzero_explicit(&passphrase_key, sizeof(passphrase_key));
152         memzero_explicit(&sb_key, sizeof(sb_key));
153 }
154
155 void bch_sb_crypt_init(struct bch_sb *sb,
156                        struct bch_sb_field_crypt *crypt,
157                        const char *passphrase)
158 {
159         crypt->key.magic = BCH_KEY_MAGIC;
160         get_random_bytes(&crypt->key.key, sizeof(crypt->key.key));
161
162         if (passphrase) {
163
164                 SET_BCH_CRYPT_KDF_TYPE(crypt, BCH_KDF_SCRYPT);
165                 SET_BCH_KDF_SCRYPT_N(crypt, ilog2(SCRYPT_N));
166                 SET_BCH_KDF_SCRYPT_R(crypt, ilog2(SCRYPT_r));
167                 SET_BCH_KDF_SCRYPT_P(crypt, ilog2(SCRYPT_p));
168
169                 struct bch_key passphrase_key = derive_passphrase(crypt, passphrase);
170
171                 assert(!bch2_key_is_encrypted(&crypt->key));
172
173                 if (bch2_chacha_encrypt_key(&passphrase_key, __bch2_sb_key_nonce(sb),
174                                            &crypt->key, sizeof(crypt->key)))
175                         die("error encrypting key");
176
177                 assert(bch2_key_is_encrypted(&crypt->key));
178
179                 memzero_explicit(&passphrase_key, sizeof(passphrase_key));
180         }
181 }