/******************************************************************************/ /* SlunkCrypt, by LoRd_MuldeR */ /* This work has been released under the CC0 1.0 Universal license! */ /******************************************************************************/ /* Internal */ #include "keygen.h" #include "compiler.h" /* CRT */ #include /* Type */ typedef struct { uint64_t hi, lo; } hash128_t; // ========================================================================== // 128-Bit math support // ========================================================================== #if defined(__GNUC__) && defined(__SIZEOF_INT128__) # define HAVE_UINT128_T 1 # define LOAD_U128(X) ((((__uint128_t)(X).hi) << 64) | (X).lo) #else # pragma message("Compiler does not support 128-bit math -> using fallback!") #endif static INLINE void multiply_u128(hash128_t *const out, const hash128_t lhs, const hash128_t *const rhs) { #ifdef HAVE_UINT128_T const __uint128_t product = LOAD_U128(lhs) * LOAD_U128(*rhs); out->lo = (uint64_t)product; out->hi = (uint64_t)(product >> 64); #else const uint64_t lolo = (lhs.lo & 0xFFFFFFFF) * (rhs->lo & 0xFFFFFFFF); const uint64_t hilo = (lhs.lo >> 32U) * (rhs->lo & 0xFFFFFFFF); const uint64_t lohi = (lhs.lo & 0xFFFFFFFF) * (rhs->lo >> 32U); const uint64_t hihi = (lhs.lo >> 32U) * (rhs->lo >> 32U); const uint64_t crss = (lolo >> 32U) + (hilo & 0xFFFFFFFF) + lohi; out->hi = (hilo >> 32U) + (crss >> 32) + hihi; out->lo = (crss << 32U) | (lolo & 0xFFFFFFFF); out->hi += (lhs.hi * rhs->lo) + (lhs.lo * rhs->hi); /* 128x128=128 */ #endif } // ========================================================================== // Hash function // ========================================================================== static const hash128_t HASH_OFFSETBASE_128 = { UINT64_C(0x6C62272E07BB0142), UINT64_C(0x62B821756295C58D) }; static const hash128_t HASH_MAGICPRIME_128 = { UINT64_C(0x0000000001000000), UINT64_C(0x000000000000013B) }; #define HASH_UPDATE(X) do \ { \ hash->lo ^= (X); \ multiply_u128(hash, *hash, &HASH_MAGICPRIME_128); \ } \ while(0) static INLINE void hash_update_u64(hash128_t *const hash, uint64_t value) { size_t i; for (i = 0U; i < sizeof(uint64_t); ++i, value >>= CHAR_BIT) { HASH_UPDATE((uint8_t)value); } } static INLINE void hash_update_str(hash128_t *const hash, const uint8_t *const data, const size_t data_len) { size_t i; for (i = 0U; i < data_len; ++i) { HASH_UPDATE(data[i]); } } static INLINE hash128_t hash_code(const hash128_t *const seed, const uint8_t *const data, const size_t data_len) { hash128_t hash = HASH_OFFSETBASE_128; hash_update_u64(&hash, seed->lo); hash_update_u64(&hash, seed->hi); hash_update_str(&hash, data, data_len); return hash; } // ========================================================================== // Key derivation // ========================================================================== static INLINE uint64_t keygen_loop(uint64_t seed, const uint64_t i, const uint8_t *const passwd, const size_t passwd_len, const size_t rounds) { hash128_t hash = { seed, i }; size_t u; for (u = 0U, seed = 0U; u < rounds; ++u) { hash = hash_code(&hash, passwd, passwd_len); seed ^= hash.hi ^ hash.lo; } return seed; } void slunkcrypt_keygen(keydata_t *const key, const uint64_t salt, const uint16_t pepper, const uint8_t *const passwd, const size_t passwd_len, const size_t rounds) { key->a = keygen_loop(salt, UINT64_C(0x162603FA1CDA99D3) + pepper, passwd, passwd_len, rounds); key->b = keygen_loop(salt, UINT64_C(0xBFDEC4A6C1A46E09) + pepper, passwd, passwd_len, rounds); key->c = keygen_loop(salt, UINT64_C(0x6BA17D11624973EE) + pepper, passwd, passwd_len, rounds); }