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 "slunkcrypt.h"
18 const uint16_t SLUNKCRYPT_VERSION_MAJOR
= LIB_VERSION_MAJOR
;
19 const uint16_t SLUNKCRYPT_VERSION_MINOR
= LIB_VERSION_MINOR
;
20 const uint16_t SLUNKCRYPT_VERSION_PATCH
= LIB_VERSION_PATCH
;
21 const char *const SLUNKCRYPT_BUILD
= __DATE__
", " __TIME__
;
24 #define BOOLIFY(X) (!!(X))
25 #define THREAD_COUNT(X) (((X)->thread_pool) ? slunkcrypt_thrdpl_count((X)->thread_pool) : 1U)
28 const int SLUNKCRYPT_HAVE_THREADS
= BOOLIFY(MAX_THREADS
> 1U);
30 // ==========================================================================
32 // ==========================================================================
36 uint32_t x
, y
, z
, w
, v
, d
;
43 const uint8_t (*wheel
)[256U];
52 uint8_t wheel
[256U][256U];
53 thread_state_t thread_data
[MAX_THREADS
];
59 thrdpl_t
*thread_pool
;
64 // ==========================================================================
66 // ==========================================================================
68 volatile int g_slunkcrypt_abort_flag
= 0;
70 #define CHECK_ABORTED() do \
72 if (g_slunkcrypt_abort_flag) \
79 // ==========================================================================
80 // Byte access (endianness agnostic)
81 // ==========================================================================
83 static INLINE
uint32_t lower_u64(const uint64_t value
)
85 return (uint32_t)(value
& 0xFFFFFFFF);
88 static INLINE
uint32_t upper_u64(const uint64_t value
)
90 return (uint32_t)(value
>> 32U);
93 // ==========================================================================
94 // Deterministic random bit generator
95 // ==========================================================================
97 static INLINE
void random_init(rand_state_t
*const state
, const keydata_t
*const key
)
99 slunkcrypt_bzero(state
, sizeof(rand_state_t
));
100 state
->x
= lower_u64(key
->a
);
101 state
->y
= upper_u64(key
->a
);
102 state
->z
= lower_u64(key
->b
);
103 state
->w
= upper_u64(key
->b
);
104 state
->v
= lower_u64(key
->c
);
105 state
->d
= upper_u64(key
->c
);
108 static INLINE
uint32_t random_next(rand_state_t
*const state
)
110 const uint32_t t
= state
->x
^ (state
->x
>> 2);
115 state
->v
^= (state
->v
<< 4) ^ t
^ (t
<< 1);
116 return (state
->d
+= 0x000587C5) + state
->v
;
119 static INLINE
void random_skip(rand_state_t
*const state
, const size_t skip_count
)
122 for (i
= 0U; i
< skip_count
; ++i
)
124 UNUSED
/*volatile*/ uint32_t q
= random_next(state
);
128 static INLINE
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
)
133 slunkcrypt_keygen(&key
, salt
++, pepper
, passwd
, passwd_len
);
134 random_init(state
, &key
);
135 slunkcrypt_bzero(&key
, sizeof(keydata_t
));
137 while (!(state
->x
|| state
->y
|| state
->z
|| state
->w
|| state
->v
));
138 random_skip(state
, 97U);
141 // ==========================================================================
143 // ==========================================================================
145 static int initialize_state(crypt_data_t
*const data
, const size_t thread_count
, const uint64_t nonce
, const uint8_t *const passwd
, const size_t passwd_len
, const int mode
)
147 uint8_t temp
[256U][256U];
149 const int reverse_mode
= BOOLIFY(mode
);
151 /* initialize state */
152 slunkcrypt_bzero(data
, sizeof(crypt_data_t
));
154 /* initialize counter */
155 random_seed(&data
->thread_data
[0].random
, nonce
, (uint16_t)(-1), passwd
, passwd_len
);
156 data
->thread_data
[0].counter
= random_next(&data
->thread_data
[0].random
);
158 /* set up the wheel permutations */
159 for (r
= 0U; r
< 256U; ++r
)
161 random_seed(&data
->thread_data
[0].random
, nonce
, (uint16_t)r
, passwd
, passwd_len
);
162 for (i
= 0U; i
< 256U; ++i
)
164 const size_t j
= random_next(&data
->thread_data
[0].random
) % (i
+ 1U);
167 data
->wheel
[r
][i
] = data
->wheel
[r
][j
];
169 data
->wheel
[r
][j
] = (uint8_t)i
;
174 /* reverse the wheels, if requested */
177 for (r
= 0U; r
< 256U; ++r
)
179 for (i
= 0U; i
< 256U; ++i
)
181 temp
[r
][data
->wheel
[r
][i
]] = (uint8_t)i
;
184 for (r
= 0U; r
< 256U; ++r
)
186 memcpy(data
->wheel
[255U - r
], temp
[r
], 256U);
188 slunkcrypt_bzero(temp
, sizeof(temp
));
192 /* initialize thread state */
193 data
->thread_data
[0].reverse_mode
= reverse_mode
;
194 data
->thread_data
[0].wheel
= (const uint8_t(*)[256]) data
->wheel
;
195 data
->thread_data
[0].index_off
= 0U;
196 random_seed(&data
->thread_data
[0].random
, nonce
, 256U, passwd
, passwd_len
);
197 for (i
= 1U; i
< thread_count
; ++i
)
199 data
->thread_data
[i
].reverse_mode
= data
->thread_data
[0].reverse_mode
;
200 data
->thread_data
[i
].wheel
= data
->thread_data
[0].wheel
;
201 data
->thread_data
[i
].counter
= data
->thread_data
[0].counter
+ ((uint32_t)i
);
202 data
->thread_data
[i
].index_off
= data
->thread_data
[i
- 1U].index_off
+ 1U;
203 memcpy(&data
->thread_data
[i
].random
, &data
->thread_data
[0].random
, sizeof(rand_state_t
));
204 random_skip(&data
->thread_data
[i
].random
, i
* 63U);
208 return SLUNKCRYPT_SUCCESS
;
212 slunkcrypt_bzero(data
, sizeof(crypt_data_t
));
213 return SLUNKCRYPT_ABORTED
;
216 // ==========================================================================
218 // ==========================================================================
220 static INLINE
void update_offset(uint8_t *const offset
, uint32_t seed
, rand_state_t
*const state
, const int reverse
)
223 for (i
= 0U; i
< 256U; ++i
, seed
>>= CHAR_BIT
)
225 if (i
&& (!(i
& 3U)))
227 seed
= random_next(state
);
229 offset
[reverse
? (255U - i
) : i
] = (uint8_t)seed
;
233 static INLINE
uint8_t process_next_symbol(thread_state_t
*const state
, uint8_t value
)
235 uint8_t offset
[256U];
237 update_offset(offset
, state
->counter
, &state
->random
, state
->reverse_mode
);
238 for (i
= 0U; i
< 256U; ++i
)
240 value
= (state
->wheel
[i
][(value
+ offset
[i
]) & 0xFF] - offset
[i
]) & 0xFF;
245 // ==========================================================================
246 // Thread entry point
247 // ==========================================================================
249 static INLINE
void update_index(thread_state_t
*const state
, const size_t thread_count
, const size_t length
)
251 const size_t remaining
= thread_count
- (length
% thread_count
);
252 if (remaining
!= thread_count
)
254 state
->index_off
= (state
->index_off
+ remaining
) % thread_count
;
258 static void thread_worker(const size_t thread_count
, void *const context
, uint8_t *const buffer
, const size_t length
)
260 thread_state_t
*const state
= (thread_state_t
*) context
;
263 for (i
= state
->index_off
; i
< length
; i
+= thread_count
)
265 buffer
[i
] = process_next_symbol(state
, buffer
[i
]);
266 state
->counter
+= (uint32_t)thread_count
;
267 random_skip(&state
->random
, 63U * (thread_count
- 1U));
270 update_index(state
, thread_count
, length
);
273 // ==========================================================================
275 // ==========================================================================
277 int slunkcrypt_generate_nonce(uint64_t *const nonce
)
281 return SLUNKCRYPT_FAILURE
;
285 if (slunkcrypt_random_bytes((uint8_t*)nonce
, sizeof(uint64_t)) != sizeof(uint64_t))
287 return SLUNKCRYPT_FAILURE
;
291 return SLUNKCRYPT_SUCCESS
;
294 slunkcrypt_t
slunkcrypt_alloc(const uint64_t nonce
, const uint8_t *const passwd
, const size_t passwd_len
, const int mode
)
296 slunkparam_t param
= { SLUNKCRYPT_PARAM_VERSION
, 0U };
297 return slunkcrypt_alloc_ext(nonce
, passwd
, passwd_len
, mode
, ¶m
);
300 slunkcrypt_t
slunkcrypt_alloc_ext(const uint64_t nonce
, const uint8_t *const passwd
, const size_t passwd_len
, const int mode
, const slunkparam_t
*const param
)
302 crypt_state_t
* state
= NULL
;
304 if ((!passwd
) || (passwd_len
< SLUNKCRYPT_PWDLEN_MIN
) || (passwd_len
> SLUNKCRYPT_PWDLEN_MAX
) ||
305 (mode
< SLUNKCRYPT_ENCRYPT
) || (mode
> SLUNKCRYPT_DECRYPT
) || (!param
) || (param
->version
== 0U) || (param
->version
> SLUNKCRYPT_PARAM_VERSION
))
307 return SLUNKCRYPT_NULL
;
310 if (!(state
= (crypt_state_t
*)malloc(sizeof(crypt_state_t
))))
312 return SLUNKCRYPT_NULL
;
315 if ((state
->thread_pool
= slunkcrypt_thrdpl_create(param
->thread_count
, thread_worker
)))
317 const size_t thread_count
= slunkcrypt_thrdpl_count(state
->thread_pool
);
319 for (i
= 0U; i
< thread_count
; ++i
)
321 slunkcrypt_thrdpl_init(state
->thread_pool
, i
, &state
->data
.thread_data
[i
]);
325 if (initialize_state(&state
->data
, THREAD_COUNT(state
), nonce
, passwd
, passwd_len
, mode
) == SLUNKCRYPT_SUCCESS
)
327 return (slunkcrypt_t
)state
;
330 slunkcrypt_free((slunkcrypt_t
)state
);
331 return SLUNKCRYPT_NULL
;
334 int slunkcrypt_reset(const slunkcrypt_t context
, const uint64_t nonce
, const uint8_t *const passwd
, const size_t passwd_len
, const int mode
)
336 crypt_state_t
*const state
= (crypt_state_t
*) context
;
337 int result
= SLUNKCRYPT_FAILURE
;
339 if ((!state
) || (!passwd
) || (passwd_len
< SLUNKCRYPT_PWDLEN_MIN
) || (passwd_len
> SLUNKCRYPT_PWDLEN_MAX
) || (mode
< SLUNKCRYPT_ENCRYPT
) || (mode
> SLUNKCRYPT_DECRYPT
))
341 return SLUNKCRYPT_FAILURE
;
343 if ((result
= initialize_state(&state
->data
, THREAD_COUNT(state
), nonce
, passwd
, passwd_len
, mode
)) != SLUNKCRYPT_SUCCESS
)
345 slunkcrypt_bzero(&state
->data
, sizeof(crypt_data_t
));
350 int slunkcrypt_process(const slunkcrypt_t context
, const uint8_t *const input
, uint8_t *const output
, size_t length
)
352 crypt_state_t
*const state
= (crypt_state_t
*)context
;
355 return SLUNKCRYPT_FAILURE
;
360 memcpy(output
, input
, length
);
361 return slunkcrypt_inplace(context
, output
, length
);
364 return SLUNKCRYPT_SUCCESS
;
367 int slunkcrypt_inplace(const slunkcrypt_t context
, uint8_t *const buffer
, size_t length
)
369 crypt_state_t
*const state
= (crypt_state_t
*)context
;
372 return SLUNKCRYPT_FAILURE
;
377 if (THREAD_COUNT(state
) > 1U)
379 slunkcrypt_thrdpl_exec(state
->thread_pool
, buffer
, length
);
383 thread_worker(1U, &state
->data
.thread_data
[0U], buffer
, length
);
388 return SLUNKCRYPT_SUCCESS
;
391 slunkcrypt_bzero(buffer
, length
);
392 slunkcrypt_bzero(&state
->data
, sizeof(crypt_data_t
));
393 return SLUNKCRYPT_ABORTED
;
396 void slunkcrypt_free(const slunkcrypt_t context
)
398 crypt_state_t
*const state
= (crypt_state_t
*) context
;
401 if (state
->thread_pool
)
403 slunkcrypt_thrdpl_destroy(state
->thread_pool
);
405 slunkcrypt_bzero(state
, sizeof(crypt_state_t
));