#include "lib/cc/torint.h"
#include "lib/malloc/malloc.h"
+#include "lib/testsupport/testsupport.h"
typedef struct aes_cnt_cipher_t aes_cnt_cipher_t;
FREE_AND_NULL(aes_raw_t, aes_raw_free_, (cipher))
void aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block);
void aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block);
+
+void aes_raw_counter_xor(const aes_raw_t *aes,
+ const uint8_t *iv, uint32_t iv_offset,
+ uint8_t *data, size_t n);
+#endif
+
+#ifdef TOR_AES_PRIVATE
+#include "lib/arch/bytes.h"
+
+/** Increment the big-endian 128-bit counter in 'iv' by 'offset'. */
+static inline void
+aes_ctr_add_iv_offset(uint8_t *iv, uint32_t offset)
+{
+
+ uint64_t h_hi = tor_ntohll(get_uint64(iv + 0));
+ uint64_t h_lo = tor_ntohll(get_uint64(iv + 8));
+ h_lo += offset;
+ h_hi += (h_lo < offset);
+ set_uint64(iv + 0, tor_htonll(h_hi));
+ set_uint64(iv + 8, tor_htonll(h_lo));
+}
#endif
#endif /* !defined(TOR_AES_H) */
**/
#define USE_AES_RAW
+#define TOR_AES_PRIVATE
#include "orconfig.h"
#include "lib/crypt_ops/aes.h"
tor_assert(result);
return (aes_raw_t *)result;
}
-
void
aes_raw_free_(aes_raw_t *cipher_)
{
/* This is the same function call for NSS. */
aes_raw_encrypt(cipher, block);
}
+
+static inline void
+xor_bytes(uint8_t *outp, const uint8_t *inp, size_t n)
+{
+ for (size_t i = 0; i < n; ++i) {
+ outp[i] ^= inp[i];
+ }
+}
+
+void
+aes_raw_counter_xor(const aes_raw_t *cipher,
+ const uint8_t *iv, uint32_t iv_offset,
+ uint8_t *data, size_t n)
+{
+ uint8_t counter[16];
+ uint8_t buf[16];
+
+ memcpy(counter, iv, 16);
+ aes_ctr_add_iv_offset(counter, iv_offset);
+
+ while (n) {
+ memcpy(buf, counter, 16);
+ aes_raw_encrypt(cipher, buf);
+ if (n >= 16) {
+ xor_bytes(data, buf, 16);
+ n -= 16;
+ data += 16;
+ } else {
+ xor_bytes(data, buf, n);
+ break;
+ }
+ aes_ctr_add_iv_offset(counter, 1);
+ }
+}
**/
#define USE_AES_RAW
+#define TOR_AES_PRIVATE
#include "orconfig.h"
#include "lib/crypt_ops/aes.h"
* make sure that we have a fixed version.)
*/
+/* Helper function to use EVP with openssl's counter-mode wrapper. */
+static void
+evp_block128_fn(const uint8_t in[16],
+ uint8_t out[16],
+ const void *key)
+{
+ EVP_CIPHER_CTX *ctx = (void*)key;
+ int inl=16, outl=16;
+ EVP_EncryptUpdate(ctx, out, &outl, in, inl);
+}
+
#ifdef USE_EVP_AES_CTR
/* We don't actually define the struct here. */
#define UPDATE_CTR_BUF(c, n)
#endif /* defined(USING_COUNTER_VARS) */
-/* Helper function to use EVP with openssl's counter-mode wrapper. */
-static void
-evp_block128_fn(const uint8_t in[16],
- uint8_t out[16],
- const void *key)
-{
- EVP_CIPHER_CTX *ctx = (void*)key;
- int inl=16, outl=16;
- EVP_EncryptUpdate(ctx, out, &outl, in, inl);
-}
-
/** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place.
* Uses the key in <b>cipher</b>, and advances the counter by <b>len</b> bytes
* as it encrypts.
}
}
-/** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value
- * in <b>iv</b>. */
-static void
-aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv)
-{
-#ifdef USING_COUNTER_VARS
- cipher->counter3 = tor_ntohl(get_uint32(iv));
- cipher->counter2 = tor_ntohl(get_uint32(iv+4));
- cipher->counter1 = tor_ntohl(get_uint32(iv+8));
- cipher->counter0 = tor_ntohl(get_uint32(iv+12));
-#endif /* defined(USING_COUNTER_VARS) */
- cipher->pos = 0;
- memcpy(cipher->ctr_buf.buf, iv, 16);
-}
-
#endif /* defined(USE_EVP_AES_CTR) */
/* ========
tor_assert(r == 1);
tor_assert(outl == 16);
}
+
+/**
+ * Use the AES encryption key AES in counter mode,
+ * starting at the position (iv + iv_offset)*16,
+ * to encrypt the 'n' bytes of data in 'data'.
+ *
+ * Unlike aes_crypt_inplace, this function can re-use the same key repeatedly
+ * with diferent IVs.
+ */
+void
+aes_raw_counter_xor(const aes_raw_t *cipher,
+ const uint8_t *iv, uint32_t iv_offset,
+ uint8_t *data, size_t n)
+{
+ uint8_t counter[16];
+ uint8_t buf[16];
+ unsigned int pos = 0;
+
+ memcpy(counter, iv, 16);
+ if (iv_offset) {
+ aes_ctr_add_iv_offset(counter, iv_offset);
+ }
+
+ CRYPTO_ctr128_encrypt(data, data, n,
+ (EVP_CIPHER_CTX *)cipher,
+ counter, buf, &pos, evp_block128_fn);
+}
#define CRYPTO_CURVE25519_PRIVATE
#define CRYPTO_RAND_PRIVATE
#define USE_AES_RAW
+#define TOR_AES_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
#include "lib/crypt_ops/aes.h"
#undef T
}
+static void
+test_crypto_aes_raw_ctr_equiv(void *arg)
+{
+ (void) arg;
+ size_t buflen = 65536;
+ uint8_t *buf = tor_malloc_zero(buflen);
+ aes_cnt_cipher_t *c = NULL;
+ aes_raw_t *c_raw = NULL;
+
+ const uint8_t iv[16];
+ const uint8_t key[16];
+
+ // Simple case, IV with zero offset.
+ for (int i = 0; i < 32; ++i) {
+ crypto_rand((char*)iv, sizeof(iv));
+ crypto_rand((char*)key, sizeof(key));
+ c = aes_new_cipher(key, iv, 128);
+ c_raw = aes_raw_new(key, 128, true);
+
+ aes_crypt_inplace(c, (char*)buf, buflen);
+ aes_raw_counter_xor(c_raw, iv, 0, buf, buflen);
+ tt_assert(fast_mem_is_zero((char*)buf, buflen));
+
+ aes_cipher_free(c);
+ aes_raw_free(c_raw);
+ }
+ // Trickier case, IV with offset == 31.
+ for (int i = 0; i < 32; ++i) {
+ crypto_rand((char*)iv, sizeof(iv));
+ crypto_rand((char*)key, sizeof(key));
+ c = aes_new_cipher(key, iv, 128);
+ c_raw = aes_raw_new(key, 128, true);
+
+ aes_crypt_inplace(c, (char*)buf, buflen);
+ size_t off = 31*16;
+ aes_raw_counter_xor(c_raw, iv, 31, buf + off, buflen - off);
+ tt_assert(fast_mem_is_zero((char*)buf + off, buflen - off));
+
+ aes_cipher_free(c);
+ aes_raw_free(c_raw);
+ }
+
+ done:
+ aes_cipher_free(c);
+ aes_raw_free(c_raw);
+ tor_free(buf);
+}
+
+/* Make sure that our IV addition code is correct.
+ *
+ * We test this function separately to make sure we handle corner cases well;
+ * the corner cases are rare enough that we shouldn't expect to see them in
+ * randomized testing.
+ */
+static void
+test_crypto_aes_cnt_iv_manip(void *arg)
+{
+ (void)arg;
+ uint8_t buf[16];
+ uint8_t expect[16];
+ int n;
+#define T(pre, off, post) STMT_BEGIN { \
+ n = base16_decode((char*)buf, sizeof(buf), \
+ (pre), strlen(pre)); \
+ tt_int_op(n, OP_EQ, sizeof(buf)); \
+ n = base16_decode((char*)expect, sizeof(expect), \
+ (post), strlen(post)); \
+ tt_int_op(n, OP_EQ, sizeof(expect)); \
+ aes_ctr_add_iv_offset(buf, (off)); \
+ tt_mem_op(buf, OP_EQ, expect, 16); \
+ } STMT_END
+
+ T("00000000000000000000000000000000", 0x4032,
+ "00000000000000000000000000004032");
+ T("0000000000000000000000000000ffff", 0x4032,
+ "00000000000000000000000000014031");
+ // We focus on "31" here because that's what CGO uses.
+ T("000000000000000000000000ffffffe0", 31,
+ "000000000000000000000000ffffffff");
+ T("000000000000000000000000ffffffe1", 31,
+ "00000000000000000000000100000000");
+ T("0000000100000000ffffffffffffffe0", 31,
+ "0000000100000000ffffffffffffffff");
+ T("0000000100000000ffffffffffffffe1", 31,
+ "00000001000000010000000000000000");
+ T("0000000ffffffffffffffffffffffff0", 31,
+ "0000001000000000000000000000000f");
+ T("ffffffffffffffffffffffffffffffe0", 31,
+ "ffffffffffffffffffffffffffffffff");
+ T("ffffffffffffffffffffffffffffffe1", 31,
+ "00000000000000000000000000000000");
+ T("ffffffffffffffffffffffffffffffe8", 31,
+ "00000000000000000000000000000007");
+
+#undef T
+ done:
+ ;
+}
+
#ifndef COCCI
#define CRYPTO_LEGACY(name) \
{ #name, test_crypto_ ## name , 0, NULL, NULL }
{ "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL },
{ "polyval", test_crypto_polyval, 0, NULL, NULL },
{ "aes_raw", test_crypto_aes_raw, 0, NULL, NULL },
+ { "aes_raw_ctr_equiv", test_crypto_aes_raw_ctr_equiv, 0, NULL, NULL },
+ { "aes_cnt_iv_manip", test_crypto_aes_cnt_iv_manip, 0, NULL, NULL },
END_OF_TESTCASES
};