Update copyrights to 2021, using "make update-copyright"
[tor.git] / src / lib / crypt_ops / crypto_pwbox.c
blob792cc11e180cf0d2bce4156bf9a378cb380ddf7e
1 /* Copyright (c) 2014-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file crypto_pwbox.c
7 * \brief Code for encrypting secrets in a password-protected form and saving
8 * them to disk.
9 */
11 #include <string.h>
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"
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.
36 #define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN)
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.
46 int
47 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)
52 uint8_t *result = NULL, *encrypted_portion;
53 size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128);
54 ssize_t result_len;
55 int spec_len;
56 uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
57 pwbox_encoded_t *enc = NULL;
58 ssize_t enc_len;
60 crypto_cipher_t *cipher;
61 int rv;
63 enc = pwbox_encoded_new();
64 tor_assert(enc);
66 pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN);
68 spec_len = secret_to_key_make_specifier(
69 pwbox_encoded_getarray_skey_header(enc),
70 S2K_MAXLEN,
71 s2k_flags);
72 if (BUG(spec_len < 0 || spec_len > S2K_MAXLEN))
73 goto err;
74 pwbox_encoded_setlen_skey_header(enc, spec_len);
75 enc->header_len = spec_len;
77 crypto_rand((char*)enc->iv, sizeof(enc->iv));
79 pwbox_encoded_setlen_data(enc, encrypted_len);
80 encrypted_portion = pwbox_encoded_getarray_data(enc);
82 set_uint32(encrypted_portion, tor_htonl((uint32_t)input_len));
83 memcpy(encrypted_portion+4, input, input_len);
85 /* Now that all the data is in position, derive some keys, encrypt, and
86 * digest */
87 const int s2k_rv = secret_to_key_derivekey(keys, sizeof(keys),
88 pwbox_encoded_getarray_skey_header(enc),
89 spec_len,
90 secret, secret_len);
91 if (BUG(s2k_rv < 0))
92 goto err;
94 cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
95 crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len);
96 crypto_cipher_free(cipher);
98 result_len = pwbox_encoded_encoded_len(enc);
99 if (BUG(result_len < 0))
100 goto err;
101 result = tor_malloc(result_len);
102 enc_len = pwbox_encoded_encode(result, result_len, enc);
103 if (BUG(enc_len < 0))
104 goto err;
105 tor_assert(enc_len == result_len);
107 crypto_hmac_sha256((char*) result + result_len - 32,
108 (const char*)keys + CIPHER_KEY_LEN,
109 DIGEST256_LEN,
110 (const char*)result,
111 result_len - 32);
113 *out = result;
114 *outlen_out = result_len;
115 rv = 0;
116 goto out;
118 /* LCOV_EXCL_START
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.
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.
133 err:
134 tor_free(result);
135 rv = -1;
136 /* LCOV_EXCL_STOP */
137 out:
138 pwbox_encoded_free(enc);
139 memwipe(keys, 0, sizeof(keys));
140 return rv;
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.
153 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)
157 uint8_t *result = NULL;
158 const uint8_t *encrypted;
159 uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
160 uint8_t hmac[DIGEST256_LEN];
161 uint32_t result_len;
162 size_t encrypted_len;
163 crypto_cipher_t *cipher = NULL;
164 int rv = UNPWBOX_CORRUPTED;
165 ssize_t got_len;
167 pwbox_encoded_t *enc = NULL;
169 got_len = pwbox_encoded_parse(&enc, inp, input_len);
170 if (got_len < 0 || (size_t)got_len != input_len)
171 goto err;
173 /* Now derive the keys and check the hmac. */
174 if (secret_to_key_derivekey(keys, sizeof(keys),
175 pwbox_encoded_getarray_skey_header(enc),
176 pwbox_encoded_getlen_skey_header(enc),
177 secret, secret_len) < 0)
178 goto err;
180 crypto_hmac_sha256((char *)hmac,
181 (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN,
182 (const char*)inp, input_len - DIGEST256_LEN);
184 if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) {
185 rv = UNPWBOX_BAD_SECRET;
186 goto err;
189 /* How long is the plaintext? */
190 encrypted = pwbox_encoded_getarray_data(enc);
191 encrypted_len = pwbox_encoded_getlen_data(enc);
192 if (encrypted_len < 4)
193 goto err;
195 cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
196 crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4);
197 result_len = tor_ntohl(result_len);
198 if (encrypted_len < result_len + 4)
199 goto err;
201 /* Allocate a buffer and decrypt */
202 result = tor_malloc_zero(result_len);
203 crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len);
205 *out = result;
206 *outlen_out = result_len;
208 rv = UNPWBOX_OKAY;
209 goto out;
211 err:
212 tor_free(result);
214 out:
215 crypto_cipher_free(cipher);
216 pwbox_encoded_free(enc);
217 memwipe(keys, 0, sizeof(keys));
218 return rv;