tor

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

commit b604329cf2b766c1e552acdb2b4a23614aaefbb4
parent 83b9f63b860efab0473bcfa41c8c12912af2aeca
Author: Nick Mathewson <nickm@torproject.org>
Date:   Sun, 20 Apr 2025 10:22:54 -0400

Implement low-level encryption functions for CGO.

These include a regular LRW2 tweakable block cipher,
a pseudorandom function,
and a UIV+ tweakable wide-block rugged pseudorandom permutation.

Also included are a few test vectors from the reference
 implementation.

Diffstat:
Msrc/core/crypto/include.am | 6++++--
Asrc/core/crypto/relay_crypto_cgo.c | 335+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/crypto/relay_crypto_cgo.h | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/cgo_vectors.inc | 373+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test/include.am | 2++
Msrc/test/test.c | 1+
Msrc/test/test.h | 1+
Asrc/test/test_crypto_cgo.c | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 1190 insertions(+), 2 deletions(-)

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,335 @@ +/* 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 "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" + +#if 0 +// XXXX debugging. +#include "lib/encoding/binascii.h" +#include <stdio.h> +#endif + +#include <string.h> + + +/** 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); +} + +/** + * 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); +} + +/** + * 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); +} + +// XXXX temporarily suppress unused-function warnings +void temporary(void); +void temporary(void) +{ + (void)cgo_et_init; + (void)cgo_et_encrypt; + (void)cgo_et_decrypt; + (void)cgo_et_clear; + + (void)cgo_prf_init; + (void)cgo_prf_xor_t0; + (void)cgo_prf_gen_t1; + (void)cgo_prf_clear; + + (void)cgo_uiv_init; + (void)cgo_uiv_encrypt; + (void)cgo_uiv_decrypt; + (void)cgo_uiv_update; + (void)cgo_uiv_clear; +} diff --git a/src/core/crypto/relay_crypto_cgo.h b/src/core/crypto/relay_crypto_cgo.h @@ -0,0 +1,165 @@ +/* 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" + +#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); + +#endif + +#endif /* !defined(TOR_RELAY_CRYPTO_CGO_H) */ diff --git a/src/test/cgo_vectors.inc b/src/test/cgo_vectors.inc @@ -0,0 +1,373 @@ +/* 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"}, +}, +}; 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 @@ -628,6 +628,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_cgo.c b/src/test/test_crypto_cgo.c @@ -0,0 +1,309 @@ +/* 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 "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 + +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); +} + +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 }, + END_OF_TESTCASES +};