crypto_pwbox.c (6900B)
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 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 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; 59 60 crypto_cipher_t *cipher; 61 int rv; 62 63 enc = pwbox_encoded_new(); 64 tor_assert(enc); 65 66 pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN); 67 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; 76 77 crypto_rand((char*)enc->iv, sizeof(enc->iv)); 78 79 pwbox_encoded_setlen_data(enc, encrypted_len); 80 encrypted_portion = pwbox_encoded_getarray_data(enc); 81 82 set_uint32(encrypted_portion, tor_htonl((uint32_t)input_len)); 83 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 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; 93 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); 97 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); 106 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); 112 113 *out = result; 114 *outlen_out = result_len; 115 rv = 0; 116 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 out: 138 pwbox_encoded_free(enc); 139 memwipe(keys, 0, sizeof(keys)); 140 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 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 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; 166 167 pwbox_encoded_t *enc = NULL; 168 169 got_len = pwbox_encoded_parse(&enc, inp, input_len); 170 if (got_len < 0 || (size_t)got_len != input_len) 171 goto err; 172 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; 179 180 crypto_hmac_sha256((char *)hmac, 181 (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN, 182 (const char*)inp, input_len - DIGEST256_LEN); 183 184 if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) { 185 rv = UNPWBOX_BAD_SECRET; 186 goto err; 187 } 188 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; 194 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; 200 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); 204 205 *out = result; 206 *outlen_out = result_len; 207 208 rv = UNPWBOX_OKAY; 209 goto out; 210 211 err: 212 tor_free(result); 213 214 out: 215 crypto_cipher_free(cipher); 216 pwbox_encoded_free(enc); 217 memwipe(keys, 0, sizeof(keys)); 218 return rv; 219 }