/******************************************************************************/ /* MCrypt, by LoRd_MuldeR */ /* This work has been released under the CC0 1.0 Universal license! */ /******************************************************************************/ #ifdef _WIN32 #define _CRT_RAND_S 1 #endif #include #include const char* const LIBMCRYPT_VERSION = "1.0.0"; const char* const LIBMCRYPT_BUILDNO = __DATE__", "__TIME__; typedef struct { uint8_t box[256U][256U]; uint8_t inv[256U][256U]; uint8_t off[256U]; uint8_t pos; } crypt_state_t; typedef struct { uint32_t a, b, c, d; uint32_t counter; } rand_state_t; // ========================================================================== // Hash function // ========================================================================== static void hash_update(uint64_t* const h, const uint8_t* const data, const size_t data_len) { for (size_t i = 0U; i < data_len; ++i) { *h ^= data[i]; *h *= 0x00000100000001B3ull; } } static uint64_t hash_code(const uint64_t salt, const uint16_t pepper, const uint8_t* const data, const size_t data_len) { uint64_t h = 0xCBF29CE484222325ull; hash_update(&h, (uint8_t*)&salt, sizeof(uint64_t)); hash_update(&h, (uint8_t*)&pepper, sizeof(uint16_t)); hash_update(&h, data, data_len); return h; } // ========================================================================== // PRNG // ========================================================================== static void random_init(rand_state_t* const state, const uint64_t seed_0, const uint64_t seed_1) { state->counter = 0U; state->a = (uint32_t)(seed_0 & 0xFFFFFFFF); state->b = (uint32_t)((seed_0 >> 32) & 0xFFFFFFFF); state->c = (uint32_t)(seed_1 & 0xFFFFFFFF); state->d = (uint32_t)((seed_1 >> 32) & 0xFFFFFFFF); } static uint32_t random_next(rand_state_t* const state) { uint32_t t = state->d; const uint32_t s = state->a; state->d = state->c; state->c = state->b; state->b = s; t ^= t >> 2; t ^= t << 1; t ^= s ^ (s << 4); state->a = t; return t + (state->counter += 362437U); } static void random_seed(rand_state_t* const state, const uint64_t salt, const uint16_t pepper, const uint8_t* const key, const size_t key_len) { const uint64_t hash_code_0 = hash_code(salt, pepper & 0x7FFF, key, key_len); const uint64_t hash_code_1 = hash_code(salt, pepper | 0x8000, key, key_len); random_init(state, hash_code_0, hash_code_1); for (size_t i = 0U; i < 13U; ++i) { random_next(state); } } // ========================================================================== // Initialization // ========================================================================== static void initialize_state(crypt_state_t* const crypt_state, const uint64_t salt, const uint8_t* const key, const size_t key_len) { rand_state_t rand_state; for (size_t r = 0U; r < 256U; ++r) { random_seed(&rand_state, salt, (uint16_t)r, key, key_len); crypt_state->off[r] = (uint8_t)random_next(&rand_state); for (size_t i = 0U; i < 256U; ++i) { const size_t j = random_next(&rand_state) % (i + 1U); if (j != i) { crypt_state->box[r][i] = crypt_state->box[r][j]; } crypt_state->box[r][j] = (uint8_t)i; } for (size_t i = 0U; i < 256U; ++i) { const size_t j = crypt_state->box[r][i]; crypt_state->inv[r][j] = (uint8_t)i; } } random_seed(&rand_state, salt, 0x0100, key, key_len); crypt_state->pos = (uint8_t)random_next(&rand_state); mcrypt_bzero(&rand_state, sizeof(rand_state_t)); } // ========================================================================== // Encrypt / Decrypt // ========================================================================== static uint8_t process_enc(crypt_state_t* const crypt_state, uint8_t value) { for (size_t i = 0U; i < 256U; ++i) { value = crypt_state->box[i][(value + crypt_state->off[i]) & 0xFF]; } ++crypt_state->off[crypt_state->pos++]; return value; } static uint8_t process_dec(crypt_state_t* const crypt_state, uint8_t value) { size_t i = 256U; while (i--) { value = (crypt_state->inv[i][value] - crypt_state->off[i]) & 0xFF; } ++crypt_state->off[crypt_state->pos++]; return value; } // ========================================================================== // Public API // ========================================================================== int mcrypt_generate_seed(uint64_t* const seed) { if (seed) { return mcrypt_random_bytes((uint8_t*)seed, sizeof(uint64_t)); } return -1; } mcrypt_t mcrypt_alloc(const uint64_t salt, const char* const passphrase) { if (!passphrase) { return ((mcrypt_t)NULL); } crypt_state_t* const state = (crypt_state_t*)malloc(sizeof(crypt_state_t)); if (!state) { return ((mcrypt_t)NULL); } initialize_state(state, salt, (uint8_t*)passphrase, strlen(passphrase)); return ((mcrypt_t)state); } int mcrypt_enc_process(const mcrypt_t context, const uint8_t* const input, uint8_t* const output, size_t length) { crypt_state_t* const state = (crypt_state_t*)context; if (!context) { return -1; } for (size_t i = 0; i < length; ++i) { output[i] = process_enc(state, input[i]); } return 0; } int mcrypt_enc_process_inplace(const mcrypt_t context, uint8_t* const buffer, size_t length) { crypt_state_t* const state = (crypt_state_t*)context; if (!context) { return -1; } for (size_t i = 0; i < length; ++i) { buffer[i] = process_enc(state, buffer[i]); } return 0; } int mcrypt_dec_process(const mcrypt_t context, const uint8_t* const input, uint8_t* const output, size_t length) { crypt_state_t* const state = (crypt_state_t*)context; if (!context) { return -1; } for (size_t i = 0; i < length; ++i) { output[i] = process_dec(state, input[i]); } return 0; } int mcrypt_dec_process_inplace(const mcrypt_t context, uint8_t* const buffer, size_t length) { crypt_state_t* const state = (crypt_state_t*)context; if (!context) { return -1; } for (size_t i = 0; i < length; ++i) { buffer[i] = process_dec(state, buffer[i]); } return 0; } void mcrypt_free(const mcrypt_t context) { crypt_state_t* const state = (crypt_state_t*)context; if (context) { mcrypt_bzero((void*)context, sizeof(crypt_state_t)); free(context); } }