1
0
Fork 0
SlunkCrypt/libslunkcrypt/src/slunkcrypt.c

421 lines
11 KiB
C

/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
/* Internal */
#include "../include/slunkcrypt.h"
#include "version.h"
/* CRT */
#include <string.h>
#include <limits.h>
#include <assert.h>
/* Compiler compatibility */
#if defined(_MSC_VER)
# define FORCE_INLINE __forceinline
# define UNUSED __pragma(warning(suppress: 4189))
#elif defined(__GNUC__)
# define FORCE_INLINE __attribute__((always_inline)) inline
# define UNUSED __attribute__((unused))
#else
# define FORCE_INLINE inline
# define UNUSED
#endif
/* Version info */
const uint16_t SLUNKCRYPT_VERSION_MAJOR = MY_VERSION_MAJOR;
const uint16_t SLUNKCRYPT_VERSION_MINOR = MY_VERSION_MINOR;
const uint16_t SLUNKCRYPT_VERSION_PATCH = MY_VERSION_PATCH;
const char *const SLUNKCRYPT_BUILD = __DATE__ " " __TIME__;
/* Const */
#define HASH_MAGIC_PRIME 0x00000100000001B3ull
#define HASH_OFFSET_BASE 0xCBF29CE484222325ull
/* Utilities */
#define BOOLIFY(X) (!!(X))
// ==========================================================================
// Data structures
// ==========================================================================
typedef struct
{
uint64_t a, b, c;
}
key_data_t;
typedef struct
{
uint32_t x, y, z, w, v, d;
}
rand_state_t;
typedef struct
{
int reverse_mode;
uint8_t wheel[256U][256U];
rand_state_t random;
}
crypt_state_t;
// ==========================================================================
// Abort flag
// ==========================================================================
volatile int g_slunkcrypt_abort_flag = 0;
#define CHECK_ABORTED() do \
{ \
if (g_slunkcrypt_abort_flag) \
{ \
goto aborted; \
} \
} \
while (0)
// ==========================================================================
// Byte access (endianness agnostic)
// ==========================================================================
static FORCE_INLINE uint32_t lower_u64(const uint64_t value)
{
return (uint32_t)(value & 0xFFFFFFFF);
}
static FORCE_INLINE uint32_t upper_u64(const uint64_t value)
{
return (uint32_t)((value >> 32U) & 0xFFFFFFFF);
}
static FORCE_INLINE uint8_t byte_u16(const uint16_t value, const size_t off)
{
assert(off < sizeof(uint16_t));
return (uint8_t)((value >> (CHAR_BIT * off)) & 0xFF);
}
static FORCE_INLINE uint8_t byte_u64(const uint64_t value, const size_t off)
{
assert(off < sizeof(uint64_t));
return (uint8_t)((value >> (CHAR_BIT * off)) & 0xFF);
}
// ==========================================================================
// Hash function
// ==========================================================================
static FORCE_INLINE void hash_update_str(uint64_t* const hash, const uint8_t *const data, const size_t data_len)
{
size_t i;
for (i = 0U; i < data_len; ++i)
{
*hash = ((*hash) ^ data[i]) * HASH_MAGIC_PRIME;
}
}
static FORCE_INLINE void hash_update_u64(uint64_t *const hash, const uint64_t value)
{
size_t i;
for (i = 0U; i < sizeof(uint64_t); ++i)
{
*hash = ((*hash) ^ byte_u64(value, i)) * HASH_MAGIC_PRIME;
}
}
static FORCE_INLINE void hash_update_u16(uint64_t *const hash, const uint16_t value)
{
size_t i;
for (i = 0U; i < sizeof(uint16_t); ++i)
{
*hash = ((*hash) ^ byte_u16(value, i)) * HASH_MAGIC_PRIME;
}
}
static uint64_t hash_code_init(const uint64_t salt, const uint16_t i, const uint8_t *const data, const size_t data_len)
{
uint64_t hash = HASH_OFFSET_BASE;
hash_update_u64(&hash, salt);
hash_update_u16(&hash, i);
hash_update_str(&hash, data, data_len);
return hash;
}
static uint64_t hash_code_next(const uint64_t salt, const uint8_t *const data, const size_t data_len)
{
uint64_t hash = HASH_OFFSET_BASE;
hash_update_u64(&hash, salt);
hash_update_str(&hash, data, data_len);
return hash;
}
// ==========================================================================
// Key derivation
// ==========================================================================
static FORCE_INLINE uint64_t keygen_loop(uint64_t salt, const uint16_t i, const uint8_t *const passwd, const size_t passwd_len)
{
size_t u;
uint64_t result = salt = hash_code_init(salt, i, passwd, passwd_len);
for (u = 1U; u < 99971U; ++u)
{
result ^= salt = hash_code_next(salt, passwd, passwd_len);
}
return result;
}
static void generate_key(key_data_t *const key, const uint64_t salt, const uint16_t pepper, const uint8_t *const passwd, const size_t passwd_len)
{
key->a = keygen_loop(salt, (pepper & 0x3FFF) | 0x0000, passwd, passwd_len);
key->b = keygen_loop(salt, (pepper & 0x3FFF) | 0x4000, passwd, passwd_len);
key->c = keygen_loop(salt, (pepper & 0x3FFF) | 0x8000, passwd, passwd_len);
}
// ==========================================================================
// Deterministic random bit generator
// ==========================================================================
static void random_init(rand_state_t *const state, const key_data_t *const key)
{
slunkcrypt_bzero(state, sizeof(rand_state_t));
state->x = lower_u64(key->a);
state->y = upper_u64(key->a);
state->z = lower_u64(key->b);
state->w = upper_u64(key->b);
state->v = lower_u64(key->c);
state->d = upper_u64(key->c);
}
static uint32_t random_next(rand_state_t *const state)
{
const uint32_t t = state->x ^ (state->x >> 2);
state->x = state->y;
state->y = state->z;
state->z = state->w;
state->w = state->v;
state->v ^= (state->v << 4) ^ t ^ (t << 1);
return (state->d += 0x000587C5) + state->v;
}
static void random_seed(rand_state_t *const state, uint64_t salt, const uint16_t pepper, const uint8_t *const passwd, const size_t passwd_len)
{
size_t i;
key_data_t key;
do
{
generate_key(&key, salt++, pepper, passwd, passwd_len);
random_init(state, &key);
slunkcrypt_bzero(&key, sizeof(key_data_t));
}
while (!(state->x || state->y || state->z || state->w || state->v));
for (i = 0U; i < 97U; ++i)
{
UNUSED volatile uint32_t q = random_next(state);
}
}
// ==========================================================================
// Initialization
// ==========================================================================
static int initialize_state(crypt_state_t *const state, const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode)
{
uint8_t temp[256U][256U];
size_t r, i;
/* initialize state */
slunkcrypt_bzero(state, sizeof(crypt_state_t));
const int reverse = state->reverse_mode = BOOLIFY(mode);
/* set up the wheel permutations */
for (r = 0U; r < 256U; ++r)
{
random_seed(&state->random, nonce, (uint16_t)r, passwd, passwd_len);
for (i = 0U; i < 256U; ++i)
{
const size_t j = random_next(&state->random) % (i + 1U);
if (j != i)
{
state->wheel[r][i] = state->wheel[r][j];
}
state->wheel[r][j] = (uint8_t)i;
}
CHECK_ABORTED();
}
/* reverse the wheels, if requested */
if (reverse)
{
for (r = 0U; r < 256U; ++r)
{
for (i = 0U; i < 256U; ++i)
{
temp[r][state->wheel[r][i]] = (uint8_t)i;
}
}
for (r = 0U; r < 256U; ++r)
{
memcpy(state->wheel[255U - r], temp[r], 256U);
}
slunkcrypt_bzero(temp, sizeof(temp));
CHECK_ABORTED();
}
random_seed(&state->random, nonce, 256U, passwd, passwd_len);
return SLUNKCRYPT_SUCCESS;
/* user abort request */
aborted:
slunkcrypt_bzero(state, sizeof(crypt_state_t));
return SLUNKCRYPT_ABORTED;
}
// ==========================================================================
// Encrypt / Decrypt
// ==========================================================================
static FORCE_INLINE void calculate_offsets(uint8_t *const offset, rand_state_t *const state, const int reverse)
{
uint32_t temp = 0U;
size_t i;
for (i = 0U; i < 256U; ++i, temp >>= CHAR_BIT)
{
if (!temp)
{
temp = random_next(state);
}
offset[reverse ? (255U - i) : i] = (uint8_t)temp;
}
}
static FORCE_INLINE uint8_t process_next_symbol(crypt_state_t *const crypt_state_t, uint8_t value)
{
uint8_t offset[256U];
size_t i;
calculate_offsets(offset, &crypt_state_t->random, crypt_state_t->reverse_mode);
for (i = 0U; i < 256U; ++i)
{
value = (crypt_state_t->wheel[i][(value + offset[i]) & 0xFF] - offset[i]) & 0xFF;
}
return value;
}
// ==========================================================================
// Public API
// ==========================================================================
int slunkcrypt_generate_nonce(uint64_t *const nonce)
{
if (!nonce)
{
return SLUNKCRYPT_FAILURE;
}
do
{
if (slunkcrypt_random_bytes((uint8_t*)nonce, sizeof(uint64_t)) != sizeof(uint64_t))
{
return SLUNKCRYPT_FAILURE;
}
}
while (!(*nonce));
return SLUNKCRYPT_SUCCESS;
}
slunkcrypt_t slunkcrypt_alloc(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode)
{
crypt_state_t* state = NULL;
if ((!passwd) || (passwd_len < SLUNKCRYPT_PWDLEN_MIN) || (passwd_len > SLUNKCRYPT_PWDLEN_MAX) || (mode < SLUNKCRYPT_ENCRYPT) || (mode > SLUNKCRYPT_DECRYPT))
{
return SLUNKCRYPT_NULL;
}
if (!(state = (crypt_state_t*)malloc(sizeof(crypt_state_t))))
{
return SLUNKCRYPT_NULL;
}
if (initialize_state(state, nonce, passwd, passwd_len, mode) == SLUNKCRYPT_SUCCESS)
{
return ((slunkcrypt_t)state);
}
else
{
slunkcrypt_bzero(state, sizeof(crypt_state_t));
return SLUNKCRYPT_NULL;
}
}
int slunkcrypt_reset(const slunkcrypt_t context, const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode)
{
crypt_state_t *const state = (crypt_state_t*)context;
int result = SLUNKCRYPT_FAILURE;
if ((!state) || (!passwd) || (passwd_len < SLUNKCRYPT_PWDLEN_MIN) || (passwd_len > SLUNKCRYPT_PWDLEN_MAX) || (mode < SLUNKCRYPT_ENCRYPT) || (mode > SLUNKCRYPT_DECRYPT))
{
return SLUNKCRYPT_FAILURE;
}
if ((result = initialize_state(state, nonce, passwd, passwd_len, mode)) != SLUNKCRYPT_SUCCESS)
{
slunkcrypt_bzero(state, sizeof(crypt_state_t));
}
return result;
}
int slunkcrypt_process(const slunkcrypt_t context, const uint8_t *const input, uint8_t *const output, size_t length)
{
crypt_state_t *const state = (crypt_state_t*)context;
if (!state)
{
return SLUNKCRYPT_FAILURE;
}
if (length > 0U)
{
size_t i;
for (i = 0; i < length; ++i)
{
output[i] = process_next_symbol(state, input[i]);
CHECK_ABORTED();
}
}
return SLUNKCRYPT_SUCCESS;
aborted:
slunkcrypt_bzero(state, sizeof(crypt_state_t));
return SLUNKCRYPT_ABORTED;
}
int slunkcrypt_inplace(const slunkcrypt_t context, uint8_t *const buffer, size_t length)
{
crypt_state_t *const state = (crypt_state_t*)context;
if (!state)
{
return SLUNKCRYPT_FAILURE;
}
if (length > 0U)
{
size_t i;
for (i = 0; i < length; ++i)
{
buffer[i] = process_next_symbol(state, buffer[i]);
CHECK_ABORTED();
}
}
return SLUNKCRYPT_SUCCESS;
aborted:
slunkcrypt_bzero(state, sizeof(crypt_state_t));
return SLUNKCRYPT_ABORTED;
}
void slunkcrypt_free(const slunkcrypt_t context)
{
crypt_state_t *const state = (crypt_state_t*)context;
if (state)
{
slunkcrypt_bzero(state, sizeof(crypt_state_t));
free(state);
}
}