Import ipcrypt

This commit is contained in:
Frank Denis
2025-12-08 23:15:08 +01:00
parent be8e2275ca
commit 22f9b38d39
11 changed files with 1427 additions and 0 deletions
@@ -0,0 +1,144 @@
#include <stdlib.h>
#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;
}
@@ -0,0 +1,18 @@
#ifndef ipcrypt_implementations_H
#define ipcrypt_implementations_H
#include <stddef.h>
#include <stdint.h>
#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
@@ -0,0 +1,299 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#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 <immintrin.h>
# include <wmmintrin.h>
# 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
@@ -0,0 +1,8 @@
#ifndef ipcrypt_aesni_H
#define ipcrypt_aesni_H
#include "implementations.h"
extern struct ipcrypt_implementation ipcrypt_aesni_implementation;
#endif
@@ -0,0 +1,331 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#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 <arm_neon.h>
# 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
@@ -0,0 +1,8 @@
#ifndef ipcrypt_armcrypto_H
#define ipcrypt_armcrypto_H
#include "implementations.h"
extern struct ipcrypt_implementation ipcrypt_armcrypto_implementation;
#endif
+267
View File
@@ -0,0 +1,267 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#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
};
@@ -0,0 +1,8 @@
#ifndef ipcrypt_soft_H
#define ipcrypt_soft_H
#include "implementations.h"
extern struct ipcrypt_implementation ipcrypt_soft_implementation;
#endif
@@ -0,0 +1,96 @@
#ifndef crypto_ipcrypt_H
#define crypto_ipcrypt_H
#include <stddef.h>
#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
+205
View File
@@ -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;
}
+43
View File
@@ -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!