Line data Source code
1 : /* Copyright (c) 2014-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file crypto_pwbox.c
6 : *
7 : * \brief Code for encrypting secrets in a password-protected form and saving
8 : * them to disk.
9 : */
10 :
11 : #include <string.h>
12 :
13 : #include "lib/arch/bytes.h"
14 : #include "lib/crypt_ops/crypto_cipher.h"
15 : #include "lib/crypt_ops/crypto_digest.h"
16 : #include "lib/crypt_ops/crypto_pwbox.h"
17 : #include "lib/crypt_ops/crypto_rand.h"
18 : #include "lib/crypt_ops/crypto_s2k.h"
19 : #include "lib/crypt_ops/crypto_util.h"
20 : #include "lib/ctime/di_ops.h"
21 : #include "lib/intmath/muldiv.h"
22 : #include "trunnel/pwbox.h"
23 : #include "lib/log/util_bug.h"
24 :
25 : /* 8 bytes "TORBOX00"
26 : 1 byte: header len (H)
27 : H bytes: header, denoting secret key algorithm.
28 : 16 bytes: IV
29 : Round up to multiple of 128 bytes, then encrypt:
30 : 4 bytes: data len
31 : data
32 : zeros
33 : 32 bytes: HMAC-SHA256 of all previous bytes.
34 : */
35 :
36 : #define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN)
37 :
38 : /**
39 : * Make an authenticated passphrase-encrypted blob to encode the
40 : * <b>input_len</b> bytes in <b>input</b> using the passphrase
41 : * <b>secret</b> of <b>secret_len</b> bytes. Allocate a new chunk of memory
42 : * to hold the encrypted data, and store a pointer to that memory in
43 : * *<b>out</b>, and its size in <b>outlen_out</b>. Use <b>s2k_flags</b> as an
44 : * argument to the passphrase-hashing function.
45 : */
46 : int
47 6 : crypto_pwbox(uint8_t **out, size_t *outlen_out,
48 : const uint8_t *input, size_t input_len,
49 : const char *secret, size_t secret_len,
50 : unsigned s2k_flags)
51 : {
52 6 : uint8_t *result = NULL, *encrypted_portion;
53 6 : size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128);
54 6 : ssize_t result_len;
55 6 : int spec_len;
56 6 : uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
57 6 : pwbox_encoded_t *enc = NULL;
58 6 : ssize_t enc_len;
59 :
60 6 : crypto_cipher_t *cipher;
61 6 : int rv;
62 :
63 6 : enc = pwbox_encoded_new();
64 6 : tor_assert(enc);
65 :
66 6 : pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN);
67 :
68 6 : spec_len = secret_to_key_make_specifier(
69 : pwbox_encoded_getarray_skey_header(enc),
70 : S2K_MAXLEN,
71 : s2k_flags);
72 6 : if (BUG(spec_len < 0 || spec_len > S2K_MAXLEN))
73 0 : goto err;
74 6 : pwbox_encoded_setlen_skey_header(enc, spec_len);
75 6 : enc->header_len = spec_len;
76 :
77 6 : crypto_rand((char*)enc->iv, sizeof(enc->iv));
78 :
79 6 : pwbox_encoded_setlen_data(enc, encrypted_len);
80 6 : encrypted_portion = pwbox_encoded_getarray_data(enc);
81 :
82 6 : set_uint32(encrypted_portion, tor_htonl((uint32_t)input_len));
83 6 : memcpy(encrypted_portion+4, input, input_len);
84 :
85 : /* Now that all the data is in position, derive some keys, encrypt, and
86 : * digest */
87 6 : const int s2k_rv = secret_to_key_derivekey(keys, sizeof(keys),
88 6 : pwbox_encoded_getarray_skey_header(enc),
89 : spec_len,
90 : secret, secret_len);
91 6 : if (BUG(s2k_rv < 0))
92 0 : goto err;
93 :
94 6 : cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
95 6 : crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len);
96 6 : crypto_cipher_free(cipher);
97 :
98 6 : result_len = pwbox_encoded_encoded_len(enc);
99 6 : if (BUG(result_len < 0))
100 0 : goto err;
101 6 : result = tor_malloc(result_len);
102 6 : enc_len = pwbox_encoded_encode(result, result_len, enc);
103 6 : if (BUG(enc_len < 0))
104 0 : goto err;
105 6 : tor_assert(enc_len == result_len);
106 :
107 6 : crypto_hmac_sha256((char*) result + result_len - 32,
108 : (const char*)keys + CIPHER_KEY_LEN,
109 : DIGEST256_LEN,
110 : (const char*)result,
111 6 : result_len - 32);
112 :
113 6 : *out = result;
114 6 : *outlen_out = result_len;
115 6 : rv = 0;
116 6 : goto out;
117 :
118 : /* LCOV_EXCL_START
119 :
120 : This error case is often unreachable if we're correctly coded, unless
121 : somebody adds a new error case somewhere, or unless you're building
122 : without scrypto support.
123 :
124 : - make_specifier can't fail, unless S2K_MAX_LEN is too short.
125 : - secret_to_key_derivekey can't really fail unless we're missing
126 : scrypt, or the underlying function fails, or we pass it a bogus
127 : algorithm or parameters.
128 : - pwbox_encoded_encoded_len can't fail unless we're using trunnel
129 : incorrectly.
130 : - pwbox_encoded_encode can't fail unless we're using trunnel wrong,
131 : or it's buggy.
132 : */
133 : err:
134 : tor_free(result);
135 : rv = -1;
136 : /* LCOV_EXCL_STOP */
137 6 : out:
138 6 : pwbox_encoded_free(enc);
139 6 : memwipe(keys, 0, sizeof(keys));
140 6 : return rv;
141 : }
142 :
143 : /**
144 : * Try to decrypt the passphrase-encrypted blob of <b>input_len</b> bytes in
145 : * <b>input</b> using the passphrase <b>secret</b> of <b>secret_len</b> bytes.
146 : * On success, return 0 and allocate a new chunk of memory to hold the
147 : * decrypted data, and store a pointer to that memory in *<b>out</b>, and its
148 : * size in <b>outlen_out</b>. On failure, return UNPWBOX_BAD_SECRET if
149 : * the passphrase might have been wrong, and UNPWBOX_CORRUPT if the object is
150 : * definitely corrupt.
151 : */
152 : int
153 21 : crypto_unpwbox(uint8_t **out, size_t *outlen_out,
154 : const uint8_t *inp, size_t input_len,
155 : const char *secret, size_t secret_len)
156 : {
157 21 : uint8_t *result = NULL;
158 21 : const uint8_t *encrypted;
159 21 : uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
160 21 : uint8_t hmac[DIGEST256_LEN];
161 21 : uint32_t result_len;
162 21 : size_t encrypted_len;
163 21 : crypto_cipher_t *cipher = NULL;
164 21 : int rv = UNPWBOX_CORRUPTED;
165 21 : ssize_t got_len;
166 :
167 21 : pwbox_encoded_t *enc = NULL;
168 :
169 21 : got_len = pwbox_encoded_parse(&enc, inp, input_len);
170 21 : if (got_len < 0 || (size_t)got_len != input_len)
171 5 : goto err;
172 :
173 : /* Now derive the keys and check the hmac. */
174 32 : if (secret_to_key_derivekey(keys, sizeof(keys),
175 16 : pwbox_encoded_getarray_skey_header(enc),
176 : pwbox_encoded_getlen_skey_header(enc),
177 : secret, secret_len) < 0)
178 0 : goto err;
179 :
180 16 : crypto_hmac_sha256((char *)hmac,
181 : (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN,
182 : (const char*)inp, input_len - DIGEST256_LEN);
183 :
184 16 : if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) {
185 10 : rv = UNPWBOX_BAD_SECRET;
186 10 : goto err;
187 : }
188 :
189 : /* How long is the plaintext? */
190 6 : encrypted = pwbox_encoded_getarray_data(enc);
191 6 : encrypted_len = pwbox_encoded_getlen_data(enc);
192 6 : if (encrypted_len < 4)
193 0 : goto err;
194 :
195 6 : cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
196 6 : crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4);
197 6 : result_len = tor_ntohl(result_len);
198 6 : if (encrypted_len < result_len + 4)
199 0 : goto err;
200 :
201 : /* Allocate a buffer and decrypt */
202 6 : result = tor_malloc_zero(result_len);
203 6 : crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len);
204 :
205 6 : *out = result;
206 6 : *outlen_out = result_len;
207 :
208 6 : rv = UNPWBOX_OKAY;
209 6 : goto out;
210 :
211 : err:
212 21 : tor_free(result);
213 :
214 21 : out:
215 21 : crypto_cipher_free(cipher);
216 21 : pwbox_encoded_free(enc);
217 21 : memwipe(keys, 0, sizeof(keys));
218 21 : return rv;
219 : }
|