diff options
author | Nick Mathewson <nickm@torproject.org> | 2014-09-24 10:51:39 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2014-09-25 11:58:14 -0400 |
commit | 3b7d0ed08e13d5b806b86818acec00c9352cf1c5 (patch) | |
tree | a4ca9a417606f09db1c6b4d62ebefe2331cd5875 /src/common/crypto_pwbox.c | |
parent | 301114940143b0d950b3a8dd69e2d6ee0bc6244d (diff) | |
download | tor-3b7d0ed08e13d5b806b86818acec00c9352cf1c5.tar.gz tor-3b7d0ed08e13d5b806b86818acec00c9352cf1c5.zip |
Use trunnel for crypto_pwbox encoding/decoding.
This reduces the likelihood that I have made any exploitable errors
in the encoding/decoding.
This commit also imports the trunnel runtime source into Tor.
Diffstat (limited to 'src/common/crypto_pwbox.c')
-rw-r--r-- | src/common/crypto_pwbox.c | 98 |
1 files changed, 56 insertions, 42 deletions
diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c index c021974632..91659db2bc 100644 --- a/src/common/crypto_pwbox.c +++ b/src/common/crypto_pwbox.c @@ -4,8 +4,9 @@ #include "crypto_pwbox.h" #include "di_ops.h" #include "util.h" +#include "pwbox.h" -/* 7 bytes "TORBOX0" +/* 8 bytes "TORBOX00" 1 byte: header len (H) H bytes: header, denoting secret key algorithm. 16 bytes: IV @@ -16,7 +17,7 @@ 32 bytes: HMAC-SHA256 of all previous bytes. */ -#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 32 + CIPHER_IV_LEN) +#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN) /** * Make an authenticated passphrase-encrypted blob to encode the @@ -32,31 +33,34 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, const char *secret, size_t secret_len, unsigned s2k_flags) { - uint8_t *result, *encrypted_portion, *hmac, *iv; + uint8_t *result = NULL, *encrypted_portion; size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128); - size_t result_len = encrypted_len + MAX_OVERHEAD; + ssize_t result_len; int spec_len; uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN]; + pwbox_encoded_t *enc = NULL; + ssize_t enc_len; crypto_cipher_t *cipher; int rv; - /* Allocate a buffer and put things in the right place. */ - result = tor_malloc_zero(result_len); - memcpy(result, "TORBOX0", 7); + enc = pwbox_encoded_new(); + + pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN); - spec_len = secret_to_key_make_specifier(result + 8, - result_len - 8, - s2k_flags); - if (spec_len < 0 || spec_len > 255) + spec_len = secret_to_key_make_specifier( + pwbox_encoded_getarray_skey_header(enc), + S2K_MAXLEN, + s2k_flags); + if (spec_len < 0 || spec_len > S2K_MAXLEN) goto err; - result[7] = (uint8_t) spec_len; + pwbox_encoded_setlen_skey_header(enc, spec_len); + enc->header_len = spec_len; - tor_assert(8 + spec_len + CIPHER_IV_LEN + encrypted_len <= result_len); + crypto_rand((char*)enc->iv, sizeof(enc->iv)); - iv = result + 8 + spec_len; - encrypted_portion = result + 8 + spec_len + CIPHER_IV_LEN; - hmac = encrypted_portion + encrypted_len; + pwbox_encoded_setlen_data(enc, encrypted_len); + encrypted_portion = pwbox_encoded_getarray_data(enc); set_uint32(encrypted_portion, htonl(input_len)); memcpy(encrypted_portion+4, input, input_len); @@ -64,24 +68,32 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, /* Now that all the data is in position, derive some keys, encrypt, and * digest */ if (secret_to_key_derivekey(keys, sizeof(keys), - result+8, spec_len, + pwbox_encoded_getarray_skey_header(enc), + spec_len, secret, secret_len) < 0) goto err; - crypto_rand((char*)iv, CIPHER_IV_LEN); - - cipher = crypto_cipher_new_with_iv((char*)keys, (char*)iv); + cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len); crypto_cipher_free(cipher); - crypto_hmac_sha256((char*)hmac, + result_len = pwbox_encoded_encoded_len(enc); + if (result_len < 0) + goto err; + result = tor_malloc(result_len); + enc_len = pwbox_encoded_encode(result, result_len, enc); + if (enc_len < 0) + goto err; + tor_assert(enc_len == result_len); + + crypto_hmac_sha256((char*) result + result_len - 32, (const char*)keys + CIPHER_KEY_LEN, - sizeof(keys)-CIPHER_KEY_LEN, + DIGEST256_LEN, (const char*)result, - 8 + CIPHER_IV_LEN + spec_len + encrypted_len); + result_len - 32); *out = result; - *outlen_out = 8 + CIPHER_IV_LEN + spec_len + encrypted_len + DIGEST256_LEN; + *outlen_out = result_len; rv = 0; goto out; @@ -90,6 +102,7 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, rv = -1; out: + pwbox_encoded_free(enc); memwipe(keys, 0, sizeof(keys)); return rv; } @@ -109,47 +122,47 @@ crypto_unpwbox(uint8_t **out, size_t *outlen_out, const char *secret, size_t secret_len) { uint8_t *result = NULL; - const uint8_t *encrypted, *iv; + const uint8_t *encrypted; uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN]; - size_t spec_bytes; uint8_t hmac[DIGEST256_LEN]; uint32_t result_len; + size_t encrypted_len; crypto_cipher_t *cipher = NULL; int rv = UNPWBOX_CORRUPTED; + ssize_t got_len; - if (input_len < 32) - goto err; - - if (tor_memneq(inp, "TORBOX0", 7)) - goto err; + pwbox_encoded_t *enc = NULL; - spec_bytes = inp[7]; - if (input_len < 8 + spec_bytes) + got_len = pwbox_encoded_parse(&enc, inp, input_len); + if (got_len < 0 || (size_t)got_len != input_len) goto err; /* Now derive the keys and check the hmac. */ if (secret_to_key_derivekey(keys, sizeof(keys), - inp+8, spec_bytes, + pwbox_encoded_getarray_skey_header(enc), + pwbox_encoded_getlen_skey_header(enc), secret, secret_len) < 0) goto err; crypto_hmac_sha256((char *)hmac, - (const char*)keys + CIPHER_KEY_LEN, sizeof(keys)-CIPHER_KEY_LEN, - (const char*)inp, input_len - DIGEST256_LEN); + (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN, + (const char*)inp, input_len - DIGEST256_LEN); - if (tor_memneq(hmac, inp + input_len - DIGEST256_LEN, DIGEST256_LEN)) { + if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) { rv = UNPWBOX_BAD_SECRET; goto err; } - iv = inp + 8 + spec_bytes; - encrypted = inp + 8 + spec_bytes + CIPHER_IV_LEN; - /* How long is the plaintext? */ - cipher = crypto_cipher_new_with_iv((char*)keys, (char*)iv); + encrypted = pwbox_encoded_getarray_data(enc); + encrypted_len = pwbox_encoded_getlen_data(enc); + if (encrypted_len < 4) + goto err; + + cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4); result_len = ntohl(result_len); - if (input_len < 8 + spec_bytes + 4 + result_len + 32) + if (encrypted_len < result_len + 4) goto err; /* Allocate a buffer and decrypt */ @@ -167,6 +180,7 @@ crypto_unpwbox(uint8_t **out, size_t *outlen_out, out: crypto_cipher_free(cipher); + pwbox_encoded_free(enc); memwipe(keys, 0, sizeof(keys)); return rv; } |