Fixed a few warnings on Linux.
[slunkcrypt.git] / libslunkcrypt / src / slunkcrypt.c
blob3b56270bd978c907cc7e0628917774d48c4bcb6f
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 MAGIC_PRIME 0x00000100000001B3ull
36 // ==========================================================================
37 // Data structures
38 // ==========================================================================
40 typedef struct
42 uint64_t a, b;
44 key_data_t;
46 typedef struct
48 uint8_t wheel_fwd[256U][256U];
49 uint8_t wheel_bwd[256U][256U];
50 uint8_t step_fwd[256U];
51 uint8_t step_bwd[256U];
52 uint8_t rotation_fwd[2U][256U];
53 uint8_t rotation_bwd[2U][256U];
54 uint8_t counter;
56 crypt_state_t;
58 typedef struct
60 uint32_t a, b, c, d;
61 uint32_t counter;
63 rand_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 return SLUNKCRYPT_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]) * 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)) * 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)) * MAGIC_PRIME;
137 static uint64_t hash_code(const uint64_t salt, const uint16_t pepper, const uint8_t* const data, const size_t data_len)
139 uint64_t hash = 0xCBF29CE484222325ull;
140 hash_update_u64(&hash, salt);
141 hash_update_u16(&hash, pepper);
142 hash_update_str(&hash, data, data_len);
143 return hash;
146 // ==========================================================================
147 // Key derivation
148 // ==========================================================================
150 static FORCE_INLINE uint64_t keygen_loop(uint64_t value, const uint16_t pepper, const uint8_t* const passwd, const size_t passwd_len)
152 size_t i;
153 for (i = 0U; i < 99971U; ++i)
155 value ^= hash_code(value, pepper, passwd, passwd_len);
157 return value;
160 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)
162 key->a = keygen_loop(salt, pepper & 0x7FFF, passwd, passwd_len);
163 key->b = keygen_loop(salt, pepper | 0x8000, passwd, passwd_len);
166 // ==========================================================================
167 // PRNG
168 // ==========================================================================
170 static void random_init(rand_state_t* const state, const uint64_t seed_0, const uint64_t seed_1)
172 slunkcrypt_bzero(state, sizeof(rand_state_t));
173 state->a = lower_u64(seed_0);
174 state->b = upper_u64(seed_0);
175 state->c = lower_u64(seed_1);
176 state->d = upper_u64(seed_1);
179 static uint32_t random_next(rand_state_t *const state)
181 uint32_t t = state->d;
182 const uint32_t s = state->a;
183 state->d = state->c;
184 state->c = state->b;
185 state->b = s;
186 t ^= t >> 2;
187 t ^= t << 1;
188 t ^= s ^ (s << 4);
189 state->a = t;
190 return t + (state->counter += 362437U);
193 static void random_seed(rand_state_t* const state, const uint64_t salt, const uint16_t pepper, const uint8_t *const passwd, const size_t passwd_len)
195 key_data_t key;
196 size_t i;
197 generate_key(&key, salt, pepper, passwd, passwd_len);
198 random_init(state, key.a, key.b);
199 slunkcrypt_bzero(&key, sizeof(key_data_t));
200 for (i = 0U; i < 97U; ++i)
202 UNUSED volatile uint32_t u = random_next(state);
206 // ==========================================================================
207 // Initialization
208 // ==========================================================================
210 static int initialize_state(crypt_state_t* const crypt_state, const uint64_t nonce, const uint8_t* const passwd, const size_t passwd_len)
212 rand_state_t rand_state;
213 size_t r, i;
214 slunkcrypt_bzero(crypt_state, sizeof(crypt_state_t));
216 /* set up wheels and initial rotation */
217 for (r = 0U; r < 256U; ++r)
219 random_seed(&rand_state, nonce, (uint16_t)r, passwd, passwd_len);
220 crypt_state->rotation_bwd[0U][255U - r] = crypt_state->rotation_fwd[0U][r] = (uint8_t)random_next(&rand_state);
221 crypt_state->rotation_bwd[1U][255U - r] = crypt_state->rotation_fwd[1U][r] = 0U;
222 for (i = 0U; i < 256U; ++i)
224 const size_t j = random_next(&rand_state) % (i + 1U);
225 if (j != i)
227 crypt_state->wheel_fwd[r][i] = crypt_state->wheel_fwd[r][j];
229 crypt_state->wheel_fwd[r][j] = (uint8_t)i;
231 for (i = 0U; i < 256U; ++i)
233 const size_t j = crypt_state->wheel_fwd[r][i];
234 crypt_state->wheel_bwd[255U - r][j] = (uint8_t)i;
236 CHECK_ABORTED();
239 /* set up stepping */
240 random_seed(&rand_state, nonce, 256U, passwd, passwd_len);
241 for (i = 0U; i < 256U; ++i)
243 const size_t j = random_next(&rand_state) % (i + 1U);
244 if (j != i)
246 crypt_state->step_fwd[i] = crypt_state->step_fwd[j];
247 crypt_state->step_bwd[i] = crypt_state->step_bwd[j];
249 crypt_state->step_fwd[j] = (uint8_t)i;
250 crypt_state->step_bwd[j] = (uint8_t)(255U - i);
253 slunkcrypt_bzero(&rand_state, sizeof(rand_state_t));
254 return SLUNKCRYPT_SUCCESS;
257 // ==========================================================================
258 // Encrypt / Decrypt
259 // ==========================================================================
261 static FORCE_INLINE void increment(uint8_t *const arr, const int rev)
263 size_t i;
264 for (i = 0U; i < 256U; ++i)
266 if (++arr[rev ? (255U - i) : i] != 0U)
268 break;
273 static FORCE_INLINE uint8_t process_enc(crypt_state_t* const crypt_state, uint8_t value)
275 size_t i;
276 for (i = 0U; i < 256U; ++i)
278 const uint8_t offset = crypt_state->rotation_fwd[0U][i] + crypt_state->rotation_fwd[1U][i];
279 value = crypt_state->wheel_fwd[i][(value + offset) & 0xFF];
281 ++crypt_state->rotation_fwd[0U][crypt_state->step_fwd[crypt_state->counter++]];
282 increment(crypt_state->rotation_fwd[1U], 0);
283 return value;
286 static FORCE_INLINE uint8_t process_dec(crypt_state_t* const crypt_state, uint8_t value)
288 size_t i;
289 for (i = 0U; i < 256U; ++i)
291 const uint8_t offset = crypt_state->rotation_bwd[0U][i] + crypt_state->rotation_bwd[1U][i];
292 value = (crypt_state->wheel_bwd[i][value] - offset) & 0xFF;
294 ++crypt_state->rotation_bwd[0U][crypt_state->step_bwd[crypt_state->counter++]];
295 increment(crypt_state->rotation_bwd[1U], 1);
296 return value;
299 // ==========================================================================
300 // Public API
301 // ==========================================================================
303 int slunkcrypt_generate_nonce(uint64_t* const nonce)
305 if (!nonce)
307 return SLUNKCRYPT_FAILURE;
311 if (slunkcrypt_random_bytes((uint8_t*)nonce, sizeof(uint64_t)) != sizeof(uint64_t))
313 return SLUNKCRYPT_FAILURE;
316 while (!(*nonce));
317 return SLUNKCRYPT_SUCCESS;
320 slunkcrypt_t slunkcrypt_alloc(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len)
322 crypt_state_t* state = NULL;
323 if ((!passwd) || (passwd_len < SLUNKCRYPT_PWDLEN_MIN) || (passwd_len > SLUNKCRYPT_PWDLEN_MAX))
325 return SLUNKCRYPT_NULL;
327 if (!(state = (crypt_state_t*)malloc(sizeof(crypt_state_t))))
329 return SLUNKCRYPT_NULL;
331 if (initialize_state(state, nonce, passwd, passwd_len) == SLUNKCRYPT_SUCCESS)
333 return ((slunkcrypt_t)state);
335 else
337 slunkcrypt_bzero(state, sizeof(crypt_state_t));
338 return SLUNKCRYPT_NULL;
342 int slunkcrypt_reset(const slunkcrypt_t context, const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len)
344 crypt_state_t* const state = (crypt_state_t*)context;
345 int result = SLUNKCRYPT_FAILURE;
346 if ((!state) || (!passwd) || (passwd_len < SLUNKCRYPT_PWDLEN_MIN) || (passwd_len > SLUNKCRYPT_PWDLEN_MAX))
348 return SLUNKCRYPT_FAILURE;
350 if ((result = initialize_state(state, nonce, passwd, passwd_len)) != SLUNKCRYPT_SUCCESS)
352 slunkcrypt_bzero(state, sizeof(crypt_state_t));
354 return result;
357 int slunkcrypt_encrypt(const slunkcrypt_t context, const uint8_t* const input, uint8_t* const output, size_t length)
359 crypt_state_t* const state = (crypt_state_t*)context;
360 if (!state)
362 return SLUNKCRYPT_FAILURE;
364 if (length > 0U)
366 size_t i;
367 for (i = 0; i < length; ++i)
369 output[i] = process_enc(state, input[i]);
370 CHECK_ABORTED();
373 return SLUNKCRYPT_SUCCESS;
376 int slunkcrypt_encrypt_inplace(const slunkcrypt_t context, uint8_t* const buffer, size_t length)
378 crypt_state_t* const state = (crypt_state_t*)context;
379 if (!state)
381 return SLUNKCRYPT_FAILURE;
383 if (length > 0U)
385 size_t i;
386 for (i = 0; i < length; ++i)
388 buffer[i] = process_enc(state, buffer[i]);
389 CHECK_ABORTED();
392 return SLUNKCRYPT_SUCCESS;
396 int slunkcrypt_decrypt(const slunkcrypt_t context, const uint8_t* const input, uint8_t* const output, size_t length)
398 crypt_state_t* const state = (crypt_state_t*)context;
399 if (!state)
401 return SLUNKCRYPT_FAILURE;
403 if (length > 0U)
405 size_t i;
406 for (i = 0; i < length; ++i)
408 output[i] = process_dec(state, input[i]);
409 CHECK_ABORTED();
412 return SLUNKCRYPT_SUCCESS;
415 int slunkcrypt_decrypt_inplace(const slunkcrypt_t context, uint8_t* const buffer, size_t length)
417 crypt_state_t* const state = (crypt_state_t*)context;
418 if (!state)
420 return SLUNKCRYPT_FAILURE;
422 if (length > 0U)
424 size_t i;
425 for (i = 0; i < length; ++i)
427 buffer[i] = process_dec(state, buffer[i]);
428 CHECK_ABORTED();
431 return SLUNKCRYPT_SUCCESS;
434 void slunkcrypt_free(const slunkcrypt_t context)
436 crypt_state_t* const state = (crypt_state_t*)context;
437 if (state)
439 slunkcrypt_bzero(state, sizeof(crypt_state_t));
440 free(state);