From 22f9b38d393db7ac98648442fd7ab78d1efd3abb Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 8 Dec 2025 23:15:08 +0100 Subject: [PATCH] Import ipcrypt --- src/libsodium/crypto_ipcrypt/crypto_ipcrypt.c | 144 ++++++++ .../crypto_ipcrypt/implementations.h | 18 + src/libsodium/crypto_ipcrypt/ipcrypt_aesni.c | 299 ++++++++++++++++ src/libsodium/crypto_ipcrypt/ipcrypt_aesni.h | 8 + .../crypto_ipcrypt/ipcrypt_armcrypto.c | 331 ++++++++++++++++++ .../crypto_ipcrypt/ipcrypt_armcrypto.h | 8 + src/libsodium/crypto_ipcrypt/ipcrypt_soft.c | 267 ++++++++++++++ src/libsodium/crypto_ipcrypt/ipcrypt_soft.h | 8 + src/libsodium/include/sodium/crypto_ipcrypt.h | 96 +++++ test/default/ipcrypt.c | 205 +++++++++++ test/default/ipcrypt.exp | 43 +++ 11 files changed, 1427 insertions(+) create mode 100644 src/libsodium/crypto_ipcrypt/crypto_ipcrypt.c create mode 100644 src/libsodium/crypto_ipcrypt/implementations.h create mode 100644 src/libsodium/crypto_ipcrypt/ipcrypt_aesni.c create mode 100644 src/libsodium/crypto_ipcrypt/ipcrypt_aesni.h create mode 100644 src/libsodium/crypto_ipcrypt/ipcrypt_armcrypto.c create mode 100644 src/libsodium/crypto_ipcrypt/ipcrypt_armcrypto.h create mode 100644 src/libsodium/crypto_ipcrypt/ipcrypt_soft.c create mode 100644 src/libsodium/crypto_ipcrypt/ipcrypt_soft.h create mode 100644 src/libsodium/include/sodium/crypto_ipcrypt.h create mode 100644 test/default/ipcrypt.c create mode 100644 test/default/ipcrypt.exp diff --git a/src/libsodium/crypto_ipcrypt/crypto_ipcrypt.c b/src/libsodium/crypto_ipcrypt/crypto_ipcrypt.c new file mode 100644 index 00000000..5a97cec8 --- /dev/null +++ b/src/libsodium/crypto_ipcrypt/crypto_ipcrypt.c @@ -0,0 +1,144 @@ + +#include + +#include "core.h" +#include "crypto_ipcrypt.h" +#include "private/common.h" +#include "private/implementations.h" +#include "randombytes.h" +#include "runtime.h" + +#include "ipcrypt_soft.h" + +#if defined(HAVE_ARMCRYPTO) && defined(NATIVE_LITTLE_ENDIAN) +# include "ipcrypt_armcrypto.h" +#endif + +#if defined(HAVE_AVXINTRIN_H) && defined(HAVE_WMMINTRIN_H) +# include "ipcrypt_aesni.h" +#endif + +static const ipcrypt_implementation *implementation = &ipcrypt_soft_implementation; + +size_t +crypto_ipcrypt_inputbytes(void) +{ + return crypto_ipcrypt_INPUTBYTES; +} + +size_t +crypto_ipcrypt_keybytes(void) +{ + return crypto_ipcrypt_KEYBYTES; +} + +size_t +crypto_ipcrypt_nd_keybytes(void) +{ + return crypto_ipcrypt_ND_KEYBYTES; +} + +size_t +crypto_ipcrypt_nd_tweakbytes(void) +{ + return crypto_ipcrypt_ND_TWEAKBYTES; +} + +size_t +crypto_ipcrypt_nd_bytes(void) +{ + return crypto_ipcrypt_ND_BYTES; +} + +size_t +crypto_ipcrypt_ndx_keybytes(void) +{ + return crypto_ipcrypt_NDX_KEYBYTES; +} + +size_t +crypto_ipcrypt_ndx_tweakbytes(void) +{ + return crypto_ipcrypt_NDX_TWEAKBYTES; +} + +size_t +crypto_ipcrypt_ndx_bytes(void) +{ + return crypto_ipcrypt_NDX_BYTES; +} + +void +crypto_ipcrypt_keygen(unsigned char k[crypto_ipcrypt_KEYBYTES]) +{ + randombytes_buf(k, crypto_ipcrypt_KEYBYTES); +} + +void +crypto_ipcrypt_ndx_keygen(unsigned char k[crypto_ipcrypt_NDX_KEYBYTES]) +{ + randombytes_buf(k, crypto_ipcrypt_NDX_KEYBYTES); +} + +void +crypto_ipcrypt_encrypt(unsigned char *out, const unsigned char *in, const unsigned char *k) +{ + implementation->encrypt(out, in, k); +} + +void +crypto_ipcrypt_decrypt(unsigned char *out, const unsigned char *in, const unsigned char *k) +{ + implementation->decrypt(out, in, k); +} + +void +crypto_ipcrypt_nd_encrypt(unsigned char *out, + const unsigned char *in, + const unsigned char *t, + const unsigned char *k) +{ + implementation->nd_encrypt(out, in, t, k); +} + +void +crypto_ipcrypt_nd_decrypt(unsigned char *out, const unsigned char *in, const unsigned char *k) +{ + implementation->nd_decrypt(out, in, k); +} + +void +crypto_ipcrypt_ndx_encrypt(unsigned char *out, + const unsigned char *in, + const unsigned char *t, + const unsigned char *k) +{ + implementation->ndx_encrypt(out, in, t, k); +} + +void +crypto_ipcrypt_ndx_decrypt(unsigned char *out, const unsigned char *in, const unsigned char *k) +{ + implementation->ndx_decrypt(out, in, k); +} + +int +_crypto_ipcrypt_pick_best_implementation(void) +{ + implementation = &ipcrypt_soft_implementation; + +#if defined(HAVE_ARMCRYPTO) && defined(NATIVE_LITTLE_ENDIAN) + if (sodium_runtime_has_armcrypto()) { + implementation = &ipcrypt_armcrypto_implementation; + return 0; + } +#endif + +#if defined(HAVE_AVXINTRIN_H) && defined(HAVE_WMMINTRIN_H) + if (sodium_runtime_has_aesni()) { + implementation = &ipcrypt_aesni_implementation; + return 0; + } +#endif + return 0; +} diff --git a/src/libsodium/crypto_ipcrypt/implementations.h b/src/libsodium/crypto_ipcrypt/implementations.h new file mode 100644 index 00000000..42ab5824 --- /dev/null +++ b/src/libsodium/crypto_ipcrypt/implementations.h @@ -0,0 +1,18 @@ +#ifndef ipcrypt_implementations_H +#define ipcrypt_implementations_H + +#include +#include + +#include "crypto_ipcrypt.h" + +typedef struct ipcrypt_implementation { + void (*encrypt)(uint8_t *out, const uint8_t *in, const uint8_t *k); + void (*decrypt)(uint8_t *out, const uint8_t *in, const uint8_t *k); + void (*nd_encrypt)(uint8_t *out, const uint8_t *in, const uint8_t *t, const uint8_t *k); + void (*nd_decrypt)(uint8_t *out, const uint8_t *in, const uint8_t *k); + void (*ndx_encrypt)(uint8_t *out, const uint8_t *in, const uint8_t *t, const uint8_t *k); + void (*ndx_decrypt)(uint8_t *out, const uint8_t *in, const uint8_t *k); +} ipcrypt_implementation; + +#endif diff --git a/src/libsodium/crypto_ipcrypt/ipcrypt_aesni.c b/src/libsodium/crypto_ipcrypt/ipcrypt_aesni.c new file mode 100644 index 00000000..fe02cba5 --- /dev/null +++ b/src/libsodium/crypto_ipcrypt/ipcrypt_aesni.c @@ -0,0 +1,299 @@ +#include +#include +#include + +#include "crypto_ipcrypt.h" +#include "utils.h" + +#include "private/common.h" + +#if defined(HAVE_AVXINTRIN_H) && defined(HAVE_WMMINTRIN_H) + +# include "ipcrypt_aesni.h" + +# ifdef __clang__ +# pragma clang attribute push(__attribute__((target("aes,avx"))), apply_to = function) +# elif defined(__GNUC__) +# pragma GCC target("aes,avx") +# endif + +# include +# include + +# define ROUNDS 10 + +typedef __m128i BlockVec; + +# define LOAD128(a) _mm_loadu_si128((const BlockVec *) (const void *) (a)) +# define STORE128(a, b) _mm_storeu_si128((BlockVec *) (void *) (a), (b)) +# define AES_ENCRYPT(block_vec, rkey) _mm_aesenc_si128((block_vec), (rkey)) +# define AES_ENCRYPTLAST(block_vec, rkey) _mm_aesenclast_si128((block_vec), (rkey)) +# define AES_DECRYPT(block_vec, rkey) _mm_aesdec_si128((block_vec), (rkey)) +# define AES_DECRYPTLAST(block_vec, rkey) _mm_aesdeclast_si128((block_vec), (rkey)) +# define AES_KEYGEN(block_vec, rc) _mm_aeskeygenassist_si128((block_vec), (rc)) +# define AES_IMC(rkey) _mm_aesimc_si128(rkey) +# define XOR128(a, b) _mm_xor_si128((a), (b)) +# define XOR128_3(a, b, c) _mm_xor_si128(_mm_xor_si128((a), (b)), (c)) +# define SET64x2(a, b) _mm_set_epi64x((uint64_t) (a), (uint64_t) (b)) +# define BYTESHL128(a, b) _mm_slli_si128(a, b) +# define SHUFFLE32x4(x, a, b, c, d) _mm_shuffle_epi32((x), _MM_SHUFFLE((d), (c), (b), (a))) + +typedef BlockVec KeySchedule[1 + ROUNDS]; + +static void +expand_key(KeySchedule rkeys, const uint8_t key[16]) +{ + BlockVec t, s; + size_t i = 0; + +# define EXPAND_KEY(RC) \ + rkeys[i++] = t; \ + s = AES_KEYGEN(t, RC); \ + t = XOR128(t, BYTESHL128(t, 4)); \ + t = XOR128(t, BYTESHL128(t, 8)); \ + t = XOR128(t, SHUFFLE32x4(s, 3, 3, 3, 3)); + + t = LOAD128(key); + EXPAND_KEY(0x01); + EXPAND_KEY(0x02); + EXPAND_KEY(0x04); + EXPAND_KEY(0x08); + EXPAND_KEY(0x10); + EXPAND_KEY(0x20); + EXPAND_KEY(0x40); + EXPAND_KEY(0x80); + EXPAND_KEY(0x1b); + EXPAND_KEY(0x36); + rkeys[i++] = t; +} + +static void +aes_encrypt(uint8_t out[16], const uint8_t in[16], const KeySchedule rkeys) +{ + BlockVec t; + size_t i; + + t = XOR128(LOAD128(in), rkeys[0]); + for (i = 1; i < ROUNDS; i++) { + t = AES_ENCRYPT(t, rkeys[i]); + } + t = AES_ENCRYPTLAST(t, rkeys[ROUNDS]); + STORE128(out, t); +} + +static void +aes_decrypt(uint8_t out[16], const uint8_t in[16], const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + BlockVec t; + size_t i; + + for (i = 0; i < ROUNDS - 1; i++) { + rkeys_inv[i] = AES_IMC(rkeys[ROUNDS - 1 - i]); + } + t = XOR128(LOAD128(in), rkeys[ROUNDS]); + for (i = 0; i < ROUNDS - 1; i++) { + t = AES_DECRYPT(t, rkeys_inv[i]); + } + t = AES_DECRYPTLAST(t, rkeys[0]); + STORE128(out, t); +} + +static BlockVec +tweak_expand(const uint8_t tweak[8]) +{ + return _mm_shuffle_epi8(_mm_loadu_si64((const void *) tweak), + _mm_setr_epi8(0x00, 0x01, -128, -128, 0x02, 0x03, -128, -128, 0x04, + 0x05, -128, -128, 0x06, 0x07, -128, -128)); +} + +static void +aes_encrypt_with_tweak(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[8], + const KeySchedule rkeys) +{ + const BlockVec tweak_block = tweak_expand(tweak); + BlockVec t; + size_t i; + + t = XOR128_3(LOAD128(in), tweak_block, rkeys[0]); + for (i = 1; i < ROUNDS; i++) { + t = AES_ENCRYPT(t, XOR128(tweak_block, rkeys[i])); + } + t = AES_ENCRYPTLAST(t, XOR128(tweak_block, rkeys[ROUNDS])); + STORE128(out, t); +} + +static void +aes_decrypt_with_tweak(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[8], + const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + const BlockVec tweak_block = tweak_expand(tweak); + const BlockVec tweak_block_inv = AES_IMC(tweak_block); + BlockVec t; + size_t i; + + for (i = 0; i < ROUNDS - 1; i++) { + rkeys_inv[i] = AES_IMC(rkeys[ROUNDS - 1 - i]); + } + t = XOR128_3(LOAD128(in), tweak_block, rkeys[ROUNDS]); + for (i = 0; i < ROUNDS - 1; i++) { + t = AES_DECRYPT(t, XOR128(tweak_block_inv, rkeys_inv[i])); + } + t = AES_DECRYPTLAST(t, XOR128(tweak_block, rkeys[0])); + STORE128(out, t); +} + +static BlockVec +aes_xex_tweak(const uint8_t tweak[16], const KeySchedule tkeys) +{ + BlockVec tt; + size_t i; + + tt = XOR128(LOAD128(tweak), tkeys[0]); + for (i = 1; i < ROUNDS; i++) { + tt = AES_ENCRYPT(tt, tkeys[i]); + } + tt = AES_ENCRYPTLAST(tt, tkeys[ROUNDS]); + return tt; +} + +static void +aes_xex_encrypt(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[16], + const KeySchedule tkeys, const KeySchedule rkeys) +{ + const BlockVec tt = aes_xex_tweak(tweak, tkeys); + BlockVec t; + size_t i; + + t = XOR128(XOR128(LOAD128(in), tt), rkeys[0]); + for (i = 1; i < ROUNDS; i++) { + t = AES_ENCRYPT(t, rkeys[i]); + } + t = AES_ENCRYPTLAST(t, XOR128(rkeys[ROUNDS], tt)); + STORE128(out, t); +} + +static void +aes_xex_decrypt(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[16], + const KeySchedule tkeys, const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + const BlockVec tt = aes_xex_tweak(tweak, tkeys); + BlockVec t; + size_t i; + + for (i = 0; i < ROUNDS - 1; i++) { + rkeys_inv[i] = AES_IMC(rkeys[ROUNDS - 1 - i]); + } + t = XOR128(XOR128(LOAD128(in), tt), rkeys[ROUNDS]); + for (i = 0; i < ROUNDS - 1; i++) { + t = AES_DECRYPT(t, rkeys_inv[i]); + } + t = AES_DECRYPTLAST(t, XOR128(rkeys[0], tt)); + STORE128(out, t); +} + +static void +encrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_encrypt(out, in, rkeys); +} + +static void +decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_decrypt(out, in, rkeys); +} + +static void +nd_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *t, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + memcpy(out, t, 8); + aes_encrypt_with_tweak(out + 8, in, t, rkeys); +} + +static void +nd_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_decrypt_with_tweak(out, in + 8, in, rkeys); +} + +static void +ndx_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *t, const uint8_t *k) +{ + KeySchedule tkeys; + KeySchedule rkeys; + uint8_t diff[16]; + size_t i; + uint8_t d; + + expand_key(tkeys, k + 16); + expand_key(rkeys, k); + + STORE128(diff, XOR128(tkeys[ROUNDS / 2], rkeys[ROUNDS / 2])); + d = 0; + for (i = 0; i < 16; i++) { + d |= diff[i]; + } + if (d == 0) { + for (i = 0; i < 16; i++) { + diff[i] = k[i] ^ 0x5a; + } + expand_key(rkeys, diff); + } + + memcpy(out, t, 16); + aes_xex_encrypt(out + 16, in, t, tkeys, rkeys); +} + +static void +ndx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule tkeys; + KeySchedule rkeys; + uint8_t diff[16]; + size_t i; + uint8_t d; + + expand_key(tkeys, k + 16); + expand_key(rkeys, k); + + STORE128(diff, XOR128(tkeys[ROUNDS / 2], rkeys[ROUNDS / 2])); + d = 0; + for (i = 0; i < 16; i++) { + d |= diff[i]; + } + if (d == 0) { + for (i = 0; i < 16; i++) { + diff[i] = k[i] ^ 0x5a; + } + expand_key(rkeys, diff); + } + + aes_xex_decrypt(out, in + 16, in, tkeys, rkeys); +} + +struct ipcrypt_implementation ipcrypt_aesni_implementation = { + SODIUM_C99(.encrypt =) encrypt, SODIUM_C99(.decrypt =) decrypt, + SODIUM_C99(.nd_encrypt =) nd_encrypt, SODIUM_C99(.nd_decrypt =) nd_decrypt, + SODIUM_C99(.ndx_encrypt =) ndx_encrypt, SODIUM_C99(.ndx_decrypt =) ndx_decrypt +}; + +# ifdef __clang__ +# pragma clang attribute pop +# endif + +#endif diff --git a/src/libsodium/crypto_ipcrypt/ipcrypt_aesni.h b/src/libsodium/crypto_ipcrypt/ipcrypt_aesni.h new file mode 100644 index 00000000..f01a0c93 --- /dev/null +++ b/src/libsodium/crypto_ipcrypt/ipcrypt_aesni.h @@ -0,0 +1,8 @@ +#ifndef ipcrypt_aesni_H +#define ipcrypt_aesni_H + +#include "implementations.h" + +extern struct ipcrypt_implementation ipcrypt_aesni_implementation; + +#endif diff --git a/src/libsodium/crypto_ipcrypt/ipcrypt_armcrypto.c b/src/libsodium/crypto_ipcrypt/ipcrypt_armcrypto.c new file mode 100644 index 00000000..a7edfdbf --- /dev/null +++ b/src/libsodium/crypto_ipcrypt/ipcrypt_armcrypto.c @@ -0,0 +1,331 @@ +#include +#include +#include + +#include "crypto_ipcrypt.h" +#include "utils.h" + +#include "private/common.h" + +#if defined(HAVE_ARMCRYPTO) && defined(NATIVE_LITTLE_ENDIAN) + +# include "ipcrypt_armcrypto.h" + +# ifndef __ARM_FEATURE_CRYPTO +# define __ARM_FEATURE_CRYPTO 1 +# endif +# ifndef __ARM_FEATURE_AES +# define __ARM_FEATURE_AES 1 +# endif + +# include + +# ifdef __clang__ +# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), \ + apply_to = function) +# elif defined(__GNUC__) +# pragma GCC target("+simd+crypto") +# endif + +# define ROUNDS 10 + +typedef uint64x2_t BlockVec; + +# define LOAD128(a) vld1q_u64((const uint64_t *) (const void *) (a)) +# define STORE128(a, b) vst1q_u64((uint64_t *) (void *) (a), (b)) +# define XOR128(a, b) veorq_u64((a), (b)) +# define XOR128_3(a, b, c) veorq_u64(veorq_u64((a), (b)), (c)) +# define SET64x2(a, b) vsetq_lane_u64((uint64_t) (a), vmovq_n_u64((uint64_t) (b)), 1) +# define BYTESHL128(a, b) \ + vreinterpretq_u64_u8(vextq_s8(vdupq_n_s8(0), (int8x16_t) vreinterpretq_u8_u64(a), 16 - (b))) + +# define AES_XENCRYPT(block_vec, rkey) \ + vreinterpretq_u64_u8( \ + vaesmcq_u8(vaeseq_u8(vreinterpretq_u8_u64(rkey), vreinterpretq_u8_u64(block_vec)))) +# define AES_XENCRYPTLAST(block_vec, rkey) \ + vreinterpretq_u64_u8(vaeseq_u8(vreinterpretq_u8_u64(rkey), vreinterpretq_u8_u64(block_vec))) +# define AES_XDECRYPT(block_vec, rkey) \ + vreinterpretq_u64_u8( \ + vaesimcq_u8(vaesdq_u8(vreinterpretq_u8_u64(rkey), vreinterpretq_u8_u64(block_vec)))) +# define AES_XDECRYPTLAST(block_vec, rkey) \ + vreinterpretq_u64_u8(vaesdq_u8(vreinterpretq_u8_u64(rkey), vreinterpretq_u8_u64(block_vec))) +# define RKINVERT(rkey) vreinterpretq_u64_u8(vaesimcq_u8(vreinterpretq_u8_u64(rkey))) + +# define SHUFFLE32x4(x, a, b, c, d) \ + vreinterpretq_u64_u32(__builtin_shufflevector( \ + vreinterpretq_u32_u64(x), vreinterpretq_u32_u64(x), (a), (b), (c), (d))) + +typedef BlockVec KeySchedule[1 + ROUNDS]; + +static BlockVec +AES_KEYGEN(BlockVec block_vec, const int rc) +{ + uint8x16_t a = vaeseq_u8(vreinterpretq_u8_u64(block_vec), vmovq_n_u8(0)); + const uint8x16_t b = + __builtin_shufflevector(a, a, 4, 1, 14, 11, 1, 14, 11, 4, 12, 9, 6, 3, 9, 6, 3, 12); + const uint64x2_t c = SET64x2((uint64_t) rc << 32, (uint64_t) rc << 32); + return XOR128(vreinterpretq_u64_u8(b), c); +} + +static void +expand_key(KeySchedule rkeys, const uint8_t key[16]) +{ + BlockVec t, s; + size_t i = 0; + +# define EXPAND_KEY(RC) \ + rkeys[i++] = t; \ + s = AES_KEYGEN(t, RC); \ + t = XOR128(t, BYTESHL128(t, 4)); \ + t = XOR128(t, BYTESHL128(t, 8)); \ + t = XOR128(t, SHUFFLE32x4(s, 3, 3, 3, 3)); + + t = LOAD128(key); + EXPAND_KEY(0x01); + EXPAND_KEY(0x02); + EXPAND_KEY(0x04); + EXPAND_KEY(0x08); + EXPAND_KEY(0x10); + EXPAND_KEY(0x20); + EXPAND_KEY(0x40); + EXPAND_KEY(0x80); + EXPAND_KEY(0x1b); + EXPAND_KEY(0x36); + rkeys[i++] = t; +} + +static void +aes_encrypt(uint8_t out[16], const uint8_t in[16], const KeySchedule rkeys) +{ + BlockVec t; + size_t i; + + t = AES_XENCRYPT(LOAD128(in), rkeys[0]); + for (i = 1; i < ROUNDS - 1; i++) { + t = AES_XENCRYPT(t, rkeys[i]); + } + t = AES_XENCRYPTLAST(t, rkeys[i]); + t = XOR128(t, rkeys[ROUNDS]); + STORE128(out, t); +} + +static void +aes_decrypt(uint8_t out[16], const uint8_t in[16], const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + BlockVec t; + size_t i; + + for (i = 0; i < ROUNDS - 1; i++) { + rkeys_inv[i] = RKINVERT(rkeys[ROUNDS - 1 - i]); + } + t = AES_XDECRYPT(LOAD128(in), rkeys[ROUNDS]); + for (i = 0; i < ROUNDS - 2; i++) { + t = AES_XDECRYPT(t, rkeys_inv[i]); + } + t = AES_XDECRYPTLAST(t, rkeys_inv[i]); + t = XOR128(t, rkeys[0]); + STORE128(out, t); +} + +static BlockVec +tweak_expand(const uint8_t tweak[8]) +{ + return vreinterpretq_u64_u32(vmovl_u16(vld1_u16((const uint16_t *) (tweak)))); +} + +static void +aes_encrypt_with_tweak(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[8], + const KeySchedule rkeys) +{ + const BlockVec tweak_block = tweak_expand(tweak); + BlockVec t; + size_t i; + + t = AES_XENCRYPT(LOAD128(in), XOR128(tweak_block, rkeys[0])); + for (i = 1; i < ROUNDS - 1; i++) { + t = AES_XENCRYPT(t, XOR128(tweak_block, rkeys[i])); + } + t = AES_XENCRYPTLAST(t, XOR128(tweak_block, rkeys[i])); + t = XOR128(t, XOR128(tweak_block, rkeys[ROUNDS])); + STORE128(out, t); +} + +static void +aes_decrypt_with_tweak(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[8], + const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + const BlockVec tweak_block = tweak_expand(tweak); + const BlockVec tweak_block_inv = RKINVERT(tweak_block); + BlockVec t; + size_t i; + + for (i = 0; i < ROUNDS - 1; i++) { + rkeys_inv[i] = RKINVERT(rkeys[ROUNDS - 1 - i]); + } + t = AES_XDECRYPT(LOAD128(in), XOR128(tweak_block, rkeys[ROUNDS])); + for (i = 0; i < ROUNDS - 2; i++) { + t = AES_XDECRYPT(t, XOR128(tweak_block_inv, rkeys_inv[i])); + } + t = AES_XDECRYPTLAST(t, XOR128(tweak_block_inv, rkeys_inv[i])); + t = XOR128(t, XOR128(tweak_block, rkeys[0])); + STORE128(out, t); +} + +static BlockVec +aes_xex_tweak(const uint8_t tweak[16], const KeySchedule tkeys) +{ + BlockVec tt; + size_t i; + + tt = AES_XENCRYPT(LOAD128(tweak), tkeys[0]); + for (i = 1; i < ROUNDS - 1; i++) { + tt = AES_XENCRYPT(tt, tkeys[i]); + } + tt = AES_XENCRYPTLAST(tt, tkeys[i]); + tt = XOR128(tt, tkeys[ROUNDS]); + return tt; +} + +static void +aes_xex_encrypt(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[16], + const KeySchedule tkeys, const KeySchedule rkeys) +{ + const BlockVec tt = aes_xex_tweak(tweak, tkeys); + BlockVec t; + size_t i; + + t = AES_XENCRYPT(XOR128(LOAD128(in), tt), rkeys[0]); + for (i = 1; i < ROUNDS - 1; i++) { + t = AES_XENCRYPT(t, rkeys[i]); + } + t = AES_XENCRYPTLAST(t, rkeys[i]); + t = XOR128_3(t, rkeys[ROUNDS], tt); + STORE128(out, t); +} + +static void +aes_xex_decrypt(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[16], + const KeySchedule tkeys, const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + const BlockVec tt = aes_xex_tweak(tweak, tkeys); + BlockVec t; + size_t i; + + for (i = 0; i < ROUNDS - 1; i++) { + rkeys_inv[i] = RKINVERT(rkeys[ROUNDS - 1 - i]); + } + t = AES_XDECRYPT(XOR128(LOAD128(in), tt), rkeys[ROUNDS]); + for (i = 0; i < ROUNDS - 2; i++) { + t = AES_XDECRYPT(t, rkeys_inv[i]); + } + t = AES_XDECRYPTLAST(t, rkeys_inv[i]); + t = XOR128_3(t, rkeys[0], tt); + STORE128(out, t); +} + +static void +encrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_encrypt(out, in, rkeys); +} + +static void +decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_decrypt(out, in, rkeys); +} + +static void +nd_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *t, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + memcpy(out, t, 8); + aes_encrypt_with_tweak(out + 8, in, t, rkeys); +} + +static void +nd_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_decrypt_with_tweak(out, in + 8, in, rkeys); +} + +static void +ndx_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *t, const uint8_t *k) +{ + KeySchedule tkeys; + KeySchedule rkeys; + uint8_t diff[16]; + size_t i; + uint8_t d; + + expand_key(tkeys, k + 16); + expand_key(rkeys, k); + + STORE128(diff, XOR128(tkeys[ROUNDS / 2], rkeys[ROUNDS / 2])); + d = 0; + for (i = 0; i < 16; i++) { + d |= diff[i]; + } + if (d == 0) { + for (i = 0; i < 16; i++) { + diff[i] = k[i] ^ 0x5a; + } + expand_key(rkeys, diff); + } + + memcpy(out, t, 16); + aes_xex_encrypt(out + 16, in, t, tkeys, rkeys); +} + +static void +ndx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule tkeys; + KeySchedule rkeys; + uint8_t diff[16]; + size_t i; + uint8_t d; + + expand_key(tkeys, k + 16); + expand_key(rkeys, k); + + STORE128(diff, XOR128(tkeys[ROUNDS / 2], rkeys[ROUNDS / 2])); + d = 0; + for (i = 0; i < 16; i++) { + d |= diff[i]; + } + if (d == 0) { + for (i = 0; i < 16; i++) { + diff[i] = k[i] ^ 0x5a; + } + expand_key(rkeys, diff); + } + + aes_xex_decrypt(out, in + 16, in, tkeys, rkeys); +} + +struct ipcrypt_implementation ipcrypt_armcrypto_implementation = { + SODIUM_C99(.encrypt =) encrypt, SODIUM_C99(.decrypt =) decrypt, + SODIUM_C99(.nd_encrypt =) nd_encrypt, SODIUM_C99(.nd_decrypt =) nd_decrypt, + SODIUM_C99(.ndx_encrypt =) ndx_encrypt, SODIUM_C99(.ndx_decrypt =) ndx_decrypt +}; + +# ifdef __clang__ +# pragma clang attribute pop +# endif + +#endif diff --git a/src/libsodium/crypto_ipcrypt/ipcrypt_armcrypto.h b/src/libsodium/crypto_ipcrypt/ipcrypt_armcrypto.h new file mode 100644 index 00000000..4195e0ee --- /dev/null +++ b/src/libsodium/crypto_ipcrypt/ipcrypt_armcrypto.h @@ -0,0 +1,8 @@ +#ifndef ipcrypt_armcrypto_H +#define ipcrypt_armcrypto_H + +#include "implementations.h" + +extern struct ipcrypt_implementation ipcrypt_armcrypto_implementation; + +#endif diff --git a/src/libsodium/crypto_ipcrypt/ipcrypt_soft.c b/src/libsodium/crypto_ipcrypt/ipcrypt_soft.c new file mode 100644 index 00000000..6f12a792 --- /dev/null +++ b/src/libsodium/crypto_ipcrypt/ipcrypt_soft.c @@ -0,0 +1,267 @@ +#include +#include +#include + +#include "crypto_ipcrypt.h" +#include "utils.h" + +#include "private/common.h" +#include "private/softaes.h" + +#include "ipcrypt_soft.h" + +#define ROUNDS 10 + +typedef SoftAesBlock aes_block_t; +#define AES_BLOCK_XOR(A, B) softaes_block_xor((A), (B)) +#define AES_BLOCK_AND(A, B) softaes_block_and((A), (B)) +#define AES_BLOCK_LOAD(A) softaes_block_load(A) +#define AES_BLOCK_LOAD_64x2(A, B) softaes_block_load64x2((A), (B)) +#define AES_BLOCK_STORE(A, B) softaes_block_store((A), (B)) +#define AES_ENC(A, B) softaes_block_encrypt((A), (B)) +#define AES_DEC(A, B) softaes_block_decrypt((A), (B)) +#define AES_INV_MIX(A) softaes_inv_mix_columns((A)) + +typedef aes_block_t KeySchedule[1 + ROUNDS]; + +static void +expand_key(KeySchedule rkeys, const uint8_t key[16]) +{ + softaes_expand_key128(rkeys, key); +} + +static void +aes_encrypt(uint8_t out[16], const uint8_t in[16], const KeySchedule rkeys) +{ + aes_block_t t; + size_t i; + + t = AES_BLOCK_XOR(AES_BLOCK_LOAD(in), rkeys[0]); + for (i = 1; i < ROUNDS; i++) { + t = AES_ENC(t, rkeys[i]); + } + t = AES_ENC(t, rkeys[ROUNDS]); + AES_BLOCK_STORE(out, t); +} + +static void +aes_decrypt(uint8_t out[16], const uint8_t in[16], const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + aes_block_t t; + size_t i; + + for (i = 0; i <= ROUNDS; i++) { + rkeys_inv[i] = rkeys[i]; + } + softaes_invert_key_schedule128(rkeys_inv); + + t = AES_BLOCK_XOR(AES_BLOCK_LOAD(in), rkeys_inv[ROUNDS]); + for (i = ROUNDS - 1; i > 0; i--) { + t = AES_DEC(t, rkeys_inv[i]); + } + t = AES_DEC(t, rkeys_inv[0]); + AES_BLOCK_STORE(out, t); +} + +static aes_block_t +tweak_expand(const uint8_t tweak[8]) +{ + aes_block_t out; + + out.w0 = ((uint32_t) tweak[0]) | ((uint32_t) tweak[1] << 16); + out.w1 = ((uint32_t) tweak[2]) | ((uint32_t) tweak[3] << 16); + out.w2 = ((uint32_t) tweak[4]) | ((uint32_t) tweak[5] << 16); + out.w3 = ((uint32_t) tweak[6]) | ((uint32_t) tweak[7] << 16); + + return out; +} + +static void +aes_encrypt_with_tweak(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[8], + const KeySchedule rkeys) +{ + const aes_block_t tweak_block = tweak_expand(tweak); + aes_block_t t; + size_t i; + + t = AES_BLOCK_XOR(AES_BLOCK_XOR(AES_BLOCK_LOAD(in), tweak_block), rkeys[0]); + for (i = 1; i < ROUNDS; i++) { + t = AES_ENC(t, AES_BLOCK_XOR(tweak_block, rkeys[i])); + } + t = AES_ENC(t, AES_BLOCK_XOR(tweak_block, rkeys[ROUNDS])); + AES_BLOCK_STORE(out, t); +} + +static void +aes_decrypt_with_tweak(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[8], + const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + const aes_block_t tweak_block = tweak_expand(tweak); + const aes_block_t tweak_block_inv = AES_INV_MIX(tweak_block); + aes_block_t t; + size_t i; + + for (i = 0; i <= ROUNDS; i++) { + rkeys_inv[i] = rkeys[i]; + } + softaes_invert_key_schedule128(rkeys_inv); + + t = AES_BLOCK_XOR(AES_BLOCK_XOR(AES_BLOCK_LOAD(in), tweak_block), rkeys_inv[ROUNDS]); + for (i = ROUNDS - 1; i > 0; i--) { + t = AES_DEC(t, AES_BLOCK_XOR(tweak_block_inv, rkeys_inv[i])); + } + t = AES_DEC(t, AES_BLOCK_XOR(tweak_block, rkeys_inv[0])); + AES_BLOCK_STORE(out, t); +} + +static aes_block_t +aes_xex_tweak(const uint8_t tweak[16], const KeySchedule tkeys) +{ + aes_block_t tt; + size_t i; + + tt = AES_BLOCK_XOR(AES_BLOCK_LOAD(tweak), tkeys[0]); + for (i = 1; i < ROUNDS; i++) { + tt = AES_ENC(tt, tkeys[i]); + } + tt = AES_ENC(tt, tkeys[ROUNDS]); + return tt; +} + +static void +aes_xex_encrypt(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[16], + const KeySchedule tkeys, const KeySchedule rkeys) +{ + const aes_block_t tt = aes_xex_tweak(tweak, tkeys); + aes_block_t t; + size_t i; + + t = AES_BLOCK_XOR(AES_BLOCK_XOR(AES_BLOCK_LOAD(in), tt), rkeys[0]); + for (i = 1; i < ROUNDS; i++) { + t = AES_ENC(t, rkeys[i]); + } + t = AES_ENC(t, AES_BLOCK_XOR(rkeys[ROUNDS], tt)); + AES_BLOCK_STORE(out, t); +} + +static void +aes_xex_decrypt(uint8_t out[16], const uint8_t in[16], const uint8_t tweak[16], + const KeySchedule tkeys, const KeySchedule rkeys) +{ + KeySchedule rkeys_inv; + const aes_block_t tt = aes_xex_tweak(tweak, tkeys); + aes_block_t t; + size_t i; + + for (i = 0; i <= ROUNDS; i++) { + rkeys_inv[i] = rkeys[i]; + } + softaes_invert_key_schedule128(rkeys_inv); + + t = AES_BLOCK_XOR(AES_BLOCK_XOR(AES_BLOCK_LOAD(in), tt), rkeys_inv[ROUNDS]); + for (i = ROUNDS - 1; i > 0; i--) { + t = AES_DEC(t, rkeys_inv[i]); + } + t = AES_DEC(t, AES_BLOCK_XOR(rkeys_inv[0], tt)); + AES_BLOCK_STORE(out, t); +} + +static void +encrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_encrypt(out, in, rkeys); +} + +static void +decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_decrypt(out, in, rkeys); +} + +static void +nd_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *t, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + memcpy(out, t, 8); + aes_encrypt_with_tweak(out + 8, in, t, rkeys); +} + +static void +nd_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule rkeys; + + expand_key(rkeys, k); + aes_decrypt_with_tweak(out, in + 8, in, rkeys); +} + +static void +ndx_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *t, const uint8_t *k) +{ + KeySchedule tkeys; + KeySchedule rkeys; + uint8_t diff[16]; + size_t i; + uint8_t d; + + expand_key(tkeys, k + 16); + expand_key(rkeys, k); + + AES_BLOCK_STORE(diff, AES_BLOCK_XOR(tkeys[ROUNDS / 2], rkeys[ROUNDS / 2])); + d = 0; + for (i = 0; i < 16; i++) { + d |= diff[i]; + } + if (d == 0) { + for (i = 0; i < 16; i++) { + diff[i] = k[i] ^ 0x5a; + } + expand_key(rkeys, diff); + } + + memcpy(out, t, 16); + aes_xex_encrypt(out + 16, in, t, tkeys, rkeys); +} + +static void +ndx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k) +{ + KeySchedule tkeys; + KeySchedule rkeys; + uint8_t diff[16]; + size_t i; + uint8_t d; + + expand_key(tkeys, k + 16); + expand_key(rkeys, k); + + AES_BLOCK_STORE(diff, AES_BLOCK_XOR(tkeys[ROUNDS / 2], rkeys[ROUNDS / 2])); + d = 0; + for (i = 0; i < 16; i++) { + d |= diff[i]; + } + if (d == 0) { + for (i = 0; i < 16; i++) { + diff[i] = k[i] ^ 0x5a; + } + expand_key(rkeys, diff); + } + + aes_xex_decrypt(out, in + 16, in, tkeys, rkeys); +} + +struct ipcrypt_implementation ipcrypt_soft_implementation = { + SODIUM_C99(.encrypt =) encrypt, SODIUM_C99(.decrypt =) decrypt, + SODIUM_C99(.nd_encrypt =) nd_encrypt, SODIUM_C99(.nd_decrypt =) nd_decrypt, + SODIUM_C99(.ndx_encrypt =) ndx_encrypt, SODIUM_C99(.ndx_decrypt =) ndx_decrypt +}; diff --git a/src/libsodium/crypto_ipcrypt/ipcrypt_soft.h b/src/libsodium/crypto_ipcrypt/ipcrypt_soft.h new file mode 100644 index 00000000..757c8844 --- /dev/null +++ b/src/libsodium/crypto_ipcrypt/ipcrypt_soft.h @@ -0,0 +1,8 @@ +#ifndef ipcrypt_soft_H +#define ipcrypt_soft_H + +#include "implementations.h" + +extern struct ipcrypt_implementation ipcrypt_soft_implementation; + +#endif diff --git a/src/libsodium/include/sodium/crypto_ipcrypt.h b/src/libsodium/include/sodium/crypto_ipcrypt.h new file mode 100644 index 00000000..c27ebc1b --- /dev/null +++ b/src/libsodium/include/sodium/crypto_ipcrypt.h @@ -0,0 +1,96 @@ +#ifndef crypto_ipcrypt_H +#define crypto_ipcrypt_H + +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_ipcrypt_INPUTBYTES 16U +SODIUM_EXPORT +size_t crypto_ipcrypt_inputbytes(void); + +#define crypto_ipcrypt_KEYBYTES 16U +SODIUM_EXPORT +size_t crypto_ipcrypt_keybytes(void); + +#define crypto_ipcrypt_ND_KEYBYTES 16U +SODIUM_EXPORT +size_t crypto_ipcrypt_nd_keybytes(void); + +#define crypto_ipcrypt_ND_TWEAKBYTES 8U +SODIUM_EXPORT +size_t crypto_ipcrypt_nd_tweakbytes(void); + +#define crypto_ipcrypt_ND_BYTES 24U +SODIUM_EXPORT +size_t crypto_ipcrypt_nd_bytes(void); + +#define crypto_ipcrypt_NDX_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_ipcrypt_ndx_keybytes(void); + +#define crypto_ipcrypt_NDX_TWEAKBYTES 16U +SODIUM_EXPORT +size_t crypto_ipcrypt_ndx_tweakbytes(void); + +#define crypto_ipcrypt_NDX_BYTES 32U +SODIUM_EXPORT +size_t crypto_ipcrypt_ndx_bytes(void); + +SODIUM_EXPORT +void crypto_ipcrypt_keygen(unsigned char k[crypto_ipcrypt_KEYBYTES]) __attribute__((nonnull)); + +SODIUM_EXPORT +void crypto_ipcrypt_ndx_keygen(unsigned char k[crypto_ipcrypt_NDX_KEYBYTES]) + __attribute__((nonnull)); + +SODIUM_EXPORT +void crypto_ipcrypt_encrypt(unsigned char out[crypto_ipcrypt_INPUTBYTES], + const unsigned char in[crypto_ipcrypt_INPUTBYTES], + const unsigned char k[crypto_ipcrypt_KEYBYTES]) + __attribute__((nonnull)); + +SODIUM_EXPORT +void crypto_ipcrypt_decrypt(unsigned char out[crypto_ipcrypt_INPUTBYTES], + const unsigned char in[crypto_ipcrypt_INPUTBYTES], + const unsigned char k[crypto_ipcrypt_KEYBYTES]) + __attribute__((nonnull)); + +SODIUM_EXPORT +void crypto_ipcrypt_nd_encrypt(unsigned char out[crypto_ipcrypt_ND_BYTES], + const unsigned char in[crypto_ipcrypt_INPUTBYTES], + const unsigned char t[crypto_ipcrypt_ND_TWEAKBYTES], + const unsigned char k[crypto_ipcrypt_ND_KEYBYTES]) + __attribute__((nonnull)); + +SODIUM_EXPORT +void crypto_ipcrypt_nd_decrypt(unsigned char out[crypto_ipcrypt_INPUTBYTES], + const unsigned char in[crypto_ipcrypt_ND_BYTES], + const unsigned char k[crypto_ipcrypt_ND_KEYBYTES]) + __attribute__((nonnull)); + +SODIUM_EXPORT +void crypto_ipcrypt_ndx_encrypt(unsigned char out[crypto_ipcrypt_NDX_BYTES], + const unsigned char in[crypto_ipcrypt_INPUTBYTES], + const unsigned char t[crypto_ipcrypt_NDX_TWEAKBYTES], + const unsigned char k[crypto_ipcrypt_NDX_KEYBYTES]) + __attribute__((nonnull)); + +SODIUM_EXPORT +void crypto_ipcrypt_ndx_decrypt(unsigned char out[crypto_ipcrypt_INPUTBYTES], + const unsigned char in[crypto_ipcrypt_NDX_BYTES], + const unsigned char k[crypto_ipcrypt_NDX_KEYBYTES]) + __attribute__((nonnull)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/default/ipcrypt.c b/test/default/ipcrypt.c new file mode 100644 index 00000000..6727cdfe --- /dev/null +++ b/test/default/ipcrypt.c @@ -0,0 +1,205 @@ +#define TEST_NAME "ipcrypt" +#include "cmptest.h" + +#ifdef DEBUG_TEST +# define DPRINT(...) fprintf(stderr, __VA_ARGS__) +#else +# define DPRINT(...) \ + do { \ + } while (0) +#endif + +static void +print_hex(const unsigned char *data, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + printf("%02x", data[i]); + } +} + +int +main(void) +{ + unsigned char key[crypto_ipcrypt_KEYBYTES]; + unsigned char ndx_key[crypto_ipcrypt_NDX_KEYBYTES]; + unsigned char input[crypto_ipcrypt_INPUTBYTES]; + unsigned char output[crypto_ipcrypt_INPUTBYTES]; + unsigned char nd_output[crypto_ipcrypt_ND_BYTES]; + unsigned char ndx_output[crypto_ipcrypt_NDX_BYTES]; + unsigned char tweak_nd[crypto_ipcrypt_ND_TWEAKBYTES]; + unsigned char tweak_ndx[crypto_ipcrypt_NDX_TWEAKBYTES]; + unsigned char decrypted[crypto_ipcrypt_INPUTBYTES]; + size_t i; + + printf("crypto_ipcrypt_INPUTBYTES: %zu\n", crypto_ipcrypt_inputbytes()); + printf("crypto_ipcrypt_KEYBYTES: %zu\n", crypto_ipcrypt_keybytes()); + printf("crypto_ipcrypt_ND_KEYBYTES: %zu\n", crypto_ipcrypt_nd_keybytes()); + printf("crypto_ipcrypt_ND_TWEAKBYTES: %zu\n", crypto_ipcrypt_nd_tweakbytes()); + printf("crypto_ipcrypt_ND_BYTES: %zu\n", crypto_ipcrypt_nd_bytes()); + printf("crypto_ipcrypt_NDX_KEYBYTES: %zu\n", crypto_ipcrypt_ndx_keybytes()); + printf("crypto_ipcrypt_NDX_TWEAKBYTES: %zu\n", crypto_ipcrypt_ndx_tweakbytes()); + printf("crypto_ipcrypt_NDX_BYTES: %zu\n", crypto_ipcrypt_ndx_bytes()); + + /* Test 1: Format-preserving encryption with known key/input */ + memset(key, 0x00, sizeof key); + key[0] = 0x01; + key[1] = 0x02; + key[2] = 0x03; + key[3] = 0x04; + key[4] = 0x05; + key[5] = 0x06; + key[6] = 0x07; + key[7] = 0x08; + key[8] = 0x09; + key[9] = 0x0a; + key[10] = 0x0b; + key[11] = 0x0c; + key[12] = 0x0d; + key[13] = 0x0e; + key[14] = 0x0f; + key[15] = 0x10; + + /* IPv4-mapped IPv6 address: ::ffff:192.0.2.1 */ + memset(input, 0x00, sizeof input); + input[10] = 0xff; + input[11] = 0xff; + input[12] = 0xc0; /* 192 */ + input[13] = 0x00; /* 0 */ + input[14] = 0x02; /* 2 */ + input[15] = 0x01; /* 1 */ + + printf("\nTest 1: Format-preserving encryption\n"); + printf("Key: "); + print_hex(key, sizeof key); + printf("\nInput: "); + print_hex(input, sizeof input); + printf("\n"); + + crypto_ipcrypt_encrypt(output, input, key); + printf("Encrypted: "); + print_hex(output, sizeof output); + printf("\n"); + + crypto_ipcrypt_decrypt(decrypted, output, key); + printf("Decrypted: "); + print_hex(decrypted, sizeof decrypted); + printf("\n"); + + if (memcmp(input, decrypted, sizeof input) != 0) { + printf("FAILED: Decrypted does not match input\n"); + return 1; + } + printf("OK: Round-trip successful\n"); + + /* Test 2: Non-deterministic encryption (ND mode with 8-byte tweak) */ + memset(tweak_nd, 0, sizeof tweak_nd); + tweak_nd[0] = 0xaa; + tweak_nd[1] = 0xbb; + tweak_nd[2] = 0xcc; + tweak_nd[3] = 0xdd; + tweak_nd[4] = 0xee; + tweak_nd[5] = 0xff; + tweak_nd[6] = 0x11; + tweak_nd[7] = 0x22; + + printf("\nTest 2: Non-deterministic encryption (ND mode)\n"); + printf("Tweak: "); + print_hex(tweak_nd, sizeof tweak_nd); + printf("\n"); + + crypto_ipcrypt_nd_encrypt(nd_output, input, tweak_nd, key); + printf("ND Encrypted: "); + print_hex(nd_output, sizeof nd_output); + printf("\n"); + + crypto_ipcrypt_nd_decrypt(decrypted, nd_output, key); + printf("ND Decrypted: "); + print_hex(decrypted, sizeof decrypted); + printf("\n"); + + if (memcmp(input, decrypted, sizeof input) != 0) { + printf("FAILED: ND decrypted does not match input\n"); + return 1; + } + printf("OK: ND round-trip successful\n"); + + /* Test 3: Non-deterministic encryption with extended tweak (NDX mode) */ + memset(ndx_key, 0x00, sizeof ndx_key); + for (i = 0; i < sizeof ndx_key; i++) { + ndx_key[i] = (unsigned char) (i + 1); + } + + memset(tweak_ndx, 0, sizeof tweak_ndx); + for (i = 0; i < sizeof tweak_ndx; i++) { + tweak_ndx[i] = (unsigned char) (0xaa + i); + } + + printf("\nTest 3: Non-deterministic encryption (NDX mode with 16-byte tweak)\n"); + printf("NDX Key: "); + print_hex(ndx_key, sizeof ndx_key); + printf("\nNDX Tweak: "); + print_hex(tweak_ndx, sizeof tweak_ndx); + printf("\n"); + + crypto_ipcrypt_ndx_encrypt(ndx_output, input, tweak_ndx, ndx_key); + printf("NDX Encrypted: "); + print_hex(ndx_output, sizeof ndx_output); + printf("\n"); + + crypto_ipcrypt_ndx_decrypt(decrypted, ndx_output, ndx_key); + printf("NDX Decrypted: "); + print_hex(decrypted, sizeof decrypted); + printf("\n"); + + if (memcmp(input, decrypted, sizeof input) != 0) { + printf("FAILED: NDX decrypted does not match input\n"); + return 1; + } + printf("OK: NDX round-trip successful\n"); + + /* Test 4: Keygen functions - skip random output in .exp */ + printf("\nTest 4: Key generation\n"); + crypto_ipcrypt_keygen(key); + printf("Random key generated (skipped in output)\n"); + + crypto_ipcrypt_ndx_keygen(ndx_key); + printf("Random NDX key generated (skipped in output)\n"); + + /* Test 5: Different inputs produce different outputs */ + printf("\nTest 5: Different inputs produce different outputs\n"); + memset(key, 0x42, sizeof key); + + for (i = 0; i < 4; i++) { + memset(input, 0, sizeof input); + input[10] = 0xff; + input[11] = 0xff; + input[15] = (unsigned char) i; + + crypto_ipcrypt_encrypt(output, input, key); + printf("Input[%zu]: ", i); + print_hex(input, sizeof input); + printf(" -> "); + print_hex(output, sizeof output); + printf("\n"); + } + + /* Test 6: Verify deterministic encryption */ + printf("\nTest 6: Verify deterministic encryption\n"); + memset(key, 0x55, sizeof key); + memset(input, 0xaa, sizeof input); + + crypto_ipcrypt_encrypt(output, input, key); + crypto_ipcrypt_encrypt(decrypted, input, key); + + if (memcmp(output, decrypted, sizeof output) != 0) { + printf("FAILED: Deterministic encryption produced different outputs\n"); + return 1; + } + printf("OK: Deterministic encryption verified\n"); + + printf("\nAll tests passed!\n"); + + return 0; +} diff --git a/test/default/ipcrypt.exp b/test/default/ipcrypt.exp new file mode 100644 index 00000000..de780f04 --- /dev/null +++ b/test/default/ipcrypt.exp @@ -0,0 +1,43 @@ +crypto_ipcrypt_INPUTBYTES: 16 +crypto_ipcrypt_KEYBYTES: 16 +crypto_ipcrypt_ND_KEYBYTES: 16 +crypto_ipcrypt_ND_TWEAKBYTES: 8 +crypto_ipcrypt_ND_BYTES: 24 +crypto_ipcrypt_NDX_KEYBYTES: 32 +crypto_ipcrypt_NDX_TWEAKBYTES: 16 +crypto_ipcrypt_NDX_BYTES: 32 + +Test 1: Format-preserving encryption +Key: 0102030405060708090a0b0c0d0e0f10 +Input: 00000000000000000000ffffc0000201 +Encrypted: 574549939d262d3dc317324ac05a8d59 +Decrypted: 00000000000000000000ffffc0000201 +OK: Round-trip successful + +Test 2: Non-deterministic encryption (ND mode) +Tweak: aabbccddeeff1122 +ND Encrypted: aabbccddeeff1122377e9a17198d908604f3261d45fd639a +ND Decrypted: 00000000000000000000ffffc0000201 +OK: ND round-trip successful + +Test 3: Non-deterministic encryption (NDX mode with 16-byte tweak) +NDX Key: 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20 +NDX Tweak: aaabacadaeafb0b1b2b3b4b5b6b7b8b9 +NDX Encrypted: aaabacadaeafb0b1b2b3b4b5b6b7b8b97df52c417f76ef314bbe7bea5b30bcea +NDX Decrypted: 00000000000000000000ffffc0000201 +OK: NDX round-trip successful + +Test 4: Key generation +Random key generated (skipped in output) +Random NDX key generated (skipped in output) + +Test 5: Different inputs produce different outputs +Input[0]: 00000000000000000000ffff00000000 -> 05406dbec71c4163c3033a3a76b9ebad +Input[1]: 00000000000000000000ffff00000001 -> 1672fc1d4626d0db668088eb5b54a40e +Input[2]: 00000000000000000000ffff00000002 -> 748c9d664ca12e3669ae344a280202c8 +Input[3]: 00000000000000000000ffff00000003 -> 524ca1315033ea4509bbaabf93c3ec80 + +Test 6: Verify deterministic encryption +OK: Deterministic encryption verified + +All tests passed!