mirror of
https://github.com/jedisct1/libsodium.git
synced 2026-08-25 08:37:13 +09:00
Import ipcrypt
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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!
|
||||
Reference in New Issue
Block a user