Slightly tweak stepping algorithm to include a counter.
[slunkcrypt.git] / libslunkcrypt / src / slunkcrypt.c
blob7378babd6c8e176cb1da9c3d7401e8bc419207c7
1 /******************************************************************************/
2 /* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
3 /* This work has been released under the CC0 1.0 Universal license! */
4 /******************************************************************************/
6 /* Internal */
7 #include "../include/slunkcrypt.h"
8 #include "version.h"
10 /* CRT */
11 #include <string.h>
12 #include <limits.h>
13 #include <assert.h>
15 /* Compiler compatibility */
16 #if defined(_MSC_VER)
17 # define FORCE_INLINE __forceinline
18 # define UNUSED __pragma(warning(suppress: 4189))
19 #elif defined(__GNUC__)
20 # define FORCE_INLINE __attribute__((always_inline)) inline
21 # define UNUSED __attribute__((unused))
22 #else
23 # define FORCE_INLINE inline
24 # define UNUSED
25 #endif
27 /* Version info */
28 const uint16_t SLUNKCRYPT_VERSION_MAJOR = MY_VERSION_MAJOR;
29 const uint16_t SLUNKCRYPT_VERSION_MINOR = MY_VERSION_MINOR;
30 const uint16_t SLUNKCRYPT_VERSION_PATCH = MY_VERSION_PATCH;
31 const char *const SLUNKCRYPT_BUILD = __DATE__ " " __TIME__;
33 /* Const */
34 #define HASH_MAGIC_PRIME 0x00000100000001B3ull
35 #define HASH_OFFSET_BASE 0xCBF29CE484222325ull
37 /* Utilities */
38 #define BOOLIFY(X) (!!(X))
40 // ==========================================================================
41 // Data structures
42 // ==========================================================================
44 typedef struct
46 uint64_t a, b, c;
48 key_data_t;
50 typedef struct
52 uint32_t x, y, z, w, v, d;
54 rand_state_t;
56 typedef struct
58 int reverse_mode;
59 uint8_t wheel[256U][256U];
60 uint32_t counter;
61 rand_state_t random;
63 crypt_state_t;
65 // ==========================================================================
66 // Abort flag
67 // ==========================================================================
69 volatile int g_slunkcrypt_abort_flag = 0;
71 #define CHECK_ABORTED() do \
72 { \
73 if (g_slunkcrypt_abort_flag) \
74 { \
75 goto aborted; \
76 } \
77 } \
78 while (0)
80 // ==========================================================================
81 // Byte access (endianness agnostic)
82 // ==========================================================================
84 static FORCE_INLINE uint32_t lower_u64(const uint64_t value)
86 return (uint32_t)(value & 0xFFFFFFFF);
89 static FORCE_INLINE uint32_t upper_u64(const uint64_t value)
91 return (uint32_t)((value >> 32U) & 0xFFFFFFFF);
94 static FORCE_INLINE uint8_t byte_u16(const uint16_t value, const size_t off)
96 assert(off < sizeof(uint16_t));
97 return (uint8_t)((value >> (CHAR_BIT * off)) & 0xFF);
100 static FORCE_INLINE uint8_t byte_u64(const uint64_t value, const size_t off)
102 assert(off < sizeof(uint64_t));
103 return (uint8_t)((value >> (CHAR_BIT * off)) & 0xFF);
106 // ==========================================================================
107 // Hash function
108 // ==========================================================================
110 static FORCE_INLINE void hash_update_str(uint64_t* const hash, const uint8_t *const data, const size_t data_len)
112 size_t i;
113 for (i = 0U; i < data_len; ++i)
115 *hash = ((*hash) ^ data[i]) * HASH_MAGIC_PRIME;
119 static FORCE_INLINE void hash_update_u64(uint64_t *const hash, const uint64_t value)
121 size_t i;
122 for (i = 0U; i < sizeof(uint64_t); ++i)
124 *hash = ((*hash) ^ byte_u64(value, i)) * HASH_MAGIC_PRIME;
128 static FORCE_INLINE void hash_update_u16(uint64_t *const hash, const uint16_t value)
130 size_t i;
131 for (i = 0U; i < sizeof(uint16_t); ++i)
133 *hash = ((*hash) ^ byte_u16(value, i)) * HASH_MAGIC_PRIME;
137 static uint64_t hash_code_init(const uint64_t salt, const uint16_t i, const uint8_t *const data, const size_t data_len)
139 uint64_t hash = HASH_OFFSET_BASE;
140 hash_update_u64(&hash, salt);
141 hash_update_u16(&hash, i);
142 hash_update_str(&hash, data, data_len);
143 return hash;
146 static uint64_t hash_code_next(const uint64_t salt, const uint8_t *const data, const size_t data_len)
148 uint64_t hash = HASH_OFFSET_BASE;
149 hash_update_u64(&hash, salt);
150 hash_update_str(&hash, data, data_len);
151 return hash;
154 // ==========================================================================
155 // Key derivation
156 // ==========================================================================
158 static FORCE_INLINE uint64_t keygen_loop(uint64_t salt, const uint16_t i, const uint8_t *const passwd, const size_t passwd_len)
160 size_t u;
161 uint64_t result = salt = hash_code_init(salt, i, passwd, passwd_len);
162 for (u = 1U; u < 99971U; ++u)
164 result ^= salt = hash_code_next(salt, passwd, passwd_len);
166 return result;
169 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)
171 key->a = keygen_loop(salt, (pepper & 0x3FFF) | 0x0000, passwd, passwd_len);
172 key->b = keygen_loop(salt, (pepper & 0x3FFF) | 0x4000, passwd, passwd_len);
173 key->c = keygen_loop(salt, (pepper & 0x3FFF) | 0x8000, passwd, passwd_len);
176 // ==========================================================================
177 // Deterministic random bit generator
178 // ==========================================================================
180 static void random_init(rand_state_t *const state, const key_data_t *const key)
182 slunkcrypt_bzero(state, sizeof(rand_state_t));
183 state->x = lower_u64(key->a);
184 state->y = upper_u64(key->a);
185 state->z = lower_u64(key->b);
186 state->w = upper_u64(key->b);
187 state->v = lower_u64(key->c);
188 state->d = upper_u64(key->c);
191 static uint32_t random_next(rand_state_t *const state)
193 const uint32_t t = state->x ^ (state->x >> 2);
194 state->x = state->y;
195 state->y = state->z;
196 state->z = state->w;
197 state->w = state->v;
198 state->v ^= (state->v << 4) ^ t ^ (t << 1);
199 return (state->d += 0x000587C5) + state->v;
202 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)
204 size_t i;
205 key_data_t key;
208 generate_key(&key, salt++, pepper, passwd, passwd_len);
209 random_init(state, &key);
210 slunkcrypt_bzero(&key, sizeof(key_data_t));
212 while (!(state->x || state->y || state->z || state->w || state->v));
213 for (i = 0U; i < 97U; ++i)
215 UNUSED volatile uint32_t q = random_next(state);
219 // ==========================================================================
220 // Initialization
221 // ==========================================================================
223 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)
225 uint8_t temp[256U][256U];
226 size_t r, i;
227 const int reverse = BOOLIFY(mode);
229 /* initialize state */
230 slunkcrypt_bzero(state, sizeof(crypt_state_t));
231 state->reverse_mode = reverse;
233 /* initialize counter */
234 random_seed(&state->random, nonce, (uint16_t)(-1), passwd, passwd_len);
235 state->counter = random_next(&state->random);
237 /* set up the wheel permutations */
238 for (r = 0U; r < 256U; ++r)
240 random_seed(&state->random, nonce, (uint16_t)r, passwd, passwd_len);
241 for (i = 0U; i < 256U; ++i)
243 const size_t j = random_next(&state->random) % (i + 1U);
244 if (j != i)
246 state->wheel[r][i] = state->wheel[r][j];
248 state->wheel[r][j] = (uint8_t)i;
250 CHECK_ABORTED();
253 /* reverse the wheels, if requested */
254 if (reverse)
256 for (r = 0U; r < 256U; ++r)
258 for (i = 0U; i < 256U; ++i)
260 temp[r][state->wheel[r][i]] = (uint8_t)i;
263 for (r = 0U; r < 256U; ++r)
265 memcpy(state->wheel[255U - r], temp[r], 256U);
267 slunkcrypt_bzero(temp, sizeof(temp));
268 CHECK_ABORTED();
271 random_seed(&state->random, nonce, 256U, passwd, passwd_len);
272 return SLUNKCRYPT_SUCCESS;
274 /* aborted */
275 aborted:
276 slunkcrypt_bzero(state, sizeof(crypt_state_t));
277 return SLUNKCRYPT_ABORTED;
280 // ==========================================================================
281 // Encrypt / Decrypt
282 // ==========================================================================
284 static FORCE_INLINE void update_offset(uint8_t *const offset, uint32_t seed, rand_state_t *const state, const int reverse)
286 size_t i;
287 for (i = 0U; i < 256U; ++i, seed >>= CHAR_BIT)
289 if (i && (!(i & 3U)))
291 seed = random_next(state);
293 offset[reverse ? (255U - i) : i] = (uint8_t)seed;
297 static FORCE_INLINE uint8_t process_next_symbol(crypt_state_t *const state, uint8_t value)
299 uint8_t offset[256U];
300 size_t i;
301 update_offset(offset, state->counter++, &state->random, state->reverse_mode);
302 for (i = 0U; i < 256U; ++i)
304 value = (state->wheel[i][(value + offset[i]) & 0xFF] - offset[i]) & 0xFF;
306 return value;
309 // ==========================================================================
310 // Public API
311 // ==========================================================================
313 int slunkcrypt_generate_nonce(uint64_t *const nonce)
315 if (!nonce)
317 return SLUNKCRYPT_FAILURE;
321 if (slunkcrypt_random_bytes((uint8_t*)nonce, sizeof(uint64_t)) != sizeof(uint64_t))
323 return SLUNKCRYPT_FAILURE;
326 while (!(*nonce));
327 return SLUNKCRYPT_SUCCESS;
330 slunkcrypt_t slunkcrypt_alloc(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode)
332 crypt_state_t* state = NULL;
333 if ((!passwd) || (passwd_len < SLUNKCRYPT_PWDLEN_MIN) || (passwd_len > SLUNKCRYPT_PWDLEN_MAX) || (mode < SLUNKCRYPT_ENCRYPT) || (mode > SLUNKCRYPT_DECRYPT))
335 return SLUNKCRYPT_NULL;
337 if (!(state = (crypt_state_t*)malloc(sizeof(crypt_state_t))))
339 return SLUNKCRYPT_NULL;
341 if (initialize_state(state, nonce, passwd, passwd_len, mode) == SLUNKCRYPT_SUCCESS)
343 return ((slunkcrypt_t)state);
345 else
347 slunkcrypt_bzero(state, sizeof(crypt_state_t));
348 return SLUNKCRYPT_NULL;
352 int slunkcrypt_reset(const slunkcrypt_t context, const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode)
354 crypt_state_t *const state = (crypt_state_t*)context;
355 int result = SLUNKCRYPT_FAILURE;
356 if ((!state) || (!passwd) || (passwd_len < SLUNKCRYPT_PWDLEN_MIN) || (passwd_len > SLUNKCRYPT_PWDLEN_MAX) || (mode < SLUNKCRYPT_ENCRYPT) || (mode > SLUNKCRYPT_DECRYPT))
358 return SLUNKCRYPT_FAILURE;
360 if ((result = initialize_state(state, nonce, passwd, passwd_len, mode)) != SLUNKCRYPT_SUCCESS)
362 slunkcrypt_bzero(state, sizeof(crypt_state_t));
364 return result;
367 int slunkcrypt_process(const slunkcrypt_t context, const uint8_t *const input, uint8_t *const output, size_t length)
369 crypt_state_t *const state = (crypt_state_t*)context;
370 if (!state)
372 return SLUNKCRYPT_FAILURE;
375 if (length > 0U)
377 size_t i;
378 for (i = 0; i < length; ++i)
380 output[i] = process_next_symbol(state, input[i]);
381 CHECK_ABORTED();
385 return SLUNKCRYPT_SUCCESS;
387 aborted:
388 slunkcrypt_bzero(state, sizeof(crypt_state_t));
389 return SLUNKCRYPT_ABORTED;
392 int slunkcrypt_inplace(const slunkcrypt_t context, uint8_t *const buffer, size_t length)
394 crypt_state_t *const state = (crypt_state_t*)context;
395 if (!state)
397 return SLUNKCRYPT_FAILURE;
400 if (length > 0U)
402 size_t i;
403 for (i = 0; i < length; ++i)
405 buffer[i] = process_next_symbol(state, buffer[i]);
406 CHECK_ABORTED();
410 return SLUNKCRYPT_SUCCESS;
412 aborted:
413 slunkcrypt_bzero(state, sizeof(crypt_state_t));
414 return SLUNKCRYPT_ABORTED;
417 void slunkcrypt_free(const slunkcrypt_t context)
419 crypt_state_t *const state = (crypt_state_t*)context;
420 if (state)
422 slunkcrypt_bzero(state, sizeof(crypt_state_t));
423 free(state);