diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/crypto_pwbox.c | 167 | ||||
-rw-r--r-- | src/common/crypto_pwbox.h | 20 | ||||
-rw-r--r-- | src/common/include.am | 2 |
3 files changed, 189 insertions, 0 deletions
diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c new file mode 100644 index 0000000000..61b6ebe96f --- /dev/null +++ b/src/common/crypto_pwbox.c @@ -0,0 +1,167 @@ + +#include "crypto.h" +#include "crypto_s2k.h" +#include "crypto_pwbox.h" +#include "di_ops.h" +#include "util.h" + +/* 7 bytes "TORBOX0" + 1 byte: header len (H) + H bytes: header, denoting secret key algorithm. + Round up to multiple of 128 bytes, then encrypt: + 4 bytes: data len + data + zeros + 32 bytes: HMAC-SHA256 of all previous bytes. +*/ + +#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 32) + +/** + * Make an authenticated passphrase-encrypted blob to encode the + * <b>input_len</b> bytes in <b>input</b> using the passphrase + * <b>secret</b> of <b>secret_len</b> bytes. Allocate a new chunk of memory + * to hold the encrypted data, and store a pointer to that memory in + * *<b>out</b>, and its size in <b>outlen_out</b>. Use <b>s2k_flags</b> as an + * argument to the passphrase-hashing function. + */ +int +crypto_pwbox(uint8_t **out, size_t *outlen_out, + const uint8_t *input, size_t input_len, + const char *secret, size_t secret_len, + unsigned s2k_flags) +{ + uint8_t *result, *encrypted_portion, *hmac; + size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128); + size_t result_len = encrypted_len + MAX_OVERHEAD; + int spec_len; + uint8_t keys[CIPHER_KEY_LEN + DIGEST256_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); + + spec_len = secret_to_key_make_specifier(result + 8, + result_len - 8, + s2k_flags); + if (spec_len < 0 || spec_len > 255) + goto err; + result[7] = (uint8_t) spec_len; + + tor_assert(8 + spec_len + encrypted_len <= result_len); + + encrypted_portion = result + 8 + spec_len; + hmac = encrypted_portion + encrypted_len; + + set_uint32(encrypted_portion, htonl(input_len)); + memcpy(encrypted_portion+4, input, input_len); + + /* 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, + secret, secret_len) < 0) + goto err; + + cipher = crypto_cipher_new((char*)keys); + crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len); + crypto_cipher_free(cipher); + + crypto_hmac_sha256((char*)hmac, + (const char*)keys + CIPHER_KEY_LEN, + sizeof(keys)-CIPHER_KEY_LEN, + (const char*)result, 8 + spec_len + encrypted_len); + + *out = result; + *outlen_out = 8 + spec_len + encrypted_len + DIGEST256_LEN; + rv = 0; + goto out; + + err: + tor_free(result); + rv = -1; + + out: + memwipe(keys, 0, sizeof(keys)); + return rv; +} + +/** + * Try to decrypt the passphrase-encrypted blob of <b>input_len</b> bytes in + * <b>input</b> using the passphrase <b>secret</b> of <b>secret_len</b> bytes. + * On success, return 0 and allocate a new chunk of memory to hold the + * decrypted data, and store a pointer to that memory in *<b>out</b>, and its + * size in <b>outlen_out</b>. On failure, return UNPWBOX_BAD_SECRET if + * the passphrase might have been wrong, and UNPWBOX_CORRUPT if the object is + * definitely corrupt. + */ +int +crypto_unpwbox(uint8_t **out, size_t *outlen_out, + const uint8_t *inp, size_t input_len, + const char *secret, size_t secret_len) +{ + uint8_t *result = NULL; + 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; + crypto_cipher_t *cipher = NULL; + int rv = UNPWBOX_CORRUPTED; + + if (input_len < 32) + goto err; + + if (tor_memneq(inp, "TORBOX0", 7)) + goto err; + + spec_bytes = inp[7]; + if (input_len < 8 + spec_bytes) + goto err; + + /* Now derive the keys and check the hmac. */ + if (secret_to_key_derivekey(keys, sizeof(keys), + inp+8, spec_bytes, + 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); + + if (tor_memneq(hmac, inp + input_len - DIGEST256_LEN, DIGEST256_LEN)) { + rv = UNPWBOX_BAD_SECRET; + goto err; + } + + encrypted = inp + 8 + spec_bytes; + + /* How long is the plaintext? */ + cipher = crypto_cipher_new((char*)keys); + 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) + goto err; + + /* Allocate a buffer and decrypt */ + result = tor_malloc_zero(result_len); + crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len); + + *out = result; + *outlen_out = result_len; + + rv = UNPWBOX_OKAY; + goto out; + + err: + tor_free(result); + + out: + crypto_cipher_free(cipher); + memwipe(keys, 0, sizeof(keys)); + return rv; +} + diff --git a/src/common/crypto_pwbox.h b/src/common/crypto_pwbox.h new file mode 100644 index 0000000000..aadd477078 --- /dev/null +++ b/src/common/crypto_pwbox.h @@ -0,0 +1,20 @@ +#ifndef CRYPTO_PWBOX_H_INCLUDED_ +#define CRYPTO_PWBOX_H_INCLUDED_ + +#include "torint.h" + +#define UNPWBOX_OKAY 0 +#define UNPWBOX_BAD_SECRET -1 +#define UNPWBOX_CORRUPTED -2 + +int crypto_pwbox(uint8_t **out, size_t *outlen_out, + const uint8_t *inp, size_t input_len, + const char *secret, size_t secret_len, + unsigned s2k_flags); + +int crypto_unpwbox(uint8_t **out, size_t *outlen_out, + const uint8_t *inp, size_t input_len, + const char *secret, size_t secret_len); + +#endif + diff --git a/src/common/include.am b/src/common/include.am index 0fb1962720..83a3706489 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -75,6 +75,7 @@ LIBOR_A_SOURCES = \ LIBOR_CRYPTO_A_SOURCES = \ src/common/aes.c \ src/common/crypto.c \ + src/common/crypto_pwbox.c \ src/common/crypto_s2k.c \ src/common/crypto_format.c \ src/common/torgzip.c \ @@ -111,6 +112,7 @@ COMMONHEADERS = \ src/common/container.h \ src/common/crypto.h \ src/common/crypto_curve25519.h \ + src/common/crypto_pwbox.h \ src/common/crypto_s2k.h \ src/common/di_ops.h \ src/common/memarea.h \ |