#include "aes.h" #include "pkcs7_padding.h" #include "pbkdf2-sha256.h" #include "enc.h" #include "enc_boards.h" #include "raw_hid.h" #include "eeprom.h" #include "usb_descriptor.h" // TEMP -> need to be customized #include "sendstring_german.h" #include "keymap_german.h" #include #include static ENC_CTX enc_ctx; static enc_request_state_t enc_request; #ifdef ENC_HW_RND_STM32F4 # include "stm32f4xx.h" # ifndef ENC_HW_RND # define ENC_HW_RND 0x01 # endif # ifndef RNG_NVIC_PREEMPTION_PRIORITY # define RNG_NVIC_PREEMPTION_PRIORITY 0x02 # endif # ifndef RNG_NVIC_SUBPRIORITY # define RNG_NVIC_SUBPRIORITY 0x00 # endif #endif #ifdef ENC_HW_RND_STM32F4 void enc_rnd_init(void) { /* Enable RNG clock source */ RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; /* RNG Peripheral enable */ RNG->CR |= RNG_CR_RNGEN; } void enc_rnd_deinit(void) { /* Disable RNG peripheral */ RNG->CR &= ~RNG_CR_RNGEN; /* Disable RNG clock source */ RCC->AHB2ENR &= ~RCC_AHB2ENR_RNGEN; } uint32_t enc_rnd_get(void) { /* Wait until one RNG number is ready */ while (!(RNG->SR & (RNG_SR_DRDY))) ; /* Get a 32-bit Random number */ return RNG->DR; } #else void enc_rnd_init(void) { srand(enc_ctx.state.seed); } void enc_rnd_deinit(void) { return; } uint32_t enc_rnd_get(void) { uint32_t ret; uint8_t *v = (uint8_t *)&ret; for (int i = 0; i < 4; i++, v++) { *v = rand() % 256; } return ret; } #endif uint8_t *encrypt_cbc(int size, uint8_t *data, uint8_t *key, uint16_t *osize) { if (size <= 0) { return NULL; } int dsize = size; // Proper Length of report if (size % 16) { dsize += 16 - (size % 16); } // Make the uint8_t arrays uint8_t hexarray[dsize]; // Initialize them with zeros memset(hexarray, 0, dsize); // Fill the uint8_t arrays for (int i = 0; i < size; i++) { hexarray[i] = (uint8_t)data[i]; } pkcs7_padding_pad_buffer(hexarray, size, sizeof(hexarray), 16); uint8_t enchexarray[dsize + 16]; memset(enchexarray, 0, dsize + 16); for (int i = 0; i < dsize; i++) { enchexarray[i + 16] = hexarray[i]; } enc_rnd_init(); for (int i = 0; i < 16;) { uint32_t rnd = enc_rnd_get(); uint8_t *v = (uint8_t *)&rnd; for (int j = 0; j < 4; j++, v++, i++) { enchexarray[i] = *v; } } enc_rnd_deinit(); // start the encryption struct AES_ctx ctx; AES_init_ctx_iv(&ctx, key, enchexarray); // encrypt AES_CBC_encrypt_buffer(&ctx, enchexarray + 16, dsize); uint8_t *ret = malloc((dsize + 16) * sizeof(uint8_t)); if (!ret) { return ret; } memcpy(ret, enchexarray, (dsize + 16) * sizeof(uint8_t)); *osize = dsize + 16; return ret; } uint8_t *decrypt_cbc(int size, uint8_t *data, uint8_t *key, uint16_t *osize) { if (size <= 16) { return NULL; } // Make the uint8_t arrays uint8_t hexarray[size - 16]; // Initialize them with zeros memset(hexarray, 0, size - 16); // Fill the uint8_t arrays for (int i = 0; i < size - 16; i++) { hexarray[i] = (uint8_t)data[i + 16]; } // start the decryption struct AES_ctx ctx; AES_init_ctx_iv(&ctx, key, data); // decrypt AES_CBC_decrypt_buffer(&ctx, hexarray, size - 16); size_t dsize = pkcs7_padding_data_length(hexarray, size - 16, 16); if (dsize == 0) { dsize = size - 16; } uint8_t *ret = malloc(dsize * sizeof(uint8_t)); if (!ret) { return ret; } memcpy(ret, hexarray, dsize * sizeof(uint8_t)); *osize = dsize; return ret; } void enc_clear_ctx(void) { memset(enc_ctx.state.pw, 0, 32 * sizeof(uint16_t)); memset(enc_ctx.state.pw_check, 0, 32 * sizeof(uint16_t)); memset(enc_ctx.state.key, 0, 64 * sizeof(uint8_t)); enc_ctx.state.pw_ready = false; enc_ctx.state.pw_check_ready = false; enc_ctx.state.key_ready = false; enc_ctx.state.pw_size = 0; enc_ctx.state.pw_check_size = 0; enc_ctx.state.key_size = 0; enc_ctx.state.seed = 0; #ifdef ENC_HW_RND enc_ctx.state.seed_ready = true; #else enc_ctx.state.seed_ready = false; #endif enc_ctx.mode.sub_mode = ENC_SUB_MODE_NONE; enc_ctx.mode.pw_timeout_enabled = false; enc_ctx.mode.req_timeout_enabled = false; memset(&enc_ctx.keys, 0x00, 36 * sizeof(uint8_t)); } void enc_switch_mode(uint8_t mode) { enc_ctx.mode.sub_mode = ENC_SUB_MODE_NONE; switch (mode) { case ENC_MODE_CLOSED: enc_clear_ctx(); break; case ENC_MODE_INIT: case ENC_MODE_KEY: enc_ctx.mode.sub_mode = ENC_SUB_MODE_SEED; break; } enc_ctx.mode.mode = mode; } void enc_config_store(void) { eeprom_write_block(&enc_ctx.cnf, (uint8_t *)ENC_EEPROM_ADDR, ENC_EEPROM_SIZE); } int enc_config_load(void) { if (enc_ctx.state.cfg_ready) { return 0; } memset(&enc_ctx.cnf, 0x00, sizeof(enc_config_t)); eeprom_read_block(&enc_ctx.cnf, (uint8_t *)ENC_EEPROM_ADDR, ENC_EEPROM_SIZE); // validating paranoia mode -> need hw support for read data protection if (enc_ctx.cnf.flags.paranoia_mode == ENC_TRUE) { #ifdef ENC_OPTLOCK enc_ctx.cnf.flags.paranoia_mode = enc_is_flash_locked(); #else // paranoia mode not supported enc_ctx.cnf.flags.paranoia_mode = ENC_FALSE; #endif } enc_ctx.state.cfg_ready = true; return 0; } int enc_unlock(void) { enc_config_load(); if (!enc_ctx.state.pw_ready) { return -1; } eeprom_read_block(&enc_ctx.cnf, (uint8_t *)ENC_EEPROM_ADDR, ENC_EEPROM_SIZE); unsigned char pw_hash[32]; memset(pw_hash, 0x00, 32); PKCS5_PBKDF2_HMAC((unsigned char *)enc_ctx.state.pw, enc_ctx.state.pw_size * 2, (unsigned char *)enc_ctx.cnf.salt, 16, 2000, 32, pw_hash); int size = 32; uint8_t *vsalt = decrypt_cbc(size, enc_ctx.cnf.validate, pw_hash, (uint16_t *)&size); if (!vsalt) { return -1; } if (memcmp(vsalt, enc_ctx.cnf.salt, 16 * sizeof(uint8_t)) != 0) { free(vsalt); if (enc_ctx.cnf.flags.paranoia_mode == ENC_TRUE) { if ((enc_ctx.cnf.flags.error_count >= enc_ctx.cnf.flags.max_error) && enc_ctx.cnf.flags.max_error > 0) { memset(&enc_ctx.cnf, 0x00, ENC_EEPROM_SIZE); enc_config_store(); return -1; } enc_ctx.cnf.flags.error_count++; enc_config_store(); } return -1; } free(vsalt); if (enc_ctx.cnf.flags.paranoia_mode == ENC_TRUE) { enc_ctx.cnf.flags.error_count = 0; enc_config_store(); } size = 52; uint8_t *keys = decrypt_cbc(size, enc_ctx.cnf.key_store, pw_hash, (uint16_t *)&size); if (!keys) { return -1; } memcpy(&enc_ctx.keys, keys, 36 * sizeof(uint8_t)); enc_ctx.state.seed = enc_ctx.keys.seed; enc_ctx.state.seed_ready = true; if (enc_ctx.cnf.flags.timeout > 0) { enc_ctx.state.pw_timer = timer_read32(); enc_ctx.mode.pw_timeout_enabled = true; enc_ctx.mode.pw_timeout = ((enc_ctx.cnf.flags.timeout * 60000) - timer_elapsed32(enc_ctx.state.pw_timer)) / 1000; } return 0; } void encrypt_keys(void) { if (!enc_ctx.state.pw_ready) { return; } unsigned char pw_hash[32]; memset(pw_hash, 0x00, 32); PKCS5_PBKDF2_HMAC((unsigned char *)enc_ctx.state.pw, enc_ctx.state.pw_size * 2, (unsigned char *)enc_ctx.cnf.salt, 16, 2000, 32, pw_hash); int size = 36; uint8_t *keys = encrypt_cbc(size, (uint8_t *)&enc_ctx.keys, pw_hash, (uint16_t *)&size); if (!keys) { return; } memcpy(enc_ctx.cnf.key_store, keys, size * sizeof(uint8_t)); free(keys); size = 16; uint8_t *validate = encrypt_cbc(size, (uint8_t *)&enc_ctx.cnf.salt, pw_hash, (uint16_t *)&size); if (!validate) { return; } memcpy(enc_ctx.cnf.validate, validate, size * sizeof(uint8_t)); free(validate); /*memset(enc_ctx.cnf.keys.s, 0x00, 64*sizeof(uint8_t));*/ } int initialize_enc(uint8_t *key, uint8_t *iv, bool use_state_key) { enc_ctx.cnf.flags.max_error = 0; enc_ctx.cnf.flags.error_count = 0; enc_ctx.cnf.flags.paranoia_mode = ENC_FALSE; enc_ctx.cnf.flags.secure_mode = ENC_FALSE; enc_ctx.cnf.flags.timeout = 0; enc_ctx.mode.pw_timeout_enabled = false; enc_ctx.mode.req_timeout_enabled = false; enc_ctx.cnf.flags.initialized = ENC_TRUE; // set to zero memset(enc_ctx.cnf.identifier, 0x00, 8 * sizeof(uint8_t)); memset(enc_ctx.cnf.salt, 0x00, 16 * sizeof(uint8_t)); memset(enc_ctx.cnf.validate, 0x00, 32 * sizeof(uint8_t)); memset(&enc_ctx.keys, 0x00, 36 * sizeof(uint8_t)); if (key && iv) { // todo restore return -1; } enc_rnd_init(); for (int i = 0; i < 8;) { uint32_t rnd = enc_rnd_get(); uint8_t *v = (uint8_t *)&rnd; for (int j = 0; j < 4; j++, v++, i++) { enc_ctx.cnf.identifier[i] = *v; } } for (int i = 0; i < 16;) { uint32_t rnd = enc_rnd_get(); uint8_t *v = (uint8_t *)&rnd; for (int j = 0; j < 4; j++, v++, i++) { enc_ctx.cnf.salt[i] = *v; } } if (!use_state_key) { for (int i = 0; i < 32;) { uint32_t rnd = enc_rnd_get(); uint8_t *v = (uint8_t *)&rnd; for (int j = 0; j < 4; j++, v++, i++) { enc_ctx.keys.key[i] = *v; } } } else { char hex[2]; int ki = 0; char *ptr; for (int i = 0; i < 64; i+=2, ki++) { hex[0] = enc_ctx.state.key[i]; hex[1] = enc_ctx.state.key[i+1]; enc_ctx.keys.key[ki] = (uint8_t) strtol(hex, &ptr, 16); } } enc_ctx.keys.seed = enc_ctx.state.seed; enc_rnd_deinit(); encrypt_keys(); enc_config_store(); return 0; } void _enc_clear_request(void) { if (enc_request.data.data) free(enc_request.data.data); enc_request.req_header.magic[0] = 0; enc_request.req_header.magic[1] = 0; enc_request.req_header.size = 0; enc_request.req_header.cmd = ENC_CMD_NONE; enc_request.req_header.id = 0; enc_request.req_cmd = ENC_CMD_NONE; enc_request.req_id = 0; enc_request.state_cmd = ENC_CMD_NONE; enc_request.state_cmd_old = ENC_CMD_NONE; // res_data must be only a pointer to usb hid data -> free is never needed enc_request.res_data = NULL; enc_request.req_timer = 0; } void _enc_set_response_data_status(uint8_t status, uint8_t *data, bool zero) { if (zero && data) memset(data, 0x00, RAW_EPSIZE * sizeof(uint8_t)); data[0] = status; } void _enc_set_response_status(uint8_t status, bool zero) { _enc_set_response_data_status(status, enc_request.res_data, zero); if ((status != ENC_ERR_OK) && (status != ENC_ERR_RETRY) && (status != ENC_ERR_MORE_DATA)) { // reset request on errors _enc_clear_request(); } } int _enc_init_request(uint8_t *data) { _enc_clear_request(); memcpy(&enc_request.req_header, data, ENC_REQUEST_HEADER_LEN); if ((enc_request.req_header.magic[0] != 0x03) || (enc_request.req_header.magic[1] != 0xFF)) { // magic number not matching -> calling custom raw_hid_receive function return -66; } // get keys has a fixed size of 32 if (enc_request.req_header.cmd == ENC_CMD_GET_KEYS) enc_request.req_header.size = 32; enc_request.res_data = data; enc_request.data.dpos = 0; enc_request.data.dsize = enc_request.req_header.size; enc_request.data.data = malloc(enc_request.data.dsize * sizeof(uint8_t)); if (!enc_request.data.data) { _enc_set_response_status(ENC_ERR_EMPTY_BUF, true); return -1; } enc_request.req_cmd = enc_request.req_header.cmd; enc_request.req_id = enc_request.req_header.id; enc_request.req_timer = timer_read32(); return 0; } bool _enc_request_verification(void) { if (enc_request.req_header.id != enc_request.req_id) { _enc_set_response_status(ENC_ERR_NOT_ALLOWED, true); return false; } // set timeout if no response is received enc_request.req_timer = timer_read32(); return true; } bool _enc_request_approval(void) { if (enc_ctx.cnf.flags.secure_mode) { if (enc_ctx.mode.req_cmd != enc_request.req_cmd) { enc_ctx.mode.sub_mode = ENC_SUB_MODE_NONE; enc_ctx.mode.req_timeout_enabled = false; } switch (enc_ctx.mode.sub_mode) { case ENC_SUB_MODE_NONE: enc_ctx.mode.sub_mode = ENC_SUB_MODE_REQUEST; enc_ctx.mode.req_cmd = enc_request.req_cmd; enc_ctx.state.req_timer = timer_read32(); enc_ctx.mode.req_timeout_enabled = true; enc_ctx.mode.req_timeout = ((15 * 1000) - timer_elapsed32(enc_ctx.state.req_timer)) / 1000; _enc_set_response_status(ENC_ERR_RETRY, true); uint16_t size = 5; memcpy(enc_request.res_data + 1, &size, sizeof(uint16_t)); enc_request.res_data[4] = enc_ctx.mode.req_cmd; memcpy(enc_request.res_data + 5, &enc_ctx.mode.req_timeout, sizeof(uint32_t)); return false; case ENC_SUB_MODE_REQUEST: _enc_set_response_status(ENC_ERR_RETRY, true); size = 5; memcpy(enc_request.res_data + ENC_RESPONSE_HEADER_POS_SIZE, &size, sizeof(uint16_t)); enc_request.res_data[ENC_RESPONSE_HEADER_LEN + 1] = enc_ctx.mode.req_cmd; memcpy(enc_request.res_data + ENC_RESPONSE_HEADER_LEN + 2, &enc_ctx.mode.req_timeout, sizeof(uint32_t)); return false; case ENC_SUB_MODE_REQUEST_DENY: enc_ctx.mode.sub_mode = ENC_SUB_MODE_NONE; enc_ctx.mode.req_timeout_enabled = false; _enc_set_response_status(ENC_ERR_NOT_ALLOWED, true); return false; case ENC_SUB_MODE_REQUEST_ALLOW: enc_ctx.mode.sub_mode = ENC_SUB_MODE_NONE; enc_ctx.mode.req_timeout_enabled = false; return true; } } return true; } void _enc_cmd_get_mode(uint8_t*); void _enc_cmd_get_bufsize(uint8_t*); void _enc_cmd_get_cfg(uint8_t*); int _enc_handle_request(uint8_t *data) { enc_request_header_t enc_request_header; memcpy(&enc_request_header, data, ENC_REQUEST_HEADER_LEN); if ((enc_request_header.magic[0] != 0x03) || (enc_request_header.magic[1] != 0xFF)) { // magic number not matching -> calling custom raw_hid_receive function return -66; } switch (enc_request_header.cmd) { case ENC_CMD_GET_MODE: _enc_cmd_get_mode(data); return 0; case ENC_CMD_GET_BUFSIZE: _enc_cmd_get_bufsize(data); return 0; case ENC_CMD_GET_CFG: _enc_cmd_get_cfg(data); return 0; default: if (enc_ctx.mode.mode == ENC_MODE_KEY || enc_ctx.mode.mode == ENC_MODE_INIT || enc_ctx.mode.mode == ENC_MODE_LOAD) { _enc_set_response_status(ENC_ERR_NOT_ALLOWED, true); return -1; } break; } if (enc_request.req_cmd == ENC_CMD_NONE) { int ret = _enc_init_request(data); if (ret) return ret; } switch (enc_request.req_cmd) { case ENC_CMD_UNLOCK: case ENC_CMD_LOCK: case ENC_CMD_RESET: case ENC_CMD_ENCRYPT: case ENC_CMD_DECRYPT: case ENC_CMD_SET_KEYS: case ENC_CMD_GET_KEYS: case ENC_CMD_SET_CFG: case ENC_CMD_INITIALIZE: break; default: _enc_set_response_status(ENC_ERR_INVALID, true); return -1; } // approval needed for some requests if (enc_request.state_cmd == ENC_CMD_NONE) { if (!_enc_request_approval()) return -1; enc_request.state_cmd = enc_request.req_cmd; } // verify request origin if (!_enc_request_verification()) return -1; switch (enc_request.req_cmd) { case ENC_CMD_ENCRYPT: case ENC_CMD_DECRYPT: case ENC_CMD_SET_KEYS: if (enc_request.state_cmd == enc_request.req_cmd) enc_request.state_cmd = ENC_CMD_SET_BUFFER; break; case ENC_CMD_GET_KEYS: if (enc_request.state_cmd == enc_request.req_cmd) enc_request.state_cmd = ENC_CMD_GET_BUFFER; break; } return 0; } void _enc_cmd_get_buffer(void) { _enc_set_response_status(ENC_ERR_MORE_DATA, true); int boundary = RAW_EPSIZE - ENC_RESPONSE_HEADER_LEN; int data_boundary = enc_request.data.dsize - enc_request.data.dpos; uint16_t size = data_boundary; if (size > boundary) { size = boundary; } memcpy(enc_request.res_data + ENC_RESPONSE_HEADER_POS_SIZE, &size, sizeof(uint16_t)); memcpy(enc_request.res_data + ENC_RESPONSE_HEADER_LEN, enc_request.data.data + enc_request.data.dpos, size * sizeof(uint8_t)); if (data_boundary <= boundary) { _enc_set_response_status(ENC_ERR_OK, false); _enc_clear_request(); return; } enc_request.data.dpos += boundary; } void _enc_cmd_set_buffer(void) { bool fin = false; int boundary = RAW_EPSIZE - ENC_REQUEST_HEADER_LEN; if ((enc_request.data.dsize - enc_request.data.dpos) <= boundary) { fin = true; boundary = enc_request.data.dsize - enc_request.data.dpos; } memcpy(enc_request.data.data + enc_request.data.dpos, enc_request.res_data + ENC_REQUEST_HEADER_LEN, boundary); enc_request.data.dpos += boundary; if (fin) { enc_request.data.dpos = 0; enc_request.state_cmd = ENC_CMD_GET_BUFFER; _enc_set_response_status(ENC_ERR_MORE_DATA, true); return; } _enc_set_response_status(ENC_ERR_OK, true); } void _enc_cmd_reset(void) { if (enc_ctx.mode.mode != ENC_MODE_OPEN) { _enc_set_response_status(ENC_ERR_NO_CTX, true); return; } memset(&enc_ctx.cnf, 0x00, ENC_EEPROM_SIZE); memset(&enc_ctx.state, 0x00, sizeof(enc_state_t)); enc_config_store(); enc_switch_mode(ENC_MODE_CLOSED); _enc_set_response_status(ENC_ERR_OK, true); _enc_clear_request(); } bool _enc_cmd_encrypt(void) { if (enc_ctx.mode.mode != ENC_MODE_OPEN) { _enc_set_response_status(ENC_ERR_NO_CTX, true); return false; } // already encrypted if (enc_request.data.dpos != 0) return true; uint8_t *enc_data = encrypt_cbc(enc_request.data.dsize, enc_request.data.data, enc_ctx.keys.key, &enc_request.data.dsize); if (!enc_data) { _enc_set_response_status(ENC_ERR_EMPTY_BUF, true); return false; } if (enc_request.data.data) { free(enc_request.data.data); } enc_request.data.data = malloc(enc_request.data.dsize * sizeof(uint8_t)); if (!enc_request.data.data) { free(enc_data); _enc_set_response_status(ENC_ERR_EMPTY_BUF, true); return false; } memcpy(enc_request.data.data, enc_data, enc_request.data.dsize * sizeof(uint8_t)); free(enc_data); return true; } bool _enc_cmd_decrypt(void) { if (enc_ctx.mode.mode != ENC_MODE_OPEN) { _enc_set_response_status(ENC_ERR_NO_CTX, true); return false; } // already decrypted if (enc_request.data.dpos != 0) return true; uint8_t *dec_data = decrypt_cbc(enc_request.data.dsize, enc_request.data.data, enc_ctx.keys.key, &enc_request.data.dsize); if (!dec_data) { _enc_set_response_status(ENC_ERR_EMPTY_BUF, true); return false; } if (enc_request.data.data) { free(enc_request.data.data); } enc_request.data.data = malloc(enc_request.data.dsize * sizeof(uint8_t)); if (!enc_request.data.data) { free(dec_data); _enc_set_response_status(ENC_ERR_EMPTY_BUF, true); return false; } memcpy(enc_request.data.data, dec_data, enc_request.data.dsize * sizeof(uint8_t)); free(dec_data); return true; } void _enc_cmd_unlock(void) { if (enc_ctx.mode.mode == ENC_MODE_OPEN) return; enc_switch_mode(ENC_MODE_LOAD); _enc_set_response_status(ENC_ERR_OK, true); _enc_clear_request(); } void _enc_cmd_lock(void) { if (enc_ctx.mode.mode != ENC_MODE_OPEN) return; enc_switch_mode(ENC_MODE_CLOSED); _enc_set_response_status(ENC_ERR_OK, true); _enc_clear_request(); } void _enc_cmd_set_cfg(void) { if (enc_request.req_header.size != 2) { _enc_set_response_status(ENC_ERR_INVALID, true); return; } if (enc_ctx.mode.mode != ENC_MODE_OPEN) { _enc_set_response_status(ENC_ERR_NO_CTX, true); return; } uint8_t cfg = enc_request.res_data[ENC_REQUEST_HEADER_LEN]; uint8_t val = enc_request.res_data[ENC_REQUEST_HEADER_LEN+1]; switch (cfg) { case ENC_CFG_PARANOIA: if (val != ENC_TRUE && val != ENC_FALSE) { _enc_set_response_status(ENC_ERR_INVALID, true); return; } if (enc_ctx.cnf.flags.paranoia_mode == ENC_TRUE) { _enc_set_response_status(ENC_ERR_NOT_ALLOWED, true); return; } #ifdef ENC_OPTLOCK enc_flash_lock(); if (enc_is_flash_locked() != ENC_TRUE) { _enc_set_response_status(ENC_ERR_INVALID, true); return; } #else _enc_set_response_status(ENC_ERR_HW_SUPPORT, true); return; #endif enc_ctx.cnf.flags.paranoia_mode = val; break; case ENC_CFG_SECURE: if (val != ENC_TRUE && val != ENC_FALSE) { _enc_set_response_status(ENC_ERR_INVALID, true); return; } enc_ctx.cnf.flags.secure_mode = val; break; case ENC_CFG_MAX_ERROR: if (val < 0 || val > 15) { _enc_set_response_status(ENC_ERR_INVALID, true); return; } enc_ctx.cnf.flags.max_error = val; break; case ENC_CFG_TIMEOUT: if (val < 0 || val > 60) { _enc_set_response_status(ENC_ERR_INVALID, true); return; } if (val != enc_ctx.cnf.flags.timeout) { enc_ctx.cnf.flags.timeout = val; if (val > 0) { enc_ctx.state.pw_timer = timer_read32(); enc_ctx.mode.pw_timeout_enabled = true; enc_ctx.mode.pw_timeout = ((enc_ctx.cnf.flags.timeout * 60000) - timer_elapsed32(enc_ctx.state.pw_timer)) / 1000; } else { enc_ctx.mode.pw_timeout_enabled = false; } } break; default: _enc_set_response_status(ENC_ERR_INVALID, true); return; } enc_config_store(); _enc_set_response_status(ENC_ERR_OK, true); } void _enc_cmd_get_mode(uint8_t *data) { _enc_set_response_data_status(ENC_ERR_OK, data, true); uint16_t size = 2; memcpy(data + 1, &size, sizeof(uint16_t)); data[3] = enc_ctx.mode.mode; data[4] = enc_ctx.mode.sub_mode; } void _enc_cmd_get_cfg(uint8_t *data) { _enc_set_response_data_status(ENC_ERR_OK, data, true); uint16_t size = 6; memcpy(data + 1, &size, sizeof(uint16_t)); data[3] = enc_ctx.cnf.flags.max_error; data[4] = enc_ctx.cnf.flags.error_count; data[5] = enc_ctx.cnf.flags.paranoia_mode; data[6] = enc_ctx.cnf.flags.secure_mode; data[7] = enc_ctx.cnf.flags.timeout; data[8] = enc_ctx.cnf.flags.initialized; } void _enc_cmd_get_bufsize(uint8_t *data) { _enc_set_response_data_status(ENC_ERR_OK, data, true); uint16_t size = 1; memcpy(data + 1, &size, sizeof(uint16_t)); data[3] = RAW_EPSIZE; } bool _enc_cmd_get_keys(void) { if (enc_ctx.mode.mode != ENC_MODE_OPEN) { _enc_set_response_status(ENC_ERR_NO_CTX, true); return false; } // already copied if (enc_request.data.dpos != 0) return true; memcpy(enc_request.data.data, enc_ctx.keys.key, 32 * sizeof(uint8_t)); return true; } bool _enc_cmd_set_keys(void) { if (enc_ctx.mode.mode != ENC_MODE_OPEN) { _enc_set_response_status(ENC_ERR_NO_CTX, true); return false; } // already copied if (enc_request.data.dpos != 0) return true; if (enc_request.data.dsize != 32) { _enc_set_response_status(ENC_ERR_INVALID, true); return false; } memcpy(enc_ctx.keys.key, enc_request.data.data, enc_request.data.dsize * sizeof(uint8_t)); encrypt_keys(); enc_config_store(); return true; } void _enc_cmd_initialize(void) { _enc_set_response_status(ENC_ERR_OK, true); memset(&enc_ctx.cnf, 0x00, sizeof(enc_config_t)); enc_config_store(); _enc_clear_request(); } void housekeeping_task_kb(void) { if (enc_request.req_cmd != ENC_CMD_NONE) { if (timer_elapsed32(enc_request.req_timer) >= (ENC_HID_REQUEST_TIMEOUT * 1000)) _enc_clear_request(); } if (enc_ctx.mode.sub_mode == ENC_SUB_MODE_REQUEST) { if (timer_elapsed32(enc_ctx.state.req_timer) >= (15 * 1000)) { enc_ctx.mode.sub_mode = ENC_SUB_MODE_NONE; } else { enc_ctx.mode.req_timeout = ((15 * 1000) - timer_elapsed32(enc_ctx.state.req_timer)) / 1000; } } if (enc_ctx.mode.mode != ENC_MODE_OPEN) { return; } if (timer_elapsed32(enc_ctx.state.pw_timer) >= (enc_ctx.cnf.flags.timeout * 60000)) { if (!enc_ctx.mode.pw_timeout_enabled) { return; } enc_switch_mode(ENC_MODE_CLOSED); return; } enc_ctx.mode.pw_timeout = ((enc_ctx.cnf.flags.timeout * 60000) - timer_elapsed32(enc_ctx.state.pw_timer)) / 1000; } void enc_read_seed(uint16_t keycode) { if (!enc_ctx.state.seed_ready) { if (keycode != KC_ENT) { uint8_t *_keycode = (uint8_t *)&keycode; enc_ctx.state.seed = enc_ctx.state.seed + _keycode[0]; enc_ctx.state.seed = enc_ctx.state.seed + _keycode[1]; } else { enc_ctx.state.seed_ready = true; } } } int enc_read_pw(uint16_t keycode) { if (!enc_ctx.state.pw_ready) { if (keycode != KC_ENT) { if (enc_ctx.state.pw_size >= 32) { return -1; } enc_ctx.state.pw[enc_ctx.state.pw_size] = keycode; enc_ctx.state.pw_size++; } else { enc_ctx.state.pw_ready = true; return 0; } } return 0; } int enc_read_pw_check(uint16_t keycode) { if (!enc_ctx.state.pw_check_ready) { if (keycode != KC_ENT) { if (enc_ctx.state.pw_check_size >= 32) { return -1; } enc_ctx.state.pw_check[enc_ctx.state.pw_check_size] = keycode; enc_ctx.state.pw_check_size++; } else { if (enc_ctx.state.pw_check_size != enc_ctx.state.pw_size) { return -1; } if (memcmp(enc_ctx.state.pw, enc_ctx.state.pw_check, enc_ctx.state.pw_size * sizeof(uint16_t)) == 0) { enc_ctx.state.pw_check_ready = true; return 0; } else { return -1; } } } return 0; } int enc_read_key(uint16_t keycode) { if (!enc_ctx.state.key_ready) { if (keycode != KC_ENT) { if (enc_ctx.state.key_size >= 64) { return -1; } switch (keycode) { case KC_A: enc_ctx.state.key[enc_ctx.state.key_size] = 'a'; break; case KC_B: enc_ctx.state.key[enc_ctx.state.key_size] = 'b'; break; case KC_C: enc_ctx.state.key[enc_ctx.state.key_size] = 'c'; break; case KC_D: enc_ctx.state.key[enc_ctx.state.key_size] = 'd'; break; case KC_E: enc_ctx.state.key[enc_ctx.state.key_size] = 'e'; break; case KC_F: enc_ctx.state.key[enc_ctx.state.key_size] = 'f'; break; case KC_0: enc_ctx.state.key[enc_ctx.state.key_size] = '0'; break; case KC_1: enc_ctx.state.key[enc_ctx.state.key_size] = '1'; break; case KC_2: enc_ctx.state.key[enc_ctx.state.key_size] = '2'; break; case KC_3: enc_ctx.state.key[enc_ctx.state.key_size] = '3'; break; case KC_4: enc_ctx.state.key[enc_ctx.state.key_size] = '4'; break; case KC_5: enc_ctx.state.key[enc_ctx.state.key_size] = '5'; break; case KC_6: enc_ctx.state.key[enc_ctx.state.key_size] = '6'; break; case KC_7: enc_ctx.state.key[enc_ctx.state.key_size] = '7'; break; case KC_8: enc_ctx.state.key[enc_ctx.state.key_size] = '8'; break; case KC_9: enc_ctx.state.key[enc_ctx.state.key_size] = '9'; break; default: return -1; } enc_ctx.state.key[enc_ctx.state.key_size] = keycode; enc_ctx.state.key_size++; } else { if (enc_ctx.state.key_size != 64) { return -1; } enc_ctx.state.key_ready = true; return 0; } } return 0; } void pre_init_enc(void) { enc_config_load(); _enc_clear_request(); } void eeconfig_init_enc() { memset(&enc_ctx.cnf, 0x00, sizeof(enc_config_t)); enc_config_store(); } bool process_record_enc(uint16_t keycode, keyrecord_t *record) { switch (enc_ctx.mode.mode) { case ENC_MODE_INIT: if (!enc_ctx.state.seed_ready) { enc_ctx.mode.sub_mode = ENC_SUB_MODE_SEED; } else if (!enc_ctx.state.pw_ready && enc_ctx.state.seed_ready) { enc_ctx.mode.sub_mode = ENC_SUB_MODE_PASSWORD; } else { enc_ctx.mode.sub_mode = ENC_SUB_MODE_VERIFY_PASSWORD; } if (!record->event.pressed) { return true; } if (!enc_ctx.state.seed_ready) { enc_read_seed(keycode); return false; } if (!enc_ctx.state.pw_ready && enc_ctx.state.seed_ready) { int ret = enc_read_pw(keycode); if (ret != 0) { enc_switch_mode(ENC_MODE_CLOSED); } return false; } if (!enc_ctx.state.pw_check_ready && enc_ctx.state.pw_ready && enc_ctx.state.seed_ready) { int ret = enc_read_pw_check(keycode); if (ret != 0) { enc_switch_mode(ENC_MODE_CLOSED); } return false; } else { if (initialize_enc(NULL, NULL, false) != 0) { enc_switch_mode(ENC_MODE_CLOSED); } else { enc_switch_mode(ENC_MODE_OPEN); } } return false; break; case ENC_MODE_LOAD: if (!record->event.pressed) { return true; } enc_read_pw(keycode); if (enc_ctx.state.pw_ready) { if (enc_unlock() != 0) { enc_switch_mode(ENC_MODE_CLOSED); } else { enc_switch_mode(ENC_MODE_OPEN); } } return false; break; case ENC_MODE_KEY: if (!enc_ctx.state.seed_ready) { enc_ctx.mode.sub_mode = ENC_SUB_MODE_SEED; } else if (!enc_ctx.state.pw_ready && enc_ctx.state.seed_ready) { enc_ctx.mode.sub_mode = ENC_SUB_MODE_PASSWORD; } else if (!enc_ctx.state.pw_check_ready && enc_ctx.state.pw_ready && enc_ctx.state.seed_ready) { enc_ctx.mode.sub_mode = ENC_SUB_MODE_VERIFY_PASSWORD; } else { enc_ctx.mode.sub_mode = ENC_SUB_MODE_KEY; } if (!record->event.pressed) { return true; } if (!enc_ctx.state.seed_ready) { enc_read_seed(keycode); return false; } if (!enc_ctx.state.pw_ready && enc_ctx.state.seed_ready) { int ret = enc_read_pw(keycode); if (ret != 0) { enc_switch_mode(ENC_MODE_CLOSED); } return false; } if (!enc_ctx.state.pw_check_ready && enc_ctx.state.pw_ready && enc_ctx.state.seed_ready) { int ret = enc_read_pw_check(keycode); if (ret != 0) { enc_switch_mode(ENC_MODE_CLOSED); } return false; } if (!enc_ctx.state.key_ready && enc_ctx.state.pw_check_ready && enc_ctx.state.pw_ready && enc_ctx.state.seed_ready) { int ret = enc_read_key(keycode); if (ret != 0) { enc_switch_mode(ENC_MODE_CLOSED); } return false; } else { if (initialize_enc(NULL, NULL, true) != 0) { enc_switch_mode(ENC_MODE_CLOSED); } else { enc_switch_mode(ENC_MODE_OPEN); } } return false; break; } switch (keycode) { case ENC_INIT: if (record->event.pressed) { enc_clear_ctx(); enc_switch_mode(ENC_MODE_INIT); } return false; break; case ENC_LOAD: if (record->event.pressed) { enc_clear_ctx(); enc_switch_mode(ENC_MODE_LOAD); } return false; break; case ENC_CLOSE: if (record->event.pressed) { enc_clear_ctx(); enc_switch_mode(ENC_MODE_CLOSED); } return false; break; case ENC_KEY: if (record->event.pressed) { enc_clear_ctx(); enc_switch_mode(ENC_MODE_KEY); } return false; break; case ENC_PASTE: if (record->event.pressed) { if (!enc_request.data.data) { return true; } uint8_t paste_buf[enc_request.data.dsize + 1]; memset(paste_buf, 0x00, enc_request.data.dsize + 1 * sizeof(uint8_t)); memcpy(paste_buf, enc_request.data.data, enc_request.data.dsize * sizeof(uint8_t)); send_string((const char *)paste_buf); /*send_unicode_string((const char *) paste_buf);*/ return false; } break; case ENC_KEYSPASTE: if (record->event.pressed) { if (enc_ctx.mode.mode != ENC_MODE_OPEN || enc_ctx.cnf.flags.paranoia_mode == ENC_TRUE) { return true; } char paste_buf[129]; memset(paste_buf, 0x00, 129 * sizeof(uint8_t)); char *buf_ptr = paste_buf; for (int i = 0; i < 64; i++, buf_ptr += 2) { sprintf(buf_ptr, "%02x", ((uint8_t *)&enc_ctx.keys)[i]); } send_string((const char *)paste_buf); /*send_unicode_string((const char *) paste_buf);*/ return false; } break; } /*uint8_t *_keycode = (uint8_t *) &keycode;*/ /*enc_ctx.state.seed = enc_ctx.state.seed + _keycode[0];*/ /*enc_ctx.state.seed = enc_ctx.state.seed + _keycode[1];*/ /*enc_ctx.keys.seed = enc_ctx.state.seed;*/ if (enc_ctx.mode.sub_mode == ENC_SUB_MODE_REQUEST) { if (record->event.pressed) { switch (keycode) { case ENC_REQ_ALLOW: enc_ctx.mode.sub_mode = ENC_SUB_MODE_REQUEST_ALLOW; break; case ENC_REQ_DENY: enc_ctx.mode.sub_mode = ENC_SUB_MODE_REQUEST_DENY; break; default: return true; } return false; } } return true; } // Keyboard level code can override this to handle custom messages from ENC. // See raw_hid_receive() implementation. // DO NOT call raw_hid_send() in the override function. __attribute__((weak)) void raw_hid_receive_enc_kb(uint8_t *data, uint8_t length) {} void raw_hid_receive_enc(uint8_t *data, uint8_t length) { /*uint8_t cmd = data[2];*/ /*uint16_t size = 0;*/ int res = _enc_handle_request(data); if (res == -66) { return raw_hid_receive_enc_kb(data, length); } if (res) { return; } switch (enc_request.state_cmd) { case ENC_CMD_RESET: _enc_cmd_reset(); break; case ENC_CMD_UNLOCK: _enc_cmd_unlock(); break; case ENC_CMD_LOCK: _enc_cmd_lock(); break; case ENC_CMD_SET_CFG: _enc_cmd_set_cfg(); _enc_clear_request(); break; case ENC_CMD_GET_BUFFER: bool error = false; switch (enc_request.req_cmd) { case ENC_CMD_ENCRYPT: if (!_enc_cmd_encrypt()) error = true; break; case ENC_CMD_DECRYPT: if (!_enc_cmd_decrypt()) error = true; break; case ENC_CMD_GET_KEYS: if (!_enc_cmd_get_keys()) error = true; break; case ENC_CMD_SET_KEYS: if (!_enc_cmd_set_keys()) error = true; break; } if (error) { _enc_clear_request(); break; } _enc_cmd_get_buffer(); break; case ENC_CMD_SET_BUFFER: _enc_cmd_set_buffer(); break; case ENC_CMD_INITIALIZE: _enc_cmd_initialize(); break; case ENC_CMD_NONE: break; default: raw_hid_receive_enc_kb(data, length); break; } } #ifndef VIA_ENABLE void raw_hid_receive(uint8_t *data, uint8_t length) { raw_hid_receive_enc(data, length); raw_hid_send(data, length); } #else void raw_hid_receive_kb(uint8_t *data, uint8_t length) { raw_hid_receive_enc(data, length); } #endif enc_config_flags_t enc_get_config_flags(void) { return enc_ctx.cnf.flags; } void enc_set_config_flags(enc_config_flags_t flags) { memcpy(&enc_ctx.cnf.flags, &flags, sizeof(enc_config_flags_t)); } enc_mode_t enc_get_mode(void) { return enc_ctx.mode; } void enc_set_mode(enc_mode_t mode) { memcpy(&enc_ctx.mode, &mode, sizeof(enc_mode_t)); } const char *enc_mode_to_str(uint8_t mode) { switch (mode) { case ENC_MODE_CLOSED: return "CLOSED"; case ENC_MODE_OPEN: return "OPEN"; case ENC_MODE_LOAD: return "LOAD"; case ENC_MODE_INIT: return "INIT"; } return "UNKNOWN"; } const char *enc_sub_mode_to_str(uint8_t mode) { switch (mode) { case ENC_SUB_MODE_NONE: return "NONE"; case ENC_SUB_MODE_SEED: return "SEED"; case ENC_SUB_MODE_PASSWORD: return "PASSWORD"; case ENC_SUB_MODE_VERIFY_PASSWORD: return "VERIFY PASSWORD"; case ENC_SUB_MODE_REQUEST: return "REQUEST"; case ENC_SUB_MODE_REQUEST_ALLOW: return "REQUEST ALLOW"; case ENC_SUB_MODE_REQUEST_DENY: return "REQUEST DENY"; case ENC_SUB_MODE_KEY: return "KEY"; } return "UNKNOWN"; } const char *enc_cmd_to_str(uint8_t cmd) { switch (cmd) { case ENC_CMD_RESET: return "Reset"; case ENC_CMD_ENCRYPT: return "Encrypt"; case ENC_CMD_DECRYPT: return "Decrypt"; case ENC_CMD_MORE_DATA: return "More Data"; case ENC_CMD_UNLOCK: return "Unlock"; case ENC_CMD_LOCK: return "Lock"; case ENC_CMD_SET_CFG: return "Set Config"; case ENC_CMD_GET_MODE: return "Get Mode"; case ENC_CMD_GET_BUFFER: return "Get Buffer"; case ENC_CMD_GET_KEYS: return "Get Keys"; case ENC_CMD_GET_BUFSIZE: return "Get Bufsize"; case ENC_CMD_SET_KEYS: return "Set Keys"; case ENC_CMD_GET_CFG: return "Get Config"; case ENC_CMD_INITIALIZE: return "Initialize"; default: return "Unknown"; } } const char *enc_bool_to_str(int val) { if (val == ENC_TRUE) { return "X"; } return "-"; } void enc_write_oled(bool invert) { #ifdef OLED_ENABLE for (int i = 0; i < oled_max_lines(); i++) { for (int j = 0; j < oled_max_chars(); j++) { oled_set_cursor(i, j); oled_write_P(PSTR(" "), false); } } oled_set_cursor(0, 0); switch (enc_ctx.mode.mode) { case ENC_MODE_OPEN: oled_write_P(PSTR("E: OPEN"), invert); if (enc_ctx.mode.pw_timeout_enabled) { oled_write_P(PSTR(" "), invert); oled_write(get_u16_str(enc_ctx.mode.pw_timeout, ' '), invert); oled_write_P(PSTR("s"), invert); } oled_write_P(PSTR("\n"), invert); break; case ENC_MODE_LOAD: oled_write_P(PSTR("E: LOAD - Enter Password\n"), invert); return; case ENC_MODE_INIT: oled_write_P(PSTR("E: INIT - "), invert); switch (enc_ctx.mode.sub_mode) { case ENC_SUB_MODE_SEED: oled_write_P(PSTR("Enter Seed"), invert); break; case ENC_SUB_MODE_PASSWORD: oled_write_P(PSTR("Enter Password"), invert); break; case ENC_SUB_MODE_VERIFY_PASSWORD: oled_write_P(PSTR("Enter Password again"), invert); break; case ENC_SUB_MODE_KEY: oled_write_P(PSTR("Enter Key in hex"), invert); break; } oled_write_P(PSTR("\n"), invert); return; default: oled_write_P(PSTR("E: CLOSED\n"), invert); break; } if (enc_ctx.mode.sub_mode == ENC_SUB_MODE_REQUEST) { oled_write_P(PSTR("E: Allow "), invert); oled_write_P(PSTR(enc_cmd_to_str(enc_ctx.mode.req_cmd)), invert); oled_write_P(PSTR("?"), invert); oled_write(get_u8_str(enc_ctx.mode.req_timeout, ' '), invert); oled_write_P(PSTR("s\n"), invert); return; } oled_write_P(PSTR("EF:I P S ME EC TO\n"), invert); oled_write_P(PSTR(" "), invert); oled_write_P(PSTR(enc_bool_to_str(enc_ctx.cnf.flags.initialized)), invert); oled_write_P(PSTR(" "), invert); oled_write_P(PSTR(enc_bool_to_str(enc_ctx.cnf.flags.paranoia_mode)), invert); oled_write_P(PSTR(" "), invert); oled_write_P(PSTR(enc_bool_to_str(enc_ctx.cnf.flags.secure_mode)), invert); oled_write(get_u8_str(enc_ctx.cnf.flags.max_error, ' '), invert); oled_write(get_u8_str(enc_ctx.cnf.flags.error_count, ' '), invert); oled_write(get_u8_str(enc_ctx.cnf.flags.timeout, ' '), invert); oled_write_P(PSTR("\n"), invert); #else return; #endif }