]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Move tor1 crypto functions into new file
authorNick Mathewson <nickm@torproject.org>
Wed, 28 May 2025 15:12:54 +0000 (11:12 -0400)
committerNick Mathewson <nickm@torproject.org>
Tue, 10 Jun 2025 23:06:47 +0000 (19:06 -0400)
(I'd recommend reviewing this with "show -b --color-moved")

src/core/crypto/include.am
src/core/crypto/relay_crypto.c
src/core/crypto/relay_crypto.h
src/core/crypto/relay_crypto_tor1.c [new file with mode: 0644]
src/core/crypto/relay_crypto_tor1.h [new file with mode: 0644]

index 9898220f0d05a8890c68b94c6543102e7ae9da32..b0c148619565eb34f4961376aebbfda385980c61 100644 (file)
@@ -7,7 +7,8 @@ LIBTOR_APP_A_SOURCES +=                                 \
        src/core/crypto/onion_ntor.c            \
        src/core/crypto/onion_ntor_v3.c         \
        src/core/crypto/relay_crypto.c          \
-        src/core/crypto/relay_crypto_cgo.c
+        src/core/crypto/relay_crypto_cgo.c      \
+        src/core/crypto/relay_crypto_tor1.c
 
 # ADD_C_FILE: INSERT HEADERS HERE.
 noinst_HEADERS +=                                      \
@@ -17,4 +18,5 @@ noinst_HEADERS +=                                     \
        src/core/crypto/onion_ntor.h                    \
        src/core/crypto/onion_ntor_v3.h                 \
        src/core/crypto/relay_crypto.h                  \
-        src/core/crypto/relay_crypto_cgo.h
+        src/core/crypto/relay_crypto_cgo.h              \
+       src/core/crypto/relay_crypto_tor1.h
index 2f30306605498b55c776510879030aab9dd22b24..9b9f623cc324c8bfced20884e15c7083dd5d6075 100644 (file)
 #include "app/config/config.h"
 #include "lib/crypt_ops/crypto_cipher.h"
 #include "lib/crypt_ops/crypto_util.h"
-#include "core/crypto/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN
-#include "core/or/relay.h"
 #include "core/crypto/relay_crypto.h"
+#include "core/crypto/relay_crypto_tor1.h"
 #include "core/or/sendme.h"
-#include "lib/cc/ctassert.h"
 
-#include "core/or/cell_st.h"
 #include "core/or/or_circuit_st.h"
 #include "core/or/origin_circuit_st.h"
 
-#include "core/or/congestion_control_common.h" // XXXX refactor.
-
 /* TODO CGO: This file will be largely incorrect when we have
  * CGO crypto. */
 
 // XXXX: Remove this definition once I'm done refactoring.
 #define pvt_crypto crypto_crypt_path_private_field
 
-/* Offset of digest within relay cell body for v0 cells. */
-#define V0_DIGEST_OFFSET 5
-#define V0_DIGEST_LEN 4
-#define V0_RECOGNIZED_OFFSET 1
-
-/** Update digest from the payload of cell. Assign integrity part to
- * cell.  Record full 20-byte digest in `buf`.
- */
-static void
-tor1_set_digest_v0(crypto_digest_t *digest, cell_t *cell, uint8_t *buf)
-{
-  crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE);
-  crypto_digest_get_digest(digest, (char*)buf, DIGEST_LEN);
-//  log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.",
-//    integrity[0], integrity[1], integrity[2], integrity[3]);
-  memcpy(cell->payload + V0_DIGEST_OFFSET, buf, V0_DIGEST_LEN);
-}
-
-/** Does the digest for this circuit indicate that this cell is for us?
- *
- * Update digest from the payload of cell (with the integrity part set
- * to 0). If the integrity part is valid,
- * return 1 and save the full digest in the 20-byte buffer `buf`,
- * else restore digest
- * and cell to their original state and return 0.
- */
-static int
-tor1_relay_digest_matches_v0(crypto_digest_t *digest, cell_t *cell,
-                             uint8_t *buf)
-{
-  uint32_t received_integrity, calculated_integrity;
-  uint8_t calculated_digest[DIGEST_LEN];
-  crypto_digest_checkpoint_t backup_digest;
-
-  CTASSERT(sizeof(uint32_t) == V0_DIGEST_LEN);
-
-  crypto_digest_checkpoint(&backup_digest, digest);
-
-  memcpy(&received_integrity, cell->payload + V0_DIGEST_OFFSET, V0_DIGEST_LEN);
-  memset(cell->payload + V0_DIGEST_OFFSET, 0, V0_DIGEST_LEN);
-
-//  log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.",
-//    received_integrity[0], received_integrity[1],
-//    received_integrity[2], received_integrity[3]);
-
-  crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE);
-  crypto_digest_get_digest(digest, (char*) calculated_digest, DIGEST_LEN);
-  calculated_integrity = get_uint32(calculated_digest);
-
-  int rv = 1;
-
-  if (calculated_integrity != received_integrity) {
-//    log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing.");
-// (%d vs %d).", received_integrity, calculated_integrity);
-    /* restore digest to its old form */
-    crypto_digest_restore(digest, &backup_digest);
-    /* restore the relay header */
-    memcpy(cell->payload + V0_DIGEST_OFFSET, &received_integrity,
-           V0_DIGEST_LEN);
-    rv = 0;
-  } else {
-    memcpy(buf, calculated_digest, DIGEST_LEN);
-  }
-
-  memwipe(&backup_digest, 0, sizeof(backup_digest));
-  return rv;
-}
-
-static inline bool
-relay_cell_is_recognized_v0(const cell_t *cell)
-{
-  return get_uint16(cell->payload + V0_RECOGNIZED_OFFSET) == 0;
-}
-
-/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b>
- * (in place).
- *
- * Note that we use the same operation for encrypting and for decrypting.
- */
-void
-tor1_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
-{
-  crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE);
-}
-
-/* XXXX DOCDOC */
-void
-tor1_crypt_client_originate(relay_crypto_t *tor1,
-                            cell_t *cell)
-{
-  tor1_set_digest_v0(tor1->f_digest, cell, tor1->sendme_digest);
-  tor1_crypt_one_payload(tor1->f_crypto, cell->payload);
-}
-
-/* XXXX DOCDOC */
-void
-tor1_crypt_relay_originate(relay_crypto_t *tor1,
-                           cell_t *cell)
-{
-  tor1_set_digest_v0(tor1->b_digest, cell, tor1->sendme_digest);
-  tor1_crypt_one_payload(tor1->b_crypto, cell->payload);
-}
-
-/* XXXX DOCDOC */
-void
-tor1_crypt_client_forward(relay_crypto_t *tor1, cell_t *cell)
-{
-  tor1_crypt_one_payload(tor1->f_crypto, cell->payload);
-}
-
-/* XXXX DOCDOC */
-void
-tor1_crypt_relay_backward(relay_crypto_t *tor1, cell_t *cell)
-{
-  tor1_crypt_one_payload(tor1->b_crypto, cell->payload);
-}
-
-/* XXXX DOCDOC */
-bool
-tor1_crypt_relay_forward(relay_crypto_t *tor1, cell_t *cell)
-{
-  tor1_crypt_one_payload(tor1->f_crypto, cell->payload);
-  if (relay_cell_is_recognized_v0(cell)) {
-    if (tor1_relay_digest_matches_v0(tor1->f_digest, cell,
-                                     tor1->sendme_digest)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-/* XXXX DOCDOC */
-bool
-tor1_crypt_client_backward(relay_crypto_t *tor1, cell_t *cell)
-{
-  tor1_crypt_one_payload(tor1->b_crypto, cell->payload);
-
-  if (relay_cell_is_recognized_v0(cell)) {
-    if (tor1_relay_digest_matches_v0(tor1->b_digest, cell,
-                                     tor1->sendme_digest)) {
-      return true;
-    }
-  }
-  return false;
-}
-
 /** Return the sendme_digest within the <b>crypto</b> object.
  *
  * This is the digest from the most recent cell that we originated
@@ -308,12 +157,7 @@ relay_encrypt_cell_inbound(cell_t *cell,
 void
 relay_crypto_clear(relay_crypto_t *crypto)
 {
-  if (BUG(!crypto))
-    return;
-  crypto_cipher_free(crypto->f_crypto);
-  crypto_cipher_free(crypto->b_crypto);
-  crypto_digest_free(crypto->f_digest);
-  crypto_digest_free(crypto->b_digest);
+  tor1_crypt_clear(crypto);
 }
 
 /** Initialize <b>crypto</b> from the key material in key_data.
@@ -338,80 +182,12 @@ relay_crypto_init(relay_crypto_t *crypto,
                   const char *key_data, size_t key_data_len,
                   int reverse, int is_hs_v3)
 {
-  crypto_digest_t *tmp_digest;
-  crypto_cipher_t *tmp_crypto;
-  size_t digest_len = 0;
-  size_t cipher_key_len = 0;
-
-  tor_assert(crypto);
-  tor_assert(key_data);
-  tor_assert(!(crypto->f_crypto || crypto->b_crypto ||
-             crypto->f_digest || crypto->b_digest));
-
-  /* Basic key size validation */
-  if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
-    goto err;
-  } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) {
-    goto err;
-  }
-
-  /* If we are using this crypto for next gen onion services use SHA3-256,
-     otherwise use good ol' SHA1 */
-  if (is_hs_v3) {
-    digest_len = DIGEST256_LEN;
-    cipher_key_len = CIPHER256_KEY_LEN;
-    crypto->f_digest = crypto_digest256_new(DIGEST_SHA3_256);
-    crypto->b_digest = crypto_digest256_new(DIGEST_SHA3_256);
-  } else {
-    digest_len = DIGEST_LEN;
-    cipher_key_len = CIPHER_KEY_LEN;
-    crypto->f_digest = crypto_digest_new();
-    crypto->b_digest = crypto_digest_new();
-  }
-
-  tor_assert(digest_len != 0);
-  tor_assert(cipher_key_len != 0);
-  const int cipher_key_bits = (int) cipher_key_len * 8;
-
-  crypto_digest_add_bytes(crypto->f_digest, key_data, digest_len);
-  crypto_digest_add_bytes(crypto->b_digest, key_data+digest_len, digest_len);
-
-  crypto->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len),
-                                                cipher_key_bits);
-  if (!crypto->f_crypto) {
-    log_warn(LD_BUG,"Forward cipher initialization failed.");
-    goto err;
-  }
-
-  crypto->b_crypto = crypto_cipher_new_with_bits(
-                                        key_data+(2*digest_len)+cipher_key_len,
-                                        cipher_key_bits);
-  if (!crypto->b_crypto) {
-    log_warn(LD_BUG,"Backward cipher initialization failed.");
-    goto err;
-  }
-
-  if (reverse) {
-    tmp_digest = crypto->f_digest;
-    crypto->f_digest = crypto->b_digest;
-    crypto->b_digest = tmp_digest;
-    tmp_crypto = crypto->f_crypto;
-    crypto->f_crypto = crypto->b_crypto;
-    crypto->b_crypto = tmp_crypto;
-  }
-
-  return 0;
- err:
-  relay_crypto_clear(crypto);
-  return -1;
+  return tor1_crypt_init(crypto, key_data, key_data_len, reverse, is_hs_v3);
 }
 
 /** Assert that <b>crypto</b> is valid and set. */
 void
 relay_crypto_assert_ok(const relay_crypto_t *crypto)
 {
-  tor_assert(crypto->f_crypto);
-  tor_assert(crypto->b_crypto);
-  tor_assert(crypto->f_digest);
-  tor_assert(crypto->b_digest);
+  tor1_crypt_assert_ok(crypto);
 }
index 59e00d1ae9b24606f6d837e121e21fea3b36604f..34bf189b736b2ada1a546ad2e7284723447a138c 100644 (file)
@@ -29,15 +29,4 @@ void relay_crypto_assert_ok(const relay_crypto_t *crypto);
 
 const uint8_t *relay_crypto_get_sendme_digest(relay_crypto_t *crypto);
 
-void tor1_crypt_client_originate(tor1_crypt_t *tor1,
-                                 cell_t *cell);
-void tor1_crypt_relay_originate(tor1_crypt_t *tor1,
-                                cell_t *cell);
-void tor1_crypt_relay_backward(tor1_crypt_t *tor1, cell_t *cell);
-bool tor1_crypt_relay_forward(tor1_crypt_t *tor1, cell_t *cell);
-bool tor1_crypt_client_backward(tor1_crypt_t *tor1, cell_t *cell);
-void tor1_crypt_client_forward(tor1_crypt_t *tor1, cell_t *cell);
-
-void tor1_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in);
-
 #endif /* !defined(TOR_RELAY_CRYPTO_H) */
diff --git a/src/core/crypto/relay_crypto_tor1.c b/src/core/crypto/relay_crypto_tor1.c
new file mode 100644 (file)
index 0000000..21e0139
--- /dev/null
@@ -0,0 +1,303 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_crypto_tor1.c
+ * @brief Implementation for legacy (tor1) relay cell encryption.
+ **/
+
+#include "core/or/or.h"
+#include "lib/crypt_ops/crypto_cipher.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "core/crypto/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN
+#include "core/crypto/relay_crypto_tor1.h"
+#include "lib/cc/ctassert.h"
+
+#include "core/or/cell_st.h"
+#include "core/or/relay_crypto_st.h"
+
+/* Offset of digest within relay cell body for v0 cells. */
+#define V0_DIGEST_OFFSET 5
+#define V0_DIGEST_LEN 4
+#define V0_RECOGNIZED_OFFSET 1
+
+/** Update digest from the payload of cell. Assign integrity part to
+ * cell.  Record full 20-byte digest in `buf`.
+ */
+static void
+tor1_set_digest_v0(crypto_digest_t *digest, cell_t *cell, uint8_t *buf)
+{
+  crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE);
+  crypto_digest_get_digest(digest, (char*)buf, DIGEST_LEN);
+//  log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.",
+//    integrity[0], integrity[1], integrity[2], integrity[3]);
+  memcpy(cell->payload + V0_DIGEST_OFFSET, buf, V0_DIGEST_LEN);
+}
+
+/** Does the digest for this circuit indicate that this cell is for us?
+ *
+ * Update digest from the payload of cell (with the integrity part set
+ * to 0). If the integrity part is valid,
+ * return 1 and save the full digest in the 20-byte buffer `buf`,
+ * else restore digest
+ * and cell to their original state and return 0.
+ */
+static int
+tor1_relay_digest_matches_v0(crypto_digest_t *digest, cell_t *cell,
+                             uint8_t *buf)
+{
+  uint32_t received_integrity, calculated_integrity;
+  uint8_t calculated_digest[DIGEST_LEN];
+  crypto_digest_checkpoint_t backup_digest;
+
+  CTASSERT(sizeof(uint32_t) == V0_DIGEST_LEN);
+
+  crypto_digest_checkpoint(&backup_digest, digest);
+
+  memcpy(&received_integrity, cell->payload + V0_DIGEST_OFFSET, V0_DIGEST_LEN);
+  memset(cell->payload + V0_DIGEST_OFFSET, 0, V0_DIGEST_LEN);
+
+//  log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.",
+//    received_integrity[0], received_integrity[1],
+//    received_integrity[2], received_integrity[3]);
+
+  crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE);
+  crypto_digest_get_digest(digest, (char*) calculated_digest, DIGEST_LEN);
+  calculated_integrity = get_uint32(calculated_digest);
+
+  int rv = 1;
+
+  if (calculated_integrity != received_integrity) {
+//    log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing.");
+// (%d vs %d).", received_integrity, calculated_integrity);
+    /* restore digest to its old form */
+    crypto_digest_restore(digest, &backup_digest);
+    /* restore the relay header */
+    memcpy(cell->payload + V0_DIGEST_OFFSET, &received_integrity,
+           V0_DIGEST_LEN);
+    rv = 0;
+  } else {
+    memcpy(buf, calculated_digest, DIGEST_LEN);
+  }
+
+  memwipe(&backup_digest, 0, sizeof(backup_digest));
+  return rv;
+}
+
+static inline bool
+relay_cell_is_recognized_v0(const cell_t *cell)
+{
+  return get_uint16(cell->payload + V0_RECOGNIZED_OFFSET) == 0;
+}
+
+/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b>
+ * (in place).
+ *
+ * Note that we use the same operation for encrypting and for decrypting.
+ */
+static void
+tor1_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
+{
+  crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE);
+}
+
+/** Encrypt and authenticate `cell` using the cryptographic
+ * material in `tor1`.
+ *
+ * This method should be used for the first encryption performed
+ * by the client - that is, the one corresponding to the exit node.
+ */
+void
+tor1_crypt_client_originate(tor1_crypt_t *tor1,
+                            cell_t *cell)
+{
+  tor1_set_digest_v0(tor1->f_digest, cell, tor1->sendme_digest);
+  tor1_crypt_one_payload(tor1->f_crypto, cell->payload);
+}
+
+/** Encrypt and authenticate `cell`, using the cryptographic
+ * material in `tor1`.
+ *
+ * This method should be used by relays when originating cells toward the
+ * client.
+ */
+void
+tor1_crypt_relay_originate(tor1_crypt_t *tor1,
+                           cell_t *cell)
+{
+  tor1_set_digest_v0(tor1->b_digest, cell, tor1->sendme_digest);
+  tor1_crypt_one_payload(tor1->b_crypto, cell->payload);
+}
+
+/** Encrypt `cell` using the cryptographic material in `tor1`.
+ *
+ * This method should be used by clients for cryptographic layers
+ * that are _not_ the final recipient of the cell. */
+void
+tor1_crypt_client_forward(tor1_crypt_t *tor1, cell_t *cell)
+{
+  tor1_crypt_one_payload(tor1->f_crypto, cell->payload);
+}
+
+/** Encrypt `cell` using the cryptographic material in `tor1`.
+ *
+ * This method should be used by relays on cells that are moving
+ * toward the client. */
+void
+tor1_crypt_relay_backward(tor1_crypt_t *tor1, cell_t *cell)
+{
+  tor1_crypt_one_payload(tor1->b_crypto, cell->payload);
+}
+
+/** Decrypt `cell` using the cryptographic material in `tor1`.
+ *
+ * Return `true` when we are the destination for this cell.
+ *
+ * This method should be used by relays on cells
+ * that are moving away from the client. */
+bool
+tor1_crypt_relay_forward(tor1_crypt_t *tor1, cell_t *cell)
+{
+  tor1_crypt_one_payload(tor1->f_crypto, cell->payload);
+  if (relay_cell_is_recognized_v0(cell)) {
+    if (tor1_relay_digest_matches_v0(tor1->f_digest, cell,
+                                     tor1->sendme_digest)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/** Decrypt `cell` using  the cryptographic material in `tor1`.
+ *
+ * Return `true` when this cell is recognized and authenticated
+ * as coming from the relay that also holds this cryptographic material.
+ *
+ * This method should be used by clients on incoming cells. */
+bool
+tor1_crypt_client_backward(tor1_crypt_t *tor1, cell_t *cell)
+{
+  tor1_crypt_one_payload(tor1->b_crypto, cell->payload);
+
+  if (relay_cell_is_recognized_v0(cell)) {
+    if (tor1_relay_digest_matches_v0(tor1->b_digest, cell,
+                                     tor1->sendme_digest)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/** Initialize <b>crypto</b> from the key material in key_data.
+ *
+ * If <b>is_hs_v3</b> is set, this cpath will be used for next gen hidden
+ * service circuits and <b>key_data</b> must be at least
+ * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length.
+ *
+ * If <b>is_hs_v3</b> is not set, key_data must contain CPATH_KEY_MATERIAL_LEN
+ * bytes, which are used as follows:
+ *   - 20 to initialize f_digest
+ *   - 20 to initialize b_digest
+ *   - 16 to key f_crypto
+ *   - 16 to key b_crypto
+ *
+ * (If 'reverse' is true, then f_XX and b_XX are swapped.)
+ *
+ * Return 0 if init was successful, else -1 if it failed.
+ */
+int
+tor1_crypt_init(tor1_crypt_t *crypto,
+                 const char *key_data, size_t key_data_len,
+                 int reverse, int is_hs_v3)
+{
+  crypto_digest_t *tmp_digest;
+  crypto_cipher_t *tmp_crypto;
+  size_t digest_len = 0;
+  size_t cipher_key_len = 0;
+
+  tor_assert(crypto);
+  tor_assert(key_data);
+  tor_assert(!(crypto->f_crypto || crypto->b_crypto ||
+             crypto->f_digest || crypto->b_digest));
+
+  /* Basic key size validation */
+  if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
+    goto err;
+  } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) {
+    goto err;
+  }
+
+  /* If we are using this crypto for next gen onion services use SHA3-256,
+     otherwise use good ol' SHA1 */
+  if (is_hs_v3) {
+    digest_len = DIGEST256_LEN;
+    cipher_key_len = CIPHER256_KEY_LEN;
+    crypto->f_digest = crypto_digest256_new(DIGEST_SHA3_256);
+    crypto->b_digest = crypto_digest256_new(DIGEST_SHA3_256);
+  } else {
+    digest_len = DIGEST_LEN;
+    cipher_key_len = CIPHER_KEY_LEN;
+    crypto->f_digest = crypto_digest_new();
+    crypto->b_digest = crypto_digest_new();
+  }
+
+  tor_assert(digest_len != 0);
+  tor_assert(cipher_key_len != 0);
+  const int cipher_key_bits = (int) cipher_key_len * 8;
+
+  crypto_digest_add_bytes(crypto->f_digest, key_data, digest_len);
+  crypto_digest_add_bytes(crypto->b_digest, key_data+digest_len, digest_len);
+
+  crypto->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len),
+                                                cipher_key_bits);
+  if (!crypto->f_crypto) {
+    log_warn(LD_BUG,"Forward cipher initialization failed.");
+    goto err;
+  }
+
+  crypto->b_crypto = crypto_cipher_new_with_bits(
+                                        key_data+(2*digest_len)+cipher_key_len,
+                                        cipher_key_bits);
+  if (!crypto->b_crypto) {
+    log_warn(LD_BUG,"Backward cipher initialization failed.");
+    goto err;
+  }
+
+  if (reverse) {
+    tmp_digest = crypto->f_digest;
+    crypto->f_digest = crypto->b_digest;
+    crypto->b_digest = tmp_digest;
+    tmp_crypto = crypto->f_crypto;
+    crypto->f_crypto = crypto->b_crypto;
+    crypto->b_crypto = tmp_crypto;
+  }
+
+  return 0;
+ err:
+  tor1_crypt_clear(crypto);
+  return -1;
+}
+
+/** Assert that <b>crypto</b> is valid and set. */
+void
+tor1_crypt_assert_ok(const tor1_crypt_t *crypto)
+{
+  tor_assert(crypto->f_crypto);
+  tor_assert(crypto->b_crypto);
+  tor_assert(crypto->f_digest);
+  tor_assert(crypto->b_digest);
+}
+
+void
+tor1_crypt_clear(tor1_crypt_t *crypto)
+{
+  if (BUG(!crypto))
+    return;
+  crypto_cipher_free(crypto->f_crypto);
+  crypto_cipher_free(crypto->b_crypto);
+  crypto_digest_free(crypto->f_digest);
+  crypto_digest_free(crypto->b_digest);
+}
diff --git a/src/core/crypto/relay_crypto_tor1.h b/src/core/crypto/relay_crypto_tor1.h
new file mode 100644 (file)
index 0000000..636ca2e
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay.h
+ * \brief Header file for relay_crypto_tor1.c.
+ **/
+
+#ifndef TOR_RELAY_CRYPTO_TOR1_H
+#define TOR_RELAY_CRYPTO_TOR1_H
+
+void tor1_crypt_client_originate(tor1_crypt_t *tor1,
+                                 cell_t *cell);
+void tor1_crypt_relay_originate(tor1_crypt_t *tor1,
+                                cell_t *cell);
+void tor1_crypt_relay_backward(tor1_crypt_t *tor1, cell_t *cell);
+bool tor1_crypt_relay_forward(tor1_crypt_t *tor1, cell_t *cell);
+bool tor1_crypt_client_backward(tor1_crypt_t *tor1, cell_t *cell);
+void tor1_crypt_client_forward(tor1_crypt_t *tor1, cell_t *cell);
+
+int tor1_crypt_init(relay_crypto_t *crypto,
+                    const char *key_data, size_t key_data_len,
+                    int reverse, int is_hs_v3);
+void tor1_crypt_assert_ok(const tor1_crypt_t *tor1);
+void tor1_crypt_clear(relay_crypto_t *crypto);
+
+#endif /* !defined(TOR_RELAY_CRYPTO_TOR1_H) */