1 /******************************************************************************/
2 /* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
3 /* This work has been released under the CC0 1.0 Universal license! */
4 /******************************************************************************/
7 #include "../include/slunkcrypt.h"
15 /* Compiler compatibility */
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))
23 # define FORCE_INLINE inline
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__
;
34 #define MAGIC_PRIME 0x00000100000001B3ull
36 // ==========================================================================
38 // ==========================================================================
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];
65 // ==========================================================================
67 // ==========================================================================
69 volatile int g_slunkcrypt_abort_flag
= 0;
71 #define CHECK_ABORTED() do \
73 if (g_slunkcrypt_abort_flag) \
75 return SLUNKCRYPT_ABORTED; \
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 // ==========================================================================
108 // ==========================================================================
110 static FORCE_INLINE
void hash_update_str(uint64_t* const hash
, const uint8_t* const data
, const size_t data_len
)
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
)
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
)
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
);
146 // ==========================================================================
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
)
153 for (i
= 0U; i
< 99971U; ++i
)
155 value
^= hash_code(value
, pepper
, passwd
, passwd_len
);
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 // ==========================================================================
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
;
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
)
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 // ==========================================================================
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
;
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);
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
;
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);
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 // ==========================================================================
259 // ==========================================================================
261 static FORCE_INLINE
void increment(uint8_t *const arr
, const int rev
)
264 for (i
= 0U; i
< 256U; ++i
)
266 if (++arr
[rev
? (255U - i
) : i
] != 0U)
273 static FORCE_INLINE
uint8_t process_enc(crypt_state_t
* const crypt_state
, uint8_t value
)
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);
286 static FORCE_INLINE
uint8_t process_dec(crypt_state_t
* const crypt_state
, uint8_t value
)
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);
299 // ==========================================================================
301 // ==========================================================================
303 int slunkcrypt_generate_nonce(uint64_t* const nonce
)
307 return SLUNKCRYPT_FAILURE
;
311 if (slunkcrypt_random_bytes((uint8_t*)nonce
, sizeof(uint64_t)) != sizeof(uint64_t))
313 return SLUNKCRYPT_FAILURE
;
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
);
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
));
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
;
362 return SLUNKCRYPT_FAILURE
;
367 for (i
= 0; i
< length
; ++i
)
369 output
[i
] = process_enc(state
, input
[i
]);
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
;
381 return SLUNKCRYPT_FAILURE
;
386 for (i
= 0; i
< length
; ++i
)
388 buffer
[i
] = process_enc(state
, buffer
[i
]);
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
;
401 return SLUNKCRYPT_FAILURE
;
406 for (i
= 0; i
< length
; ++i
)
408 output
[i
] = process_dec(state
, input
[i
]);
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
;
420 return SLUNKCRYPT_FAILURE
;
425 for (i
= 0; i
< length
; ++i
)
427 buffer
[i
] = process_dec(state
, buffer
[i
]);
431 return SLUNKCRYPT_SUCCESS
;
434 void slunkcrypt_free(const slunkcrypt_t context
)
436 crypt_state_t
* const state
= (crypt_state_t
*)context
;
439 slunkcrypt_bzero(state
, sizeof(crypt_state_t
));