Update comments in get_interface_addresses_ioctl
[tor.git] / src / common / crypto_pwbox.c
blobb866c7ef391f3d7ea834395d5f74a476c5da113a
2 #include "crypto.h"
3 #include "crypto_s2k.h"
4 #include "crypto_pwbox.h"
5 #include "di_ops.h"
6 #include "util.h"
7 #include "pwbox.h"
9 /* 8 bytes "TORBOX00"
10 1 byte: header len (H)
11 H bytes: header, denoting secret key algorithm.
12 16 bytes: IV
13 Round up to multiple of 128 bytes, then encrypt:
14 4 bytes: data len
15 data
16 zeros
17 32 bytes: HMAC-SHA256 of all previous bytes.
20 #define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN)
22 /**
23 * Make an authenticated passphrase-encrypted blob to encode the
24 * <b>input_len</b> bytes in <b>input</b> using the passphrase
25 * <b>secret</b> of <b>secret_len</b> bytes. Allocate a new chunk of memory
26 * to hold the encrypted data, and store a pointer to that memory in
27 * *<b>out</b>, and its size in <b>outlen_out</b>. Use <b>s2k_flags</b> as an
28 * argument to the passphrase-hashing function.
30 int
31 crypto_pwbox(uint8_t **out, size_t *outlen_out,
32 const uint8_t *input, size_t input_len,
33 const char *secret, size_t secret_len,
34 unsigned s2k_flags)
36 uint8_t *result = NULL, *encrypted_portion;
37 size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128);
38 ssize_t result_len;
39 int spec_len;
40 uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
41 pwbox_encoded_t *enc = NULL;
42 ssize_t enc_len;
44 crypto_cipher_t *cipher;
45 int rv;
47 enc = pwbox_encoded_new();
49 pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN);
51 spec_len = secret_to_key_make_specifier(
52 pwbox_encoded_getarray_skey_header(enc),
53 S2K_MAXLEN,
54 s2k_flags);
55 if (spec_len < 0 || spec_len > S2K_MAXLEN)
56 goto err;
57 pwbox_encoded_setlen_skey_header(enc, spec_len);
58 enc->header_len = spec_len;
60 crypto_rand((char*)enc->iv, sizeof(enc->iv));
62 pwbox_encoded_setlen_data(enc, encrypted_len);
63 encrypted_portion = pwbox_encoded_getarray_data(enc);
65 set_uint32(encrypted_portion, htonl((uint32_t)input_len));
66 memcpy(encrypted_portion+4, input, input_len);
68 /* Now that all the data is in position, derive some keys, encrypt, and
69 * digest */
70 if (secret_to_key_derivekey(keys, sizeof(keys),
71 pwbox_encoded_getarray_skey_header(enc),
72 spec_len,
73 secret, secret_len) < 0)
74 goto err;
76 cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
77 crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len);
78 crypto_cipher_free(cipher);
80 result_len = pwbox_encoded_encoded_len(enc);
81 if (result_len < 0)
82 goto err;
83 result = tor_malloc(result_len);
84 enc_len = pwbox_encoded_encode(result, result_len, enc);
85 if (enc_len < 0)
86 goto err;
87 tor_assert(enc_len == result_len);
89 crypto_hmac_sha256((char*) result + result_len - 32,
90 (const char*)keys + CIPHER_KEY_LEN,
91 DIGEST256_LEN,
92 (const char*)result,
93 result_len - 32);
95 *out = result;
96 *outlen_out = result_len;
97 rv = 0;
98 goto out;
100 err:
101 tor_free(result);
102 rv = -1;
104 out:
105 pwbox_encoded_free(enc);
106 memwipe(keys, 0, sizeof(keys));
107 return rv;
111 * Try to decrypt the passphrase-encrypted blob of <b>input_len</b> bytes in
112 * <b>input</b> using the passphrase <b>secret</b> of <b>secret_len</b> bytes.
113 * On success, return 0 and allocate a new chunk of memory to hold the
114 * decrypted data, and store a pointer to that memory in *<b>out</b>, and its
115 * size in <b>outlen_out</b>. On failure, return UNPWBOX_BAD_SECRET if
116 * the passphrase might have been wrong, and UNPWBOX_CORRUPT if the object is
117 * definitely corrupt.
120 crypto_unpwbox(uint8_t **out, size_t *outlen_out,
121 const uint8_t *inp, size_t input_len,
122 const char *secret, size_t secret_len)
124 uint8_t *result = NULL;
125 const uint8_t *encrypted;
126 uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
127 uint8_t hmac[DIGEST256_LEN];
128 uint32_t result_len;
129 size_t encrypted_len;
130 crypto_cipher_t *cipher = NULL;
131 int rv = UNPWBOX_CORRUPTED;
132 ssize_t got_len;
134 pwbox_encoded_t *enc = NULL;
136 got_len = pwbox_encoded_parse(&enc, inp, input_len);
137 if (got_len < 0 || (size_t)got_len != input_len)
138 goto err;
140 /* Now derive the keys and check the hmac. */
141 if (secret_to_key_derivekey(keys, sizeof(keys),
142 pwbox_encoded_getarray_skey_header(enc),
143 pwbox_encoded_getlen_skey_header(enc),
144 secret, secret_len) < 0)
145 goto err;
147 crypto_hmac_sha256((char *)hmac,
148 (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN,
149 (const char*)inp, input_len - DIGEST256_LEN);
151 if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) {
152 rv = UNPWBOX_BAD_SECRET;
153 goto err;
156 /* How long is the plaintext? */
157 encrypted = pwbox_encoded_getarray_data(enc);
158 encrypted_len = pwbox_encoded_getlen_data(enc);
159 if (encrypted_len < 4)
160 goto err;
162 cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
163 crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4);
164 result_len = ntohl(result_len);
165 if (encrypted_len < result_len + 4)
166 goto err;
168 /* Allocate a buffer and decrypt */
169 result = tor_malloc_zero(result_len);
170 crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len);
172 *out = result;
173 *outlen_out = result_len;
175 rv = UNPWBOX_OKAY;
176 goto out;
178 err:
179 tor_free(result);
181 out:
182 crypto_cipher_free(cipher);
183 pwbox_encoded_free(enc);
184 memwipe(keys, 0, sizeof(keys));
185 return rv;