Browse Source

Refactor the API for setting up a block cipher.

It allows us more flexibility on the backend if the user needs to
specify the key and IV at setup time.
Nick Mathewson 12 years ago
parent
commit
de0dca0de7
10 changed files with 129 additions and 253 deletions
  1. 3 0
      changes/crypto_api
  2. 12 4
      src/common/aes.c
  3. 1 3
      src/common/aes.h
  4. 37 121
      src/common/crypto.c
  5. 4 13
      src/common/crypto.h
  6. 2 2
      src/or/circuitbuild.c
  7. 5 8
      src/or/rendcommon.c
  8. 7 8
      src/or/routerparse.c
  9. 5 12
      src/test/bench.c
  10. 53 82
      src/test/test_crypto.c

+ 3 - 0
changes/crypto_api

@@ -0,0 +1,3 @@
+  o Code refactoring:
+    - Change the symmetric cipher interface so that creating and
+      initializing a stream cipher are no longer separate functions.

+ 12 - 4
src/common/aes.c

@@ -209,14 +209,22 @@ _aes_fill_buf(aes_cnt_cipher_t *cipher)
   }
 }
 
+static void aes_set_key(aes_cnt_cipher_t *cipher, const char *key,
+                        int key_bits);
+static void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv);
+
 /**
- * Return a newly allocated counter-mode AES128 cipher implementation.
+ * Return a newly allocated counter-mode AES128 cipher implementation,
+ * using the 128-bit key <b>key</b> and the 128-bit IV <b>iv</b>.
  */
 aes_cnt_cipher_t*
-aes_new_cipher(void)
+aes_new_cipher(const char *key, const char *iv)
 {
   aes_cnt_cipher_t* result = tor_malloc_zero(sizeof(aes_cnt_cipher_t));
 
+  aes_set_key(result, key, 128);
+  aes_set_iv(result, iv);
+
   return result;
 }
 
@@ -224,7 +232,7 @@ aes_new_cipher(void)
  * <b>key_bits</b> bits long (must be 128, 192, or 256).  Also resets
  * the counter to 0.
  */
-void
+static void
 aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
 {
   if (should_use_EVP) {
@@ -398,7 +406,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
 
 /** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value
  * in <b>iv</b>. */
-void
+static void
 aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
 {
 #ifdef USING_COUNTER_VARS

+ 1 - 3
src/common/aes.h

@@ -16,13 +16,11 @@
 struct aes_cnt_cipher;
 typedef struct aes_cnt_cipher aes_cnt_cipher_t;
 
-aes_cnt_cipher_t* aes_new_cipher(void);
+aes_cnt_cipher_t* aes_new_cipher(const char *key, const char *iv);
 void aes_cipher_free(aes_cnt_cipher_t *cipher);
-void aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits);
 void aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
                char *output);
 void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len);
-void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv);
 
 int evaluate_evp_for_aes(int force_value);
 int evaluate_ctr_for_aes(void);

+ 37 - 121
src/common/crypto.c

@@ -119,6 +119,7 @@ struct crypto_pk_t
 struct crypto_cipher_t
 {
   char key[CIPHER_KEY_LEN]; /**< The raw key. */
+  char iv[CIPHER_IV_LEN]; /**< The initial IV. */
   aes_cnt_cipher_t *cipher; /**< The key in format usable for counter-mode AES
                              * encryption */
 };
@@ -383,48 +384,37 @@ crypto_pk_free(crypto_pk_t *env)
   tor_free(env);
 }
 
-/** Create a new symmetric cipher for a given key and encryption flag
- * (1=encrypt, 0=decrypt).  Return the crypto object on success; NULL
- * on failure.
+/** Allocate and return a new symmetric cipher using the provided key and iv.
+ * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes.  If you
+ * provide NULL in place of either one, it is generated at random.
  */
 crypto_cipher_t *
-crypto_create_init_cipher(const char *key, int encrypt_mode)
+crypto_cipher_new_with_iv(const char *key, const char *iv)
 {
-  int r;
-  crypto_cipher_t *crypto = NULL;
-
-  if (! (crypto = crypto_cipher_new())) {
-    log_warn(LD_CRYPTO, "Unable to allocate crypto object");
-    return NULL;
-  }
+  crypto_cipher_t *env;
 
-  crypto_cipher_set_key(crypto, key);
+  env = tor_malloc_zero(sizeof(crypto_cipher_t));
 
-  if (encrypt_mode)
-    r = crypto_cipher_encrypt_init_cipher(crypto);
+  if (key == NULL)
+    crypto_rand(env->key, CIPHER_KEY_LEN);
+  else
+    memcpy(env->key, key, CIPHER_KEY_LEN);
+  if (iv == NULL)
+    crypto_rand(env->iv, CIPHER_IV_LEN);
   else
-    r = crypto_cipher_decrypt_init_cipher(crypto);
+    memcpy(env->iv, iv, CIPHER_IV_LEN);
 
-  if (r)
-    goto error;
-  return crypto;
+  env->cipher = aes_new_cipher(env->key, env->iv);
 
- error:
-  if (crypto)
-    crypto_cipher_free(crypto);
-  return NULL;
+  return env;
 }
 
-/** Allocate and return a new symmetric cipher.
- */
 crypto_cipher_t *
-crypto_cipher_new(void)
+crypto_cipher_new(const char *key)
 {
-  crypto_cipher_t *env;
-
-  env = tor_malloc_zero(sizeof(crypto_cipher_t));
-  env->cipher = aes_new_cipher();
-  return env;
+  char zeroiv[CIPHER_IV_LEN];
+  memset(zeroiv, 0, sizeof(zeroiv));
+  return crypto_cipher_new_with_iv(key, zeroiv);
 }
 
 /** Free a symmetric cipher.
@@ -1043,12 +1033,8 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_t *env,
   tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN);
   tor_assert(tolen >= pkeylen);
 
-  cipher = crypto_cipher_new();
-  if (!cipher) return -1;
-  if (crypto_cipher_generate_key(cipher)<0)
-    goto err;
-  if (crypto_cipher_encrypt_init_cipher(cipher)<0)
-    goto err;
+  cipher = crypto_cipher_new(NULL); /* generate a new key. */
+
   buf = tor_malloc(pkeylen+1);
   memcpy(buf, cipher->key, CIPHER_KEY_LEN);
   memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN);
@@ -1113,7 +1099,7 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_t *env,
            "No room for a symmetric key");
     goto err;
   }
-  cipher = crypto_create_init_cipher(buf, 0);
+  cipher = crypto_cipher_new(buf);
   if (!cipher) {
     goto err;
   }
@@ -1301,49 +1287,6 @@ crypto_pk_check_fingerprint_syntax(const char *s)
 
 /* symmetric crypto */
 
-/** Generate a new random key for the symmetric cipher in <b>env</b>.
- * Return 0 on success, -1 on failure.  Does not initialize the cipher.
- */
-int
-crypto_cipher_generate_key(crypto_cipher_t *env)
-{
-  tor_assert(env);
-
-  return crypto_rand(env->key, CIPHER_KEY_LEN);
-}
-
-/** Set the symmetric key for the cipher in <b>env</b> to the first
- * CIPHER_KEY_LEN bytes of <b>key</b>. Does not initialize the cipher.
- */
-void
-crypto_cipher_set_key(crypto_cipher_t *env, const char *key)
-{
-  tor_assert(env);
-  tor_assert(key);
-
-  memcpy(env->key, key, CIPHER_KEY_LEN);
-}
-
-/** Generate an initialization vector for our AES-CTR cipher; store it
- * in the first CIPHER_IV_LEN bytes of <b>iv_out</b>. */
-void
-crypto_cipher_generate_iv(char *iv_out)
-{
-  crypto_rand(iv_out, CIPHER_IV_LEN);
-}
-
-/** Adjust the counter of <b>env</b> to point to the first byte of the block
- * corresponding to the encryption of the CIPHER_IV_LEN bytes at
- * <b>iv</b>.  */
-int
-crypto_cipher_set_iv(crypto_cipher_t *env, const char *iv)
-{
-  tor_assert(env);
-  tor_assert(iv);
-  aes_set_iv(env->cipher, iv);
-  return 0;
-}
-
 /** Return a pointer to the key set for the cipher in <b>env</b>.
  */
 const char *
@@ -1352,30 +1295,6 @@ crypto_cipher_get_key(crypto_cipher_t *env)
   return env->key;
 }
 
-/** Initialize the cipher in <b>env</b> for encryption.  Return 0 on
- * success, -1 on failure.
- */
-int
-crypto_cipher_encrypt_init_cipher(crypto_cipher_t *env)
-{
-  tor_assert(env);
-
-  aes_set_key(env->cipher, env->key, CIPHER_KEY_LEN*8);
-  return 0;
-}
-
-/** Initialize the cipher in <b>env</b> for decryption. Return 0 on
- * success, -1 on failure.
- */
-int
-crypto_cipher_decrypt_init_cipher(crypto_cipher_t *env)
-{
-  tor_assert(env);
-
-  aes_set_key(env->cipher, env->key, CIPHER_KEY_LEN*8);
-  return 0;
-}
-
 /** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher
  * <b>env</b>; on success, store the result to <b>to</b> and return 0.
  * On failure, return -1.
@@ -1424,20 +1343,17 @@ crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len)
 }
 
 /** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in
- * <b>cipher</b> to the buffer in <b>to</b> of length
+ * <b>key</b> to the buffer in <b>to</b> of length
  * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus
  * CIPHER_IV_LEN bytes for the initialization vector. On success, return the
  * number of bytes written, on failure, return -1.
- *
- * This function adjusts the current position of the counter in <b>cipher</b>
- * to immediately after the encrypted data.
  */
 int
-crypto_cipher_encrypt_with_iv(crypto_cipher_t *cipher,
+crypto_cipher_encrypt_with_iv(const char *key,
                               char *to, size_t tolen,
                               const char *from, size_t fromlen)
 {
-  tor_assert(cipher);
+  crypto_cipher_t *cipher;
   tor_assert(from);
   tor_assert(to);
   tor_assert(fromlen < INT_MAX);
@@ -1447,28 +1363,27 @@ crypto_cipher_encrypt_with_iv(crypto_cipher_t *cipher,
   if (tolen < fromlen + CIPHER_IV_LEN)
     return -1;
 
-  crypto_cipher_generate_iv(to);
-  if (crypto_cipher_set_iv(cipher, to)<0)
-    return -1;
+  cipher = crypto_cipher_new_with_iv(key, NULL);
+
+  memcpy(to, cipher->iv, CIPHER_IV_LEN);
   crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen);
+  crypto_cipher_free(cipher);
   return (int)(fromlen + CIPHER_IV_LEN);
 }
 
 /** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b>
- * with the key in <b>cipher</b> to the buffer in <b>to</b> of length
+ * with the key in <b>key</b> to the buffer in <b>to</b> of length
  * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus
  * CIPHER_IV_LEN bytes for the initialization vector. On success, return the
  * number of bytes written, on failure, return -1.
- *
- * This function adjusts the current position of the counter in <b>cipher</b>
- * to immediately after the decrypted data.
  */
 int
-crypto_cipher_decrypt_with_iv(crypto_cipher_t *cipher,
+crypto_cipher_decrypt_with_iv(const char *key,
                               char *to, size_t tolen,
                               const char *from, size_t fromlen)
 {
-  tor_assert(cipher);
+  crypto_cipher_t *cipher;
+  tor_assert(key);
   tor_assert(from);
   tor_assert(to);
   tor_assert(fromlen < INT_MAX);
@@ -1478,9 +1393,10 @@ crypto_cipher_decrypt_with_iv(crypto_cipher_t *cipher,
   if (tolen < fromlen - CIPHER_IV_LEN)
     return -1;
 
-  if (crypto_cipher_set_iv(cipher, from)<0)
-    return -1;
+  cipher = crypto_cipher_new_with_iv(key, from);
+
   crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN);
+  crypto_cipher_free(cipher);
   return (int)(fromlen - CIPHER_IV_LEN);
 }
 

+ 4 - 13
src/common/crypto.h

@@ -125,11 +125,8 @@ void crypto_pk_free(crypto_pk_t *env);
 
 void crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname);
 
-/* convenience function: wraps crypto_cipher_new, set_key, and init. */
-crypto_cipher_t *crypto_create_init_cipher(const char *key,
-                                               int encrypt_mode);
-
-crypto_cipher_t *crypto_cipher_new(void);
+crypto_cipher_t *crypto_cipher_new(const char *key);
+crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv);
 void crypto_cipher_free(crypto_cipher_t *env);
 
 /* public key crypto */
@@ -189,13 +186,7 @@ int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
 int crypto_pk_check_fingerprint_syntax(const char *s);
 
 /* symmetric crypto */
-int crypto_cipher_generate_key(crypto_cipher_t *env);
-void crypto_cipher_set_key(crypto_cipher_t *env, const char *key);
-void crypto_cipher_generate_iv(char *iv_out);
-int crypto_cipher_set_iv(crypto_cipher_t *env, const char *iv);
 const char *crypto_cipher_get_key(crypto_cipher_t *env);
-int crypto_cipher_encrypt_init_cipher(crypto_cipher_t *env);
-int crypto_cipher_decrypt_init_cipher(crypto_cipher_t *env);
 
 int crypto_cipher_encrypt(crypto_cipher_t *env, char *to,
                           const char *from, size_t fromlen);
@@ -203,10 +194,10 @@ int crypto_cipher_decrypt(crypto_cipher_t *env, char *to,
                           const char *from, size_t fromlen);
 int crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *d, size_t len);
 
-int crypto_cipher_encrypt_with_iv(crypto_cipher_t *env,
+int crypto_cipher_encrypt_with_iv(const char *key,
                                   char *to, size_t tolen,
                                   const char *from, size_t fromlen);
-int crypto_cipher_decrypt_with_iv(crypto_cipher_t *env,
+int crypto_cipher_decrypt_with_iv(const char *key,
                                   char *to, size_t tolen,
                                   const char *from, size_t fromlen);
 

+ 2 - 2
src/or/circuitbuild.c

@@ -2334,12 +2334,12 @@ circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
   crypto_digest_add_bytes(cpath->b_digest, key_data+DIGEST_LEN, DIGEST_LEN);
 
   if (!(cpath->f_crypto =
-        crypto_create_init_cipher(key_data+(2*DIGEST_LEN),1))) {
+        crypto_cipher_new(key_data+(2*DIGEST_LEN)))) {
     log_warn(LD_BUG,"Forward cipher initialization failed.");
     return -1;
   }
   if (!(cpath->b_crypto =
-        crypto_create_init_cipher(key_data+(2*DIGEST_LEN)+CIPHER_KEY_LEN,0))) {
+        crypto_cipher_new(key_data+(2*DIGEST_LEN)+CIPHER_KEY_LEN))) {
     log_warn(LD_BUG,"Backward cipher initialization failed.");
     return -1;
   }

+ 5 - 8
src/or/rendcommon.c

@@ -290,11 +290,10 @@ rend_encrypt_v2_intro_points_basic(char **encrypted_out,
   enc[1] = (uint8_t)client_blocks;
 
   /* Encrypt with random session key. */
-  cipher = crypto_create_init_cipher(session_key, 1);
-  enclen = crypto_cipher_encrypt_with_iv(cipher,
+  enclen = crypto_cipher_encrypt_with_iv(session_key,
       enc + 2 + client_entries_len,
       CIPHER_IV_LEN + strlen(encoded), encoded, strlen(encoded));
-  crypto_cipher_free(cipher);
+
   if (enclen < 0) {
     log_warn(LD_REND, "Could not encrypt introduction point string.");
     goto done;
@@ -307,7 +306,7 @@ rend_encrypt_v2_intro_points_basic(char **encrypted_out,
   SMARTLIST_FOREACH_BEGIN(client_cookies, const char *, cookie) {
     client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
     /* Encrypt session key. */
-    cipher = crypto_create_init_cipher(cookie, 1);
+    cipher = crypto_cipher_new(cookie);
     if (crypto_cipher_encrypt(cipher, client_part +
                                   REND_BASIC_AUTH_CLIENT_ID_LEN,
                               session_key, CIPHER_KEY_LEN) < 0) {
@@ -374,18 +373,16 @@ rend_encrypt_v2_intro_points_stealth(char **encrypted_out,
                                      const char *descriptor_cookie)
 {
   int r = -1, enclen;
-  crypto_cipher_t *cipher;
   char *enc;
   tor_assert(encoded);
   tor_assert(descriptor_cookie);
 
   enc = tor_malloc_zero(1 + CIPHER_IV_LEN + strlen(encoded));
   enc[0] = 0x02; /* Auth type */
-  cipher = crypto_create_init_cipher(descriptor_cookie, 1);
-  enclen = crypto_cipher_encrypt_with_iv(cipher, enc + 1,
+  enclen = crypto_cipher_encrypt_with_iv(descriptor_cookie,
+                                         enc + 1,
                                          CIPHER_IV_LEN+strlen(encoded),
                                          encoded, strlen(encoded));
-  crypto_cipher_free(cipher);
   if (enclen < 0) {
     log_warn(LD_REND, "Could not encrypt introduction point string.");
     goto done;

+ 7 - 8
src/or/routerparse.c

@@ -4887,7 +4887,7 @@ rend_decrypt_introduction_points(char **ipos_decrypted,
       if (tor_memeq(ipos_encrypted + pos, client_id,
                   REND_BASIC_AUTH_CLIENT_ID_LEN)) {
         /* Attempt to decrypt introduction points. */
-        cipher = crypto_create_init_cipher(descriptor_cookie, 0);
+        cipher = crypto_cipher_new(descriptor_cookie);
         if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
                                   + pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
                                   CIPHER_KEY_LEN) < 0) {
@@ -4896,13 +4896,13 @@ rend_decrypt_introduction_points(char **ipos_decrypted,
           return -1;
         }
         crypto_cipher_free(cipher);
-        cipher = crypto_create_init_cipher(session_key, 0);
+
         len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
         dec = tor_malloc(len);
-        declen = crypto_cipher_decrypt_with_iv(cipher, dec, len,
+        declen = crypto_cipher_decrypt_with_iv(session_key, dec, len,
             ipos_encrypted + 2 + client_entries_len,
             ipos_encrypted_size - 2 - client_entries_len);
-        crypto_cipher_free(cipher);
+
         if (declen < 0) {
           log_warn(LD_REND, "Could not decrypt introduction point string.");
           tor_free(dec);
@@ -4923,7 +4923,6 @@ rend_decrypt_introduction_points(char **ipos_decrypted,
              "check your authorization for this service!");
     return -1;
   } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
-    crypto_cipher_t *cipher;
     char *dec;
     int declen;
     if (ipos_encrypted_size < CIPHER_IV_LEN + 2) {
@@ -4932,13 +4931,13 @@ rend_decrypt_introduction_points(char **ipos_decrypted,
       return -1;
     }
     dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1);
-    cipher = crypto_create_init_cipher(descriptor_cookie, 0);
-    declen = crypto_cipher_decrypt_with_iv(cipher, dec,
+
+    declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec,
                                            ipos_encrypted_size -
                                                CIPHER_IV_LEN - 1,
                                            ipos_encrypted + 1,
                                            ipos_encrypted_size - 1);
-    crypto_cipher_free(cipher);
+
     if (declen < 0) {
       log_warn(LD_REND, "Decrypting introduction points failed!");
       tor_free(dec);

+ 5 - 12
src/test/bench.c

@@ -77,9 +77,8 @@ bench_aes(void)
   uint64_t start, end;
   const int bytes_per_iter = (1<<24);
   reset_perftime();
-  c = crypto_cipher_new();
-  crypto_cipher_generate_key(c);
-  crypto_cipher_encrypt_init_cipher(c);
+  c = crypto_cipher_new(NULL);
+
   for (len = 1; len <= 8192; len *= 2) {
     int iters = bytes_per_iter / len;
     b1 = tor_malloc_zero(len);
@@ -108,9 +107,7 @@ bench_cell_aes(void)
   crypto_cipher_t *c;
   int i, misalign;
 
-  c = crypto_cipher_new();
-  crypto_cipher_generate_key(c);
-  crypto_cipher_encrypt_init_cipher(c);
+  c = crypto_cipher_new(NULL);
 
   reset_perftime();
   for (misalign = 0; misalign <= max_misalign; ++misalign) {
@@ -221,12 +218,8 @@ bench_cell_ops(void)
   or_circ->_base.purpose = CIRCUIT_PURPOSE_OR;
 
   /* Initialize crypto */
-  or_circ->p_crypto = crypto_cipher_new();
-  crypto_cipher_generate_key(or_circ->p_crypto);
-  crypto_cipher_encrypt_init_cipher(or_circ->p_crypto);
-  or_circ->n_crypto = crypto_cipher_new();
-  crypto_cipher_generate_key(or_circ->n_crypto);
-  crypto_cipher_encrypt_init_cipher(or_circ->n_crypto);
+  or_circ->p_crypto = crypto_cipher_new(NULL);
+  or_circ->n_crypto = crypto_cipher_new(NULL);
   or_circ->p_digest = crypto_digest_new();
   or_circ->n_digest = crypto_digest_new();
 

+ 53 - 82
src/test/test_crypto.c

@@ -118,14 +118,10 @@ test_crypto_aes(void *arg)
 
   memset(data2, 0, 1024);
   memset(data3, 0, 1024);
-  env1 = crypto_cipher_new();
+  env1 = crypto_cipher_new(NULL);
   test_neq(env1, 0);
-  env2 = crypto_cipher_new();
+  env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
   test_neq(env2, 0);
-  j = crypto_cipher_generate_key(env1);
-  crypto_cipher_set_key(env2, crypto_cipher_get_key(env1));
-  crypto_cipher_encrypt_init_cipher(env1);
-  crypto_cipher_decrypt_init_cipher(env2);
 
   /* Try encrypting 512 chars. */
   crypto_cipher_encrypt(env1, data2, data1, 512);
@@ -155,10 +151,8 @@ test_crypto_aes(void *arg)
   env2 = NULL;
 
   memset(data3, 0, 1024);
-  env2 = crypto_cipher_new();
+  env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
   test_neq(env2, 0);
-  crypto_cipher_set_key(env2, crypto_cipher_get_key(env1));
-  crypto_cipher_encrypt_init_cipher(env2);
   for (j = 0; j < 1024-16; j += 17) {
     crypto_cipher_encrypt(env2, data3+j, data1+j, 17);
   }
@@ -174,10 +168,9 @@ test_crypto_aes(void *arg)
   env2 = NULL;
 
   /* NIST test vector for aes. */
-  env1 = crypto_cipher_new(); /* IV starts at 0 */
-  crypto_cipher_set_key(env1, "\x80\x00\x00\x00\x00\x00\x00\x00"
-                              "\x00\x00\x00\x00\x00\x00\x00\x00");
-  crypto_cipher_encrypt_init_cipher(env1);
+  /* IV starts at 0 */
+  env1 = crypto_cipher_new("\x80\x00\x00\x00\x00\x00\x00\x00"
+                           "\x00\x00\x00\x00\x00\x00\x00\x00");
   crypto_cipher_encrypt(env1, data1,
                         "\x00\x00\x00\x00\x00\x00\x00\x00"
                         "\x00\x00\x00\x00\x00\x00\x00\x00", 16);
@@ -185,37 +178,55 @@ test_crypto_aes(void *arg)
 
   /* Now test rollover.  All these values are originally from a python
    * script. */
-  crypto_cipher_set_iv(env1, "\x00\x00\x00\x00\x00\x00\x00\x00"
-                             "\xff\xff\xff\xff\xff\xff\xff\xff");
+  crypto_cipher_free(env1);
+  env1 = crypto_cipher_new_with_iv(
+                                   "\x80\x00\x00\x00\x00\x00\x00\x00"
+                                   "\x00\x00\x00\x00\x00\x00\x00\x00",
+                                   "\x00\x00\x00\x00\x00\x00\x00\x00"
+                                   "\xff\xff\xff\xff\xff\xff\xff\xff");
   memset(data2, 0,  1024);
   crypto_cipher_encrypt(env1, data1, data2, 32);
   test_memeq_hex(data1, "335fe6da56f843199066c14a00a40231"
                         "cdd0b917dbc7186908a6bfb5ffd574d3");
-
-  crypto_cipher_set_iv(env1, "\x00\x00\x00\x00\xff\xff\xff\xff"
-                             "\xff\xff\xff\xff\xff\xff\xff\xff");
+  crypto_cipher_free(env1);
+  env1 = crypto_cipher_new_with_iv(
+                                   "\x80\x00\x00\x00\x00\x00\x00\x00"
+                                   "\x00\x00\x00\x00\x00\x00\x00\x00",
+                                   "\x00\x00\x00\x00\xff\xff\xff\xff"
+                                   "\xff\xff\xff\xff\xff\xff\xff\xff");
   memset(data2, 0,  1024);
   crypto_cipher_encrypt(env1, data1, data2, 32);
   test_memeq_hex(data1, "e627c6423fa2d77832a02b2794094b73"
                         "3e63c721df790d2c6469cc1953a3ffac");
-
-  crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
-                             "\xff\xff\xff\xff\xff\xff\xff\xff");
+  crypto_cipher_free(env1);
+  env1 = crypto_cipher_new_with_iv(
+                                   "\x80\x00\x00\x00\x00\x00\x00\x00"
+                                   "\x00\x00\x00\x00\x00\x00\x00\x00",
+                                   "\xff\xff\xff\xff\xff\xff\xff\xff"
+                                   "\xff\xff\xff\xff\xff\xff\xff\xff");
   memset(data2, 0,  1024);
   crypto_cipher_encrypt(env1, data1, data2, 32);
   test_memeq_hex(data1, "2aed2bff0de54f9328efd070bf48f70a"
                         "0EDD33D3C621E546455BD8BA1418BEC8");
 
   /* Now check rollover on inplace cipher. */
-  crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
-                             "\xff\xff\xff\xff\xff\xff\xff\xff");
+  crypto_cipher_free(env1);
+  env1 = crypto_cipher_new_with_iv(
+                                   "\x80\x00\x00\x00\x00\x00\x00\x00"
+                                   "\x00\x00\x00\x00\x00\x00\x00\x00",
+                                   "\xff\xff\xff\xff\xff\xff\xff\xff"
+                                   "\xff\xff\xff\xff\xff\xff\xff\xff");
   crypto_cipher_crypt_inplace(env1, data2, 64);
   test_memeq_hex(data2, "2aed2bff0de54f9328efd070bf48f70a"
                         "0EDD33D3C621E546455BD8BA1418BEC8"
                         "93e2c5243d6839eac58503919192f7ae"
                         "1908e67cafa08d508816659c2e693191");
-  crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
-                             "\xff\xff\xff\xff\xff\xff\xff\xff");
+  crypto_cipher_free(env1);
+  env1 = crypto_cipher_new_with_iv(
+                                   "\x80\x00\x00\x00\x00\x00\x00\x00"
+                                   "\x00\x00\x00\x00\x00\x00\x00\x00",
+                                   "\xff\xff\xff\xff\xff\xff\xff\xff"
+                                   "\xff\xff\xff\xff\xff\xff\xff\xff");
   crypto_cipher_crypt_inplace(env1, data2, 64);
   test_assert(tor_mem_is_zero(data2, 64));
 
@@ -674,7 +685,6 @@ test_crypto_s2k(void)
 static void
 test_crypto_aes_iv(void *arg)
 {
-  crypto_cipher_t *cipher;
   char *plain, *encrypted1, *encrypted2, *decrypted1, *decrypted2;
   char plain_1[1], plain_15[15], plain_16[16], plain_17[17];
   char key1[16], key2[16];
@@ -698,113 +708,76 @@ test_crypto_aes_iv(void *arg)
   crypto_rand(plain_17, 17);
   key1[0] = key2[0] + 128; /* Make sure that contents are different. */
   /* Encrypt and decrypt with the same key. */
-  cipher = crypto_create_init_cipher(key1, 1);
-  encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 4095,
+  encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 4095,
                                                  plain, 4095);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
+
   test_eq(encrypted_size, 16 + 4095);
   tt_assert(encrypted_size > 0); /* This is obviously true, since 4111 is
                                    * greater than 0, but its truth is not
                                    * obvious to all analysis tools. */
-  cipher = crypto_create_init_cipher(key1, 0);
-  decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 4095,
+  decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
                                              encrypted1, encrypted_size);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
+
   test_eq(decrypted_size, 4095);
   tt_assert(decrypted_size > 0);
   test_memeq(plain, decrypted1, 4095);
   /* Encrypt a second time (with a new random initialization vector). */
-  cipher = crypto_create_init_cipher(key1, 1);
-  encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted2, 16 + 4095,
+  encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted2, 16 + 4095,
                                              plain, 4095);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
+
   test_eq(encrypted_size, 16 + 4095);
   tt_assert(encrypted_size > 0);
-  cipher = crypto_create_init_cipher(key1, 0);
-  decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted2, 4095,
+  decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted2, 4095,
                                              encrypted2, encrypted_size);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_eq(decrypted_size, 4095);
   tt_assert(decrypted_size > 0);
   test_memeq(plain, decrypted2, 4095);
   test_memneq(encrypted1, encrypted2, encrypted_size);
   /* Decrypt with the wrong key. */
-  cipher = crypto_create_init_cipher(key2, 0);
-  decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted2, 4095,
+  decrypted_size = crypto_cipher_decrypt_with_iv(key2, decrypted2, 4095,
                                              encrypted1, encrypted_size);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_memneq(plain, decrypted2, encrypted_size);
   /* Alter the initialization vector. */
   encrypted1[0] += 42;
-  cipher = crypto_create_init_cipher(key1, 0);
-  decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 4095,
+  decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
                                              encrypted1, encrypted_size);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_memneq(plain, decrypted2, 4095);
   /* Special length case: 1. */
-  cipher = crypto_create_init_cipher(key1, 1);
-  encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 1,
+  encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 1,
                                              plain_1, 1);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_eq(encrypted_size, 16 + 1);
   tt_assert(encrypted_size > 0);
-  cipher = crypto_create_init_cipher(key1, 0);
-  decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 1,
+  decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 1,
                                              encrypted1, encrypted_size);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_eq(decrypted_size, 1);
   tt_assert(decrypted_size > 0);
   test_memeq(plain_1, decrypted1, 1);
   /* Special length case: 15. */
-  cipher = crypto_create_init_cipher(key1, 1);
-  encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 15,
+  encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 15,
                                              plain_15, 15);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_eq(encrypted_size, 16 + 15);
   tt_assert(encrypted_size > 0);
-  cipher = crypto_create_init_cipher(key1, 0);
-  decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 15,
+  decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 15,
                                              encrypted1, encrypted_size);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_eq(decrypted_size, 15);
   tt_assert(decrypted_size > 0);
   test_memeq(plain_15, decrypted1, 15);
   /* Special length case: 16. */
-  cipher = crypto_create_init_cipher(key1, 1);
-  encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 16,
+  encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 16,
                                              plain_16, 16);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_eq(encrypted_size, 16 + 16);
   tt_assert(encrypted_size > 0);
-  cipher = crypto_create_init_cipher(key1, 0);
-  decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 16,
+  decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 16,
                                              encrypted1, encrypted_size);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_eq(decrypted_size, 16);
   tt_assert(decrypted_size > 0);
   test_memeq(plain_16, decrypted1, 16);
   /* Special length case: 17. */
-  cipher = crypto_create_init_cipher(key1, 1);
-  encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 17,
+  encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 17,
                                              plain_17, 17);
-  crypto_cipher_free(cipher);
-  cipher = NULL;
   test_eq(encrypted_size, 16 + 17);
   tt_assert(encrypted_size > 0);
-  cipher = crypto_create_init_cipher(key1, 0);
-  decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 17,
+  decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 17,
                                              encrypted1, encrypted_size);
   test_eq(decrypted_size, 17);
   tt_assert(decrypted_size > 0);
@@ -817,8 +790,6 @@ test_crypto_aes_iv(void *arg)
   tor_free(encrypted2);
   tor_free(decrypted1);
   tor_free(decrypted2);
-  if (cipher)
-    crypto_cipher_free(cipher);
 }
 
 /** Test base32 decoding. */