tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit a30bd40031422589233368dffaf60d9c4fbfa959
parent c35b6704f19ec924e68cf169119aac281861106b
Author: Nick Mathewson <nickm@torproject.org>
Date:   Wed, 21 May 2025 10:15:07 -0400

Merge branch '41052_cgo_encryption' into 'main'

CGO: Crypto implementation

Closes #41052

See merge request tpo/core/tor!879
Diffstat:
MLICENSE | 27+++++++++++++++++++++++++++
MMakefile.am | 4+++-
Mconfigure.ac | 17+++++++++++++++++
Msrc/core/crypto/include.am | 6++++--
Asrc/core/crypto/relay_crypto_cgo.c | 563+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/crypto/relay_crypto_cgo.h | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ext/include.am | 15+++++++++++++++
Asrc/ext/polyval/README.tor | 28++++++++++++++++++++++++++++
Asrc/ext/polyval/ctmul.c | 311+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ext/polyval/ctmul64.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ext/polyval/pclmul.c | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ext/polyval/polyval.c | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ext/polyval/polyval.h | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/crypt_ops/aes.h | 35+++++++++++++++++++++++++++++++++++
Msrc/lib/crypt_ops/aes_nss.c | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/crypt_ops/aes_openssl.c | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/lib/tls/tortls_nss.c | 5+++++
Asrc/test/cgo_vectors.inc | 651+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test/include.am | 2++
Msrc/test/test.c | 1+
Msrc/test/test.h | 1+
Msrc/test/test_crypto.c | 224+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/test_crypto_cgo.c | 642+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 files changed, 3719 insertions(+), 27 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -383,6 +383,33 @@ src/ext/mulodi4.c is distributed under this license: or promote products derived from this Software. =============================================================================== +Parts of src/ext/polyval are based on Thomas Pornin's GHASH implementation in +BearSSL, and distributed under the following license: + + Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + +=============================================================================== If you got Tor as a static binary with OpenSSL included, then you should know: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/)" diff --git a/Makefile.am b/Makefile.am @@ -112,7 +112,8 @@ TOR_CRYPTO_LIBS = \ src/lib/libtor-tls.a \ src/lib/libtor-crypt-ops.a \ $(LIBKECCAK_TINY) \ - $(LIBDONNA) + $(LIBDONNA) \ + $(LIBPOLYVAL) if BUILD_MODULE_POW TOR_CRYPTO_LIBS += $(EQUIX_LIBS) @@ -126,6 +127,7 @@ TOR_CRYPTO_TESTING_LIBS = \ src/lib/libtor-crypt-ops-testing.a \ $(LIBKECCAK_TINY) \ $(LIBDONNA) \ + $(LIBPOLYVAL) \ $(EQUIX_LIBS) endif diff --git a/configure.ac b/configure.ac @@ -994,6 +994,23 @@ if test "x$enable_nss" = "xyes"; then [have_nss=no; AC_MSG_ERROR([You asked for NSS but I can't find it, $pkg_config_user_action, or set NSS_CFLAGS and NSS_LIBS.])]) AC_SUBST(NSS_CFLAGS) AC_SUBST(NSS_LIBS) + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + LIBS="$LIBS $NSS_LIBS" + CFLAGS="$CFLAGS $NSS_CFLAGS" + AC_MSG_CHECKING([whether NSS defines ssl_kea_ecdh_hybrid(_psk)]) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + #include <sslt.h> + int v = (int) ssl_kea_ecdh_hybrid_psk; + int v2 = (int) ssl_kea_ecdh_hybrid; + ]], [[]])], + [ AC_MSG_RESULT([yes]); + AC_DEFINE(NSS_HAS_ECDH_HYBRID, 1, [whether nss defines ecdh_hybrid key exchange.]) + ], + [ AC_MSG_RESULT([no]) ]) + LIBS="$save_LIBS" + CPPFLAGS="$save_CPPFLAGS" fi dnl ------------------------------------------------------ diff --git a/src/core/crypto/include.am b/src/core/crypto/include.am @@ -6,7 +6,8 @@ LIBTOR_APP_A_SOURCES += \ src/core/crypto/onion_fast.c \ src/core/crypto/onion_ntor.c \ src/core/crypto/onion_ntor_v3.c \ - src/core/crypto/relay_crypto.c + src/core/crypto/relay_crypto.c \ + src/core/crypto/relay_crypto_cgo.c # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ @@ -15,4 +16,5 @@ noinst_HEADERS += \ src/core/crypto/onion_fast.h \ src/core/crypto/onion_ntor.h \ src/core/crypto/onion_ntor_v3.h \ - src/core/crypto/relay_crypto.h + src/core/crypto/relay_crypto.h \ + src/core/crypto/relay_crypto_cgo.h diff --git a/src/core/crypto/relay_crypto_cgo.c b/src/core/crypto/relay_crypto_cgo.c @@ -0,0 +1,563 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2025, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file relay_crypto_cgo.c + * \brief Implementation for counter galois onion encryption. + **/ + +#define RELAY_CRYPTO_CGO_PRIVATE +#define USE_AES_RAW + +#include "orconfig.h" +#include "core/or/or.h" +#include "lib/crypt_ops/aes.h" +#include "ext/polyval/polyval.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/util_bug.h" +#include "lib/arch/bytes.h" +#include "ext/polyval/polyval.h" +#include "core/crypto/relay_crypto_cgo.h" +#include "core/or/cell_st.h" + +#if 0 +// XXXX debugging. +#include "lib/encoding/binascii.h" +#include <stdio.h> +#endif + +#include <string.h> + +static int +cgo_et_keylen(int aesbits) +{ + return (aesbits / 8) + POLYVAL_KEY_LEN; +} + +/** Initialize an instance of the tweakable block cipher, + * using an 'aesbits'-bit AES key. + * + * The total key material used from 'key' will be + * (aesbits / 8) + 16. + * + * This will be initialized for encryption or decryption depending + * on the value of 'encrypt' + */ +STATIC int +cgo_et_init(cgo_et_t *et, int aesbits, bool encrypt, + const uint8_t *key) +{ + size_t aes_key_bytes = aesbits / 8; + et->kb = aes_raw_new(key, aesbits, encrypt); + if (et->kb == NULL) + return -1; + polyval_key_init(&et->ku, key + aes_key_bytes); + return 0; +} +/** Replace the key on an existing, already initialized cgo_et_t. + * + * Does fewer allocations than a clear+init. */ +STATIC void +cgo_et_set_key(cgo_et_t *et, int aesbits, bool encrypt, + const uint8_t *key) +{ + size_t aes_key_bytes = aesbits / 8; + aes_raw_set_key(&et->kb, key, aesbits, encrypt); + polyval_key_init(&et->ku, key + aes_key_bytes); +} + +/** Helper: Compute polyval(KU, H | CMD | X_R). */ +static inline void +compute_et_mask(polyval_key_t *pvk, const et_tweak_t tweak, uint8_t *t_out) +{ + // block 0: tweak.h + // block 1: one byte of command, first 15 bytes of x_r + // block 2...: remainder of x_r, zero-padded. + polyval_t pv; + uint8_t block1[16]; + block1[0] = tweak.uiv.cmd; + memcpy(block1+1, tweak.x_r, 15); + polyval_init_from_key(&pv, pvk); + polyval_add_block(&pv, tweak.uiv.h); + polyval_add_block(&pv, block1); + polyval_add_zpad(&pv, tweak.x_r + 15, ET_TWEAK_LEN_X_R - 15); + polyval_get_tag(&pv, t_out); +} +/** XOR the 16 byte block from inp into out. */ +static void +xor_block(uint8_t *out, const uint8_t *inp) +{ + for (int i = 0; i < 16; ++i) + out[i] ^= inp[i]; +} + +/** + * Encrypt the 16-byte block in 'block'. + */ +STATIC void +cgo_et_encrypt(cgo_et_t *et, const et_tweak_t tweak, + uint8_t *block) +{ + uint8_t mask[16]; + compute_et_mask(&et->ku, tweak, mask); + xor_block(block, mask); + aes_raw_encrypt(et->kb, block); + xor_block(block, mask); +} +/** + * Decrypt the 16-byte b lock in 'block' + */ +STATIC void +cgo_et_decrypt(cgo_et_t *et, const et_tweak_t tweak, + uint8_t *block) +{ + uint8_t mask[16]; + compute_et_mask(&et->ku, tweak, mask); + xor_block(block, mask); + aes_raw_decrypt(et->kb, block); + xor_block(block, mask); +} +/** + * Release any storage held in 'et'. + * + * This _doesn't_ wipe 'et'; that's done from a higher-level function. + */ +STATIC void +cgo_et_clear(cgo_et_t *et) +{ + aes_raw_free(et->kb); +} + +static int +cgo_prf_keylen(int aesbits) +{ + return (aesbits / 8) + POLYVAL_KEY_LEN; +} + +/** + * Initialize a psedorandom function from a given key. + * Uses an internal 'aesbits'-bit AES key. + * + * The total key material used from 'key' will be + * (aesbits / 8) + 16. + */ +STATIC int +cgo_prf_init(cgo_prf_t *prf, int aesbits, + const uint8_t *key) +{ + size_t aes_key_bytes = aesbits / 8; + memset(prf,0, sizeof(*prf)); + prf->k = aes_raw_new(key, aesbits, true); + polyval_key_init(&prf->b, key + aes_key_bytes); + return 0; +} +/** Replace the key on an existing cgo_prf_t. + * + * Does fewer allocations than a clear+init. */ +STATIC void +cgo_prf_set_key(cgo_prf_t *prf, int aesbits, + const uint8_t *key) +{ + size_t aes_key_bytes = aesbits / 8; + aes_raw_set_key(&prf->k, key, aesbits, true); + polyval_key_init(&prf->b, key + aes_key_bytes); +} +/** + * Compute the PRF's results on 'input', for position t=0, + * XOR it into 'data'. + * + * 'input' must be PRF_INPUT_LEN bytes long. + * + * 'data' must be PRF_T0_DATA_LEN bytes long. + */ +STATIC void +cgo_prf_xor_t0(cgo_prf_t *prf, const uint8_t *input, + uint8_t *data) +{ + uint8_t hash[16]; + polyval_t pv; + polyval_init_from_key(&pv, &prf->b); + polyval_add_block(&pv, input); + polyval_get_tag(&pv, hash); + hash[15] &= 0xC0; // Clear the low six bits. + + aes_raw_counter_xor(prf->k, hash, 0, data, PRF_T0_DATA_LEN); +} +/** + * Generate 'n' bytes of the PRF's results on 'input', for position t=1, + * and store them into 'buf'. + * + * 'input' must be PRF_INPUT_LEN bytes long. + */ +STATIC void +cgo_prf_gen_t1(cgo_prf_t *prf, const uint8_t *input, + uint8_t *buf, size_t n) +{ + #define T1_OFFSET 31 + uint8_t hash[16]; + polyval_t pv; + polyval_init_from_key(&pv, &prf->b); + polyval_add_block(&pv, input); + polyval_get_tag(&pv, hash); + hash[15] &= 0xC0; // Clear the low six bits. + + memset(buf, 0, n); + aes_raw_counter_xor(prf->k, hash, T1_OFFSET, buf, n); +} +/** + * Release any storage held in 'prf'. + * + * This _doesn't_ wipe 'prf'; that's done from a higher-level function. + */ +STATIC void +cgo_prf_clear(cgo_prf_t *prf) +{ + aes_raw_free(prf->k); +} + +static int +cgo_uiv_keylen(int aesbits) +{ + return cgo_et_keylen(aesbits) + cgo_prf_keylen(aesbits); +} + +/** + * Initialize the 'uiv' wide-block cipher, using 'aesbits'-bit + * AES keys internally. + * + * Initializes for encryption or decryption depending on the value of + * 'encrypt'. + * + * The total key material used from 'key' will be + * (aesbits / 8) * 2 + 32. + */ +STATIC int +cgo_uiv_init(cgo_uiv_t *uiv, int aesbits, bool encrypt, + const uint8_t *key) +{ + size_t aes_key_bytes = aesbits / 8; + if (cgo_et_init(&uiv->j, aesbits, encrypt, key) < 0) + return -1; + if (cgo_prf_init(&uiv->s, aesbits, key + aes_key_bytes + POLYVAL_KEY_LEN)<0) + return -1; +#ifdef TOR_UNIT_TESTS + /* Testing only: copy the keys so we can test UIV_UPDATE function. */ + size_t total_key_len = aes_key_bytes * 2 + POLYVAL_KEY_LEN * 2; + tor_assert(total_key_len <= sizeof(uiv->uiv_keys_)); + memset(uiv->uiv_keys_, 0, sizeof(uiv->uiv_keys_)); + memcpy(uiv->uiv_keys_, key, total_key_len); +#endif + return 0; +} +/** + * Encrypt 'cell_body', with the provided tweak. + * + * The cell body must be UIV_BLOCK_LEN bytes long. + */ +STATIC void +cgo_uiv_encrypt(cgo_uiv_t *uiv, const uiv_tweak_t tweak, uint8_t *cell_body) +{ + uint8_t *X_L = cell_body; + uint8_t *X_R = cell_body + 16; + + const et_tweak_t et_tweak = { + .uiv = tweak, + .x_r = X_R, + }; + cgo_et_encrypt(&uiv->j, et_tweak, X_L); + cgo_prf_xor_t0(&uiv->s, X_L, X_R); +} +/** + * Decrypt 'cell_body', with the provided tweak. + * + * The cell body must be UIV_BLOCK_LEN bytes long. + */ +STATIC void +cgo_uiv_decrypt(cgo_uiv_t *uiv, const uiv_tweak_t tweak, uint8_t *cell_body) +{ + uint8_t *X_L = cell_body; + uint8_t *X_R = cell_body + 16; + + const et_tweak_t et_tweak = { + .uiv = tweak, + .x_r = X_R, + }; + cgo_prf_xor_t0(&uiv->s, X_L, X_R); + cgo_et_decrypt(&uiv->j, et_tweak, X_L); +} +/** + * Irreversibly ransform the keys of this UIV+, and the provided nonce, + * using the nonce as input. + * + * The nonce must be 16 bytes long. + */ +STATIC void +cgo_uiv_update(cgo_uiv_t *uiv, int aesbits, bool encrypt, uint8_t *nonce) +{ + size_t aes_bytes = aesbits / 8; + size_t single_key_len = aes_bytes + POLYVAL_KEY_LEN; + size_t total_key_len = single_key_len * 2 + 16; + // Note: We could store this on the stack, but stack-protector + // wouldn't like that. + uint8_t *new_keys = tor_malloc(total_key_len); + + cgo_prf_gen_t1(&uiv->s, nonce, new_keys, total_key_len); + + cgo_et_set_key(&uiv->j, aesbits, encrypt, new_keys); + cgo_prf_set_key(&uiv->s, aesbits, new_keys + single_key_len); + + memcpy(nonce, new_keys + single_key_len * 2, 16); + +#ifdef TOR_UNIT_TESTS + /* Testing only: copy the keys so we can test UIV_UPDATE function. */ + memset(uiv->uiv_keys_, 0, sizeof(uiv->uiv_keys_)); + memcpy(uiv->uiv_keys_, new_keys, total_key_len); +#endif + + // This is key material, so we should really discard it. + memwipe(new_keys, 0, total_key_len); + tor_free(new_keys); +} +/** + * Release any storage held in 'prf'. + * + * This _doesn't_ wipe 'prf'; that's done from a higher-level function. + */ +STATIC void +cgo_uiv_clear(cgo_uiv_t *uiv) +{ + cgo_et_clear(&uiv->j); + cgo_prf_clear(&uiv->s); +} + +/* ==================== + * High level counter galois onion implementations. + */ + +/** + * Return the total number of bytes needed to initialize a cgo_crypt_t. + */ +size_t +cgo_key_material_len(int aesbits) +{ + tor_assert(aesbits == 128 || aesbits == 192 || aesbits == 256); + return (cgo_uiv_keylen(aesbits) + CGO_TAG_LEN); +} + +/** + * Instantiate a CGO authenticated encryption object from the provided + * 'keylen' bytes in 'keys'. + * + * 'keylen' must equal 'cgo_key_material_len(aesbits)'. + * + * The client and relay must have two cgo_crypt_t objects each: + * one for the forward direction, and one for the reverse direction. + */ +cgo_crypt_t * +cgo_crypt_new(cgo_mode_t mode, int aesbits, const uint8_t *keys, size_t keylen) +{ + tor_assert(keylen == cgo_key_material_len(aesbits)); + const uint8_t *end_of_keys = keys + keylen; + // Relays encrypt; clients decrypt. + // Don't reverse this: UIV+ is only non-malleable for _encryption_. + bool encrypt = (mode == CGO_MODE_RELAY_BACKWARD || + mode == CGO_MODE_RELAY_FORWARD); + int r; + + cgo_crypt_t *cgo = tor_malloc_zero(sizeof(cgo_crypt_t)); + r = cgo_uiv_init(&cgo->uiv, aesbits, encrypt, keys); + tor_assert(r == 0); + keys += cgo_uiv_keylen(aesbits); + memcpy(cgo->nonce, keys, CGO_TAG_LEN); + keys += CGO_TAG_LEN; + tor_assert(keys == end_of_keys); + + cgo->aes_bytes = aesbits / 8; + + return cgo; +} +/** + * Clean up 'cgo' and free it. + */ +void +cgo_crypt_free_(cgo_crypt_t *cgo) +{ + if (!cgo) + return; + cgo_uiv_clear(&cgo->uiv); + memwipe(cgo, 0, sizeof(cgo_crypt_t)); + tor_free(cgo); +} + +/** + * Internal: Run the UIV Update operation on our UIV+ instance. + */ +static void +cgo_crypt_update(cgo_crypt_t *cgo, cgo_mode_t mode) +{ + bool encrypt = (mode == CGO_MODE_RELAY_BACKWARD || + mode == CGO_MODE_RELAY_FORWARD); + cgo_uiv_update(&cgo->uiv, cgo->aes_bytes * 8, encrypt, cgo->nonce); +} + +/** + * Forward CGO encryption operation at a relay: + * process an outbound cell from the client. + * + * If the cell is for this relay, set *'recognized_tag_out' + * to point to a CGO_TAG_LEN value that should be used + * if we want to acknowledge this cell with an authenticated SENDME. + * + * The value of 'recognized_tag_out' will become invalid + * as soon as any change is made to this 'cgo' object, + * or to the cell; if you need it, you should copy it immediately. + * + * If the cell is not for this relay, set *'recognized_tag_out' to NULL. + */ +void +cgo_crypt_relay_forward(cgo_crypt_t *cgo, cell_t *cell, + const uint8_t **recognized_tag_out) +{ + uiv_tweak_t h = { + .h = cgo->tprime, + .cmd = cell->command, + }; + memcpy(cgo->last_tag_relay_fwd, cell->payload, CGO_TAG_LEN); + cgo_uiv_encrypt(&cgo->uiv, h, cell->payload); + memcpy(cgo->tprime, cell->payload, CGO_TAG_LEN); + if (tor_memeq(cell->payload, cgo->nonce, CGO_TAG_LEN)) { + cgo_crypt_update(cgo, CGO_MODE_RELAY_FORWARD); + *recognized_tag_out = cgo->last_tag_relay_fwd; + } else { + *recognized_tag_out = NULL; + } +} + +/** + * Backward CGO encryption operation at a relay: + * process an inbound cell from another relay, for the client. + */ +void +cgo_crypt_relay_backward(cgo_crypt_t *cgo, cell_t *cell) +{ + uiv_tweak_t h = { + .h = cgo->tprime, + .cmd = cell->command, + }; + cgo_uiv_encrypt(&cgo->uiv, h, cell->payload); + memcpy(cgo->tprime, cell->payload, CGO_TAG_LEN); +} + +/** + * Backward CGO encryption operation at a relay: + * encrypt an inbound message that we are originating, for the client. + * + * The provided cell must have its command value set, + * and should have the first CGO_TAG_LEN bytes of its payload unused. + * + * Set '*tag_out' to a value that we should expect + * if we want an authenticated SENDME for this cell. + * + * The value of 'recognized_tag_out' will become invalid + * as soon as any change is made to this 'cgo' object, + * or to the cell; if you need it, you should copy it immediately. + */ +void +cgo_crypt_relay_originate(cgo_crypt_t *cgo, cell_t *cell, + const uint8_t **tag_out) +{ + uiv_tweak_t h = { + .h = cgo->tprime, + .cmd = cell->command, + }; + memcpy(cell->payload, cgo->nonce, CGO_TAG_LEN); + cgo_uiv_encrypt(&cgo->uiv, h, cell->payload); + memcpy(&cgo->tprime, cell->payload, CGO_TAG_LEN); + memcpy(&cgo->nonce, cell->payload, CGO_TAG_LEN); + if (tag_out) { + // tor_assert(tor_memeq(cgo->tprime, cell->payload, CGO_TAG_LEN)); + *tag_out = cgo->tprime; + } + cgo_crypt_update(cgo, CGO_MODE_RELAY_BACKWARD); +} + +/** + * Forward CGO encryption at a client: + * process a cell for a non-destination hop. + **/ +void +cgo_crypt_client_forward(cgo_crypt_t *cgo, cell_t *cell) +{ + uint8_t tprime_new[CGO_TAG_LEN]; + memcpy(tprime_new, cell->payload, CGO_TAG_LEN); + uiv_tweak_t h = { + .h = cgo->tprime, + .cmd = cell->command, + }; + cgo_uiv_decrypt(&cgo->uiv, h, cell->payload); + memcpy(cgo->tprime, tprime_new, CGO_TAG_LEN); +} + +/** + * Forward CGO encryption at a client: + * originate a cell for a given target hop. + * + * The provided cell must have its command value set, + * and should have the first CGO_TAG_LEN bytes of its payload unused. + * + * Set '*tag_out' to a value that we should expect + * if we want an authenticated SENDME for this cell. + * + * The value of 'recognized_tag_out' will become invalid + * as soon as any change is made to this 'cgo' object, + * or to the cell; if you need it, you should copy it immediately. + */ +void +cgo_crypt_client_originate(cgo_crypt_t *cgo, cell_t *cell, + const uint8_t **tag_out) +{ + memcpy(cell->payload, cgo->nonce, CGO_TAG_LEN); + cgo_crypt_client_forward(cgo, cell); + cgo_crypt_update(cgo, CGO_MODE_CLIENT_FORWARD); + *tag_out = cell->payload; +} + +/** + * Backward CGO encryption operation at a rclient. + * process an inbound cell from a relay. + * + * If the cell originated from this this relay, set *'recognized_tag_out' + * to point to a CGO_TAG_LEN value that should be used + * if we want to acknowledge this cell with an authenticated SENDME. + * + * The value of 'recognized_tag_out' will become invalid + * as soon as any change is made to this 'cgo' object, + * or to the cell; if you need it, you should copy it immediately. + * + * If the cell is not from this relay, set *'recognized_tag_out' to NULL. + */ +void +cgo_crypt_client_backward(cgo_crypt_t *cgo, cell_t *cell, + const uint8_t **recognized_tag_out) +{ + uiv_tweak_t h = { + .h = cgo->tprime, + .cmd = cell->command, + }; + uint8_t t_orig[CGO_TAG_LEN]; + memcpy(t_orig, cell->payload, CGO_TAG_LEN); + + cgo_uiv_decrypt(&cgo->uiv, h, cell->payload); + memcpy(cgo->tprime, t_orig, CGO_TAG_LEN); + if (tor_memeq(cell->payload, cgo->nonce, CGO_TAG_LEN)) { + memcpy(cgo->nonce, t_orig, CGO_TAG_LEN); + cgo_crypt_update(cgo, CGO_MODE_CLIENT_BACKWARD); + // tor_assert(tor_memeq(cgo->tprime, t_orig, CGO_TAG_LEN)); + *recognized_tag_out = cgo->tprime; + } else { + *recognized_tag_out = NULL; + } +} diff --git a/src/core/crypto/relay_crypto_cgo.h b/src/core/crypto/relay_crypto_cgo.h @@ -0,0 +1,218 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2025, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file relay_crypto_cgo.h + * \brief Header file for relay_crypto_cgo.c. + **/ + +#ifndef TOR_RELAY_CRYPTO_CGO_H +#define TOR_RELAY_CRYPTO_CGO_H + +#include "lib/testsupport/testsupport.h" + +/** + * State to implement forward _or_ reverse crypto between a client and a single + * hop on a circuit. + * + * (There needs to be one of these for each direction. + */ +typedef struct cgo_crypt_t cgo_crypt_t; + +typedef enum { + CGO_MODE_CLIENT_FORWARD, + CGO_MODE_CLIENT_BACKWARD, + CGO_MODE_RELAY_FORWARD, + CGO_MODE_RELAY_BACKWARD, +} cgo_mode_t; + +/** + * Length of a CGO cell tag. + * + * This is the value used for authenticated SENDMES. + **/ +#define CGO_TAG_LEN 16 + +struct cell_t; + +size_t cgo_key_material_len(int aesbits); +cgo_crypt_t * cgo_crypt_new(cgo_mode_t mode, int aesbits, + const uint8_t *keys, size_t keylen); +void cgo_crypt_free_(cgo_crypt_t *cgo); +#define cgo_crypt_free(cgo) \ + FREE_AND_NULL(cgo_crypt_t, cgo_crypt_free_, (cgo)) + +void cgo_crypt_relay_forward(cgo_crypt_t *cgo, struct cell_t *cell, + const uint8_t **recognized_tag_out); +void cgo_crypt_relay_backward(cgo_crypt_t *cgo, struct cell_t *cell); +void cgo_crypt_relay_originate(cgo_crypt_t *cgo, struct cell_t *cell, + const uint8_t **tag_out); +void cgo_crypt_client_forward(cgo_crypt_t *cgo, struct cell_t *cell); +void cgo_crypt_client_originate(cgo_crypt_t *cgo, struct cell_t *cell, + const uint8_t **tag_out); +void cgo_crypt_client_backward(cgo_crypt_t *cgo, struct cell_t *cell, + const uint8_t **recognized_tag_out); + +#ifdef RELAY_CRYPTO_CGO_PRIVATE +/* Internal types and definitions for CGO encryption algorithms. + * + * Where reasonable, the identifiers here are chosen to match those + * in the spec (proposal 359), which in turn were chosen to match + * those in the paper. + */ + +/** + * Tweakable block cipher, following the LRW2 construction, + * instantiated with AES. + * + * Any given instance can be used for encryption _or_ decryption, + * not both. + */ +typedef struct cgo_et_t { + /** + * AES block cipher instance + */ + aes_raw_t *kb; + /** + * Polyval key. + */ + polyval_key_t ku; +} cgo_et_t; +/** + * Keyed pseudorandom function, based on polyval and AES-CTR. + */ +typedef struct cgo_prf_t { + /** + * AES key: may be 128, 192, or 256 bits. + * + * Even though we're going to be using this in counter mode, + * we don't make an aes_cnt_cipher_t here, since that type + * does not support efficient re-use of the key with multiple + * IVs. + */ + aes_raw_t *k; + /** + * Polyval instance. + */ + polyval_key_t b; +} cgo_prf_t; +/** + * Rugged tweakable pseudorandom permutation, using the UIV+ construction. + * + * This is, roughly, a wide-block cipher where _encryption_ + * is non-malleable, but where _decryption_ is malleable. + * + * UIV+ is the basis of CGO encryption, though it is used in different + * ways for each of the relay operations. + */ +typedef struct cgo_uiv_t { + /** + * Tweakable block cipher instance. + */ + cgo_et_t j; + /** + * PRF instance. + */ + cgo_prf_t s; +#ifdef TOR_UNIT_TESTS + /** Testing only: Copy of keys used to instantiate this UIV. + * We use this in tests so that we can confirm the correctness + * of cgo_uiv_update(). + */ + uint8_t uiv_keys_[32 * 2 + 16 * 2]; +#endif +} cgo_uiv_t; +/** + * Length of the 'h' component of uiv_tweak_t. + */ +#define ET_TWEAK_LEN_H 16 +/** + * Length of the 'x_r' component of et_tweak_t. + */ +#define ET_TWEAK_LEN_X_R 493 + +/** + * Tweak for the UIV+ wide-block cipher. + */ +typedef struct uiv_tweak_t { + /** H component of the wide-block cipher. + * + * This must be ET_TWEAK_LEN_H bytes long. + **/ + const uint8_t *h; + /** Additional data component of the wide-block cipher. + * This value is sent to the cell command (RELAY or RELAY_EARLY) + * for each relay cell. + */ + const uint8_t cmd; +} uiv_tweak_t; +/** + * Tweak for the ET tweakable block cipher. + */ +typedef struct et_tweak_t { + /** Components from the UIV+ tweak. */ + uiv_tweak_t uiv; + /** + * X_R component of the ET tweak. + * + * This must be X_R bytes long. + */ + const uint8_t *x_r; +} et_tweak_t; + +/** Length of expected input to the PRF. */ +#define PRF_INPUT_LEN 16 +/** Output length for cgo_prf_xor_t0(). */ +#define PRF_T0_DATA_LEN 493 + +/** Length of block handled by uiv instantiation. */ +#define UIV_BLOCK_LEN 509 + +STATIC int cgo_et_init(cgo_et_t *et, int aesbits, bool encrypt, + const uint8_t *key); +STATIC void cgo_et_set_key(cgo_et_t *et, int aesbits, bool encrypt, + const uint8_t *key); +STATIC void cgo_et_encrypt(cgo_et_t *et, const et_tweak_t tweak, + uint8_t *block); +STATIC void cgo_et_decrypt(cgo_et_t *et, const et_tweak_t tweak, + uint8_t *block); +STATIC void cgo_et_clear(cgo_et_t *et); + +STATIC int cgo_prf_init(cgo_prf_t *prf, int aesbits, + const uint8_t *key); +STATIC void cgo_prf_set_key(cgo_prf_t *prf, int aesbits, + const uint8_t *key); +STATIC void cgo_prf_xor_t0(cgo_prf_t *prf, const uint8_t *input, + uint8_t *data); +STATIC void cgo_prf_gen_t1(cgo_prf_t *prf, const uint8_t *input, + uint8_t *buf, size_t n); +STATIC void cgo_prf_clear(cgo_prf_t *prf); + +STATIC int cgo_uiv_init(cgo_uiv_t *uiv, int aesbits, bool encrypt, + const uint8_t *key); +STATIC void cgo_uiv_encrypt(cgo_uiv_t *uiv, const uiv_tweak_t tweak, + uint8_t *cell_body); +STATIC void cgo_uiv_decrypt(cgo_uiv_t *uiv, const uiv_tweak_t tweak, + uint8_t *cell_body); +STATIC void cgo_uiv_update(cgo_uiv_t *uiv, int aesbits, bool encrypt, + uint8_t *nonce); +STATIC void cgo_uiv_clear(cgo_uiv_t *uiv); + +struct cgo_crypt_t { + cgo_uiv_t uiv; + uint8_t nonce[CGO_TAG_LEN]; + uint8_t tprime[CGO_TAG_LEN]; + /** + * Stored version of the last incoming cell tag. + * Only used for cgo_crypt_relay_fwd, where this information is not + * otherwise available after encryption. + */ + uint8_t last_tag_relay_fwd[CGO_TAG_LEN]; + uint8_t aes_bytes; +}; +#endif + +#endif /* !defined(TOR_RELAY_CRYPTO_CGO_H) */ diff --git a/src/ext/include.am b/src/ext/include.am @@ -216,6 +216,21 @@ LIBKECCAK_TINY=src/ext/keccak-tiny/libkeccak-tiny.a noinst_LIBRARIES += $(LIBKECCAK_TINY) endif +src_ext_polyval_libpolyval_a_CFLAGS=\ + @CFLAGS_CONSTTIME@ +src_ext_polyval_libpolyval_a_SOURCES= \ + src/ext/polyval/polyval.c + +POLYVAL_HDRS = \ + src/ext/polyval/polyval.h \ + src/ext/polyval/pclmul.c \ + src/ext/polyval/ctmul64.c \ + src/ext/polyval/ctmul.c + +noinst_HEADERS += $(POLYVAL_HDRS) +LIBPOLYVAL=src/ext/polyval/libpolyval.a +noinst_LIBRARIES += $(LIBPOLYVAL) + EXTRA_DIST += \ src/ext/timeouts/bench/bench-add.lua \ src/ext/timeouts/bench/bench-aux.lua \ diff --git a/src/ext/polyval/README.tor b/src/ext/polyval/README.tor @@ -0,0 +1,28 @@ +This code is based on the constant-time GHASH implementations +from BearSSL, written by Thomas Pornin. + +Up-to-date with BearSSL as of 3c040368f6791553610e362401db1efff4b4c5b8. + +The license on that code is: + +> Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> +> +> Permission is hereby granted, free of charge, to any person obtaining +> a copy of this software and associated documentation files (the +> "Software"), to deal in the Software without restriction, including +> without limitation the rights to use, copy, modify, merge, publish, +> distribute, sublicense, and/or sell copies of the Software, and to +> permit persons to whom the Software is furnished to do so, subject to +> the following conditions: +> +> The above copyright notice and this permission notice shall be +> included in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +> BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +> ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +> CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. diff --git a/src/ext/polyval/ctmul.c b/src/ext/polyval/ctmul.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * We compute "carryless multiplications" through normal integer + * multiplications, masking out enough bits to create "holes" in which + * carries may expand without altering our bits; we really use 8 data + * bits per 32-bit word, spaced every fourth bit. Accumulated carries + * may not exceed 8 in total, which fits in 4 bits. + * + * It would be possible to use a 3-bit spacing, allowing two operands, + * one with 7 non-zero data bits, the other one with 10 or 11 non-zero + * data bits; this asymmetric splitting makes the overall code more + * complex with thresholds and exceptions, and does not appear to be + * worth the effort. + */ + +/* + * We cannot really autodetect whether multiplications are "slow" or + * not. A typical example is the ARM Cortex M0+, which exists in two + * versions: one with a 1-cycle multiplication opcode, the other with + * a 32-cycle multiplication opcode. They both use exactly the same + * architecture and ABI, and cannot be distinguished from each other + * at compile-time. + * + * Since most modern CPU (even embedded CPU) still have fast + * multiplications, we use the "fast mul" code by default. + */ + +// A 32x32 -> 64 multiply. +#define MUL(x, y) (((uint64_t)(x)) * ((uint64_t)(y))) + +#ifdef BR_SLOW_MUL + +/* + * This implementation uses Karatsuba-like reduction to make fewer + * integer multiplications (9 instead of 16), at the expense of extra + * logical operations (XOR, shifts...). On modern x86 CPU that offer + * fast, pipelined multiplications, this code is about twice slower than + * the simpler code with 16 multiplications. This tendency may be + * reversed on low-end platforms with expensive multiplications. + */ + +#define MUL32(h, l, x, y) do { \ + uint64_t mul32tmp = MUL(x, y); \ + (h) = (uint32_t)(mul32tmp >> 32); \ + (l) = (uint32_t)mul32tmp; \ + } while (0) + +static inline void +bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y) +{ + uint32_t x0, x1, x2, x3; + uint32_t y0, y1, y2, y3; + uint32_t a0, a1, a2, a3, a4, a5, a6, a7, a8; + uint32_t b0, b1, b2, b3, b4, b5, b6, b7, b8; + + x0 = x & (uint32_t)0x11111111; + x1 = x & (uint32_t)0x22222222; + x2 = x & (uint32_t)0x44444444; + x3 = x & (uint32_t)0x88888888; + y0 = y & (uint32_t)0x11111111; + y1 = y & (uint32_t)0x22222222; + y2 = y & (uint32_t)0x44444444; + y3 = y & (uint32_t)0x88888888; + + /* + * (x0+W*x1)*(y0+W*y1) -> a0:b0 + * (x2+W*x3)*(y2+W*y3) -> a3:b3 + * ((x0+x2)+W*(x1+x3))*((y0+y2)+W*(y1+y3)) -> a6:b6 + */ + a0 = x0; + b0 = y0; + a1 = x1 >> 1; + b1 = y1 >> 1; + a2 = a0 ^ a1; + b2 = b0 ^ b1; + a3 = x2 >> 2; + b3 = y2 >> 2; + a4 = x3 >> 3; + b4 = y3 >> 3; + a5 = a3 ^ a4; + b5 = b3 ^ b4; + a6 = a0 ^ a3; + b6 = b0 ^ b3; + a7 = a1 ^ a4; + b7 = b1 ^ b4; + a8 = a6 ^ a7; + b8 = b6 ^ b7; + + MUL32(b0, a0, b0, a0); + MUL32(b1, a1, b1, a1); + MUL32(b2, a2, b2, a2); + MUL32(b3, a3, b3, a3); + MUL32(b4, a4, b4, a4); + MUL32(b5, a5, b5, a5); + MUL32(b6, a6, b6, a6); + MUL32(b7, a7, b7, a7); + MUL32(b8, a8, b8, a8); + + a0 &= (uint32_t)0x11111111; + a1 &= (uint32_t)0x11111111; + a2 &= (uint32_t)0x11111111; + a3 &= (uint32_t)0x11111111; + a4 &= (uint32_t)0x11111111; + a5 &= (uint32_t)0x11111111; + a6 &= (uint32_t)0x11111111; + a7 &= (uint32_t)0x11111111; + a8 &= (uint32_t)0x11111111; + b0 &= (uint32_t)0x11111111; + b1 &= (uint32_t)0x11111111; + b2 &= (uint32_t)0x11111111; + b3 &= (uint32_t)0x11111111; + b4 &= (uint32_t)0x11111111; + b5 &= (uint32_t)0x11111111; + b6 &= (uint32_t)0x11111111; + b7 &= (uint32_t)0x11111111; + b8 &= (uint32_t)0x11111111; + + a2 ^= a0 ^ a1; + b2 ^= b0 ^ b1; + a0 ^= (a2 << 1) ^ (a1 << 2); + b0 ^= (b2 << 1) ^ (b1 << 2); + a5 ^= a3 ^ a4; + b5 ^= b3 ^ b4; + a3 ^= (a5 << 1) ^ (a4 << 2); + b3 ^= (b5 << 1) ^ (b4 << 2); + a8 ^= a6 ^ a7; + b8 ^= b6 ^ b7; + a6 ^= (a8 << 1) ^ (a7 << 2); + b6 ^= (b8 << 1) ^ (b7 << 2); + a6 ^= a0 ^ a3; + b6 ^= b0 ^ b3; + *lo = a0 ^ (a6 << 2) ^ (a3 << 4); + *hi = b0 ^ (b6 << 2) ^ (b3 << 4) ^ (a6 >> 30) ^ (a3 >> 28); +} + +#else + +/* + * Simple multiplication in GF(2)[X], using 16 integer multiplications. + */ + +static inline void +bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y) +{ + uint32_t x0, x1, x2, x3; + uint32_t y0, y1, y2, y3; + uint64_t z0, z1, z2, z3; + uint64_t z; + + x0 = x & (uint32_t)0x11111111; + x1 = x & (uint32_t)0x22222222; + x2 = x & (uint32_t)0x44444444; + x3 = x & (uint32_t)0x88888888; + y0 = y & (uint32_t)0x11111111; + y1 = y & (uint32_t)0x22222222; + y2 = y & (uint32_t)0x44444444; + y3 = y & (uint32_t)0x88888888; + z0 = MUL(x0, y0) ^ MUL(x1, y3) ^ MUL(x2, y2) ^ MUL(x3, y1); + z1 = MUL(x0, y1) ^ MUL(x1, y0) ^ MUL(x2, y3) ^ MUL(x3, y2); + z2 = MUL(x0, y2) ^ MUL(x1, y1) ^ MUL(x2, y0) ^ MUL(x3, y3); + z3 = MUL(x0, y3) ^ MUL(x1, y2) ^ MUL(x2, y1) ^ MUL(x3, y0); + z0 &= (uint64_t)0x1111111111111111; + z1 &= (uint64_t)0x2222222222222222; + z2 &= (uint64_t)0x4444444444444444; + z3 &= (uint64_t)0x8888888888888888; + z = z0 | z1 | z2 | z3; + *lo = (uint32_t)z; + *hi = (uint32_t)(z >> 32); +} + +#endif + +static void +pv_mul_y_h(polyval_t *pv) +{ + uint32_t *yw = pv->y.v; + const uint32_t *hw = pv->key.h.v; + + /* + * Throughout the loop we handle the y and h values as arrays + * of 32-bit words. + */ + { + int i; + uint32_t a[9], b[9], zw[8]; + uint32_t c0, c1, c2, c3, d0, d1, d2, d3, e0, e1, e2, e3; + + /* + * We multiply two 128-bit field elements. We use + * Karatsuba to turn that into three 64-bit + * multiplications, which are themselves done with a + * total of nine 32-bit multiplications. + */ + + /* + * y[0,1]*h[0,1] -> 0..2 + * y[2,3]*h[2,3] -> 3..5 + * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6..8 + */ + a[0] = yw[0]; + b[0] = hw[0]; + a[1] = yw[1]; + b[1] = hw[1]; + a[2] = a[0] ^ a[1]; + b[2] = b[0] ^ b[1]; + + a[3] = yw[2]; + b[3] = hw[2]; + a[4] = yw[3]; + b[4] = hw[3]; + a[5] = a[3] ^ a[4]; + b[5] = b[3] ^ b[4]; + + a[6] = a[0] ^ a[3]; + b[6] = b[0] ^ b[3]; + a[7] = a[1] ^ a[4]; + b[7] = b[1] ^ b[4]; + a[8] = a[6] ^ a[7]; + b[8] = b[6] ^ b[7]; + + for (i = 0; i < 9; i ++) { + bmul(&b[i], &a[i], b[i], a[i]); + } + + c0 = a[0]; + c1 = b[0] ^ a[2] ^ a[0] ^ a[1]; + c2 = a[1] ^ b[2] ^ b[0] ^ b[1]; + c3 = b[1]; + d0 = a[3]; + d1 = b[3] ^ a[5] ^ a[3] ^ a[4]; + d2 = a[4] ^ b[5] ^ b[3] ^ b[4]; + d3 = b[4]; + e0 = a[6]; + e1 = b[6] ^ a[8] ^ a[6] ^ a[7]; + e2 = a[7] ^ b[8] ^ b[6] ^ b[7]; + e3 = b[7]; + + e0 ^= c0 ^ d0; + e1 ^= c1 ^ d1; + e2 ^= c2 ^ d2; + e3 ^= c3 ^ d3; + c2 ^= e0; + c3 ^= e1; + d0 ^= e2; + d1 ^= e3; + +#if 0 + // This rotation is GHASH-only. + /* + * GHASH specification has the bits "reversed" (most + * significant is in fact least significant), which does + * not matter for a carryless multiplication, except that + * the 255-bit result must be shifted by 1 bit. + */ + zw[0] = c0 << 1; + zw[1] = (c1 << 1) | (c0 >> 31); + zw[2] = (c2 << 1) | (c1 >> 31); + zw[3] = (c3 << 1) | (c2 >> 31); + zw[4] = (d0 << 1) | (c3 >> 31); + zw[5] = (d1 << 1) | (d0 >> 31); + zw[6] = (d2 << 1) | (d1 >> 31); + zw[7] = (d3 << 1) | (d2 >> 31); +#else + zw[0] = c0; + zw[1] = c1; + zw[2] = c2; + zw[3] = c3; + zw[4] = d0; + zw[5] = d1; + zw[6] = d2; + zw[7] = d3; +#endif + + /* + * We now do the reduction modulo the field polynomial + * to get back to 128 bits. + */ + for (i = 0; i < 4; i ++) { + uint32_t lw; + + lw = zw[i]; + zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7); + zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25); + } + memcpy(yw, zw + 4, 16); + } +} +#undef MUL diff --git a/src/ext/polyval/ctmul64.c b/src/ext/polyval/ctmul64.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This is the 64-bit variant of br_ghash_ctmul32(), with 64-bit operands + * and bit reversal of 64-bit words. + */ + +static inline uint64_t +bmul64(uint64_t x, uint64_t y) +{ + uint64_t x0, x1, x2, x3; + uint64_t y0, y1, y2, y3; + uint64_t z0, z1, z2, z3; + + x0 = x & (uint64_t)0x1111111111111111; + x1 = x & (uint64_t)0x2222222222222222; + x2 = x & (uint64_t)0x4444444444444444; + x3 = x & (uint64_t)0x8888888888888888; + y0 = y & (uint64_t)0x1111111111111111; + y1 = y & (uint64_t)0x2222222222222222; + y2 = y & (uint64_t)0x4444444444444444; + y3 = y & (uint64_t)0x8888888888888888; + z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1); + z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2); + z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3); + z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0); + z0 &= (uint64_t)0x1111111111111111; + z1 &= (uint64_t)0x2222222222222222; + z2 &= (uint64_t)0x4444444444444444; + z3 &= (uint64_t)0x8888888888888888; + return z0 | z1 | z2 | z3; +} + +static uint64_t +rev64(uint64_t x) +{ +#define RMS(m, s) do { \ + x = ((x & (uint64_t)(m)) << (s)) \ + | ((x >> (s)) & (uint64_t)(m)); \ + } while (0) + + RMS(0x5555555555555555, 1); + RMS(0x3333333333333333, 2); + RMS(0x0F0F0F0F0F0F0F0F, 4); + RMS(0x00FF00FF00FF00FF, 8); + RMS(0x0000FFFF0000FFFF, 16); + return (x << 32) | (x >> 32); + +#undef RMS +} + + +static void +pv_mul_y_h(polyval_t *pv) +{ + uint64_t y0, y1; + uint64_t h0, h1, h2, h0r, h1r, h2r; + + y0 = pv->y.lo; + y1 = pv->y.hi; + h0 = pv->key.h.lo; + h1 = pv->key.h.hi; + h0r = rev64(h0); + h1r = rev64(h1); + + h2 = h0 ^ h1; + h2r = h0r ^ h1r; + { + uint64_t y0r, y1r, y2, y2r; + uint64_t z0, z1, z2, z0h, z1h, z2h; + uint64_t v0, v1, v2, v3; + + y0r = rev64(y0); + y1r = rev64(y1); + y2 = y0 ^ y1; + y2r = y0r ^ y1r; + + z0 = bmul64(y0, h0); + z1 = bmul64(y1, h1); + z2 = bmul64(y2, h2); + z0h = bmul64(y0r, h0r); + z1h = bmul64(y1r, h1r); + z2h = bmul64(y2r, h2r); + z2 ^= z0 ^ z1; + z2h ^= z0h ^ z1h; + z0h = rev64(z0h) >> 1; + z1h = rev64(z1h) >> 1; + z2h = rev64(z2h) >> 1; + + v0 = z0; + v1 = z0h ^ z2; + v2 = z1 ^ z2h; + v3 = z1h; + +#if 0 + // This step is GHASH only. + v3 = (v3 << 1) | (v2 >> 63); + v2 = (v2 << 1) | (v1 >> 63); + v1 = (v1 << 1) | (v0 >> 63); + v0 = (v0 << 1); +#endif + + v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7); + v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57); + v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7); + v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57); + + pv->y.lo = v2; + pv->y.hi = v3; + } +} diff --git a/src/ext/polyval/pclmul.c b/src/ext/polyval/pclmul.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This is the GHASH implementation that leverages the pclmulqdq opcode + * (from the AES-NI instructions). + */ + +#include <wmmintrin.h> + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +#define BR_TARGET(x) __attribute__((target(x))) + +#if defined(__GNUC__) && !defined(__clang__) + _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul\")") +#endif + +#if 0 +/* + * Test CPU support for PCLMULQDQ. + */ +static inline int +pclmul_supported(void) +{ + /* + * Bit mask for features in ECX: + * 1 PCLMULQDQ support + */ + return br_cpuid(0, 0, 0x00000002, 0); +} + +/* see bearssl_hash.h */ +br_ghash +br_ghash_pclmul_get(void) +{ + return pclmul_supported() ? &br_ghash_pclmul : 0; +} + +BR_TARGETS_X86_UP +#endif +/* + * Call pclmulqdq. Clang appears to have trouble with the intrinsic, so, + * for that compiler, we use inline assembly. Inline assembly is + * potentially a bit slower because the compiler does not understand + * what the opcode does, and thus cannot optimize instruction + * scheduling. + * + * We use a target of "sse2" only, so that Clang may still handle the + * '__m128i' type and allocate SSE2 registers. + */ +#ifdef __clang__ + BR_TARGET("sse2") +static inline __m128i +pclmulqdq00(__m128i x, __m128i y) +{ + __asm__ ("pclmulqdq $0x00, %1, %0" : "+x" (x) : "x" (y)); + return x; +} +BR_TARGET("sse2") +static inline __m128i +pclmulqdq11(__m128i x, __m128i y) +{ + __asm__ ("pclmulqdq $0x11, %1, %0" : "+x" (x) : "x" (y)); + return x; +} +#else +#define pclmulqdq00(x, y) _mm_clmulepi64_si128(x, y, 0x00) +#define pclmulqdq11(x, y) _mm_clmulepi64_si128(x, y, 0x11) +#endif + +/* + * From a 128-bit value kw, compute kx as the XOR of the two 64-bit + * halves of kw (into the right half of kx; left half is unspecified). + */ +#define BK(kw, kx) do { \ + kx = _mm_xor_si128(kw, _mm_shuffle_epi32(kw, 0x0E)); \ + } while (0) + +/* + * Combine two 64-bit values (k0:k1) into a 128-bit (kw) value and + * the XOR of the two values (kx). + */ +#define PBK(k0, k1, kw, kx) do { \ + kw = _mm_unpacklo_epi64(k1, k0); \ + kx = _mm_xor_si128(k0, k1); \ + } while (0) + +/* + * Perform reduction in GF(2^128). The 256-bit value is in x0..x3; + * result is written in x0..x1. + */ +#define REDUCE_F128(x0, x1, x2, x3) do { \ + x1 = _mm_xor_si128( \ + x1, \ + _mm_xor_si128( \ + _mm_xor_si128( \ + x3, \ + _mm_srli_epi64(x3, 1)), \ + _mm_xor_si128( \ + _mm_srli_epi64(x3, 2), \ + _mm_srli_epi64(x3, 7)))); \ + x2 = _mm_xor_si128( \ + _mm_xor_si128( \ + x2, \ + _mm_slli_epi64(x3, 63)), \ + _mm_xor_si128( \ + _mm_slli_epi64(x3, 62), \ + _mm_slli_epi64(x3, 57))); \ + x0 = _mm_xor_si128( \ + x0, \ + _mm_xor_si128( \ + _mm_xor_si128( \ + x2, \ + _mm_srli_epi64(x2, 1)), \ + _mm_xor_si128( \ + _mm_srli_epi64(x2, 2), \ + _mm_srli_epi64(x2, 7)))); \ + x1 = _mm_xor_si128( \ + _mm_xor_si128( \ + x1, \ + _mm_slli_epi64(x2, 63)), \ + _mm_xor_si128( \ + _mm_slli_epi64(x2, 62), \ + _mm_slli_epi64(x2, 57))); \ + } while (0) + + +/* see bearssl_hash.h */ +BR_TARGET("ssse3,pclmul") +static +void pv_mul_y_h(polyval_t *pv) +{ + __m128i yw, h1w, h1x; + + h1w = pv->key.h; + BK(h1w, h1x); + + { + __m128i aw, ax; + __m128i t0, t1, t2, t3; + + aw = pv->y; + BK(aw, ax); + + t1 = pclmulqdq11(aw, h1w); + t3 = pclmulqdq00(aw, h1w); + t2 = pclmulqdq00(ax, h1x); + t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3)); + t0 = _mm_shuffle_epi32(t1, 0x0E); + t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E)); + t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E)); +#if 0 // This step is GHASH-only. + SL_256(t0, t1, t2, t3); +#endif + REDUCE_F128(t0, t1, t2, t3); + yw = _mm_unpacklo_epi64(t1, t0); + } + + pv->y = yw; +} diff --git a/src/ext/polyval/polyval.c b/src/ext/polyval/polyval.c @@ -0,0 +1,280 @@ +/* Copyright (c) 2025, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file polyval.h + * \brief Implementation for polyval universal hash function. + * + * Polyval, which was first defined for AES-GCM-SIV, is a + * universal hash based on multiplication in GF(2^128). + * Unlike the more familiar GHASH, it is defined to work on + * little-endian inputs, and so is more straightforward and efficient + * on little-endian architectures. + * + * In Tor we use it as part of the Counter Galois Onion relay + * encryption format. + **/ + +/* Implementation notes: + * + * Our implementation is based on the GHASH code from BearSSL + * by Thomas Pornin. There are three implementations: + * + * pclmul.c -- An x86-only version, based on the CLMUL instructions + * introduced for westlake processors in 2010. + * + * ctmul64.c -- A portable contant-time implementation for 64-bit + * processors. + * + * ctmul.c -- A portable constant-time implementation for 32-bit + * processors with an efficient 32x32->64 multiply instruction. + * + * Note that the "ctmul" implementations are only constant-time + * if the corresponding CPU multiply and rotate instructions are + * also constant-time. But that's an architectural assumption we + * make in Tor. + */ + +#include "ext/polyval/polyval.h" + +#include <string.h> + +typedef pv_u128_ u128; + +/* ======== + * We declare these functions, to help implement polyval. + * + * They have different definitions depending on our representation + * of 128-bit integers. + */ +/** + * Read a u128-bit little-endian integer from 'bytes', + * which may not be aligned. + */ +static inline u128 u128_from_bytes(const uint8_t *bytes); +/** + * Store a u128-bit little-endian integer to 'bytes_out', + * which may not be aligned. + */ +static inline void u128_to_bytes(u128, uint8_t *bytes_out); +/** + * XOR a u128 into the y field of a polyval_t struct. + * + * (Within the polyval struct, perform "y ^= v"). + */ +static inline void pv_xor_y(polyval_t *, u128 v); + +/* ======== + * The function which we expect our backend to implement. + */ +/** + * Within the polyval struct, perform "y *= h". + * + * (This is a carryless multiply in the Polyval galois field) + */ +static void pv_mul_y_h(polyval_t *); + +/* ===== + * Endianness conversion for big-endian platforms + */ +#ifdef WORDS_BIG_ENDIAN +#ifdef __GNUC__ +#define bswap64(x) __builtin_bswap64(x) +#define bswap32(x) __builtin_bswap32(x) +#else +/* The (compiler should optimize these into a decent bswap instruction) */ +static inline uint64_t +bswap64(uint64_t v) +{ + return + ((value & 0xFF00000000000000) >> 56) | + ((value & 0x00FF000000000000) >> 48) | + ((value & 0x0000FF0000000000) >> 40) | + ((value & 0x000000FF00000000) >> 32) | + ((value & 0x00000000FF000000) >> 24) | + ((value & 0x0000000000FF0000) >> 16) | + ((value & 0x000000000000FF00) >> 8) | + ((value & 0x00000000000000FF)); +} +static inline uint64_t +bswap32(uint64_t v) +{ + return + ((value & 0xFF000000) >> 24) | + ((value & 0x00FF0000) >> 16) | + ((value & 0x0000FF00) >> 8) | + ((value & 0x000000FF)); +} +#endif +#endif + +#ifdef WORDS_BIG_ENDIAN +#define convert_byte_order64(x) bswap64(x) +#define convert_byte_order32(x) bswap32(x) +#else +#define convert_byte_order64(x) (x) +#define convert_byte_order32(x) (x) +#endif + +#ifdef PV_USE_PCLMUL + +#include "ext/polyval/pclmul.c" + +static inline u128 +u128_from_bytes(const uint8_t *bytes) +{ + return _mm_loadu_si128((const u128*)bytes); +} +static inline void +u128_to_bytes(u128 val, uint8_t *bytes_out) +{ + _mm_storeu_si128((u128*)bytes_out, val); +} +static inline void +pv_xor_y(polyval_t *pv, u128 v) +{ + pv->y = _mm_xor_si128(pv->y, v); +} +#elif defined(PV_USE_CTMUL64) + +#include "ext/polyval/ctmul64.c" + +static inline u128 +u128_from_bytes(const uint8_t *bytes) +{ + u128 r; + memcpy(&r.lo, bytes, 8); + memcpy(&r.hi, bytes + 8, 8); + r.lo = convert_byte_order64(r.lo); + r.hi = convert_byte_order64(r.hi); + return r; +} +static inline void +u128_to_bytes(u128 val, uint8_t *bytes_out) +{ + uint64_t lo = convert_byte_order64(val.lo); + uint64_t hi = convert_byte_order64(val.hi); + memcpy(bytes_out, &lo, 8); + memcpy(bytes_out + 8, &hi, 8); +} +static inline void +pv_xor_y(polyval_t *pv, u128 val) +{ + pv->y.lo ^= val.lo; + pv->y.hi ^= val.hi; +} +#elif defined(PV_USE_CTMUL) +#include "ext/polyval/ctmul.c" + +static inline u128 +u128_from_bytes(const uint8_t *bytes) +{ + u128 r; + memcpy(&r.v, bytes, 16); + for (int i = 0; i < 4; ++i) { + r.v[i] = convert_byte_order32(r.v[i]); + } + return r; +} +static inline void +u128_to_bytes(u128 val, uint8_t *bytes_out) +{ + uint32_t v[4]; + for (int i = 0; i < 4; ++i) { + v[i] = convert_byte_order32(val.v[i]); + } + memcpy(bytes_out, v, 16); +} +static inline void +pv_xor_y(polyval_t *pv, u128 val) +{ + for (int i = 0; i < 4; ++i) { + pv->y.v[i] ^= val.v[i]; + } +} +#endif + +void +polyval_key_init(polyval_key_t *pvk, const uint8_t *key) +{ + pvk->h = u128_from_bytes(key); +} +void +polyval_init(polyval_t *pv, const uint8_t *key) +{ + polyval_key_init(&pv->key, key); + memset(&pv->y, 0, sizeof(u128)); +} +void +polyval_init_from_key(polyval_t *pv, const polyval_key_t *key) +{ + memcpy(&pv->key, key, sizeof(polyval_key_t)); + memset(&pv->y, 0, sizeof(u128)); +} +void +polyval_add_block(polyval_t *pv, const uint8_t *block) +{ + u128 b = u128_from_bytes(block); + pv_xor_y(pv, b); + pv_mul_y_h(pv); +} +void +polyval_add_zpad(polyval_t *pv, const uint8_t *data, size_t n) +{ + while (n > 16) { + polyval_add_block(pv, data); + data += 16; + n -= 16; + } + if (n) { + uint8_t block[16]; + memset(&block, 0, sizeof(block)); + memcpy(block, data, n); + polyval_add_block(pv, block); + } +} +void +polyval_get_tag(const polyval_t *pv, uint8_t *tag_out) +{ + u128_to_bytes(pv->y, tag_out); +} +void +polyval_reset(polyval_t *pv) +{ + memset(&pv->y, 0, sizeof(u128)); +} + +#if 0 +#include <stdio.h> +int +main(int c, char **v) +{ + // From RFC 8452 appendix A + uint8_t key[16] = + { 0x25, 0x62, 0x93, 0x47, 0x58, 0x92, 0x42, 0x76, + 0x1d, 0x31, 0xf8, 0x26, 0xba, 0x4b, 0x75, 0x7b }; + uint8_t block1[16] = + { 0x4f, 0x4f, 0x95, 0x66, 0x8c, 0x83, 0xdf, 0xb6, + 0x40, 0x17, 0x62, 0xbb, 0x2d, 0x01, 0xa2, 0x62 }; + uint8_t block2[16] = { + 0xd1, 0xa2, 0x4d, 0xdd, 0x27, 0x21, 0xd0, 0x06, + 0xbb, 0xe4, 0x5f, 0x20, 0xd3, 0xc9, 0xf3, 0x62 }; + uint8_t expect_result[16] = { + 0xf7, 0xa3, 0xb4, 0x7b, 0x84, 0x61, 0x19, 0xfa, + 0xe5, 0xb7, 0x86, 0x6c, 0xf5, 0xe5, 0xb7, 0x7e }; + + polyval_t pv; + uint8_t tag[16]; + polyval_init(&pv, key); + polyval_add_block(&pv, block1); + polyval_add_block(&pv, block2); + polyval_get_tag(&pv, tag); + if (!memcmp(expect_result, tag, 16)) { + puts("OK"); + return 0; + } else { + puts("NOPE"); + return 1; + } +} +#endif diff --git a/src/ext/polyval/polyval.h b/src/ext/polyval/polyval.h @@ -0,0 +1,120 @@ +/* Copyright (c) 2025, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file polyval.h + * \brief APIs for polyval universal hash function. + **/ + +#ifndef TOR_POLYVAL_H +#define TOR_POLYVAL_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +/* Decide which implementation to use. */ +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) \ + || defined(_M_X64) || defined(_M_IX86) || defined(__i486) \ + || defined(__i386__) +/* Use intel intrinsics for carryless multiply. + * + * TODO: In theory we should detect whether we have the relevant instructions, + * but they are all at least 15 years old. + */ +#define PV_USE_PCLMUL +#elif SIZEOF_VOID_P >= 8 +/* It's a 64-bit architecture; use the generic 64-bit constant-time + * implementation. + */ +#define PV_USE_CTMUL64 +#elif SIZEOF_VOID_P == 4 +/* It's a 64-bit architecture; use the generic 32-bit constant-time + * implementation. + */ +#define PV_USE_CTMUL +#else +#error "sizeof(void*) is implausibly weird." +#endif + +/** + * Declare a 128 bit integer type. + # The exact representation will depend on which implementation we've chosen. + */ +#ifdef PV_USE_PCLMUL +#include <emmintrin.h> +typedef __m128i pv_u128_; +#elif defined(PV_USE_CTMUL64) +typedef struct pv_u128_ { + uint64_t lo; + uint64_t hi; +} pv_u128_; +#elif defined(PV_USE_CTMUL) +typedef struct pv_u128_ { + uint32_t v[4]; +} pv_u128_; +#endif + +/** A key for a polyval hash, plus any precomputed key material. */ +typedef struct polyval_key_t { + pv_u128_ h; +} polyval_key_t; + +/** + * State for an instance of the polyval hash. + **/ +typedef struct polyval_t { + /** The key used for this instance of polyval. */ + polyval_key_t key; + /** The accumulator */ + pv_u128_ y; +} polyval_t; + +/** + * Length of a polyval key, in bytes. + */ +#define POLYVAL_KEY_LEN 16 +/** + * Length of a polyval block, in bytes. + */ +#define POLYVAL_BLOCK_LEN 16 +/** + * Length of a polyval tag (output), in bytes. + */ +#define POLYVAL_TAG_LEN 16 + +/** Do any necessary precomputation from a polyval key, + * and store it. + */ +void polyval_key_init(polyval_key_t *, const uint8_t *key); +/** + * Initialize a polyval instance with a given key. + */ +void polyval_init(polyval_t *, const uint8_t *key); +/** + * Initialize a polyval instance with a preconstructed key. + */ +void polyval_init_from_key(polyval_t *, const polyval_key_t *key); +/** + * Update a polyval instance with a new 16-byte block. + */ +void polyval_add_block(polyval_t *, const uint8_t *block); +/** + * Update a polyval instance with 'n' bytes from 'data'. + * If 'n' is not evenly divisible by 16, pad it at the end with zeros. + * + * NOTE: This is not a general-purpose padding construction; + * it can be insecure if your are using it in context where the input length + * is variable. + */ +void polyval_add_zpad(polyval_t *, const uint8_t *data, size_t n); +/** + * Copy the 16-byte tag from a polyval instance into 'tag_out' + */ +void polyval_get_tag(const polyval_t *, uint8_t *tag_out); +/** + * Reset a polyval instance to its original state, + * retaining its key. + */ +void polyval_reset(polyval_t *); + +#endif diff --git a/src/lib/crypt_ops/aes.h b/src/lib/crypt_ops/aes.h @@ -15,6 +15,7 @@ #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; @@ -28,4 +29,38 @@ void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len); int evaluate_evp_for_aes(int force_value); int evaluate_ctr_for_aes(void); +#ifdef USE_AES_RAW +typedef struct aes_raw_t aes_raw_t; + +aes_raw_t *aes_raw_new(const uint8_t *key, int key_bits, bool encrypt); +void aes_raw_set_key(aes_raw_t **cipher, const uint8_t *key, + int key_bits, bool encrypt); +void aes_raw_free_(aes_raw_t *cipher); +#define aes_raw_free(cipher) \ + 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) */ diff --git a/src/lib/crypt_ops/aes_nss.c b/src/lib/crypt_ops/aes_nss.c @@ -9,6 +9,9 @@ * \brief Use NSS to implement AES_CTR. **/ +#define USE_AES_RAW +#define TOR_AES_PRIVATE + #include "orconfig.h" #include "lib/crypt_ops/aes.h" #include "lib/crypt_ops/crypto_nss_mgt.h" @@ -104,3 +107,116 @@ evaluate_ctr_for_aes(void) { return 0; } + +aes_raw_t * +aes_raw_new(const uint8_t *key, int key_bits, bool encrypt) +{ + const CK_MECHANISM_TYPE ckm = CKM_AES_ECB; + SECItem keyItem = { .type = siBuffer, // ???? + .data = (unsigned char *)key, + .len = (key_bits / 8) }; + SECItem ivItem = { .type = siBuffer, + .data = NULL, + .len = 0 }; + PK11SlotInfo *slot = NULL; + PK11SymKey *keyObj = NULL; + SECItem *ivObj = NULL; + PK11Context *result = NULL; + + slot = PK11_GetBestSlot(ckm, NULL); + if (!slot) + goto err; + + CK_ATTRIBUTE_TYPE mode = encrypt ? CKA_ENCRYPT : CKA_DECRYPT; + + keyObj = PK11_ImportSymKey(slot, ckm, PK11_OriginUnwrap, + mode, &keyItem, NULL); + if (!keyObj) + goto err; + + ivObj = PK11_ParamFromIV(ckm, &ivItem); + if (!ivObj) + goto err; + + PORT_SetError(SEC_ERROR_IO); + result = PK11_CreateContextBySymKey(ckm, mode, keyObj, ivObj); + + err: + + if (ivObj) + SECITEM_FreeItem(ivObj, PR_TRUE); + if (keyObj) + PK11_FreeSymKey(keyObj); + if (slot) + PK11_FreeSlot(slot); + + tor_assert(result); + return (aes_raw_t *)result; +} +void +aes_raw_free_(aes_raw_t *cipher_) +{ + if (!cipher_) + return; + PK11Context *ctx = (PK11Context*)cipher_; + PK11_DestroyContext(ctx, PR_TRUE); +} +void +aes_raw_set_key(aes_raw_t **cipher, const uint8_t *key, + int key_bits, bool encrypt) +{ + // For NSS, I could not find a method to change the key + // of an existing context. + aes_raw_free(*cipher); + *cipher = aes_raw_new(key, key_bits, encrypt); +} +void +aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block) +{ + SECStatus s; + PK11Context *ctx = (PK11Context*)cipher; + int result_len = 0; + s = PK11_CipherOp(ctx, block, &result_len, 16, block, 16); + tor_assert(s == SECSuccess); + tor_assert(result_len == 16); +} +void +aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block) +{ + /* 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); + } +} diff --git a/src/lib/crypt_ops/aes_openssl.c b/src/lib/crypt_ops/aes_openssl.c @@ -9,6 +9,9 @@ * \brief Use OpenSSL to implement AES_CTR. **/ +#define USE_AES_RAW +#define TOR_AES_PRIVATE + #include "orconfig.h" #include "lib/crypt_ops/aes.h" #include "lib/crypt_ops/crypto_util.h" @@ -88,6 +91,17 @@ ENABLE_GCC_WARNING("-Wredundant-decls") * 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. */ @@ -340,17 +354,6 @@ aes_cipher_free_(aes_cnt_cipher_t *cipher) #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. @@ -383,19 +386,131 @@ 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>. */ -static void -aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv) +#endif /* defined(USE_EVP_AES_CTR) */ + +/* ======== + * Functions for "raw" (ECB) AES. + * + * I'm choosing the name "raw" here because ECB is not a mode; + * it's a disaster. The only way to use this safely is + * within a real construction. + */ + +/** + * Create a new instance of AES using a key of length 'key_bits' + * for raw block encryption. + * + * This is even more low-level than counter-mode, and you should + * only use it with extreme caution. + */ +aes_raw_t * +aes_raw_new(const uint8_t *key, int key_bits, bool encrypt) { -#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); + EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new(); + tor_assert(cipher); + const EVP_CIPHER *c = NULL; + switch (key_bits) { + case 128: c = EVP_aes_128_ecb(); break; + case 192: c = EVP_aes_192_ecb(); break; + case 256: c = EVP_aes_256_ecb(); break; + default: tor_assert_unreached(); + } + + int r = EVP_CipherInit(cipher, c, key, NULL, encrypt); + tor_assert(r == 1); + EVP_CIPHER_CTX_set_padding(cipher, 0); + return (aes_raw_t *)cipher; +} +/** + * Replace the key on an existing aes_raw_t. + * + * This may be faster than freeing and reallocating. + */ +void +aes_raw_set_key(aes_raw_t **cipher_, const uint8_t *key, + int key_bits, bool encrypt) +{ + const EVP_CIPHER *c = *(EVP_CIPHER**) cipher_; + switch (key_bits) { + case 128: c = EVP_aes_128_ecb(); break; + case 192: c = EVP_aes_192_ecb(); break; + case 256: c = EVP_aes_256_ecb(); break; + default: tor_assert_unreached(); + } + aes_raw_t *cipherp = *cipher_; + EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *)cipherp; + EVP_CIPHER_CTX_reset(cipher); + int r = EVP_CipherInit(cipher, c, key, NULL, encrypt); + tor_assert(r == 1); + EVP_CIPHER_CTX_set_padding(cipher, 0); } -#endif /* defined(USE_EVP_AES_CTR) */ +/** + * Release storage held by 'cipher'. + */ +void +aes_raw_free_(aes_raw_t *cipher_) +{ + if (!cipher_) + return; + EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *)cipher_; +#ifdef OPENSSL_1_1_API + EVP_CIPHER_CTX_reset(cipher); +#else + EVP_CIPHER_CTX_cleanup(cipher); +#endif + EVP_CIPHER_CTX_free(cipher); +} +#define aes_raw_free(cipher) \ + FREE_AND_NULL(aes_raw_t, aes_raw_free_, (cipher)) +/** + * Encrypt a single 16-byte block with 'cipher', + * which must have been initialized for encryption. + */ +void +aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block) +{ + int outl = 16; + int r = EVP_EncryptUpdate((EVP_CIPHER_CTX *)cipher, block, &outl, block, 16); + tor_assert(r == 1); + tor_assert(outl == 16); +} +/** + * Decrypt a single 16-byte block with 'cipher', + * which must have been initialized for decryption. + */ +void +aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block) +{ + int outl = 16; + int r = EVP_DecryptUpdate((EVP_CIPHER_CTX *)cipher, block, &outl, block, 16); + 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); +} diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c @@ -76,6 +76,11 @@ we_like_ssl_kea(SSLKEAType kt) case ssl_kea_ecdh_psk: return false; case ssl_kea_dh_psk: return false; +#ifdef NSS_HAS_ECDH_HYBRID + case ssl_kea_ecdh_hybrid_psk: return false; + case ssl_kea_ecdh_hybrid: return true; +#endif + case ssl_kea_dh: return true; case ssl_kea_ecdh: return true; case ssl_kea_tls13_any: return true; diff --git a/src/test/cgo_vectors.inc b/src/test/cgo_vectors.inc @@ -0,0 +1,651 @@ +/* CGO test vectors. Chosen from those generated by + * the python reference implementation. + */ + +/* Accept python booleans here. */ +#define True true +#define False false + +static const struct et_testvec { + bool encrypt; + const char *keys; + const char *tweaks; + const char *block; + const char *expect; +} ET_TESTVECS[] = { +// Zeroes, encrypt +{ + // Encrypt + True, + // (KB,KU) + "0000000000000000000000000000000000000000000000000000000000000000", + // T + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // M + "00000000000000000000000000000000", + // OUTPUT + "66e94bd4ef8a2c3b884cfa59ca342b2e", +}, +// Zeroes, decrypt +{ + // Encrypt + False, + // (KB,KU) + "0000000000000000000000000000000000000000000000000000000000000000", + // T + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // M + "00000000000000000000000000000000", + // OUTPUT + "140f0f1011b5223d79587717ffd9ec3a", +}, +// Pseudorandom 1, Encrypt +{ + // Encrypt + True, + // (KB,KU) + "39dd87e0b958cec5d2ba04a17fad9f134770f20f14038bdcd751056a7f16041f", + // T + "fbf69df9bfc3bec7e4a5dd0c9785dd18727dab2b11baf2898b3b775baed777d209812a71e8d5a1f624a4c2c3ccd91064f494f5deb2b7ab362cda53df3e0291cc439052a05cdbc8fe259f7190792b637eeaf0c5ebdf7d02ec6b89beecf131a916f5c6989267e28defaa5937b35f0a1ce1ef91838c408b2d199170f29e76ae21b8b62a733e4de9d281e6935d20d991e3e1801907f6477f9fd40bd4e72de681336e603bb7ec17d512728864b7cebc9bc6bbc0629082830fa3702cb2eff0fb289b7431d4e1b0b6109599c91c4c78540792331e592fe8c0c190ea18275386ec3d85f68996b6891e484ad4b0601008ead6ed60145f8d01b81d1cf31556744b1676f6c5caea56c5cd424350e0bc3c478efc2e11d868ddf73185627c778ba8b7d684f3d0b9dfe7e1b63985bb43e37a2e5938cae8b1741cb58aea2b383de9bf0531e344a5651f7f145aad1656e695e30ee6483b5e18e43b0aa6e308f2e1c8cfdd85a118476c9ca91c8ca993563b2df014289738c4b6ce772e2ac36a26547b97ba26673e28e634f88a91007e220f1beaa97ae00972954fc705de30642014fa5c4c07792a0f0b4a8ef3c6f0584b1029171a28cd5898e760c91f71c5f9610747ae21f30f1b1bfa7e4df9aedfa8b006f29e89e5b182ac9957067f86767ed5620abcb2c50a41c423e48a676864a2d151c5bf2442f3b90bfd7c047f92cd112367d0579c9f02", + // M + "40f417ba5a4c78a23e6540b52b68e1e6", + // OUTPUT + "84bfff8347889f1a9f2cf930c82677be", +}, +// Pseudorandom 1, Decrypt +{ + // Encrypt + False, + // (KB,KU) + "39dd87e0b958cec5d2ba04a17fad9f134770f20f14038bdcd751056a7f16041f", + // T + "fbf69df9bfc3bec7e4a5dd0c9785dd18727dab2b11baf2898b3b775baed777d209812a71e8d5a1f624a4c2c3ccd91064f494f5deb2b7ab362cda53df3e0291cc439052a05cdbc8fe259f7190792b637eeaf0c5ebdf7d02ec6b89beecf131a916f5c6989267e28defaa5937b35f0a1ce1ef91838c408b2d199170f29e76ae21b8b62a733e4de9d281e6935d20d991e3e1801907f6477f9fd40bd4e72de681336e603bb7ec17d512728864b7cebc9bc6bbc0629082830fa3702cb2eff0fb289b7431d4e1b0b6109599c91c4c78540792331e592fe8c0c190ea18275386ec3d85f68996b6891e484ad4b0601008ead6ed60145f8d01b81d1cf31556744b1676f6c5caea56c5cd424350e0bc3c478efc2e11d868ddf73185627c778ba8b7d684f3d0b9dfe7e1b63985bb43e37a2e5938cae8b1741cb58aea2b383de9bf0531e344a5651f7f145aad1656e695e30ee6483b5e18e43b0aa6e308f2e1c8cfdd85a118476c9ca91c8ca993563b2df014289738c4b6ce772e2ac36a26547b97ba26673e28e634f88a91007e220f1beaa97ae00972954fc705de30642014fa5c4c07792a0f0b4a8ef3c6f0584b1029171a28cd5898e760c91f71c5f9610747ae21f30f1b1bfa7e4df9aedfa8b006f29e89e5b182ac9957067f86767ed5620abcb2c50a41c423e48a676864a2d151c5bf2442f3b90bfd7c047f92cd112367d0579c9f02", + // M + "40f417ba5a4c78a23e6540b52b68e1e6", + // OUTPUT + "e2c0bfdef28b5504cf0ec708a6866a17", +}}; + +static const struct prf_testvec { + const char *keys; + int t; + const char *input; + const char *expect; +} PRF_TESTVECS[] = { +// All zeros, t=0 +{ + // K,B + "0000000000000000000000000000000000000000000000000000000000000000", + // T + 0, + // t + "00000000000000000000000000000000", + // OUTPUT + "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c", +}, +// All zeros, t=1 +{ + // K,B + "0000000000000000000000000000000000000000000000000000000000000000", + // T + 1, + // t + "00000000000000000000000000000000", + // OUTPUT + "7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f7329612dce4a0e5bc792b5b5a55f9c2f30e07", +}, +// All ones, t=0 +{ + // K,B + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // T + 0, + // t + "ffffffffffffffffffffffffffffffff", + // OUTPUT + "3ae902931ae8d3ba07a2efdbf0411525c966356463673443646d3ed3e5ba68a61ccd8ae0d8f8d84adca5c0023f02efd10cc7bc7c9fbfd169bf47a792bbba07d6c9338101d0c28e476e99520413a37c3c9045909a8d37c6cba7f9e33254ff0b2ea11ccd6d0a6eed028bb3acccb38fe0a50ea2ca51dc35dc12541f5ce00611336ef966d9a9027a6342c09590d056880e79bfd1a271aff821114649e33a6b4d83be0883b3ad4b315ac6b77017c748a8bb71a981678ff9c6ca086507efb6e8850043767bea06d66ee5e9b2870107474150044488a2d00bd1d5154e0f1aeac5af0b73049004f8717baa13c1ae0088f2dfdf8e08a612aa11a8bb64ab2a4d292967504a6cb451a56275b756c2d7f65aab728617154693a7b31d048802b0ce635754977fb851bb21dddcd9564795e31523fcc35ccfc066b9542508b4daa65b4c9083b12a5cd08f7c45906523d5d7131f279959900473a756e48ababa93fb42663401d84bef93c6cfd6e02fc17797a7004671d21d3bc35cb2e9a344da0a16c300f3c977b6c892e0c2a9517862bec47a51fd49c5a4d46620ea5df9a055e89c2d54abffb00704c1219175433bc1683d93c75ffd7feccc605092b197c5aa5aa995ba0c0e33870b0f513a5eefd9d64fc6e89862709ca9876df86c189181e70e4eed2d876a12480b64afaffe54ba4ac8f23043d8", +}, +// All ones, t=1 +{ + // K,B + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // T + 1, + // t + "ffffffffffffffffffffffffffffffff", + // OUTPUT + "be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df4b263f03af0acda2f9721d0f4c0783c7", +}, +// Pseudorandom 1, t=0 +{ + // K,B + "908bf9a158c67f9cd5cb5cee476a4b30b9ec92756d94b1f9f40073c185c39780", + // T + 0, + // t + "d5d73799a0f37a1c7ff3ceb187ebd059", + // OUTPUT + "0573c27e297dad58e84942c498d3c376c1f8423dea1df70338259814f2b939ffe074b22fae1385e2d453aca882cb6257ec4fc86915f05be11ae36df4d8678ff29f68c45797c2a4158c4c30c703faeda452858ae37b7735f47b2924cd6f6040e7f6b19958f6d5a12aae72b589d6f85e5a3267881b2916da948fe1626d68ee60a13c90599b40f8a14fd8d1354bc5beb23f38043d7e547b879f618302426dd7785bc2caf44b31a2e1ec5d4dcb4047415d0bbc6900dfdfa01e61c4aa3624f6d7f03cc1641610bd0d6f155cae7465a3d1e0ae8db7d5a00afd27824fd35b65a91728981566c7a046f1773210b76a449b76b5684eb3532a06225d89b70aae1d20c27d03c528b00051a3eb74f3b217b3d474076b8c4bab837476c6191bc7ae8266328d5a65f6a2c55c30999984e2747b7dc45af9e43533b750d9196cd2d64947b6dcf839821002441a428bbbeee45de052502aa76385b47aedbdbeed500c359fdd1ba042a5c9956a1b2e3e456472665f7a674d898a9c5ee58e6288304a323986f0d09b731ae401ac5f8ebeaf808cecce9945439ec76cccb5aafb875faf1274bc29beb29413e01ef72cb37eebc06428c24221f8af3c5ea742fc41506d501d8e45bed5d982ab16669da486c985a3e140eb55c754aaf3d7923d76519f8bac02e0e0c0961411d8c010d1c58498caeae8c69c62", +}, +// Pseudorandom 1, t=1 +{ + // K,B + "908bf9a158c67f9cd5cb5cee476a4b30b9ec92756d94b1f9f40073c185c39780", + // T + 1, + // t + "d5d73799a0f37a1c7ff3ceb187ebd059", + // OUTPUT + "75c5c6787bd0edf325cf772b8c09478df5094f093eddda9d4b7c2ab4ebcdd84c87192038ade81b8560ef7f5a3eb89a4957cf9bd138c575b6951f9940d44d443f47616dfdaf73be7a4664aa46bc279c20", +}, +// Pseudorandom 2, t=0 +{ + // K,B + "fcd9361d1dca1c7b9a24f754464eeda5727152bc98a818b2e720a0afa9103e10", + // T + 0, + // t + "d22ea954482f5bc511c6fcae80233d57", + // OUTPUT + "e5be8144283c5b638a7bbcae231cfb9d6727ee8f04bcf0f3c7ff94930facee8030712bc8b0d151a5ea27c4f614cd46fe1ef9eee2f64c8d8ddfce7ab1ed01cdd610e7b341b75408a6a8310ed62389348b76a59277a0eee05bdd5f5227d43fc113294b3af71d505a0c88d920387f44ef33029797d0c282991683adca83449e68aff578df836ee6b89cfc5fb0e8ce0d8d5146a09d57ec816e0fbbbdf80b298dfe6509aefcc892a6dd4bbbbfc6d9507e4013305986bb9d0cc050de172faa2039623cb93177a0b7c5966933ad2ee6fa930dbfe24148b63561551364fdcc3a1e1a5381d62a9508c6bd86a43ed602e5fcc0cee2c8d2a67c7de50428fa72ef75fd4aafe4bbc17cb03ffeb69066e5c6ee65c1df67fc9c33515d45cfc504c2d2db213b36df5a6b7864ccf11061464048329f2a79b6935b4219aab811fa07896497ba8dc47c1f2e9207e4be7a4f3651bba673d4911787df8423cc60601785ac5072516954efa6e30f27c04136f6bdff2d23b0489b2d7c9aea7f5320d48c337eeb2dd4f06eedab55316ba8f45b6f9a584ae8241183a261b467be3b500febbb609a38895d92f0aa8ca31197e81c85aefcea4d7a5f0d4f7825de0260f9563db272720c723a38f935113d1f2a89b02303eced1312316f29001f224a730031ac6e002916a2077fff2de0cb740622692fde1ffe1811", +}, +// Pseudorandom 2, t=1 +{ + // K,B + "fcd9361d1dca1c7b9a24f754464eeda5727152bc98a818b2e720a0afa9103e10", + // T + 1, + // t + "d22ea954482f5bc511c6fcae80233d57", + // OUTPUT + "242f479249fefc782eb74cb5304e54cf9f1230ba8908c1a322650edd916ecf76527d3a84db32d8ca0931b0420c8bcf388042cb152ee080af416a37cf2e0406de5ebb9c27061650e72552ecadca5af451", +}, +// Pseudorandom 3, t=0 +{ + // K,B + "b445f9a92d267dbd3b2dd9ad0cf90538b4013b72df0a23ef997f7baf9440733a", + // T + 0, + // t + "1d16d4b08c19887a050603dc8f17bb6d", + // OUTPUT + "d609818f6c26b96efadb6e5d84ed63c4d426e133cc72acc222a161feb8810f99d0d8dbace6181b8f41e601cf7bd33a3a23e84bf8898505e222a42fb889fe759e48fda34e6d39c357e6445864e55633bc264d4f4d33d0afd20a51ad1b3d6d18288d6930ac9775e6928cdce46642b5b81bdbbdb469f1d6f1a889a2c76c0258ca6a95c5f590c54f1503ec46f1b3ad6e93233f9f4ca9a57bc14aa505f4678d9fee8fa7b8f047252569b83c79e3a4abea6d4a481e159e91dced13f58be46f41ef52f1ebb17cd68875f2dee11ab6409fe5f0d5a189fdc86b4b214f2ccd47d419e66ba3889bac4b7da810b3ba647082662c74c2e2972962d8af31fc05a22e0df7f5e87a6bdfb2b414bf55e46581ca982bca237a0af99030d079b6e81404b6bad3011bdf114e2d042e019342a41b06d1ece656ff994b80796747ca413f783c903f0980873c95b1b3d6d3c99410d75993a9b28ae23d26847da256e09f7c727f1b05eb1fa4aea6d0b4b69307363c2ec7d75e136c14f3ca44d2d2bf001095ee5505bcb56c06842233411e5bc38da56d97c1ce6b1807db9b832fc10625d55fb259a5cd75c0a1d27a8b8a8c9b2a98bdfe7903a927026f2d2616b481e13e3bf7eb1039ec892a2fa054fd8dd6aac76b0efbece35b374310583d1c5f594604c3a49b35af7c3065f9f5f3bbe5cac3e8522a0654463c", +}, +// Pseudorandom 3, t=1 +{ + // K,B + "b445f9a92d267dbd3b2dd9ad0cf90538b4013b72df0a23ef997f7baf9440733a", + // T + 1, + // t + "1d16d4b08c19887a050603dc8f17bb6d", + // OUTPUT + "85da4380c7376cdd451aef93c15303626a9a54b1b21ddf5fa88beb1ade9331438764e8ad4f640dae16e3708806bab62d948e2ac6210b198184d0bface602a49f606d13e72574d7cda3e8458736d180b6", +}, +}; + +static const struct uiv_testvec { + bool encrypt; + const char *keys; + const char *tweaks; + const char *x_l; + const char *x_r; + struct { + const char *y_l; + const char *y_r; + } y; +} UIV_TESTVECS[] = { +// All zeros, encrypt +{ + // Encrypt + True, + // {J,S} + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // H + "0000000000000000000000000000000000", + // X_L + "00000000000000000000000000000000", + // X_R + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={Y_L, Y_R} + {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}, +}, +// All zeros, decrypt +{ + // Encrypt + False, + // {J,S} + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // H + "0000000000000000000000000000000000", + // X_L + "00000000000000000000000000000000", + // X_R + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={Y_L, Y_R} + {"140f0f1011b5223d79587717ffd9ec3a", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}, +}, +// All ones, encrypt +{ + // Encrypt + True, + // {J,S} + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // H + "ffffffffffffffffffffffffffffffffff", + // X_L + "ffffffffffffffffffffffffffffffff", + // X_R + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={Y_L, Y_R} + {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"}, +}, +// All ones, decrypt +{ + // Encrypt + False, + // {J,S} + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // H + "ffffffffffffffffffffffffffffffffff", + // X_L + "ffffffffffffffffffffffffffffffff", + // X_R + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={Y_L, Y_R} + {"a9166add184e00b007217cb4e4f52ee5", "c516fd6ce5172c45f85d10240fbeeada3699ca9b9c98cbbc9b92c12c1a459759e332751f270727b5235a3ffdc0fd102ef338438360402e9640b8586d4445f82936cc7efe2f3d71b89166adfbec5c83c36fba6f6572c8393458061ccdab00f4d15ee33292f59112fd744c53334c701f5af15d35ae23ca23edabe0a31ff9eecc9106992656fd859cbd3f6a6f2fa977f186402e5d8e5007deeeb9b61cc594b27c41f77c4c52b4cea539488fe838b757448e567e9870063935f79af81049177affbc898415f929911a164d78fef8b8beaffbbb775d2ff42e2aeab1f0e5153a50f48cfb6ffb078e8455ec3e51ff770d202071f759ed55ee57449b54d5b2d6d698afb5934bae5a9d8a48a93d2809a5548d79e8eab96c584ce2fb77fd4f319ca8ab688047ae44de222326a9b86a1ceadc033ca3303f9946abdaf74b2559a4b36f7c4ed5a32f7083ba6f9adc2a28ece0d866a66ffb8c58a91b7545456c04bd99cbfe27b4106c3930291fd03e886858ffb98e2de2c43ca34d165cbb25f5e93cff0c368849376d1f3d56ae879d413b85ae02b63a5b2b99df15a2065faa1763d2ab54004ff8fb3ede6e8abcc43e97c26c38a0028013339faf6d4e683a55a5566a45f3f1cc78f4f0aec5a1102629b03917679d8f635678920793e76e7e18f1b112d27895edb7f49b505001ab45b5370dcfbc27"}, +}, +// Pseudorandom 1, Encrypt +{ + // Encrypt + True, + // {J,S} + "22169d562646db8ce3322daf9fa8e84bed57dac18beabdb619b40f5a02786e439e6132a5b7e7445ef962e2c7f30a0b2ec994ee1935e1787d6f89cbc15b9254d5", + // H + "81b1a82c63d8dd9f682f734e82e259a14b", + // X_L + "db4adc246c6a54fe55e11901f08f0eee", + // X_R + "dccb8aa0570982d5b08fa6b4fbb3bc7bcd7e1cb374f114fcdd0ed53255c523c1e8ecabfbaab00105af9933eff304a40877e3006be82417e44462fc6955777baf2f2f9c99966ddee30b7c65050dcc8f5d7bc22f9192e1c4a83ca0a2338deca9da4fed14058812ace259e9851f50c83d97515b647ff56749a3c615e1860a404e9b05619a48aa3e5f09779e72c77dfdd1ab5d796860178938efffb4e43bda443c2fba0d5be14baa375d881ee5e14d760a12c4d9807c8c54b714a75324c4074296ba8c86beceb4dc2337946f0af67c759d999d56aceebefd80438dc625b0b50f749440e8cd5bcee1afa05ff8cff1bfd3e0e68930b74b3baa7e6cb723896afc3098326716e0554319c9f8f3683a8fd359ae48a3591dac67adeea6e24600037cb1a42c38b23a9e7c31e6d0b13b84e88341458050856c476f6875dfe17806e0cd72baeebd0e1108fb13088a887153a1d13bac414ed120c26bda5bc08202fc1489746305dcda5dfc3e6a869b52d63654f3bc35841a2345df8691caf1de06d5ebd214af729e239efd62d05060eab13fb973ffb41f461224e2eee1f739529d37e8db40c065e52de7b8f19fbf695470341062c7f212d8cf5310cc17f487e04e8ed03fe50f3758eda9e41bf37af62f94709b16e01b4305d1a5ccad2bcacc7e35d4a1d1a40c26dbf3153739175ca65ab59cc1c9", + // Output={Y_L, Y_R} + {"9ff8aec547f02caae7555ad7b0cb1372", "d2ceaad0ef52ac304d9550f0c365fa7728dca633f4f62228b241e47754dfa01c709e66f54a018e667573dbf5063c10a6167592250a8f6af17c68d5e190c5e8bdb40082b54e428ada58b3a805cdd56d87cc56591f8ac5f310eb37ce4d8a6ea6a80c3d7316f872aeb8a1a40ef7d1f0bbd1711d38c500eccc0acb88c1a3491ceee45bf82ba3fdf939dcbedb4f140fae21339f671df748d18e8bc8d72eb8e7cf18feafcd6f363345e2b05bc2d4d6f3affb8589d002aadb711d5ad2fa81398137b9e88f5a8663787e746bb878c0973d9b80145f8dd18bce30ea10e13ad07aeb469f62c4507ff8aaba09ed988a794232b5fc4e64466103366ed474fb99406fc80dd5ae5cb90001b1485476978dada0df83456feb3674ec7070b177871203410c5f7adbefbf5069c64bce59ef381514cb2a8d0804d855cca0a9c84d4c60c44e7242ffc479aabf357016166e9b184311c0e04dd9d1c512ae508b8f8c6bfdba68d46e338250f23668aaf11f45f57bfbc8e32d14ccab853af085a17405058ecd993cb21b41f8456c54a3900a50c270fc2b0931394ba257fd49bf79ae54d9c39a8504067b9cee1e42b688dcc606bee57006bc561b991dd10c56c129d1db8997e0d163fd06fca83249f146e348a4f35d0cb47d0ea6b3c6c587487f3816e13c2494d6d1e866fa182855cd668462a30b4e7019d2"}, +}, +// Pseudorandom 1, Decrypt +{ + // Encrypt + False, + // {J,S} + "22169d562646db8ce3322daf9fa8e84bed57dac18beabdb619b40f5a02786e439e6132a5b7e7445ef962e2c7f30a0b2ec994ee1935e1787d6f89cbc15b9254d5", + // H + "81b1a82c63d8dd9f682f734e82e259a14b", + // X_L + "db4adc246c6a54fe55e11901f08f0eee", + // X_R + "dccb8aa0570982d5b08fa6b4fbb3bc7bcd7e1cb374f114fcdd0ed53255c523c1e8ecabfbaab00105af9933eff304a40877e3006be82417e44462fc6955777baf2f2f9c99966ddee30b7c65050dcc8f5d7bc22f9192e1c4a83ca0a2338deca9da4fed14058812ace259e9851f50c83d97515b647ff56749a3c615e1860a404e9b05619a48aa3e5f09779e72c77dfdd1ab5d796860178938efffb4e43bda443c2fba0d5be14baa375d881ee5e14d760a12c4d9807c8c54b714a75324c4074296ba8c86beceb4dc2337946f0af67c759d999d56aceebefd80438dc625b0b50f749440e8cd5bcee1afa05ff8cff1bfd3e0e68930b74b3baa7e6cb723896afc3098326716e0554319c9f8f3683a8fd359ae48a3591dac67adeea6e24600037cb1a42c38b23a9e7c31e6d0b13b84e88341458050856c476f6875dfe17806e0cd72baeebd0e1108fb13088a887153a1d13bac414ed120c26bda5bc08202fc1489746305dcda5dfc3e6a869b52d63654f3bc35841a2345df8691caf1de06d5ebd214af729e239efd62d05060eab13fb973ffb41f461224e2eee1f739529d37e8db40c065e52de7b8f19fbf695470341062c7f212d8cf5310cc17f487e04e8ed03fe50f3758eda9e41bf37af62f94709b16e01b4305d1a5ccad2bcacc7e35d4a1d1a40c26dbf3153739175ca65ab59cc1c9", + // Output={Y_L, Y_R} + {"1c1593f30a020d44b7b2cf9b75204808", "c8135c678f97432394c2fa38ee6f590104a99028da2624a44d9a503adf1fe0d236ed5253d2e1cfca479c1b41609ef7cab58d7bb4d8e50e21108f837791f2e3066d3c40672f8e0f1a304d25ba20401a8aac6b15c1582788fe8996277b5cb554cd82e0920f212293b8bc4357349465f75e2f688a084d4c4741e2b384523d51cf94062cb7e6c1481eb48f1eb37e00937e0a2b2e12c88ac1b8ca2eef537b74b9f22e016b1a72818eddd1bde1e3643f4aa8fbf1e69543475131c17e8562c6c7d9a4375936fcc1c6ffeb131195e2168cd26368c3ab40f436563b4a5b6db2a7fa61e521321dad4d1aaaca8d0b38d68de26f402233d3bc25c78cd9019d2985f0f02c51cd07423726bd7ef3d19a8bb7b5a94d54ed86c460e7b02388fcedaa99902bc43c8339a171e89dc8123a9cd05287f2c0a39fdf24dd56dcf4326c163d38c9282d1f2f9a0faf50beb6e5caeb300a6192f6c1aaa5ba515bb677bb399edfcb05eab48870e79018d60ccdf3f1b5b6eb1e1a9e24a8a11da26c0919e6ec7db6a1260d6299e7a2830d48d3bf33b40f4c5cc0c4acae037a4bf5731fff732f44752bd002c8493f1d48ea6c5f0cbbd596d679c7130d687211e74a96473275f2c8df1634ad36aab16eb0221777e98f62057d669b51bee20ab45db78b619aa619a40245d9ddd074a35c54b77f7ccc0410c00719e423"}, +}, +// Pseudorandom 2, Encrypt +{ + // Encrypt + True, + // {J,S} + "e61126a280c66e99171b1ec940a75ba6d4c3301062760a9ff9f9b332433b8408af4a49ad5326b95da7f501bb8b34bce8ce6e8c33f57263a4779a161d3736b7e4", + // H + "837d18ad2b0162977d3461349b00bcfdd7", + // X_L + "4b9fa9b1d31ada9a15d29cd0bd920a53", + // X_R + "c819e68a3dbdb6e730e4c9ed6dc11187f7ef0f021f63f0da32b55c8e2c78d4bc55d0e487329542e0b63a8f57313a146443cb5b8ba9eaf77d7e80884333b0e33b806da9cb32e231b5a23aa9ffa6f598df337126b26d6f9ef0d6c6a1bb59d83d253ea0ddc7272d633eb785dd7649fb7618a3b2c721cfba7d3e3d4a95fafcb90c2c60a52258ff3da3e1ab1205747e049e4730d734eaa5744a18fa8b8c4aed37d28857a5877839a40659e9754795859dad3163d6358234072ae62f64e58c861fd2225c60a708bb9b199e2070315e6d8eda8365b7cdaf5d067280086fda2a304ccbf3177fb0d34bbc3b02b4aaf42e535fbf2a15b782a8f3004eecda69aade92eb7bc92b6d552172bd26db28dcdf36547fa2794bf598db51ba0578f176e0cd3db04bf8333819a17f9c0d6faa9128930a3d8e93170d1bdf4e17a26f794631c870d9fd0edc73c3ce51753cbf59f3c942b689ccd08d8c0e0b19840b5113b760893b7d3b3a7c8f2c8794cab2f35a49d1d3f8c93bc353f376904d1961d3958cdc7a1841fe305c5c48b98f3b829ab1540876c3bd9d73e979107ab6f8146fe8acf33bde92b0a0ec2088dca60ae8374bda9d36977e5653762e8744d2b66d5bcc26dde754ec5eb3f665fbdd1ce2d0a7a48c499c0a5b846a7cb3c478484703c31ebb0c20c66bc1c1722529be0bb850d9bff7437ca7", + // Output={Y_L, Y_R} + {"6db7f5e28e54c81ce9a22df58eef5f65", "bc742015a226d2f1f855c06e9c12ce9866a311622befc8ff5f796c1813308fecb8c91b7fdc00de93198498afeec55422f678fd1822131877c947236c4c978b0f0fc3d0ddeee5770bac3c635895d9b922399a0062e4c80b9ea753f89608ed6920fc2f8a9e09ba87b40c6ef2a9354524e7f0ac1d967ef520a348e37fccc35f584ed5270b7e4694cd263a25f8869e07693df3f9a5fbc6aa4f8697456fa830e07f6ab89d3ae18790b6208c09ec2cf530239bb7d514691a01b4a772233693dc398bc6b4a08e412dce4d3b3556c0aa8ad2d0ee474ef56c1dd232b677c2d38be103921b8373e9e1c8ef2e98ededce0439351e74ca751db03e8213cd6adb6ee5a7b3103675776b82e59120d21e4b4e03e01aa420c254530ed74c24dcc514ddb241450642dedd0c5b1a0f7c2a7af243b96f1d1312ff8448a0c3a2b9cdaa90c45d11fdd82e6b17bc83f246313d7d67dd380165ceac938f5cd7896ffb8c22669526345f42892e1cb2b5af64f39139e6f3d5ed8e03efa61d653bbfcdf387c9ccf9de686b9603a681143ccd21a12004c810acc7e9c17bbdeba632bc9e5f0c6d3cbf72c8e7b958fb66d38bdb77c1e170de541b0750d942e9f8bcf123bd4a369af220135816b6d9b09778a8bc5e0378ec82678c1344a978fd1b271376ac31ba3981a1639a3808a8cd35424daa91d59f6e34967434"}, +}, +// Pseudorandom 2, Decrypt +{ + // Encrypt + False, + // {J,S} + "e61126a280c66e99171b1ec940a75ba6d4c3301062760a9ff9f9b332433b8408af4a49ad5326b95da7f501bb8b34bce8ce6e8c33f57263a4779a161d3736b7e4", + // H + "837d18ad2b0162977d3461349b00bcfdd7", + // X_L + "4b9fa9b1d31ada9a15d29cd0bd920a53", + // X_R + "c819e68a3dbdb6e730e4c9ed6dc11187f7ef0f021f63f0da32b55c8e2c78d4bc55d0e487329542e0b63a8f57313a146443cb5b8ba9eaf77d7e80884333b0e33b806da9cb32e231b5a23aa9ffa6f598df337126b26d6f9ef0d6c6a1bb59d83d253ea0ddc7272d633eb785dd7649fb7618a3b2c721cfba7d3e3d4a95fafcb90c2c60a52258ff3da3e1ab1205747e049e4730d734eaa5744a18fa8b8c4aed37d28857a5877839a40659e9754795859dad3163d6358234072ae62f64e58c861fd2225c60a708bb9b199e2070315e6d8eda8365b7cdaf5d067280086fda2a304ccbf3177fb0d34bbc3b02b4aaf42e535fbf2a15b782a8f3004eecda69aade92eb7bc92b6d552172bd26db28dcdf36547fa2794bf598db51ba0578f176e0cd3db04bf8333819a17f9c0d6faa9128930a3d8e93170d1bdf4e17a26f794631c870d9fd0edc73c3ce51753cbf59f3c942b689ccd08d8c0e0b19840b5113b760893b7d3b3a7c8f2c8794cab2f35a49d1d3f8c93bc353f376904d1961d3958cdc7a1841fe305c5c48b98f3b829ab1540876c3bd9d73e979107ab6f8146fe8acf33bde92b0a0ec2088dca60ae8374bda9d36977e5653762e8744d2b66d5bcc26dde754ec5eb3f665fbdd1ce2d0a7a48c499c0a5b846a7cb3c478484703c31ebb0c20c66bc1c1722529be0bb850d9bff7437ca7", + // Output={Y_L, Y_R} + {"e6d9d943df0c57ffcf625bd142f023cc", "16fcd880981c22d459e61a502213668f6f040c57f9db8cf39fc07bce35a9df2e2cd083359e833944bb1da2d107caa11d171abfe5878787ca89c5460753a8df4c3af7d9e1091a68e1976eba0ba81005f60f1fb2f26b6163896070efb1c39e31d24bfcd23e897062645b5d5766ab81eef662ca789d4e5bf7aa76414d01acd67e9ec372e63f5a676fb4645cbff0c47b3ec0c667b781ac42a0fedb75eaf39fce4da7f37a660db56ca92836609ca32faa4987f232e89177cee0b45ab8d34ca1c9a9f29fcd057cc6e491387f75e01ffc40ddef01c0bb557803cb514afb19718a9b918ed266f5c3283d93b6fdd1232758f059a0f6f78b7d5e8cb0d61a7e974936b6bf007a0121db05051a3f3279c3b295de61af596f8ce8820480f666f963ad4c9af0490272f88eb01bdad77ca43c8d5cc3abf7b1d1b6b15890b43008d68ddbc9f2426985d6ef946cae5099b1b81eb500959d8e5571b438f796aafadfa85ae29e6373878f0eac3f91e75cd37c609064e57fc588bdba25f5f2cd095e14d01fe72ddb30f784fe97ccb7619ebe809a5acb24f73a69f9a3b348b99ff554fa316b4b16cb7cdcd79602ac17003057e7bff980521e43a57a43df4c13ed71740767ab277e1da09b371843aa1160b599b5cc0b1cb4c31d348718b64b9a6d66cd691185465ae5dcea649391b342bea21d430df41080"}, +}, +}; + +static const struct uiv_update_testvec { + const char *keys; + const char *nonce; + struct { + const char *new_keys; + const char *new_nonce; + } output; +} UIV_UPDATE_TESTVECS[] = { +// All zeros +{ + // {J,S} + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // N + "00000000000000000000000000000000", + // Output={{J',S'}, N'} + {"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07"}, +}, +// All ones +{ + // {J,S} + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // N + "ffffffffffffffffffffffffffffffff", + // Output={{J',S'}, N'} + {"be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df", "4b263f03af0acda2f9721d0f4c0783c7"}, +}, +// Pseudorandom 1 +{ + // {J,S} + "bf9b13b7097f5eee96b15423348ebf7aa13da31a2955a72ff17c7f75f9fd92f3280bb2d8992bc2a5f70f8e4e10f0404f16f3a0bbb91975bae7e11180adcba6da", + // N + "1ecb6e1ee6f0531c233676fd1c3ca701", + // Output={{J',S'}, N'} + {"4c03bdb301aaa20b907ac88ecd3174bb1b476a00a81ad67cb4eceba22354ce8f241ab2da59d565781634e9252358006b5b78166ea59028e1ff40a71687dd2f11", "30151c332e40594324ef033a469d4f50"}, +}, +// Pseudorandom 2 +{ + // {J,S} + "e773e6211d22f03e0220bd6e69803b2d0bfbd6321a9e0184e49660bc1989318a868d5ccd3f769537c4990df2998cddc14cd853d8614c6e7e3548af9c824b457d", + // N + "d8097e67afff2d56a6279229cfb37f29", + // Output={{J',S'}, N'} + {"c9f14480f4d46a1e40ba3daaab9004ec0e7afab84f3c60da9f7f01ab46aab7a81e2138eed6f141047bc4169013450134586120852ca9a952417b402834fbedf4", "c79fdf8d9ae28e55eaed6e556e12b994"}, +}, +// Pseudorandom 3 +{ + // {J,S} + "a150329bf382e5c3b11619ac72ac3b2cdf55b19e94fd2f92bfca40ef540274ba571c53695d5d8f0d4d4935d2b599ee095754d3bbdd9929d60997eb4f745e0a48", + // N + "071652e3ea1b1d299ac07ab3df431090", + // Output={{J',S'}, N'} + {"7c7a284801c7aa0f727f8e24b87a2dca1b7550577924490291a7343924dfd1b9e2b86e4f7db39b77715888f7d3b9aa4ea44bd72a8b1eb79df0d46f25c130fc87", "3c8ecadfbe9ee9587332a6568c7f2476"}, +}, +}; + +typedef struct cgo_tv_state_t { + const char *keys; + const char *nonce; + const char *tprime; +} cgo_tv_state_t; + +static const struct cgo_relay_testvec { + bool inbound; + cgo_tv_state_t state_in; + const char *cmd; + const char *tag; + const char *msg; + struct { + cgo_tv_state_t state; + struct { + const char *t_out; + const char *msg_out; + } result; + } output; +} CGO_RELAY_TESTVECS[] = { +// All zeros, inbound +{ + // Inbound + True, + // R = {K, N, T'} + {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, + // AD + "00", + // T + "00000000000000000000000000000000", + // C + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={R', {T_out, C_out}} + {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}}, +}, +// All zeros, outbound +{ + // Inbound + False, + // R = {K, N, T'} + {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, + // AD + "00", + // T + "00000000000000000000000000000000", + // C + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={R', {T_out, C_out}} + {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}}, +}, +// All ones, inbound +{ + // Inbound + True, + // R = {K, N, T'} + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, + // AD + "ff", + // T + "ffffffffffffffffffffffffffffffff", + // C + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={R', {T_out, C_out}} + {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "7209baed4b605b158b7eb25de2200e83"}, {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"}}, +}, +// All ones, outbound +{ + // Inbound + False, + // R = {K, N, T'} + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, + // AD + "ff", + // T + "ffffffffffffffffffffffffffffffff", + // C + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={R', {T_out, C_out}} + {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "7209baed4b605b158b7eb25de2200e83"}, {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"}}, +}, +// Pseudorandom 1, inbound +{ + // Inbound + True, + // R = {K, N, T'} + {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"}, + // AD + "88", + // T + "5de86524ea1542e8f1b8ea118c12d1fd", + // C + "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37", + // Output={R', {T_out, C_out}} + {{"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "84fe1db6790ae6e32e418a70bb70d695"}, {"84fe1db6790ae6e32e418a70bb70d695", "be638eacedc6fbbdf8d9f75f414b3b43ff4fdef3c261a24ffec5eae75a3a1016432bdfc6df956b1e19eb011dc891238d86938ee98d7e0beac3df360818e45aff037e42e345153f5814937d53f92492b03f526c3e85464912742bbb26df3258e7fe0e3fdd7c8b855122543a6d277f896bec6875e6d320d5f329b90d1e57ea2aa9691542c13c9601f7dae18313737387a85eff1ba244be546cd1511782555b8ab90306bd85170e3a489c13f892f4430ae39c49ab1514d05b510709da34651dbe600f68642541ee9ab2163a0e442b6017014c80e05b622d53fa40cbd5eaafbfec34289c5b48c2908a2e7749e1c3f0cceab57bea1f3c925756e477d0c32c1d6262f259a5b20b8234aba22c36604fa6c9f0b953724089b549b7442adae8a91a7a7c3070aad0099d3cb94c17b2f767a8933bbae1de8322d73d9688f6f211b9b3922e758b2407179083490d3bd2d3f366e012f86aa268c2d24ea843953b3cc4a83f33c795f5df035da1c7ef4b160d013d201adcc469def9b4c6334cb9f091f789ba1a23cb2a667564eea9ea3a24c5f1fea54c8f7842ba6266c5405b6cf5f611ee4d0253b09500ce0e704ae2b9aad6271b59ac3e34a446c03c1cf261757c6798d6cc9fe6be8793666d8d046cb5aee99a0598184b3c614444a7b0ed812fe46c1e7ae9a0aee9f49908e705896edf53a3a90f"}}, +}, +// Pseudorandom 1, outbound +{ + // Inbound + False, + // R = {K, N, T'} + {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"}, + // AD + "88", + // T + "5de86524ea1542e8f1b8ea118c12d1fd", + // C + "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37", + // Output={R', {T_out, C_out}} + {{"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "84fe1db6790ae6e32e418a70bb70d695"}, {"84fe1db6790ae6e32e418a70bb70d695", "be638eacedc6fbbdf8d9f75f414b3b43ff4fdef3c261a24ffec5eae75a3a1016432bdfc6df956b1e19eb011dc891238d86938ee98d7e0beac3df360818e45aff037e42e345153f5814937d53f92492b03f526c3e85464912742bbb26df3258e7fe0e3fdd7c8b855122543a6d277f896bec6875e6d320d5f329b90d1e57ea2aa9691542c13c9601f7dae18313737387a85eff1ba244be546cd1511782555b8ab90306bd85170e3a489c13f892f4430ae39c49ab1514d05b510709da34651dbe600f68642541ee9ab2163a0e442b6017014c80e05b622d53fa40cbd5eaafbfec34289c5b48c2908a2e7749e1c3f0cceab57bea1f3c925756e477d0c32c1d6262f259a5b20b8234aba22c36604fa6c9f0b953724089b549b7442adae8a91a7a7c3070aad0099d3cb94c17b2f767a8933bbae1de8322d73d9688f6f211b9b3922e758b2407179083490d3bd2d3f366e012f86aa268c2d24ea843953b3cc4a83f33c795f5df035da1c7ef4b160d013d201adcc469def9b4c6334cb9f091f789ba1a23cb2a667564eea9ea3a24c5f1fea54c8f7842ba6266c5405b6cf5f611ee4d0253b09500ce0e704ae2b9aad6271b59ac3e34a446c03c1cf261757c6798d6cc9fe6be8793666d8d046cb5aee99a0598184b3c614444a7b0ed812fe46c1e7ae9a0aee9f49908e705896edf53a3a90f"}}, +}, +// Pseudorandom 2, inbound +{ + // Inbound + True, + // R = {K, N, T'} + {"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "db34fd587ddf145c5aa1ac58bef5756d"}, + // AD + "ab", + // T + "867464943ada7a8decef75a961214f9a", + // C + "0f0cfeed7dcd312b7b769cc859b20a8e18da16451925a0153ae6a57226fec6b2048dea4584e47e078ecbce0f2ca6413a2bb4e30fd6628a036d1749556adb012d110e23c979dc26c2aee3f24bf2ccf27cfd6d294073a20e9c4c5401c09bc4b2e38b6002b2b320b408b99798db1222034813fd70723a141de5a11679a56b704b1cd8751e919565ea129ce1f9fc2883c7d4cac0d8fd4da61d57501788105ef0d622fca6bfbf72b11a3a03d388c99e4aea582db920872be152bf89dc672383263936d93c0c9915db9b103cbcff5e90f4d9dbae0c4ea8e8464332b9ffaa478735faee477e28355be86f572e2ccca91e60e1874edd1d592b0f4f625276dd5a270a830147365c3fa20168088477c08c56352015ee962d1ce6d24456c96b649921ecffbafa21ff713e2d0da18f2e72e49830ada7878b7fba8eb3700c1db10cbd62ddd6bf1350374a10df5578e6b0774b510d15f11bbe95fd3ed87a8bd68c5110621e12d708f266ee8e48979e2d0fb222c008faea9d9f4ae14951301f9359ed133c5328e6fdd817e83ad84341500752b052bea6432841c801ffd68856c597dc0ce006c89222f1173194044de3d0f75b670923c4de63c683de97990af9430f83ba7510220f56a46e8a47b6ee46a4fcc132d33e059dc3783e3dfe2ecd673588feeb4af5945e18693238520aada42ab371ff4e", + // Output={R', {T_out, C_out}} + {{"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "61637a70ae9a95105b1e78ff6892e60e"}, {"61637a70ae9a95105b1e78ff6892e60e", "b9b2516c278a8b4bba221b185e990d4814e94b8ea6ef5e7585945ec250c1d427d2c322e3c3f3f406a43408296e0820debb518543be2ed9a18d61b0ac46e1de159101fb6431711f43eb3e35a0ab1451c30e4d895f888cfada66cffe67de67254e8bd4b3e0834f07033206c3449ae8f8ced104c14a0df0ac8fc2757ae63e1cdc99da87f5bc9fc66d2bb5216e641c04f234da501fa721263229948e51ce73c355e302219f6a8f24daeb6c771ff7aeb7f16fc431551618d32c3ea78543bc71d95593a1675b5a1fa936db5945dff819abb197da2dfa460a7619033c9de74679f02fa73badd4ce89a43b25517a12eedd5b3464ca44f4c68e8f14e671f366a541f340b376a5890202f72e15cc22ba1d2573190e3cc65ba042e874d05ed11a16bd5f93a8defb047a223d647b54b0531fc76beb3c7a23766d7cf84479aaa3c25a8b7cc40a31603283aaf98daedc2990c2c4b6006d0a9e80be6bc1a34e65b12a7414acc4046f5f653b0ea2b44e1c93ce1ae8763aa88c366349db4b2305b57030290e989f65d035fdf0375bd889552a79f6647a5810ed2020c1821e78b150501f3e41e4b836ea079fc7b89e215efd9dfb02bcbeb857b0940cb70f64840b40cddf0fc3e3ff3e561b709d8eccbd62b6cb28ebe49003cd1569eb569e87bc24c5d245079da7ae610146aef4225b6f3c6e0ce3aacc"}}, +}, +}; + +static const struct cgo_relay_originate_testvec { + cgo_tv_state_t state_in; + const char *cmd; + const char *msg; + struct { + cgo_tv_state_t state; + struct { + const char *t_out; + const char *msg_out; + } result; + } output; +} CGO_RELAY_ORIGINATE_TESTVECS[] = { +// All zeroes, originating +{ + // R = {K, N, T'} + {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, + // AD + "00", + // M + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={R', {T_out, C_out}} + {{"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}}, +}, +// Pseudorandom 1, originating +{ + // R = {K, N, T'} + {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"}, + // AD + "88", + // M + "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37", + // Output={R', {T_out, C_out}} + {{"c24b000843784bc008c70b977e62ed82085ed0cda9f841da2c89d1832e763b9e283c36875fa41caae5913293d8014451c10fedddf362849bcaaa1833a3b8fcd8", "497798331f2c32ca4de4b1b55b82c306", "b8b3b69f6e175a5649013ca99c838291"}, {"b8b3b69f6e175a5649013ca99c838291", "94773462bcfb3728ec6f2f4e3b7020234abd8a6fa778a49788509b6452556e951f49a20a552035b38143907c59788c6865dac89ec22af08cc98ed1fcf55debccd3bb18c91340205524b36e1ec0ca0c082f79c575e7e0c77ade4b6084f6b6a12592f9a24c715bc92ee2531641cb11c6e9a462242354d655c392fccc1c84af5217cefb9806eb9990cf36034188600b2a123d860d0c661362f511e7d4eafc46a38c030fbe884a681fedef9c04375793435784579a3640ce2d75d9553936e877c3c24b33e0ffa88d59fed2fbbaf91e446c8d37a6b1400f7dfcd6ba8fa425c36e111a71c661f81ac8824524038a8dab5ac5a17014f4e7af5638e27e14869b51a9a2ff43fc9b3d7205e9f2e9f20c80d52778c26589179631345b0cedcb76d4862e3f88dcd27074da5d8b36ce7f2fbb972dafe327fd0e68620f5b284b1a7f1e64e33df2abd0f4aabe30b0e168f52ea39f1c5755276bc5c25cfa3960c2646ac13cbf2d9d1748e9c8db3664a98b4ef4e6f4a401cde973a62f0d4a6409447dfd2500b916015e50d79eeaa6508295d7959cb45af82b2b1b081b84911f9feeb994ddc5c472b342eef82d611809051658215158b99f5e3002e97f343e3b29eaad6489557573780b13956e4665dd0b859631d9937d4f90e0f810b36babfe8a1371b6eb985fd600d8353962cca9ce5b9d2ebf0da8"}}, +}, +// Pseudorandom 2, originating +{ + // R = {K, N, T'} + {"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "db34fd587ddf145c5aa1ac58bef5756d"}, + // AD + "ab", + // M + "0f0cfeed7dcd312b7b769cc859b20a8e18da16451925a0153ae6a57226fec6b2048dea4584e47e078ecbce0f2ca6413a2bb4e30fd6628a036d1749556adb012d110e23c979dc26c2aee3f24bf2ccf27cfd6d294073a20e9c4c5401c09bc4b2e38b6002b2b320b408b99798db1222034813fd70723a141de5a11679a56b704b1cd8751e919565ea129ce1f9fc2883c7d4cac0d8fd4da61d57501788105ef0d622fca6bfbf72b11a3a03d388c99e4aea582db920872be152bf89dc672383263936d93c0c9915db9b103cbcff5e90f4d9dbae0c4ea8e8464332b9ffaa478735faee477e28355be86f572e2ccca91e60e1874edd1d592b0f4f625276dd5a270a830147365c3fa20168088477c08c56352015ee962d1ce6d24456c96b649921ecffbafa21ff713e2d0da18f2e72e49830ada7878b7fba8eb3700c1db10cbd62ddd6bf1350374a10df5578e6b0774b510d15f11bbe95fd3ed87a8bd68c5110621e12d708f266ee8e48979e2d0fb222c008faea9d9f4ae14951301f9359ed133c5328e6fdd817e83ad84341500752b052bea6432841c801ffd68856c597dc0ce006c89222f1173194044de3d0f75b670923c4de63c683de97990af9430f83ba7510220f56a46e8a47b6ee46a4fcc132d33e059dc3783e3dfe2ecd673588feeb4af5945e18693238520aada42ab371ff4e", + // Output={R', {T_out, C_out}} + {{"60b9d644a620c3f36181f6f3ecbb0be41d400b78822dd3247247d286a5b80baec2dfc3694f119beab9b40fd538844d159e7bf256fb2ce53fe33e4c8763180b0a", "094b5cdc3a49cc51aab3e1f331f03df6", "99daac5f8bdba8f4807e719c768cb3ce"}, {"99daac5f8bdba8f4807e719c768cb3ce", "30db410a04452437045b7f51210bd01eab5d034c146c766ef73a9500b1c7f75d5ea7b1fe47f8eb927bcac6fb756e80cdd48b381a431c858432047410cd526bd91283a53ab94371bff4c4370e8dc8671349316759bdd01bbe432423a66a8497a7091c8056af277112a04c65946dbf82d076e66647456e991ff44c689e57d475956a3c1dd5f1a870e711ed57dc287b96f6437e2e4194e341a2dc5913631eab53f899f09ee41361b4d74c508f42ae972c93d21797342242b7e4e39d24888dfd215458a8e134fb9da152a0b1e5304685919f5dc3da8a0dc04906763075432ce92afe1283b1d344c36832bb54cf47a28c13263fd34558ef1c7827b4d8c1aea20f23316b04d1750bf42b6317a421618c3af00f5469d28aa52e8aef1e76d80754a52982285c1d558c61268d40f2e931c0b3848f70da72b07867df56de689a19f2db0a379207ca462a0bc97a3ea7d111a144454432e4d0eb3ee1fc5f905923effa1b196ce29f9c07d32fabcdfcce4c2d582a7b80b65fff05ffd2b5e7d91fca0817e9458c68d6919ad442ca1d20d77c7c0b6e924af2665d9eeaeeac28692f978eecd4e1d5878ce300f8035d0a7ff6050a172c1d328bb392e4d55198a976d45f7d9670eeb67ed4b79c95b219fc9cf3c7613c128e2224d2799d9459b4941a248589d7bc1cd644ac96aa49e0d630288b73a028"}}, +}, +// Pseudorandom 3, originating +{ + // R = {K, N, T'} + {"f69da975bf0055353e52a8b3fa834b1bcedf1445e4b2f1dca13f59a306e8040ce64d5922b2b9de5735a96e2fa2e9524e99ce5b8888fd000f570f148191bdb54f", "8e4219f5b72d0bbf1f47005632816b36", "c5301aaf38e66f698293618354d06e0a"}, + // AD + "90", + // M + "727ee8dff3a22ad873545c040d22a67a6caac97c308a0f4109da1a1d67695d9fd7570a27593fefcdc0ce568ff6f8998a03791e12720a86d95110540073e104a86ba14ac9e58705ff20ebfced49a91d832a635924193dbf14ff995da7d4cbb4752d364908c1096606cee429adad73513bfd848fb6132fad9531178b419d4c6670224e858ff0a413b083b58cb6a8297bc7474e48050ac926c3a568df88feb135e9011d26eb2327c0797fd821a9bca3052e116f26844a2a5d23542ea666f2225700dd134cc166e2cd36f88be6a4b367be083e7d7be99a9205489de7ece3308846fcad66dd249ada0c559999fc3dd9e36036831e3e2aa51d0190b227f3bb54b365ea668009298612308361537b66e143fdb5b3da43a6a141910b7daef3dd4c5a819749c1d5d005c3c39bf7d2d749754614e794c51a965694904d30fa5be6fba2360ccf46c4ed2b4829f6434bb8951e82580a4da3d7075d734c4c12560693b9bacb1ce7ee953d7ce9dec24d7a129e8e582a3e2e1168e7b966c2e435b21f9b7ba83e27023b287e7fc420c5934af909e1a3fcb8415347c5ebd30aebaf6fe11cbea60d8dbe78cd54736dcb6a0cab929175417510d0ab2c4688b91c8d75d5a9b51ff15fddeb1a08402dc7748eb5b9d219f4ecb4116be1765a03fd06fc01d8e366b945cf6557257ef0ec2b74619d4e081c89", + // Output={R', {T_out, C_out}} + {{"c658a50d452e0ac66a543a15dfb30f791509266d47e259d56374787e3e2ccc49a06c6d2d65553223ace6097a3fb7cee5f4af4602a4c73c8128391e2454b7caa1", "2436c77f19dee78ff65f39967659e7d5", "276d823e18b1a06c0fe224431630b7b2"}, {"276d823e18b1a06c0fe224431630b7b2", "545b61a9a2d88a6f0e389c864fcdec76f5d04b836a1d1a48b26895f4c8829af6de70ac08578f2e1cd054f4a9ab5efbdbd872b712ca451270f472a621a95827a382829d794395ae507ccc1df35a677d069207296faa9c2a1d3a454ada30deac8e3a2fd4cfa69c298f9ae0f6a6d15b2a3404c84233c29fc8e85cdf009dfab83ff18f0a7f9ed8a4d7ef10e6fae321c5c526f01dc5f045ec9504e270cb634b072b03d1a0ef8b013913684b935d2883bdfd49ce8dbde8e603663b7ebe869072d61462aea8f7da0d7bc4be054032995c5f5862493f3e45580d9415a3f68eb083092a4c1066f06725da1751b025efb015683cc1935cfafafe7aef90d9c18f2a5f2cce060716838303ca8b7de3164fc09a9d15ccbedd7c24bd47f9585b3b333012ce3a1718cd8ad493b90695734350ac345c42c911d5038b9f288d2d5da8e1bafe1f22967eef3f705a49310f7ebb0837303ede480564cbd5174d354c15668846ed5e9b40002f831d118aeb1d78fd41a9e80064da3bc0f84fe0898e0e2d81cf20a14baebb1f1d784682fce429625f6a8999177f9e1adf515638280279f5dbbb8eff1fb09ba3782cb6bb49ae28b38883808c69c70a45cf2efb5932c67c77756a9eae3cc63cab0f3554cc55e6fe6f1d1fe6a7fd27c248fa0f491a5c459c0e51bc06d9574cb22c1c4d5aa64b4b66875233bbdd"}}, +}, +}; + +static const struct cgo_client_originate_testvec { + cgo_tv_state_t state_in[3]; + int target_hop; + const char *cmd; + const char *msg; + struct { + cgo_tv_state_t state[3]; + struct { + const char *t_out; + const char *msg_out; + } result; + } output; +} CGO_CLIENT_ORIGINATE_TESTVECS[] = { +// All zeros, hop 3/3 +{ + // S{} + {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}}, + // d + 3, + // AD + "00", + // M + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={S'{}, T, C} + {{{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "af65bb470269ecd7af01f68f1a2b7b78"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "140f0f1011b5223d79587717ffd9ec3a"}, {"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07", "00000000000000000000000000000000"}}, {"1471e71e6fb1f04233a8ec5daa6209e0", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}}, +}, +// All ones, hop 3/3 +{ + // S{} + {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}}, + // d + 3, + // AD + "ff", + // M + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={S'{}, T, C} + {{{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "3cf25f81c98d0be16ddbbffeefbdc308"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "a9166add184e00b007217cb4e4f52ee5"}, {"be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df", "4b263f03af0acda2f9721d0f4c0783c7", "ffffffffffffffffffffffffffffffff"}}, {"c8c388584500c58ced7ee209c08b920a", "c0685473f8558a9f9f2f22cfb31f211c6b25b7ebdabf2507b4269636caa01e1f6d4f4f5690c48d6940361059b37516b52b9d9ad93388f964666e7492a6adb91645a02cf39eed4ebd0354d8f484106c04ebb0e53d858c75a44e3145471bf93d09d48af913fdcefa6a0dd3fb730e604035d494f0a5706c3b63424253b7287392a44e9b2f66f765dd7cda20c76a2444a4dfa84170d810eb13e720867170c243ff4d9662b1df15b826c664f1a52e4f57be57b49105895e8ae3b87fd969034f67ae9784d946935dac622cb4cf786ad937174ceab2c766be361f8efc0479aa0b45c5e90da1dcee6802b5acf53dfee7a12e27d55e832b5f77360cd7190522d9057a556b8e1de773a0c29cc20c44dd963395cce1c19633fe1e386a3cc87082d5e645914d96ce3d8dcb9653dedacd8bfc2fe5d7a3e9e205a9c0961dd83d5b5515842fa3291877146081d5d776c4675de92b3f92edd80d7792b9a9f203c6650a33e54822d45a92c7136cf4fdbe6fe698ed6d3596cce17853aa988142a5925e1cd4382fb4d43307c26d57676c1ae5aaec6100de8414f8fc763e87a052f3d7519d539499d90f427c951d91348d9f0c7d77dd454bd8cd80b9b13a1870f95ea19e8dbdfd78ca4cfd520e5bcfcbd751252775165790b250b0d87989a60ccbd4243f8409a28d1d0536d9d9ad51ee474d24a92870b7"}}, +}, +// Pesudorandom 1, hop 1/3 +{ + // S{} + {{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "63c839b54659920bbf42c8a76eedc3a9"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}}, + // d + 1, + // AD + "00", + // M + "32b9e80d44f7fd35dc254f1b07cd10ca91e1c9ba7835a9581e99245677c1ecec22de4e30ef1799ab658305c8266d4f1c71e4ad51cd9d5798de85ece04f6ee9636ad4a14a132278df2c34a449b7d53cf71fb4e55affbc7cbc6699b97356a81d4f70591177aa509df7d8ada37bd7c6082059081e8058087bd5e357544b2b2067c62a3cb123592b44bef8ccb5f259e859ac8d6c9cf599605b370a067dced095f96dd03b3577d20b78afeb8c25cbe3b2e52f2105e952603af981a739216fc6fa29f1a417ea501199a74bab8821e828a1e66e8e0de40138aca846902f7e2c5545cb2263a8b148e65fd793abbd831d97771d5ecbc07bcde5b5cfa02489783302174b36f7570c546fcb05b1d1031089b806d9b54d2b0ebf0fa0ce8b486e26c36825b55a1bcdd001b4a6ab3686ae3b5fef3500837a1eb58e44602c87ce6d384d3dab73fc18e662f03a4112c6fd70ee2063a5dd37bc159f2584b8bcc63106ff6f219cb3e45d57e3b78c88fb0acbba7b58f2f3c54d1877160199583876e1a321bfaa813e0ce1e1803fff094e437ca879ab2d85248050f720bfac980a8455f1bd83ad8648af0052a3ff1203a75b033254edcbfc144c53ec72b603b404aac06021d51524953e9d267c912cc82d61b70d47775d80451ae59071ce7596f3dfe60ff0f636ec06689993ed52f8efd7d04415350421", + // Output={S'{}, T, C} + {{{"d0f4674c280810a523aa25f98bbcff032b4f78f536ab763365384c3f55117e26da677483b85954db5e0840ee66ed269c7089e404f881dea4ecfa1619ca809444", "2b6b31a8b26936bf1823ea99b866d000", "475cec821a2bb29682c9de4ed89fa2bc"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}}, {"7d05e89f33820206b821fdd7a7465525", "f97feaae58ac1c0e4a69df97b1da3641d0c8795a1ab5e957d94629b9b181129b58bdc5df73588c0068bc67ef14a50d8cb8dd1dce8c1c5ff6b7a0616bbde921f442dd876b3622f88918ba01234920759d4ec3f1079f4d5029b9903fd2b9c60540b89b59134c36b64b58509791cb6b3074f84fed410f27cd4d868a9cb59df2ebe9e3358ed557c4ed2d91e7f3080468734df02536d5e30c27d4021d5ce00eb38b08cde074587fb321510139c4d865da92a4b0ba3833d8b110e3c81e3226099677f91f570add37f6867e9faae6331bc0ca19e475ac75d8dd688b1d77cfa5c28f3e0838bb3f8457bbe7bfb567826cf42913108c268d710253c74dc09def9885c61a3e0ca65231121d746a720d0f6454d09613e9620c0ffe922be22aae5c7e5ac17b083cff28c48c1c205834880689df9dfc5085775695ac3931dce1b05a669c96664fcdb86794d3883de5f9396c351ef26880f8f5d1f64bde7c73fdf177363343a37497de8e9aa4e139c196c9069e4b9a4cfc71e89a8deb80a2a1810e9584002f3d054e64c7e3afd7f215cdac0ea35ae8e6e88c290006ef80c1a193be34f89ac8ac8f03971c2d8f35fa0ceddf9a34d9482bc9cb9787faf942606131abcce19b6ab1aba23bd45c31d15e1189987114f507661916aae148f80b03a3d769a277ca9ce8c2e9d46f4b58319a72627eba3024"}}, +}, +// Pesudorandom 1, hop 3/3 +{ + // S{} + {{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "63c839b54659920bbf42c8a76eedc3a9"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}}, + // d + 3, + // AD + "00", + // M + "32b9e80d44f7fd35dc254f1b07cd10ca91e1c9ba7835a9581e99245677c1ecec22de4e30ef1799ab658305c8266d4f1c71e4ad51cd9d5798de85ece04f6ee9636ad4a14a132278df2c34a449b7d53cf71fb4e55affbc7cbc6699b97356a81d4f70591177aa509df7d8ada37bd7c6082059081e8058087bd5e357544b2b2067c62a3cb123592b44bef8ccb5f259e859ac8d6c9cf599605b370a067dced095f96dd03b3577d20b78afeb8c25cbe3b2e52f2105e952603af981a739216fc6fa29f1a417ea501199a74bab8821e828a1e66e8e0de40138aca846902f7e2c5545cb2263a8b148e65fd793abbd831d97771d5ecbc07bcde5b5cfa02489783302174b36f7570c546fcb05b1d1031089b806d9b54d2b0ebf0fa0ce8b486e26c36825b55a1bcdd001b4a6ab3686ae3b5fef3500837a1eb58e44602c87ce6d384d3dab73fc18e662f03a4112c6fd70ee2063a5dd37bc159f2584b8bcc63106ff6f219cb3e45d57e3b78c88fb0acbba7b58f2f3c54d1877160199583876e1a321bfaa813e0ce1e1803fff094e437ca879ab2d85248050f720bfac980a8455f1bd83ad8648af0052a3ff1203a75b033254edcbfc144c53ec72b603b404aac06021d51524953e9d267c912cc82d61b70d47775d80451ae59071ce7596f3dfe60ff0f636ec06689993ed52f8efd7d04415350421", + // Output={S'{}, T, C} + {{{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "959551c3e8dc83f3cf2e0bf11a1acae3"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "9e9c84b867f7dbeb705bfcce09431813"}, {"12f2e45f012ffc1430fee1fb322879ba934f887fe2e7e7ce98071c61bc1086dbb2877845f5fb3869d3a4d23cdbcb44c85aeb9e43771755c9be3bbdb42ecac024", "88ba0caf597d953a26064c5872bdea5b", "e459433194d5ce2daf958ef6cb22a391"}}, {"3222f41f846157bdc258ac55d8f7bd6e", "fb76e827b3a0b6b8d031ea07b273c8f47763cd2c7af610dd0109ff42838bc39d5128492788a36426fc5ab17bab4906c7c4a390ceabe14ccc96ac2ec36dac92ed2a579097d1cb2258aef9cf35e950113adbb305b7ac73e1c1ea9b4e10ff39adc6b129cad8020fdcb349fd383595c61bb551d026b84ed74674bcfbbe027b4814713487a53e5aac4120da59d27b0abce7f438294860c211f19160b53deb9ab5abf49996a1d474518196a1020b460282f9dc3802db33c19e3b50d74fc5f8083403227d9801a158977f36cb2eae1525488660b59e5f45f346f24def7044f1b8e714268ff423d8c9b895e936669b4df15a99ba6382b02349f792b2383a4bd632efb6b6a5b7cbb82eaae1b0261f5386844813f23e08eeb68d63162681d51bf0d38beff2c34afc2e57772887f5c0e341ff2b7c003b24d32bb3873c7f6d5b946c36b18eb0ddfe907c201cd42b7373eb52d0c4bd8eed5179a2081504847f7f99fe529139cdde799105e8c05cf8376eaddf4af1f779835910659ff93ad3f55b25defbcc10567d23247a0f2e688363f91f90184cda34d8e4ad80d4f9f47d9d1af9c10474f7e66bef3ad0a49fbdc8020899289bea741a004df514b8ec5bf2443e3de433cd25916b2889fe6a624e65c4b1306d9feb14fbad48e2c212cb4aa8db92c31b87c20da5b493410fdafaab09fdfb57c9aa"}}, +}, +// Pesudorandom 2, hop 2/3 +{ + // S{} + {{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "7dae89533c98d159590a3bc5da3d5fb6"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "eeb1f87fd5c7a6b016b6df886c3f2f92"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}}, + // d + 2, + // AD + "da", + // M + "346681ef9e47fff29ddaf41628ae3021888028316787f1887b6c099c921a8915b4d7937a9565d928764fae620b57d117ccd75cf8b633f2d1f1404b65f2479c8d8d590a15da2b40b14987d8968b7d210965f158627a72ba31ccecd5727f2dabf17dacc69027ccf4c53da96a75e6d28a15ffecaec1965a62402a1cc5e9cc26be181689132f54956f99192ac9bbb929c5aec7048a6653ad40cbc4fb029ea97bc15c8b05395e822af36a8b949817ee0f022c8f971eefc5b31bb46e095d4aea07fa97854e1ca4a208bebb65a605089f60a21ef5685b67d312edff8b2cc81830eab9d27ab0a7be29b7c88abb995492564772d518a912c6b40f58ab41c0497995d9b593f0387a3e597728d08f5267fba8370a062817cdf506119e0c5cc69900709195a2288322de578af491698360ad1f6b34b341e10eb21e22f6c5a6e12e26250aeb528aaa533d592b268fb22b3e77ada84d478ee9d0f2742cbb54be14503c21e39efcc73774b24bf28747203c5ff456457139fec8a46c8243b4b9738c27972e6d8f0ef9fa18944aaeed4deb437522f04795ecd7bee79f0a6d7c6c6acd90dac9a935d5f252134cd4ca1e2e0c4386fdae67950f1234cda5472e61a32bf9f037c068fe81a955d1e56a92ad1a8f16e6a31bfc0f8b3cef96410a72b92a75b09a0071ff0c0e99dd322ab7d8e4a2a2c2122af6", + // Output={S'{}, T, C} + {{{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "2d8aa5329c2fab108e90f64a904c4def"}, {"64b7371338ad74c249ba606c677f38b5c08ba69a7ae33c1be26ef81ea604a24a968678f48075273c6b35311642a72466fd2a6b059217f66752b0c9e15de40a5f", "5f6d3291d9d5bf3c3bece127fbf3886b", "2e666844518d40d4a1efee952db70f36"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}}, {"9527488f5d1c2671e0e8139423149285", "c036126d33eea9f7cf865a9ab8e8eaace3a59f1064fa7506d45862ceb119ed854e1ab2f4294c77beb60564e2095f1f219dac41a024361e0fce045947a5e104a6db4b35175b09fca762121d46be7b4b20c674e4a13a53585586c8318549b86c02db4a554e1a43674237136f91e91e75c7ef74e6d4bceeb682e27ffbd2f47ddf667ad89fea7c48e6fbe69b8a3e54eb31585612719394480416296689d427a59b0f3adf4d92fa239c983a2c010cffe9366c01a1c945757ba07aec7c3df58b95f567e8de04d5719c2c7c62cd44668d43777b87db9126b2fccb62b241ec9d9701e8a34125a4dc2653a3de1f77415cafa76bc2713bed61c44001fb23170d716d008f12b236c0380253f2779fe52e6b2c011ffe312617b149c0b2b47055dc832ead1b297ead29028a4a0dbed96809c2aede9b276458a8a6c142a6a7876de3cfba1d4d0dea00095a66b9e925a3593b956a7e734b074941fc60d656e27a7d24f196cfe928400a180a1b7eb591c7b4e394b2c13040a98612e078094586bb197a585505335f4b5f1f721df1ee76ef27a8f6927fc40077be55a45b093d4fa1057a4a88937174885732f91d04a87424539302c7f9590e4d0b62abfdbd0f162fa3c7d750b8f212a2612127fd2443416736578deeccc76284c164a282f94786812031a19f35629e253a86c730f08676fbd0b0b41d"}}, +}, +// Pesudorandom 2, hop 3/3 +{ + // S{} + {{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "7dae89533c98d159590a3bc5da3d5fb6"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "eeb1f87fd5c7a6b016b6df886c3f2f92"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}}, + // d + 3, + // AD + "da", + // M + "346681ef9e47fff29ddaf41628ae3021888028316787f1887b6c099c921a8915b4d7937a9565d928764fae620b57d117ccd75cf8b633f2d1f1404b65f2479c8d8d590a15da2b40b14987d8968b7d210965f158627a72ba31ccecd5727f2dabf17dacc69027ccf4c53da96a75e6d28a15ffecaec1965a62402a1cc5e9cc26be181689132f54956f99192ac9bbb929c5aec7048a6653ad40cbc4fb029ea97bc15c8b05395e822af36a8b949817ee0f022c8f971eefc5b31bb46e095d4aea07fa97854e1ca4a208bebb65a605089f60a21ef5685b67d312edff8b2cc81830eab9d27ab0a7be29b7c88abb995492564772d518a912c6b40f58ab41c0497995d9b593f0387a3e597728d08f5267fba8370a062817cdf506119e0c5cc69900709195a2288322de578af491698360ad1f6b34b341e10eb21e22f6c5a6e12e26250aeb528aaa533d592b268fb22b3e77ada84d478ee9d0f2742cbb54be14503c21e39efcc73774b24bf28747203c5ff456457139fec8a46c8243b4b9738c27972e6d8f0ef9fa18944aaeed4deb437522f04795ecd7bee79f0a6d7c6c6acd90dac9a935d5f252134cd4ca1e2e0c4386fdae67950f1234cda5472e61a32bf9f037c068fe81a955d1e56a92ad1a8f16e6a31bfc0f8b3cef96410a72b92a75b09a0071ff0c0e99dd322ab7d8e4a2a2c2122af6", + // Output={S'{}, T, C} + {{{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "d0c6f32d192ad998d5fa04b32a872f8e"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "c0ae73b766ba40692b47a08c07265205"}, {"7e710ab0fcc90e1919c4996abac395e440e26eadf2df429defc893bfa97eedc55afa0504c9cee635bb933013d5d1fd54ddd30d5dc8fedcc5b55368837e00c085", "43d445810df84f486bdbe4d69637633f", "df6876f95d2387d8f419d018a826ffed"}}, {"0e49b626343b62d9155ffca96b076d70", "d64d402225cfc1e55c277c5827d8fea52c683693568928ad817bdb161852f9bbb6b316c78c4ef24d3b2620bd584e128e709a399a6c320ab5943816d786a0b7d81f0023b522ebac91e4fc79d9f6b3f5dcc22f17f486ef93518e2f885327ebac19daaaa3998dfdcb5880d76a196a8bba54a0b9169427d1f83abf95fcc8f63dfeb03d50d083e11c38a55d2efbe2c607648a5caa3698393faaaf339ca1d4c48cab8184ec20d8dc4ad03793ff1806b802e932c33f00fa0253bc7da8fa560b19cac163bbf26e4507642fcc39b5df28b3941fccbd30e3e00b64f471a51d7555c3d1b6655b0a6d9d33b9cd0494163591675c50ebb5a867e849a9c6ee43a177d7fe9f6aa992c817b26316054b49894f973ae166fb20f2bfc50704f610e2cc61be08e1305fa58f15b716aaacb50c98e0dba34a300a1aa4296f7826f0ad740f36eef6d18205b1118227c285acef158b4093dd541eed76a3492240be48e89fa54cad77b020631413a8b562e655289f94191bc462b71ddf0b41a034ca1c291aa4feb0148207e2ea0d5409e801dcec151b0a5a220ac43b8be70c8c92d6eb4f9c6f44bf0fd3487c5d007ba8ddd8bbbca51fb3c679ffc0a493392039f32e7272f173e71d4a2a5f001f999dd9523c79ca3e32c99260b20f1e960a830bd7ed81d891c316c8851b3470c64b7fb15d7ebdb8d09399e74f"}}, +}, +}; diff --git a/src/test/include.am b/src/test/include.am @@ -162,6 +162,7 @@ src_test_test_SOURCES += \ src/test/test_crypto.c \ src/test/test_crypto_ope.c \ src/test/test_crypto_rng.c \ + src/test/test_crypto_cgo.c \ src/test/test_data.c \ src/test/test_dir.c \ src/test/test_dirauth_ports.c \ @@ -382,6 +383,7 @@ noinst_HEADERS+= \ src/test/example_extrainfo.inc \ src/test/failing_routerdescs.inc \ src/test/ed25519_vectors.inc \ + src/test/cgo_vectors.inc \ src/test/test_descriptors.inc \ src/test/test_hs_descriptor.inc \ src/test/vote_descriptors.inc diff --git a/src/test/test.c b/src/test/test.c @@ -629,6 +629,7 @@ struct testgroup_t testgroups[] = { #endif { "crypto/pem/", pem_tests }, { "crypto/rng/", crypto_rng_tests }, + { "crypto/cgo/", crypto_cgo_tests }, { "dir/", dir_tests }, { "dir/auth/ports/", dirauth_port_tests }, { "dir/auth/process_descs/", process_descs_tests }, diff --git a/src/test/test.h b/src/test/test.h @@ -122,6 +122,7 @@ extern struct testcase_t controller_tests[]; extern struct testcase_t crypto_ope_tests[]; extern struct testcase_t crypto_openssl_tests[]; extern struct testcase_t crypto_rng_tests[]; +extern struct testcase_t crypto_cgo_tests[]; extern struct testcase_t crypto_tests[]; extern struct testcase_t dirauth_port_tests[]; extern struct testcase_t dir_handle_get_tests[]; diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c @@ -6,6 +6,8 @@ #include "orconfig.h" #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" @@ -21,6 +23,7 @@ #include "lib/crypt_ops/crypto_init.h" #include "ed25519_vectors.inc" #include "test/log_test_helpers.h" +#include "ext/polyval/polyval.h" #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> @@ -3188,6 +3191,223 @@ test_crypto_failure_modes(void *arg) ; } +static void +test_crypto_polyval(void *arg) +{ + (void)arg; + polyval_t pv; + uint8_t key[16]; + uint8_t input[48]; + uint8_t output[16]; + uint8_t output2[16]; + char *mem_op_hex_tmp=NULL; + + // From RFC 8452 + const char *key_hex = "25629347589242761d31f826ba4b757b"; + const char *input_hex = + "4f4f95668c83dfb6401762bb2d01a262" + "d1a24ddd2721d006bbe45f20d3c9f362"; + memset(input, 0, sizeof(input)); + base16_decode((char*)key,sizeof(key), key_hex, strlen(key_hex)); + base16_decode((char*)input,sizeof(input), input_hex, strlen(input_hex)); + + // Two blocks, directly. + polyval_init(&pv, key); + polyval_add_block(&pv, input); + polyval_add_block(&pv, input+16); + polyval_get_tag(&pv, output); + test_memeq_hex(output, "f7a3b47b846119fae5b7866cf5e5b77e"); + // Two blocks, as a string. + polyval_reset(&pv); + polyval_add_zpad(&pv, input, 32); + polyval_get_tag(&pv, output); + test_memeq_hex(output, "f7a3b47b846119fae5b7866cf5e5b77e"); + + // Now make sure that zero-padding works. + input[32] = 77; + polyval_reset(&pv); + polyval_add_block(&pv, input); + polyval_add_block(&pv, input+16); + polyval_add_block(&pv, input+32); + polyval_get_tag(&pv, output); + + polyval_reset(&pv); + polyval_add_zpad(&pv, input, 33); + polyval_get_tag(&pv, output2); + tt_mem_op(output, OP_EQ, output2, 16); + + done: + tor_free(mem_op_hex_tmp); +} + +static void +test_aes_raw_one(int keybits, + const char *key_hex, + const char *plaintext_hex, + const char *ciphertext_hex) +{ + aes_raw_t *enc = NULL; + aes_raw_t *dec = NULL; + uint8_t key[32]; // max key size. + uint8_t pt[16], ct[16], block[16]; + tt_int_op(keybits, OP_EQ, strlen(key_hex) * 8 / 2); + base16_decode((char*)key, sizeof(key), key_hex, strlen(key_hex)); + base16_decode((char*)pt, sizeof(pt), plaintext_hex, strlen(plaintext_hex)); + base16_decode((char*)ct, sizeof(ct), ciphertext_hex, strlen(ciphertext_hex)); + + enc = aes_raw_new(key, keybits, true); + dec = aes_raw_new(key, keybits, false); + memcpy(block, pt, sizeof(pt)); + aes_raw_encrypt(enc, block); + tt_mem_op(block, OP_EQ, ct, 16); + aes_raw_decrypt(dec, block); + tt_mem_op(block, OP_EQ, pt, 16); + + done: + aes_raw_free(enc); + aes_raw_free(dec); +} + +static void +test_crypto_aes_raw(void *arg) +{ + (void)arg; + +#define T test_aes_raw_one + + /* From https://csrc.nist.gov/CSRC/media/Projects/ + Cryptographic-Algorithm-Validation-Program/documents/aes/AESAVS.pdf */ + const char *z128 = + "00000000000000000000000000000000"; + const char *z192 = + "00000000000000000000000000000000" + "0000000000000000"; + const char *z256 = + "00000000000000000000000000000000" + "00000000000000000000000000000000"; + + T(128, z128, + "f34481ec3cc627bacd5dc3fb08f273e6", + "0336763e966d92595a567cc9ce537f5e"); + T(192, z192, + "1b077a6af4b7f98229de786d7516b639", + "275cfc0413d8ccb70513c3859b1d0f72"); + T(256, z256, + "014730f80ac625fe84f026c60bfd547d", + "5c9d844ed46f9885085e5d6a4f94c7d7"); + T(128, + "10a58869d74be5a374cf867cfb473859", z128, + "6d251e6944b051e04eaa6fb4dbf78465"); + T(192, + "e9f065d7c13573587f7875357dfbb16c53489f6a4bd0f7cd", z128, + "0956259c9cd5cfd0181cca53380cde06"); + T(256, + "c47b0294dbbbee0fec4757f22ffeee35" + "87ca4730c3d33b691df38bab076bc558", z128, + "46f2fb342d6f0ab477476fc501242c5f"); + +#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 } @@ -3255,5 +3475,9 @@ struct testcase_t crypto_tests[] = { { "blake2b", test_crypto_blake2b, 0, NULL, NULL }, { "hashx", test_crypto_hashx, 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 }; diff --git a/src/test/test_crypto_cgo.c b/src/test/test_crypto_cgo.c @@ -0,0 +1,642 @@ +/* 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 */ + +#define RELAY_CRYPTO_CGO_PRIVATE +#define USE_AES_RAW + +#include "orconfig.h" +#include "core/or/or.h" +#include "test/test.h" +#include "lib/cc/compat_compiler.h" +#include "lib/crypt_ops/aes.h" +#include "ext/polyval/polyval.h" +#include "core/crypto/relay_crypto_cgo.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "core/or/cell_st.h" + +#include "test/cgo_vectors.inc" + +static const int AESBITS[] = { 128, 192, 256 }; + +static void +test_crypto_cgo_et_roundtrip(void *arg) +{ + (void)arg; + uint8_t key[32 + 16]; // max + uint8_t tweak_h[16]; + uint8_t tweak_x_r[493]; + uint8_t block[16], block_orig[16]; + cgo_et_t et1, et2; + memset(&et1, 0, sizeof(et1)); + memset(&et2, 0, sizeof(et2)); + + et_tweak_t tweak = { + .uiv = { + .h = tweak_h, + .cmd = 7, + }, + .x_r = tweak_x_r, + }; + + for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) { + const int aesbits = AESBITS[bi]; + + for (int i = 0; i < 16; ++i) { + crypto_rand((char*)key, sizeof(key)); + crypto_rand((char*)tweak_h, sizeof(tweak_h)); + crypto_rand((char*)tweak_x_r, sizeof(tweak_x_r)); + crypto_rand((char*)block_orig, sizeof(block_orig)); + memcpy(block, block_orig, 16); + cgo_et_init(&et1, aesbits, true, key); + cgo_et_init(&et2, aesbits, false, key); + + // encrypt-then-decrypt should round-trip. + cgo_et_encrypt(&et1, tweak, block); + tt_mem_op(block, OP_NE, block_orig, 16); + cgo_et_decrypt(&et2, tweak, block); + tt_mem_op(block, OP_EQ, block_orig, 16); + + // decrypt-then-encrypt should round-trip. + cgo_et_decrypt(&et2, tweak, block); + tt_mem_op(block, OP_NE, block_orig, 16); + cgo_et_encrypt(&et1, tweak, block); + tt_mem_op(block, OP_EQ, block_orig, 16); + + cgo_et_clear(&et1); + cgo_et_clear(&et2); + } + } + done: + cgo_et_clear(&et1); + cgo_et_clear(&et2); +} + +static void +test_crypto_cgo_uiv_roundtrip(void *arg) +{ + (void)arg; + uint8_t key[64 + 32]; // max + uint8_t tweak_h[16]; + uint8_t cell[509], cell_orig[509]; + cgo_uiv_t uiv1, uiv2; + memset(&uiv1, 0, sizeof(uiv1)); + memset(&uiv2, 0, sizeof(uiv2)); + + uiv_tweak_t tweak = { + .h = tweak_h, + .cmd = 4, + }; + + for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) { + const int aesbits = AESBITS[bi]; + + for (int i = 0; i < 16; ++i) { + crypto_rand((char*)key, sizeof(key)); + crypto_rand((char*)tweak_h, sizeof(tweak_h)); + crypto_rand((char*)cell_orig, sizeof(cell_orig)); + memcpy(cell, cell_orig, sizeof(cell_orig)); + + cgo_uiv_init(&uiv1, aesbits, true, key); + cgo_uiv_init(&uiv2, aesbits, false, key); + + // encrypt-then-decrypt should round-trip. + cgo_uiv_encrypt(&uiv1, tweak, cell); + tt_mem_op(cell, OP_NE, cell_orig, sizeof(cell)); + cgo_uiv_decrypt(&uiv2, tweak, cell); + tt_mem_op(cell, OP_EQ, cell_orig, sizeof(cell)); + + // decrypt-then-encrypt should round-trip. + cgo_uiv_decrypt(&uiv2, tweak, cell); + tt_mem_op(cell, OP_NE, cell_orig, sizeof(cell)); + cgo_uiv_encrypt(&uiv1, tweak, cell); + tt_mem_op(cell, OP_EQ, cell_orig, sizeof(cell)); + + cgo_uiv_clear(&uiv1); + cgo_uiv_clear(&uiv2); + } + } + done: + cgo_uiv_clear(&uiv1); + cgo_uiv_clear(&uiv2); +} + +#define UNHEX(out,inp) STMT_BEGIN { \ + size_t inplen = strlen(inp); \ + tt_int_op(sizeof(out), OP_EQ, inplen / 2); \ + int r = base16_decode((char*)(out), sizeof(out), inp, inplen); \ + tt_int_op(r, OP_EQ, sizeof(out)); \ + } STMT_END + +#define UNHEX2(out,inp1,inp2) STMT_BEGIN { \ + tor_free(unhex_tmp); \ + tor_asprintf(&unhex_tmp, "%s%s", inp1, inp2); \ + UNHEX(out, unhex_tmp); \ + } STMT_END + +static void +test_crypto_cgo_et_testvec(void *arg) +{ + (void)arg; + cgo_et_t et; + memset(&et, 0, sizeof(et)); + + for (int i = 0; i < (int)ARRAY_LENGTH(ET_TESTVECS); ++i) { + const struct et_testvec *tv = &ET_TESTVECS[i]; + uint8_t keys[32]; + uint8_t tweaks[16 + 1 + 493]; + uint8_t block[16], expect[16]; + UNHEX(keys, tv->keys); + UNHEX(tweaks, tv->tweaks); + UNHEX(block, tv->block); + UNHEX(expect, tv->expect); + + et_tweak_t tweak = { + .uiv = { + .h = tweaks, + .cmd = tweaks[16], + }, + .x_r = tweaks + 17, + }; + + cgo_et_init(&et, 128, tv->encrypt, keys); + if (tv->encrypt) { + cgo_et_encrypt(&et, tweak, block); + } else { + cgo_et_decrypt(&et, tweak, block); + } + cgo_et_clear(&et); + + tt_mem_op(block, OP_EQ, expect, 16); + } + + done: + cgo_et_clear(&et); +} + +static void +test_crypto_cgo_prf_testvec(void *arg) +{ + (void)arg; + cgo_prf_t prf; + memset(&prf, 0, sizeof(prf)); + + for (int i = 0; i < (int)ARRAY_LENGTH(PRF_TESTVECS); ++i) { + const struct prf_testvec *tv = &PRF_TESTVECS[i]; + uint8_t keys[32]; + uint8_t input[16]; + uint8_t expect_t0[493]; + uint8_t expect_t1[80]; + uint8_t output[493]; // max + UNHEX(keys, tv->keys); + UNHEX(input, tv->input); + + cgo_prf_init(&prf, 128, keys); + if (tv->t == 0) { + UNHEX(expect_t0, tv->expect); + memset(output, 0, sizeof(output)); + cgo_prf_xor_t0(&prf, input, output); + tt_mem_op(output, OP_EQ, expect_t0, PRF_T0_DATA_LEN); + } else { + tt_int_op(tv->t, OP_EQ, 1); + UNHEX(expect_t1, tv->expect); + cgo_prf_gen_t1(&prf, input, output, sizeof(expect_t1)); + tt_mem_op(output, OP_EQ, expect_t1, sizeof(expect_t1)); + } + cgo_prf_clear(&prf); + } + done: + cgo_prf_clear(&prf); +} + +static void +test_crypto_cgo_uiv_testvec(void *arg) +{ + (void)arg; + cgo_uiv_t uiv; + memset(&uiv, 0, sizeof(uiv)); + + for (int i = 0; i < (int)ARRAY_LENGTH(UIV_TESTVECS); ++i) { + const struct uiv_testvec *tv = &UIV_TESTVECS[i]; + uint8_t keys[64]; + uint8_t tweaks[17]; + uint8_t x_l[16], x_r[493]; + uint8_t y_l[16], y_r[493]; + uint8_t cell[509]; + UNHEX(keys, tv->keys); + UNHEX(tweaks, tv->tweaks); + UNHEX(x_l, tv->x_l); + UNHEX(x_r, tv->x_r); + UNHEX(y_l, tv->y.y_l); + UNHEX(y_r, tv->y.y_r); + + uiv_tweak_t tweak = { + .h = tweaks, + .cmd = tweaks[16] + }; + memcpy(cell, x_l, 16); + memcpy(cell+16, x_r, 493); + + cgo_uiv_init(&uiv, 128, tv->encrypt, keys); + if (tv->encrypt) { + cgo_uiv_encrypt(&uiv, tweak, cell); + } else { + cgo_uiv_decrypt(&uiv, tweak, cell); + } + cgo_uiv_clear(&uiv); + + tt_mem_op(cell, OP_EQ, y_l, 16); + tt_mem_op(cell+16, OP_EQ, y_r, 493); + } + + done: + cgo_uiv_clear(&uiv); +} + +static void +test_crypto_cgo_uiv_update_testvec(void *arg) +{ + (void)arg; + cgo_uiv_t uiv; + cgo_uiv_t uiv2; + memset(&uiv, 0, sizeof(uiv)); + memset(&uiv2, 0, sizeof(uiv2)); + + uint8_t tw[16]; + memset(tw, 42, sizeof(tw)); + uiv_tweak_t tweak = { + .h = tw, + .cmd = 42 + }; + + for (int i = 0; i < (int)ARRAY_LENGTH(UIV_UPDATE_TESTVECS); ++i) { + const struct uiv_update_testvec *tv = &UIV_UPDATE_TESTVECS[i]; + uint8_t keys[64]; + uint8_t nonce[16]; + uint8_t new_keys[64]; + uint8_t new_nonce[16]; + UNHEX(keys, tv->keys); + UNHEX(nonce, tv->nonce); + UNHEX(new_keys, tv->output.new_keys); + UNHEX(new_nonce, tv->output.new_nonce); + + cgo_uiv_init(&uiv, 128, true, keys); + cgo_uiv_update(&uiv, 128, true, nonce); + // Make sure that the recorded keys are what we expect. + tt_mem_op(uiv.uiv_keys_, OP_EQ, new_keys, 64); + tt_mem_op(nonce, OP_EQ, new_nonce, 16); + + // Construct a new UIV from these keys and make sure it acts like this one. + uint8_t cell[509], cell2[509]; + crypto_rand((char*)cell, sizeof(cell)); + memcpy(cell2, cell, 509); + cgo_uiv_init(&uiv2, 128, true, uiv.uiv_keys_); + cgo_uiv_encrypt(&uiv, tweak, cell); + cgo_uiv_encrypt(&uiv2, tweak, cell2); + tt_mem_op(cell, OP_EQ, cell2, 509); + + cgo_uiv_clear(&uiv); + cgo_uiv_clear(&uiv2); + } + done: + cgo_uiv_clear(&uiv); + cgo_uiv_clear(&uiv2); +} + +static void +test_crypto_cgo_fwd(void *arg) +{ + (void)arg; + + #define N_HOPS 3 + uint8_t key_material[N_HOPS][112]; // max. + cgo_crypt_t *client[N_HOPS]; + cgo_crypt_t *relays[N_HOPS]; + + memset(client, 0, sizeof(client)); + memset(relays, 0, sizeof(relays)); + + for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) { + const int aesbits = AESBITS[bi]; + + size_t klen = cgo_key_material_len(aesbits); + tt_uint_op(klen, OP_LE, sizeof(key_material[0])); + crypto_rand((char*)&key_material, sizeof(key_material)); + for (int i = 0; i < N_HOPS; ++i) { + client[i] = cgo_crypt_new(CGO_MODE_CLIENT_FORWARD, + aesbits, key_material[i], klen); + relays[i] = cgo_crypt_new(CGO_MODE_RELAY_FORWARD, + aesbits, key_material[i], klen); + } + for (int trial = 0; trial < 64; ++trial) { + int target_hop = crypto_rand_int(3); + cell_t cell, cell_orig; + uint8_t tag_client[CGO_TAG_LEN]; + const uint8_t *tagp = NULL; + + memset(&cell, 0, sizeof(cell)); + if (crypto_rand_int(2) == 0) { + cell.command = CELL_RELAY; + } else { + cell.command = CELL_RELAY_EARLY; + } + crypto_rand((char*) cell.payload+CGO_TAG_LEN, + sizeof(cell.payload)-CGO_TAG_LEN); + memcpy(&cell_orig, &cell, sizeof(cell)); + + // First the client encrypts the cell... + cgo_crypt_client_originate(client[target_hop], &cell, &tagp); + tt_assert(tagp); + memcpy(tag_client, tagp, CGO_TAG_LEN); + for (int i = target_hop - 1; i >= 0; --i) { + cgo_crypt_client_forward(client[i], &cell); + } + + // Now the relays handle the cell... + bool cell_recognized = false; + for (int i = 0; i < N_HOPS; ++i) { + tagp = NULL; + cgo_crypt_relay_forward(relays[i], &cell, &tagp); + if (tagp) { + tt_int_op(i, OP_EQ, target_hop); + tt_mem_op(tagp, OP_EQ, tag_client, CGO_TAG_LEN); + cell_recognized = true; + break; + } + } + tt_assert(cell_recognized); + tt_int_op(cell.command, OP_EQ, cell_orig.command); + tt_mem_op(cell.payload + CGO_TAG_LEN, OP_EQ, + cell_orig.payload + CGO_TAG_LEN, + sizeof(cell.payload) - CGO_TAG_LEN); + } + for (int i = 0; i < N_HOPS; ++i) { + cgo_crypt_free(client[i]); + cgo_crypt_free(relays[i]); + } + } + + done: + for (int i = 0; i < N_HOPS; ++i) { + cgo_crypt_free(client[i]); + cgo_crypt_free(relays[i]); + } +#undef N_HOPS +} + +static void +test_crypto_cgo_rev(void *arg) +{ + (void)arg; + + #define N_HOPS 3 + uint8_t key_material[N_HOPS][112]; // max. + cgo_crypt_t *client[N_HOPS]; + cgo_crypt_t *relays[N_HOPS]; + + memset(client, 0, sizeof(client)); + memset(relays, 0, sizeof(relays)); + + for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) { + const int aesbits = AESBITS[bi]; + + size_t klen = cgo_key_material_len(aesbits); + tt_uint_op(klen, OP_LE, sizeof(key_material[0])); + crypto_rand((char*)&key_material, sizeof(key_material)); + for (int i = 0; i < N_HOPS; ++i) { + client[i] = cgo_crypt_new(CGO_MODE_CLIENT_BACKWARD, + aesbits, key_material[i], klen); + relays[i] = cgo_crypt_new(CGO_MODE_RELAY_BACKWARD, + aesbits, key_material[i], klen); + } + for (int trial = 0; trial < 64; ++trial) { + int origin_hop = crypto_rand_int(3); + cell_t cell, cell_orig; + uint8_t tag_relay[CGO_TAG_LEN]; + const uint8_t *tagp = NULL; + + memset(&cell, 0, sizeof(cell)); + cell.command = CELL_RELAY; + crypto_rand((char*) cell.payload+CGO_TAG_LEN, + sizeof(cell.payload)-CGO_TAG_LEN); + memcpy(&cell_orig, &cell, sizeof(cell)); + + // First the specified relay encrypts the cell... + cgo_crypt_relay_originate(relays[origin_hop], &cell, &tagp); + tt_assert(tagp); + memcpy(tag_relay, tagp, CGO_TAG_LEN); + for (int i = origin_hop - 1; i >= 0; --i) { + cgo_crypt_relay_backward(relays[i], &cell); + } + + // Now the client handles the cell. + bool cell_recognized = false; + for (int i = 0; i < N_HOPS; ++i) { + tagp = NULL; + cgo_crypt_client_backward(client[i], &cell, &tagp); + if (tagp) { + tt_int_op(i, OP_EQ, origin_hop); + tt_mem_op(tagp, OP_EQ, tag_relay, CGO_TAG_LEN); + cell_recognized = true; + break; + } + } + tt_assert(cell_recognized); + tt_int_op(cell.command, OP_EQ, cell_orig.command); + tt_mem_op(cell.payload + CGO_TAG_LEN, OP_EQ, + cell_orig.payload + CGO_TAG_LEN, + sizeof(cell.payload) - CGO_TAG_LEN); + } + for (int i = 0; i < N_HOPS; ++i) { + cgo_crypt_free(client[i]); + cgo_crypt_free(relays[i]); + } + } + + done: + for (int i = 0; i < N_HOPS; ++i) { + cgo_crypt_free(client[i]); + cgo_crypt_free(relays[i]); + } +#undef N_HOPS +} + +static void +test_crypto_cgo_relay_testvec(void *arg) +{ + (void)arg; + char *unhex_tmp = NULL; + cgo_crypt_t *cgo = NULL; + for (int i = 0; i < (int)ARRAY_LENGTH(CGO_RELAY_TESTVECS); ++i) { + const struct cgo_relay_testvec *tv = &CGO_RELAY_TESTVECS[i]; + const int aesbits = 128; + uint8_t keys[80], expect_keys[80], expect_tprime[CGO_TAG_LEN], cmd[1]; + cell_t cell; + cell_t expect_cell; + tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits)); + UNHEX2(keys, tv->state_in.keys, tv->state_in.nonce); + cgo_mode_t mode = + tv->inbound ? CGO_MODE_RELAY_BACKWARD : CGO_MODE_RELAY_FORWARD; + cgo = cgo_crypt_new(mode, aesbits, keys, sizeof(keys)); + tt_assert(cgo); + UNHEX(cgo->tprime, tv->state_in.tprime); + memset(&cell, 0, sizeof(cell)); + UNHEX(cmd, tv->cmd); + cell.command = cmd[0]; + UNHEX2(cell.payload, tv->tag, tv->msg); + + memset(&expect_cell, 0, sizeof(expect_cell)); + expect_cell.command = cell.command; + UNHEX2(expect_cell.payload, + tv->output.result.t_out, tv->output.result.msg_out); + UNHEX2(expect_keys, + tv->output.state.keys, tv->output.state.nonce); + UNHEX(expect_tprime, tv->output.state.tprime); + + if (tv->inbound) { + cgo_crypt_relay_backward(cgo, &cell); + } else { + const uint8_t *tagp = NULL; + cgo_crypt_relay_forward(cgo, &cell, &tagp); + tt_ptr_op(tagp, OP_EQ, NULL); + } + + tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload)); + tt_mem_op(cgo->uiv.uiv_keys_, OP_EQ, expect_keys, 64); + tt_mem_op(cgo->nonce, OP_EQ, expect_keys + 64, 16); + tt_mem_op(cgo->tprime, OP_EQ, expect_tprime, 16); + + cgo_crypt_free(cgo); + } + done: + tor_free(unhex_tmp); + cgo_crypt_free(cgo); +} + +static void +test_crypto_cgo_relay_originate_testvec(void *arg) +{ + (void)arg; + char *unhex_tmp = NULL; + cgo_crypt_t *cgo = NULL; + for (int i = 0; i < (int)ARRAY_LENGTH(CGO_RELAY_ORIGINATE_TESTVECS); ++i) { + const struct cgo_relay_originate_testvec *tv = + &CGO_RELAY_ORIGINATE_TESTVECS[i]; + const int aesbits = 128; + uint8_t keys[80], expect_keys[80], expect_tprime[CGO_TAG_LEN], cmd[1]; + cell_t cell; + cell_t expect_cell; + tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits)); + UNHEX2(keys, tv->state_in.keys, tv->state_in.nonce); + cgo = cgo_crypt_new(CGO_MODE_RELAY_BACKWARD, aesbits, keys, sizeof(keys)); + tt_assert(cgo); + UNHEX(cgo->tprime, tv->state_in.tprime); + memset(&cell, 0, sizeof(cell)); + UNHEX(cmd, tv->cmd); + cell.command = cmd[0]; + UNHEX2(cell.payload, "00000000000000000000000000000000", tv->msg); + + memset(&expect_cell, 0, sizeof(expect_cell)); + expect_cell.command = cell.command; + UNHEX2(expect_cell.payload, + tv->output.result.t_out, tv->output.result.msg_out); + UNHEX2(expect_keys, + tv->output.state.keys, tv->output.state.nonce); + UNHEX(expect_tprime, tv->output.state.tprime); + + const uint8_t *tagp = NULL; + cgo_crypt_relay_originate(cgo, &cell, &tagp); + tt_ptr_op(tagp, OP_NE, NULL); + + tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload)); + tt_mem_op(cgo->uiv.uiv_keys_, OP_EQ, expect_keys, 64); + tt_mem_op(cgo->nonce, OP_EQ, expect_keys + 64, 16); + tt_mem_op(cgo->tprime, OP_EQ, expect_tprime, 16); + + cgo_crypt_free(cgo); + } + done: + tor_free(unhex_tmp); + cgo_crypt_free(cgo); +} + +static void +test_crypto_cgo_client_originate_testvec(void *arg) +{ + (void) arg; + char *unhex_tmp = NULL; + cgo_crypt_t *cgo[3] = { NULL, NULL, NULL }; + for (int tv_i = 0; tv_i < (int)ARRAY_LENGTH(CGO_CLIENT_ORIGINATE_TESTVECS); + ++tv_i) { + const struct cgo_client_originate_testvec *tv = + &CGO_CLIENT_ORIGINATE_TESTVECS[tv_i]; + const int aesbits = 128; + uint8_t keys[80], expect_keys[80], expect_tprime[CGO_TAG_LEN], cmd[1]; + cell_t cell; + cell_t expect_cell; + for (int i = 0; i < 3; ++i) { + tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits)); + UNHEX2(keys, tv->state_in[i].keys, tv->state_in[i].nonce); + cgo[i] = cgo_crypt_new(CGO_MODE_CLIENT_FORWARD, + aesbits, keys, sizeof(keys)); + tt_assert(cgo[i]); + UNHEX(cgo[i]->tprime, tv->state_in[i].tprime); + } + + memset(&cell, 0, sizeof(cell)); + UNHEX(cmd, tv->cmd); + cell.command = cmd[0]; + UNHEX2(cell.payload, "00000000000000000000000000000000", tv->msg); + + memset(&expect_cell, 0, sizeof(expect_cell)); + expect_cell.command = cell.command; + UNHEX2(expect_cell.payload, + tv->output.result.t_out, tv->output.result.msg_out); + + tt_int_op(tv->target_hop, OP_GE, 1); // Hop is 0-indexed. + int target_hop = tv->target_hop - 1; + const uint8_t *tagp = NULL; + cgo_crypt_client_originate(cgo[target_hop], &cell, &tagp); + tt_ptr_op(tagp, OP_NE, NULL); + for (int i = target_hop - 1; i >= 0; --i) { + cgo_crypt_client_forward(cgo[i], &cell); + } + tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload)); + + for (int i = 0; i < 3; ++i) { + UNHEX2(expect_keys, + tv->output.state[i].keys, tv->output.state[i].nonce); + UNHEX(expect_tprime, tv->output.state[i].tprime); + + tt_mem_op(cgo[i]->uiv.uiv_keys_, OP_EQ, expect_keys, 64); + tt_mem_op(cgo[i]->nonce, OP_EQ, expect_keys + 64, 16); + tt_mem_op(cgo[i]->tprime, OP_EQ, expect_tprime, 16); + } + + for (int i = 0; i < 3; ++i) + cgo_crypt_free(cgo[i]); + } + done: + tor_free(unhex_tmp); + for (int i = 0; i < 3; ++i) + cgo_crypt_free(cgo[i]); +} + +struct testcase_t crypto_cgo_tests[] = { + { "et_roundtrip", test_crypto_cgo_et_roundtrip, 0, NULL, NULL }, + { "et_testvec", test_crypto_cgo_et_testvec, 0, NULL, NULL }, + { "prf_testvec", test_crypto_cgo_prf_testvec, 0, NULL, NULL }, + { "uiv_roundtrip", test_crypto_cgo_uiv_roundtrip, 0, NULL, NULL }, + { "uiv_testvec", test_crypto_cgo_uiv_testvec, 0, NULL, NULL }, + { "uiv_update_testvec", test_crypto_cgo_uiv_update_testvec, 0, NULL, NULL }, + { "cgo_fwd", test_crypto_cgo_fwd, 0, NULL, NULL, }, + { "cgo_rev", test_crypto_cgo_rev, 0, NULL, NULL, }, + { "cgo_relay_testvec", test_crypto_cgo_relay_testvec, 0, NULL, NULL }, + { "cgo_relay_originate_testvec", test_crypto_cgo_relay_originate_testvec, + 0, NULL, NULL }, + { "cgo_client_originate_testvec", test_crypto_cgo_client_originate_testvec, + 0, NULL, NULL }, + END_OF_TESTCASES +};