Add PFX variant

This commit is contained in:
Frank Denis
2025-12-30 01:35:44 +01:00
parent b7db09d61e
commit ab8a8a1ee6
9 changed files with 894 additions and 3 deletions
@@ -80,6 +80,18 @@ crypto_ipcrypt_ndx_outputbytes(void)
return crypto_ipcrypt_NDX_OUTPUTBYTES;
}
size_t
crypto_ipcrypt_pfx_keybytes(void)
{
return crypto_ipcrypt_PFX_KEYBYTES;
}
size_t
crypto_ipcrypt_pfx_bytes(void)
{
return crypto_ipcrypt_PFX_BYTES;
}
void
crypto_ipcrypt_keygen(unsigned char k[crypto_ipcrypt_KEYBYTES])
{
@@ -92,6 +104,12 @@ crypto_ipcrypt_ndx_keygen(unsigned char k[crypto_ipcrypt_NDX_KEYBYTES])
randombytes_buf(k, crypto_ipcrypt_NDX_KEYBYTES);
}
void
crypto_ipcrypt_pfx_keygen(unsigned char k[crypto_ipcrypt_PFX_KEYBYTES])
{
randombytes_buf(k, crypto_ipcrypt_PFX_KEYBYTES);
}
void
crypto_ipcrypt_encrypt(unsigned char *out, const unsigned char *in, const unsigned char *k)
{
@@ -134,6 +152,18 @@ crypto_ipcrypt_ndx_decrypt(unsigned char *out, const unsigned char *in, const un
implementation->ndx_decrypt(out, in, k);
}
void
crypto_ipcrypt_pfx_encrypt(unsigned char *out, const unsigned char *in, const unsigned char *k)
{
implementation->pfx_encrypt(out, in, k);
}
void
crypto_ipcrypt_pfx_decrypt(unsigned char *out, const unsigned char *in, const unsigned char *k)
{
implementation->pfx_decrypt(out, in, k);
}
int
_crypto_ipcrypt_pick_best_implementation(void)
{
@@ -13,6 +13,8 @@ typedef struct ipcrypt_implementation {
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);
void (*pfx_encrypt)(uint8_t *out, const uint8_t *in, const uint8_t *k);
void (*pfx_decrypt)(uint8_t *out, const uint8_t *in, const uint8_t *k);
} ipcrypt_implementation;
#endif
+195 -1
View File
@@ -286,10 +286,204 @@ ndx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
aes_xex_decrypt(out, in + 16, in, tkeys, rkeys);
}
static int
is_ipv4_mapped(const uint8_t ip16[16])
{
static const uint8_t ipv4_mapped_prefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
return memcmp(ip16, ipv4_mapped_prefix, 12) == 0;
}
static uint8_t
pfx_get_bit(const uint8_t ip16[16], unsigned int bit_index)
{
return (ip16[15 - bit_index / 8] >> (bit_index % 8)) & 1;
}
static void
pfx_set_bit(uint8_t ip16[16], const unsigned int bit_index, const uint8_t bit_value)
{
const size_t byte_index = 15 - bit_index / 8;
const uint8_t bit_mask = (uint8_t) (1 << (bit_index % 8));
uint8_t mask = (uint8_t) -((bit_value & 1));
#if defined(__GNUC__) || defined(__clang__)
__asm__ __volatile__("" : "+r"(mask) ::);
#endif
ip16[byte_index] = (ip16[byte_index] & ~bit_mask) | (bit_mask & mask);
}
static void
pfx_shift_left(uint8_t ip16[16])
{
BlockVec v = LOAD128(ip16);
BlockVec shl = _mm_slli_epi64(v, 1);
BlockVec shr = _mm_srli_epi64(v, 63);
BlockVec car = _mm_slli_si128(shr, 8);
v = _mm_or_si128(shl, car);
STORE128(ip16, v);
}
static void
pfx_pad_prefix(uint8_t padded_prefix[16], unsigned int prefix_len_bits)
{
memset(padded_prefix, 0, 16);
if (prefix_len_bits == 0) {
padded_prefix[15] = 0x01;
} else {
padded_prefix[3] = 0x01;
padded_prefix[14] = 0xff;
padded_prefix[15] = 0xff;
}
}
static void
pfx_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
{
KeySchedule k1keys;
KeySchedule k2keys;
uint8_t diff[16];
uint8_t encrypted[16];
uint8_t padded_prefix[16];
uint8_t t[16];
BlockVec e1, e2, e;
unsigned int prefix_start = 0;
unsigned int prefix_len_bits;
unsigned int bit_pos;
uint8_t cipher_bit;
uint8_t original_bit;
size_t i;
uint8_t d;
expand_key(k1keys, k);
expand_key(k2keys, k + 16);
STORE128(diff, XOR128(k1keys[ROUNDS / 2], k2keys[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(k2keys, diff);
}
if (is_ipv4_mapped(in)) {
prefix_start = 96;
}
pfx_pad_prefix(padded_prefix, prefix_start);
memset(encrypted, 0, 16);
if (prefix_start == 96) {
encrypted[10] = 0xff;
encrypted[11] = 0xff;
}
for (prefix_len_bits = prefix_start; prefix_len_bits < 128; prefix_len_bits++) {
e1 = XOR128(LOAD128(padded_prefix), k1keys[0]);
e2 = XOR128(LOAD128(padded_prefix), k2keys[0]);
for (i = 1; i < ROUNDS; i++) {
e1 = AES_ENCRYPT(e1, k1keys[i]);
e2 = AES_ENCRYPT(e2, k2keys[i]);
}
e1 = AES_ENCRYPTLAST(e1, k1keys[ROUNDS]);
e2 = AES_ENCRYPTLAST(e2, k2keys[ROUNDS]);
e = XOR128(e1, e2);
STORE128(t, e);
cipher_bit = t[15] & 1;
bit_pos = 127 - prefix_len_bits;
original_bit = pfx_get_bit(in, bit_pos);
pfx_set_bit(encrypted, bit_pos, original_bit ^ cipher_bit);
pfx_shift_left(padded_prefix);
pfx_set_bit(padded_prefix, 0, original_bit);
}
memcpy(out, encrypted, 16);
}
static void
pfx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
{
KeySchedule k1keys;
KeySchedule k2keys;
uint8_t diff[16];
uint8_t decrypted[16];
uint8_t padded_prefix[16];
uint8_t t[16];
BlockVec e1, e2, e;
unsigned int prefix_start = 0;
unsigned int prefix_len_bits;
unsigned int bit_pos;
uint8_t cipher_bit;
uint8_t encrypted_bit;
uint8_t original_bit;
size_t i;
uint8_t d;
expand_key(k1keys, k);
expand_key(k2keys, k + 16);
STORE128(diff, XOR128(k1keys[ROUNDS / 2], k2keys[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(k2keys, diff);
}
if (is_ipv4_mapped(in)) {
prefix_start = 96;
}
pfx_pad_prefix(padded_prefix, prefix_start);
memset(decrypted, 0, 16);
if (prefix_start == 96) {
decrypted[10] = 0xff;
decrypted[11] = 0xff;
}
for (prefix_len_bits = prefix_start; prefix_len_bits < 128; prefix_len_bits++) {
e1 = XOR128(LOAD128(padded_prefix), k1keys[0]);
e2 = XOR128(LOAD128(padded_prefix), k2keys[0]);
for (i = 1; i < ROUNDS; i++) {
e1 = AES_ENCRYPT(e1, k1keys[i]);
e2 = AES_ENCRYPT(e2, k2keys[i]);
}
e1 = AES_ENCRYPTLAST(e1, k1keys[ROUNDS]);
e2 = AES_ENCRYPTLAST(e2, k2keys[ROUNDS]);
e = XOR128(e1, e2);
STORE128(t, e);
cipher_bit = t[15] & 1;
bit_pos = 127 - prefix_len_bits;
encrypted_bit = pfx_get_bit(in, bit_pos);
original_bit = encrypted_bit ^ cipher_bit;
pfx_set_bit(decrypted, bit_pos, original_bit);
pfx_shift_left(padded_prefix);
pfx_set_bit(padded_prefix, 0, original_bit);
}
memcpy(out, decrypted, 16);
}
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
SODIUM_C99(.ndx_encrypt =) ndx_encrypt, SODIUM_C99(.ndx_decrypt =) ndx_decrypt,
SODIUM_C99(.pfx_encrypt =) pfx_encrypt, SODIUM_C99(.pfx_decrypt =) pfx_decrypt
};
# ifdef __clang__
@@ -318,10 +318,209 @@ ndx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
aes_xex_decrypt(out, in + 16, in, tkeys, rkeys);
}
static int
is_ipv4_mapped(const uint8_t ip16[16])
{
static const uint8_t ipv4_mapped_prefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
return memcmp(ip16, ipv4_mapped_prefix, 12) == 0;
}
static uint8_t
pfx_get_bit(const uint8_t ip16[16], unsigned int bit_index)
{
return (ip16[15 - bit_index / 8] >> (bit_index % 8)) & 1;
}
static void
pfx_set_bit(uint8_t ip16[16], const unsigned int bit_index, const uint8_t bit_value)
{
const size_t byte_index = 15 - bit_index / 8;
const uint8_t bit_mask = (uint8_t) (1 << (bit_index % 8));
uint8_t mask = (uint8_t) -((bit_value & 1));
#if defined(__GNUC__) || defined(__clang__)
__asm__ __volatile__("" : "+r"(mask) ::);
#endif
ip16[byte_index] = (ip16[byte_index] & ~bit_mask) | (bit_mask & mask);
}
static void
pfx_shift_left(uint8_t ip16[16])
{
BlockVec v = LOAD128(ip16);
const BlockVec shl = vshlq_n_u8(vreinterpretq_u8_u64(v), 1);
const BlockVec msb = vshrq_n_u8(vreinterpretq_u8_u64(v), 7);
const BlockVec zero = vdupq_n_u8(0);
const BlockVec carries = vextq_u8(vreinterpretq_u8_u64(msb), zero, 1);
v = vreinterpretq_u64_u8(vorrq_u8(shl, carries));
STORE128(ip16, v);
}
static void
pfx_pad_prefix(uint8_t padded_prefix[16], unsigned int prefix_len_bits)
{
memset(padded_prefix, 0, 16);
if (prefix_len_bits == 0) {
padded_prefix[15] = 0x01;
} else {
padded_prefix[3] = 0x01;
padded_prefix[14] = 0xff;
padded_prefix[15] = 0xff;
}
}
static void
pfx_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
{
KeySchedule k1keys;
KeySchedule k2keys;
uint8_t diff[16];
uint8_t encrypted[16];
uint8_t padded_prefix[16];
uint8_t t[16];
BlockVec e1, e2, e;
unsigned int prefix_start = 0;
unsigned int prefix_len_bits;
unsigned int bit_pos;
uint8_t cipher_bit;
uint8_t original_bit;
size_t i;
uint8_t d;
expand_key(k1keys, k);
expand_key(k2keys, k + 16);
STORE128(diff, XOR128(k1keys[ROUNDS / 2], k2keys[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(k2keys, diff);
}
if (is_ipv4_mapped(in)) {
prefix_start = 96;
}
pfx_pad_prefix(padded_prefix, prefix_start);
memset(encrypted, 0, 16);
if (prefix_start == 96) {
encrypted[10] = 0xff;
encrypted[11] = 0xff;
}
for (prefix_len_bits = prefix_start; prefix_len_bits < 128; prefix_len_bits++) {
e1 = AES_XENCRYPT(LOAD128(padded_prefix), k1keys[0]);
e2 = AES_XENCRYPT(LOAD128(padded_prefix), k2keys[0]);
for (i = 1; i < ROUNDS - 1; i++) {
e1 = AES_XENCRYPT(e1, k1keys[i]);
e2 = AES_XENCRYPT(e2, k2keys[i]);
}
e1 = AES_XENCRYPTLAST(e1, k1keys[i]);
e2 = AES_XENCRYPTLAST(e2, k2keys[i]);
e1 = XOR128(e1, k1keys[ROUNDS]);
e2 = XOR128(e2, k2keys[ROUNDS]);
e = XOR128(e1, e2);
STORE128(t, e);
cipher_bit = t[15] & 1;
bit_pos = 127 - prefix_len_bits;
original_bit = pfx_get_bit(in, bit_pos);
pfx_set_bit(encrypted, bit_pos, original_bit ^ cipher_bit);
pfx_shift_left(padded_prefix);
pfx_set_bit(padded_prefix, 0, original_bit);
}
memcpy(out, encrypted, 16);
}
static void
pfx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
{
KeySchedule k1keys;
KeySchedule k2keys;
uint8_t diff[16];
uint8_t decrypted[16];
uint8_t padded_prefix[16];
uint8_t t[16];
BlockVec e1, e2, e;
unsigned int prefix_start = 0;
unsigned int prefix_len_bits;
unsigned int bit_pos;
uint8_t cipher_bit;
uint8_t encrypted_bit;
uint8_t original_bit;
size_t i;
uint8_t d;
expand_key(k1keys, k);
expand_key(k2keys, k + 16);
STORE128(diff, XOR128(k1keys[ROUNDS / 2], k2keys[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(k2keys, diff);
}
if (is_ipv4_mapped(in)) {
prefix_start = 96;
}
pfx_pad_prefix(padded_prefix, prefix_start);
memset(decrypted, 0, 16);
if (prefix_start == 96) {
decrypted[10] = 0xff;
decrypted[11] = 0xff;
}
for (prefix_len_bits = prefix_start; prefix_len_bits < 128; prefix_len_bits++) {
e1 = AES_XENCRYPT(LOAD128(padded_prefix), k1keys[0]);
e2 = AES_XENCRYPT(LOAD128(padded_prefix), k2keys[0]);
for (i = 1; i < ROUNDS - 1; i++) {
e1 = AES_XENCRYPT(e1, k1keys[i]);
e2 = AES_XENCRYPT(e2, k2keys[i]);
}
e1 = AES_XENCRYPTLAST(e1, k1keys[i]);
e2 = AES_XENCRYPTLAST(e2, k2keys[i]);
e1 = XOR128(e1, k1keys[ROUNDS]);
e2 = XOR128(e2, k2keys[ROUNDS]);
e = XOR128(e1, e2);
STORE128(t, e);
cipher_bit = t[15] & 1;
bit_pos = 127 - prefix_len_bits;
encrypted_bit = pfx_get_bit(in, bit_pos);
original_bit = encrypted_bit ^ cipher_bit;
pfx_set_bit(decrypted, bit_pos, original_bit);
pfx_shift_left(padded_prefix);
pfx_set_bit(padded_prefix, 0, original_bit);
}
memcpy(out, decrypted, 16);
}
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
SODIUM_C99(.ndx_encrypt =) ndx_encrypt, SODIUM_C99(.ndx_decrypt =) ndx_decrypt,
SODIUM_C99(.pfx_encrypt =) pfx_encrypt, SODIUM_C99(.pfx_decrypt =) pfx_decrypt
};
# ifdef __clang__
+195 -1
View File
@@ -260,8 +260,202 @@ ndx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
aes_xex_decrypt(out, in + 16, in, tkeys, rkeys);
}
static int
is_ipv4_mapped(const uint8_t ip16[16])
{
static const uint8_t ipv4_mapped_prefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
return memcmp(ip16, ipv4_mapped_prefix, 12) == 0;
}
static uint8_t
pfx_get_bit(const uint8_t ip16[16], unsigned int bit_index)
{
return (ip16[15 - bit_index / 8] >> (bit_index % 8)) & 1;
}
static void
pfx_set_bit(uint8_t ip16[16], const unsigned int bit_index, const uint8_t bit_value)
{
const size_t byte_index = 15 - bit_index / 8;
const uint8_t bit_mask = (uint8_t) (1 << (bit_index % 8));
uint8_t mask = (uint8_t) -((bit_value & 1));
#if defined(__GNUC__) || defined(__clang__)
__asm__ __volatile__("" : "+r"(mask) ::);
#endif
ip16[byte_index] = (ip16[byte_index] & ~bit_mask) | (bit_mask & mask);
}
static void
pfx_shift_left(uint8_t ip16[16])
{
size_t i;
for (i = 0; i < 15; i++) {
ip16[i] = (ip16[i] << 1) | (ip16[i + 1] >> 7);
}
ip16[15] <<= 1;
}
static void
pfx_pad_prefix(uint8_t padded_prefix[16], unsigned int prefix_len_bits)
{
memset(padded_prefix, 0, 16);
if (prefix_len_bits == 0) {
padded_prefix[15] = 0x01;
} else {
padded_prefix[3] = 0x01;
padded_prefix[14] = 0xff;
padded_prefix[15] = 0xff;
}
}
static void
pfx_encrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
{
KeySchedule k1keys;
KeySchedule k2keys;
uint8_t diff[16];
uint8_t encrypted[16];
uint8_t padded_prefix[16];
uint8_t t[16];
aes_block_t e1, e2, e;
unsigned int prefix_start = 0;
unsigned int prefix_len_bits;
unsigned int bit_pos;
uint8_t cipher_bit;
uint8_t original_bit;
size_t i;
uint8_t d;
expand_key(k1keys, k);
expand_key(k2keys, k + 16);
AES_BLOCK_STORE(diff, AES_BLOCK_XOR(k1keys[ROUNDS / 2], k2keys[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(k2keys, diff);
}
if (is_ipv4_mapped(in)) {
prefix_start = 96;
}
pfx_pad_prefix(padded_prefix, prefix_start);
memset(encrypted, 0, 16);
if (prefix_start == 96) {
encrypted[10] = 0xff;
encrypted[11] = 0xff;
}
for (prefix_len_bits = prefix_start; prefix_len_bits < 128; prefix_len_bits++) {
e1 = AES_BLOCK_XOR(AES_BLOCK_LOAD(padded_prefix), k1keys[0]);
e2 = AES_BLOCK_XOR(AES_BLOCK_LOAD(padded_prefix), k2keys[0]);
for (i = 1; i < ROUNDS; i++) {
e1 = AES_ENC(e1, k1keys[i]);
e2 = AES_ENC(e2, k2keys[i]);
}
e1 = AES_ENC(e1, k1keys[ROUNDS]);
e2 = AES_ENC(e2, k2keys[ROUNDS]);
e = AES_BLOCK_XOR(e1, e2);
AES_BLOCK_STORE(t, e);
cipher_bit = t[15] & 1;
bit_pos = 127 - prefix_len_bits;
original_bit = pfx_get_bit(in, bit_pos);
pfx_set_bit(encrypted, bit_pos, original_bit ^ cipher_bit);
pfx_shift_left(padded_prefix);
pfx_set_bit(padded_prefix, 0, original_bit);
}
memcpy(out, encrypted, 16);
}
static void
pfx_decrypt(uint8_t *out, const uint8_t *in, const uint8_t *k)
{
KeySchedule k1keys;
KeySchedule k2keys;
uint8_t diff[16];
uint8_t decrypted[16];
uint8_t padded_prefix[16];
uint8_t t[16];
aes_block_t e1, e2, e;
unsigned int prefix_start = 0;
unsigned int prefix_len_bits;
unsigned int bit_pos;
uint8_t cipher_bit;
uint8_t encrypted_bit;
uint8_t original_bit;
size_t i;
uint8_t d;
expand_key(k1keys, k);
expand_key(k2keys, k + 16);
AES_BLOCK_STORE(diff, AES_BLOCK_XOR(k1keys[ROUNDS / 2], k2keys[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(k2keys, diff);
}
if (is_ipv4_mapped(in)) {
prefix_start = 96;
}
pfx_pad_prefix(padded_prefix, prefix_start);
memset(decrypted, 0, 16);
if (prefix_start == 96) {
decrypted[10] = 0xff;
decrypted[11] = 0xff;
}
for (prefix_len_bits = prefix_start; prefix_len_bits < 128; prefix_len_bits++) {
e1 = AES_BLOCK_XOR(AES_BLOCK_LOAD(padded_prefix), k1keys[0]);
e2 = AES_BLOCK_XOR(AES_BLOCK_LOAD(padded_prefix), k2keys[0]);
for (i = 1; i < ROUNDS; i++) {
e1 = AES_ENC(e1, k1keys[i]);
e2 = AES_ENC(e2, k2keys[i]);
}
e1 = AES_ENC(e1, k1keys[ROUNDS]);
e2 = AES_ENC(e2, k2keys[ROUNDS]);
e = AES_BLOCK_XOR(e1, e2);
AES_BLOCK_STORE(t, e);
cipher_bit = t[15] & 1;
bit_pos = 127 - prefix_len_bits;
encrypted_bit = pfx_get_bit(in, bit_pos);
original_bit = encrypted_bit ^ cipher_bit;
pfx_set_bit(decrypted, bit_pos, original_bit);
pfx_shift_left(padded_prefix);
pfx_set_bit(padded_prefix, 0, original_bit);
}
memcpy(out, decrypted, 16);
}
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
SODIUM_C99(.ndx_encrypt =) ndx_encrypt, SODIUM_C99(.ndx_decrypt =) ndx_decrypt,
SODIUM_C99(.pfx_encrypt =) pfx_encrypt, SODIUM_C99(.pfx_decrypt =) pfx_decrypt
};
@@ -52,6 +52,14 @@ size_t crypto_ipcrypt_ndx_inputbytes(void);
SODIUM_EXPORT
size_t crypto_ipcrypt_ndx_outputbytes(void);
#define crypto_ipcrypt_PFX_KEYBYTES 32U
SODIUM_EXPORT
size_t crypto_ipcrypt_pfx_keybytes(void);
#define crypto_ipcrypt_PFX_BYTES 16U
SODIUM_EXPORT
size_t crypto_ipcrypt_pfx_bytes(void);
SODIUM_EXPORT
void crypto_ipcrypt_keygen(unsigned char k[crypto_ipcrypt_KEYBYTES]) __attribute__((nonnull));
@@ -59,6 +67,10 @@ SODIUM_EXPORT
void crypto_ipcrypt_ndx_keygen(unsigned char k[crypto_ipcrypt_NDX_KEYBYTES])
__attribute__((nonnull));
SODIUM_EXPORT
void crypto_ipcrypt_pfx_keygen(unsigned char k[crypto_ipcrypt_PFX_KEYBYTES])
__attribute__((nonnull));
SODIUM_EXPORT
void crypto_ipcrypt_encrypt(unsigned char out[crypto_ipcrypt_BYTES],
const unsigned char in[crypto_ipcrypt_BYTES],
@@ -97,6 +109,18 @@ void crypto_ipcrypt_ndx_decrypt(unsigned char out[crypto_ipcrypt_NDX_INPUT
const unsigned char k[crypto_ipcrypt_NDX_KEYBYTES])
__attribute__((nonnull));
SODIUM_EXPORT
void crypto_ipcrypt_pfx_encrypt(unsigned char out[crypto_ipcrypt_PFX_BYTES],
const unsigned char in[crypto_ipcrypt_PFX_BYTES],
const unsigned char k[crypto_ipcrypt_PFX_KEYBYTES])
__attribute__((nonnull));
SODIUM_EXPORT
void crypto_ipcrypt_pfx_decrypt(unsigned char out[crypto_ipcrypt_PFX_BYTES],
const unsigned char in[crypto_ipcrypt_PFX_BYTES],
const unsigned char k[crypto_ipcrypt_PFX_KEYBYTES])
__attribute__((nonnull));
#ifdef __cplusplus
}
#endif
+115
View File
@@ -15,13 +15,17 @@ main(void)
{
unsigned char key[crypto_ipcrypt_KEYBYTES];
unsigned char ndx_key[crypto_ipcrypt_NDX_KEYBYTES];
unsigned char pfx_key[crypto_ipcrypt_PFX_KEYBYTES];
unsigned char input[crypto_ipcrypt_BYTES];
unsigned char output[crypto_ipcrypt_BYTES];
unsigned char nd_output[crypto_ipcrypt_ND_OUTPUTBYTES];
unsigned char ndx_output[crypto_ipcrypt_NDX_OUTPUTBYTES];
unsigned char pfx_output[crypto_ipcrypt_PFX_BYTES];
unsigned char tweak_nd[crypto_ipcrypt_ND_TWEAKBYTES];
unsigned char tweak_ndx[crypto_ipcrypt_NDX_TWEAKBYTES];
unsigned char decrypted[crypto_ipcrypt_BYTES];
unsigned char encrypted1[crypto_ipcrypt_PFX_BYTES];
unsigned char encrypted2[crypto_ipcrypt_PFX_BYTES];
size_t i;
printf("crypto_ipcrypt_BYTES: %zu\n", crypto_ipcrypt_bytes());
@@ -34,6 +38,8 @@ main(void)
printf("crypto_ipcrypt_NDX_TWEAKBYTES: %zu\n", crypto_ipcrypt_ndx_tweakbytes());
printf("crypto_ipcrypt_NDX_INPUTBYTES: %zu\n", crypto_ipcrypt_ndx_inputbytes());
printf("crypto_ipcrypt_NDX_OUTPUTBYTES: %zu\n", crypto_ipcrypt_ndx_outputbytes());
printf("crypto_ipcrypt_PFX_KEYBYTES: %zu\n", crypto_ipcrypt_pfx_keybytes());
printf("crypto_ipcrypt_PFX_BYTES: %zu\n", crypto_ipcrypt_pfx_bytes());
/* Test 1: Format-preserving encryption with known key/input */
memset(key, 0x00, sizeof key);
@@ -197,6 +203,115 @@ main(void)
}
printf("OK: In-place round-trip successful\n");
/* Test 8: Prefix-preserving encryption (PFX mode) */
printf("\nTest 8: Prefix-preserving encryption (PFX mode)\n");
/* Test vector from the specification:
* Key: 0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301
* Input IP: 0.0.0.0 (IPv4-mapped)
* Expected: 151.82.155.134
*/
sodium_hex2bin(pfx_key, sizeof pfx_key,
"0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301",
64, NULL, NULL, NULL);
memset(input, 0, sizeof input);
input[10] = 0xff;
input[11] = 0xff;
/* 0.0.0.0 */
printf("PFX Key: ");
dump_hex(pfx_key, sizeof pfx_key);
printf("Input (0.0.0.0): ");
dump_hex(input, sizeof input);
crypto_ipcrypt_pfx_encrypt(pfx_output, input, pfx_key);
printf("PFX Encrypted: ");
dump_hex(pfx_output, sizeof pfx_output);
crypto_ipcrypt_pfx_decrypt(decrypted, pfx_output, pfx_key);
printf("PFX Decrypted: ");
dump_hex(decrypted, sizeof decrypted);
if (memcmp(input, decrypted, sizeof input) != 0) {
printf("FAILED: PFX decrypted does not match input\n");
return 1;
}
printf("OK: PFX round-trip successful\n");
/* Test 9: Verify prefix preservation - IPs in same /24 should share encrypted prefix */
printf("\nTest 9: Verify prefix preservation\n");
/* Use test vector key from spec */
sodium_hex2bin(pfx_key, sizeof pfx_key,
"2b7e151628aed2a6abf7158809cf4f3ca9f5ba40db214c3798f2e1c23456789a",
64, NULL, NULL, NULL);
/* 10.0.0.47 */
memset(input, 0, sizeof input);
input[10] = 0xff;
input[11] = 0xff;
input[12] = 10;
input[13] = 0;
input[14] = 0;
input[15] = 47;
crypto_ipcrypt_pfx_encrypt(encrypted1, input, pfx_key);
printf("10.0.0.47 encrypted: ");
dump_hex(encrypted1, sizeof encrypted1);
/* 10.0.0.129 */
input[15] = 129;
crypto_ipcrypt_pfx_encrypt(encrypted2, input, pfx_key);
printf("10.0.0.129 encrypted: ");
dump_hex(encrypted2, sizeof encrypted2);
/* Check that the first 24 bits of the encrypted IPv4 addresses match (bytes 12-14) */
if (memcmp(encrypted1 + 12, encrypted2 + 12, 3) != 0) {
printf("FAILED: Prefix not preserved for /24 addresses\n");
return 1;
}
printf("OK: /24 prefix preserved\n");
/* Test 10: PFX keygen */
printf("\nTest 10: PFX key generation\n");
crypto_ipcrypt_pfx_keygen(pfx_key);
printf("Random PFX key generated (skipped in output)\n");
/* Test 11: IPv6 prefix preservation */
printf("\nTest 11: IPv6 prefix-preserving encryption\n");
sodium_hex2bin(pfx_key, sizeof pfx_key,
"2b7e151628aed2a6abf7158809cf4f3ca9f5ba40db214c3798f2e1c23456789a",
64, NULL, NULL, NULL);
/* 2001:db8::1 */
memset(input, 0, sizeof input);
input[0] = 0x20;
input[1] = 0x01;
input[2] = 0x0d;
input[3] = 0xb8;
input[15] = 0x01;
crypto_ipcrypt_pfx_encrypt(encrypted1, input, pfx_key);
printf("2001:db8::1 encrypted: ");
dump_hex(encrypted1, sizeof encrypted1);
/* 2001:db8::2 */
input[15] = 0x02;
crypto_ipcrypt_pfx_encrypt(encrypted2, input, pfx_key);
printf("2001:db8::2 encrypted: ");
dump_hex(encrypted2, sizeof encrypted2);
/* Check that the first 64 bits match (bytes 0-7 for /64 prefix) */
if (memcmp(encrypted1, encrypted2, 8) != 0) {
printf("FAILED: IPv6 /64 prefix not preserved\n");
return 1;
}
printf("OK: IPv6 /64 prefix preserved\n");
printf("\nAll tests passed!\n");
return 0;
+22
View File
@@ -8,6 +8,8 @@ crypto_ipcrypt_NDX_KEYBYTES: 32
crypto_ipcrypt_NDX_TWEAKBYTES: 16
crypto_ipcrypt_NDX_INPUTBYTES: 16
crypto_ipcrypt_NDX_OUTPUTBYTES: 32
crypto_ipcrypt_PFX_KEYBYTES: 32
crypto_ipcrypt_PFX_BYTES: 16
Test 1: Format-preserving encryption
Key: 0102030405060708090a0b0c0d0e0f10
@@ -49,4 +51,24 @@ OK: Deterministic encryption verified
Test 7: In-place encryption and decryption
OK: In-place round-trip successful
Test 8: Prefix-preserving encryption (PFX mode)
PFX Key: 0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301
Input (0.0.0.0): 00000000000000000000ffff00000000
PFX Encrypted: 00000000000000000000ffff97529b86
PFX Decrypted: 00000000000000000000ffff00000000
OK: PFX round-trip successful
Test 9: Verify prefix preservation
10.0.0.47 encrypted: 00000000000000000000ffff13d6d2f4
10.0.0.129 encrypted: 00000000000000000000ffff13d6d250
OK: /24 prefix preserved
Test 10: PFX key generation
Random PFX key generated (skipped in output)
Test 11: IPv6 prefix-preserving encryption
2001:db8::1 encrypted: 7cec702c12430f70d5ff5bae0021b09b
2001:db8::2 encrypted: 7cec702c12430f70d5ff5bae0021b098
OK: IPv6 /64 prefix preserved
All tests passed!
+111
View File
@@ -204,6 +204,7 @@ crypto_core_ed25519_add
crypto_core_ed25519_bytes
crypto_core_ed25519_from_string
crypto_core_ed25519_from_string_ro
crypto_core_ed25519_from_uniform
crypto_core_ed25519_hashbytes
crypto_core_ed25519_is_valid_point
crypto_core_ed25519_nonreducedscalarbytes
@@ -230,6 +231,12 @@ crypto_core_hsalsa20_constbytes
crypto_core_hsalsa20_inputbytes
crypto_core_hsalsa20_keybytes
crypto_core_hsalsa20_outputbytes
crypto_core_keccak1600_extract_bytes
crypto_core_keccak1600_init
crypto_core_keccak1600_permute_12
crypto_core_keccak1600_permute_24
crypto_core_keccak1600_statebytes
crypto_core_keccak1600_xor_bytes
crypto_core_ristretto255_add
crypto_core_ristretto255_bytes
crypto_core_ristretto255_from_hash
@@ -310,6 +317,29 @@ crypto_hash_sha512_final
crypto_hash_sha512_init
crypto_hash_sha512_statebytes
crypto_hash_sha512_update
crypto_ipcrypt_bytes
crypto_ipcrypt_decrypt
crypto_ipcrypt_encrypt
crypto_ipcrypt_keybytes
crypto_ipcrypt_keygen
crypto_ipcrypt_nd_decrypt
crypto_ipcrypt_nd_encrypt
crypto_ipcrypt_nd_inputbytes
crypto_ipcrypt_nd_keybytes
crypto_ipcrypt_nd_outputbytes
crypto_ipcrypt_nd_tweakbytes
crypto_ipcrypt_ndx_decrypt
crypto_ipcrypt_ndx_encrypt
crypto_ipcrypt_ndx_inputbytes
crypto_ipcrypt_ndx_keybytes
crypto_ipcrypt_ndx_keygen
crypto_ipcrypt_ndx_outputbytes
crypto_ipcrypt_ndx_tweakbytes
crypto_ipcrypt_pfx_bytes
crypto_ipcrypt_pfx_decrypt
crypto_ipcrypt_pfx_encrypt
crypto_ipcrypt_pfx_keybytes
crypto_ipcrypt_pfx_keygen
crypto_kdf_blake2b_bytes_max
crypto_kdf_blake2b_bytes_min
crypto_kdf_blake2b_contextbytes
@@ -342,6 +372,16 @@ crypto_kdf_hkdf_sha512_statebytes
crypto_kdf_keybytes
crypto_kdf_keygen
crypto_kdf_primitive
crypto_kem_mlkem768_ciphertextbytes
crypto_kem_mlkem768_dec
crypto_kem_mlkem768_enc
crypto_kem_mlkem768_enc_deterministic
crypto_kem_mlkem768_keypair
crypto_kem_mlkem768_publickeybytes
crypto_kem_mlkem768_secretkeybytes
crypto_kem_mlkem768_seed_keypair
crypto_kem_mlkem768_seedbytes
crypto_kem_mlkem768_sharedsecretbytes
crypto_kx_client_session_keys
crypto_kx_keypair
crypto_kx_primitive
@@ -545,6 +585,7 @@ crypto_sign_bytes
crypto_sign_detached
crypto_sign_ed25519
crypto_sign_ed25519_bytes
crypto_sign_ed25519_contextbytes_max
crypto_sign_ed25519_detached
crypto_sign_ed25519_keypair
crypto_sign_ed25519_messagebytes_max
@@ -559,6 +600,8 @@ crypto_sign_ed25519_sk_to_pk
crypto_sign_ed25519_sk_to_seed
crypto_sign_ed25519_verify_detached
crypto_sign_ed25519ph_final_create
crypto_sign_ed25519ph_final_ctx_create
crypto_sign_ed25519ph_final_ctx_verify
crypto_sign_ed25519ph_final_verify
crypto_sign_ed25519ph_init
crypto_sign_ed25519ph_statebytes
@@ -639,6 +682,38 @@ crypto_verify_32
crypto_verify_32_bytes
crypto_verify_64
crypto_verify_64_bytes
crypto_xof_shake128
crypto_xof_shake128_blockbytes
crypto_xof_shake128_domain_standard
crypto_xof_shake128_init
crypto_xof_shake128_init_with_domain
crypto_xof_shake128_squeeze
crypto_xof_shake128_statebytes
crypto_xof_shake128_update
crypto_xof_shake256
crypto_xof_shake256_blockbytes
crypto_xof_shake256_domain_standard
crypto_xof_shake256_init
crypto_xof_shake256_init_with_domain
crypto_xof_shake256_squeeze
crypto_xof_shake256_statebytes
crypto_xof_shake256_update
crypto_xof_turboshake128
crypto_xof_turboshake128_blockbytes
crypto_xof_turboshake128_domain_standard
crypto_xof_turboshake128_init
crypto_xof_turboshake128_init_with_domain
crypto_xof_turboshake128_squeeze
crypto_xof_turboshake128_statebytes
crypto_xof_turboshake128_update
crypto_xof_turboshake256
crypto_xof_turboshake256_blockbytes
crypto_xof_turboshake256_domain_standard
crypto_xof_turboshake256_init
crypto_xof_turboshake256_init_with_domain
crypto_xof_turboshake256_squeeze
crypto_xof_turboshake256_statebytes
crypto_xof_turboshake256_update
escrypt_PBKDF2_SHA256
escrypt_alloc_region
escrypt_free_local
@@ -671,6 +746,16 @@ ge25519_p3_tobytes
ge25519_scalarmult
ge25519_scalarmult_base
ge25519_tobytes
keccak1600_ref_extract_bytes
keccak1600_ref_init
keccak1600_ref_permute_12
keccak1600_ref_permute_24
keccak1600_ref_xor_bytes
mlkem768_ref_dec
mlkem768_ref_enc
mlkem768_ref_enc_deterministic
mlkem768_ref_keypair
mlkem768_ref_seed_keypair
randombytes
randombytes_buf
randombytes_buf_deterministic
@@ -689,6 +774,16 @@ sc25519_is_canonical
sc25519_mul
sc25519_muladd
sc25519_reduce
shake128_ref
shake128_ref_init
shake128_ref_init_with_domain
shake128_ref_squeeze
shake128_ref_update
shake256_ref
shake256_ref_init
shake256_ref_init_with_domain
shake256_ref_squeeze
shake256_ref_update
sodium_add
sodium_allocarray
sodium_base642bin
@@ -739,4 +834,20 @@ sodium_stream_salsa20_xmm6_xor_ic
sodium_sub
sodium_unpad
sodium_version_string
softaes_block_decrypt
softaes_block_encrypt
softaes_expand_key128
softaes_expand_key256
softaes_inv_mix_columns
softaes_invert_key_schedule128
softaes_invert_key_schedule256
turboshake128_ref
turboshake128_ref_init
turboshake128_ref_init_with_domain
turboshake128_ref_squeeze
turboshake128_ref_update
turboshake256_ref
turboshake256_ref_init
turboshake256_ref_init_with_domain
turboshake256_ref_squeeze
turboshake256_ref_update