From 43ef5cedf078cbaed73a0ca5f93055076fb3230f Mon Sep 17 00:00:00 2001 From: Matthias Fulz Date: Sun, 26 Jun 2022 21:36:17 +0200 Subject: [PATCH] Updated encryption feature to new master -> something totally broke... --- builddefs/common_features.mk | 11 + builddefs/show_options.mk | 3 +- quantum/enc/aes.c | 572 ++++++++ quantum/enc/aes.h | 91 ++ quantum/enc/enc.c | 1250 +++++++++++++++++ quantum/enc/enc.h | 165 +++ quantum/enc/enc_boards/enc_boards.h | 14 + quantum/enc/enc_boards/enc_boards.mk | 3 + .../enc_boards/enc_stm32f40xx_stm32f41xx.c | 51 + quantum/enc/pbkdf2-sha256.h | 855 +++++++++++ quantum/enc/pkcs7_padding.c | 56 + quantum/enc/pkcs7_padding.h | 24 + quantum/quantum.c | 3 + quantum/quantum.h | 4 + quantum/quantum_keycodes.h | 11 + quantum/split_common/transaction_id_define.h | 8 + quantum/split_common/transactions.c | 53 + quantum/split_common/transport.h | 8 + quantum/via.h | 9 +- 19 files changed, 3189 insertions(+), 2 deletions(-) create mode 100644 quantum/enc/aes.c create mode 100644 quantum/enc/aes.h create mode 100644 quantum/enc/enc.c create mode 100644 quantum/enc/enc.h create mode 100644 quantum/enc/enc_boards/enc_boards.h create mode 100644 quantum/enc/enc_boards/enc_boards.mk create mode 100644 quantum/enc/enc_boards/enc_stm32f40xx_stm32f41xx.c create mode 100644 quantum/enc/pbkdf2-sha256.h create mode 100644 quantum/enc/pkcs7_padding.c create mode 100644 quantum/enc/pkcs7_padding.h diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index c976b8296d..06d9de51a7 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -556,6 +556,17 @@ ifeq ($(strip $(VIA_ENABLE)), yes) OPT_DEFS += -DVIA_ENABLE endif +ifeq ($(strip $(ENC_ENABLE)), yes) + RAW_ENABLE := yes + COMMON_VPATH += $(QUANTUM_DIR)/enc + COMMON_VPATH += $(QUANTUM_DIR)/enc/enc_boards + include $(QUANTUM_DIR)/enc/enc_boards/enc_boards.mk + OPT_DEFS += -DENC_ENABLE + SRC += aes.c + SRC += pkcs7_padding.c + SRC += enc.c +endif + VALID_MAGIC_TYPES := yes BOOTMAGIC_ENABLE ?= no ifneq ($(strip $(BOOTMAGIC_ENABLE)), no) diff --git a/builddefs/show_options.mk b/builddefs/show_options.mk index f67d009191..f2ddf5c7e4 100644 --- a/builddefs/show_options.mk +++ b/builddefs/show_options.mk @@ -11,7 +11,8 @@ BUILD_OPTION_NAMES = \ SPLIT_KEYBOARD \ DYNAMIC_KEYMAP_ENABLE \ USB_HID_ENABLE \ - VIA_ENABLE + VIA_ENABLE \ + ENC_ENABLE HARDWARE_OPTION_NAMES = \ SLEEP_LED_ENABLE \ diff --git a/quantum/enc/aes.c b/quantum/enc/aes.c new file mode 100644 index 0000000000..b22f8ba4a0 --- /dev/null +++ b/quantum/enc/aes.c @@ -0,0 +1,572 @@ +/* + +This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode. +Block size can be chosen in aes.h - available choices are AES128, AES192, AES256. + +The implementation is verified against the test vectors in: + National Institute of Standards and Technology Special Publication 800-38A 2001 ED + +ECB-AES128 +---------- + + plain-text: + 6bc1bee22e409f96e93d7e117393172a + ae2d8a571e03ac9c9eb76fac45af8e51 + 30c81c46a35ce411e5fbc1191a0a52ef + f69f2445df4f9b17ad2b417be66c3710 + + key: + 2b7e151628aed2a6abf7158809cf4f3c + + resulting cipher + 3ad77bb40d7a3660a89ecaf32466ef97 + f5d3d58503b9699de785895a96fdbaaf + 43b1cd7f598ece23881b00e3ed030688 + 7b0c785e27e8ad3f8223207104725dd4 + + +NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) + You should pad the end of the string with zeros if this is not the case. + For AES192/256 the key size is proportionally larger. + +*/ + + +/*****************************************************************************/ +/* Includes: */ +/*****************************************************************************/ +#include // CBC mode, for memset +#include "aes.h" + +/*****************************************************************************/ +/* Defines: */ +/*****************************************************************************/ +// The number of columns comprising a state in AES. This is a constant in AES. Value=4 +#define Nb 4 + +#if defined(AES256) && (AES256 == 1) + #define Nk 8 + #define Nr 14 +#elif defined(AES192) && (AES192 == 1) + #define Nk 6 + #define Nr 12 +#else + #define Nk 4 // The number of 32 bit words in a key. + #define Nr 10 // The number of rounds in AES Cipher. +#endif + +// jcallan@github points out that declaring Multiply as a function +// reduces code size considerably with the Keil ARM compiler. +// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3 +#ifndef MULTIPLY_AS_A_FUNCTION + #define MULTIPLY_AS_A_FUNCTION 0 +#endif + + + + +/*****************************************************************************/ +/* Private variables: */ +/*****************************************************************************/ +// state - array holding the intermediate results during decryption. +typedef uint8_t state_t[4][4]; + + + +// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM +// The numbers below can be computed dynamically trading ROM for RAM - +// This can be useful in (embedded) bootloader applications, where ROM is often limited. +static const uint8_t sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +static const uint8_t rsbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; +#endif + +// The round constant word array, Rcon[i], contains the values given by +// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) +static const uint8_t Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +/* + * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), + * that you can remove most of the elements in the Rcon array, because they are unused. + * + * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon + * + * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed), + * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." + */ + + +/*****************************************************************************/ +/* Private functions: */ +/*****************************************************************************/ +/* +static uint8_t getSBoxValue(uint8_t num) +{ + return sbox[num]; +} +*/ +#define getSBoxValue(num) (sbox[(num)]) + +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) +{ + unsigned i, j, k; + uint8_t tempa[4]; // Used for the column/row operations + + // The first round key is the key itself. + for (i = 0; i < Nk; ++i) + { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + // All other round keys are found from the previous round keys. + for (i = Nk; i < Nb * (Nr + 1); ++i) + { + { + k = (i - 1) * 4; + tempa[0]=RoundKey[k + 0]; + tempa[1]=RoundKey[k + 1]; + tempa[2]=RoundKey[k + 2]; + tempa[3]=RoundKey[k + 3]; + + } + + if (i % Nk == 0) + { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + const uint8_t u8tmp = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = u8tmp; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an output word. + + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = tempa[0] ^ Rcon[i/Nk]; + } +#if defined(AES256) && (AES256 == 1) + if (i % Nk == 4) + { + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + } +#endif + j = i * 4; k=(i - Nk) * 4; + RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; + RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; + RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; + RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; + } +} + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) +{ + KeyExpansion(ctx->RoundKey, key); +} +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) +{ + KeyExpansion(ctx->RoundKey, key); + memcpy (ctx->Iv, iv, AES_BLOCKLEN); +} +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) +{ + memcpy (ctx->Iv, iv, AES_BLOCKLEN); +} +#endif + +// This function adds the round key to state. +// The round key is added to the state by an XOR function. +static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey) +{ + uint8_t i,j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + } + } +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void SubBytes(state_t* state) +{ + uint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxValue((*state)[j][i]); + } + } +} + +// The ShiftRows() function shifts the rows in the state to the left. +// Each row is shifted with different offset. +// Offset = Row number. So the first row is not shifted. +static void ShiftRows(state_t* state) +{ + uint8_t temp; + + // Rotate first row 1 columns to left + temp = (*state)[0][1]; + (*state)[0][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[3][1]; + (*state)[3][1] = temp; + + // Rotate second row 2 columns to left + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to left + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[3][3]; + (*state)[3][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[1][3]; + (*state)[1][3] = temp; +} + +static uint8_t xtime(uint8_t x) +{ + return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); +} + +// MixColumns function mixes the columns of the state matrix +static void MixColumns(state_t* state) +{ + uint8_t i; + uint8_t Tmp, Tm, t; + for (i = 0; i < 4; ++i) + { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; + Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; + Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; + Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; + Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; + } +} + +// Multiply is used to multiply numbers in the field GF(2^8) +// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary +// The compiler seems to be able to vectorize the operation better this way. +// See https://github.com/kokke/tiny-AES-c/pull/34 +#if MULTIPLY_AS_A_FUNCTION +static uint8_t Multiply(uint8_t x, uint8_t y) +{ + return (((y & 1) * x) ^ + ((y>>1 & 1) * xtime(x)) ^ + ((y>>2 & 1) * xtime(xtime(x))) ^ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ + } +#else +#define Multiply(x, y) \ + ( ((y & 1) * x) ^ \ + ((y>>1 & 1) * xtime(x)) ^ \ + ((y>>2 & 1) * xtime(xtime(x))) ^ \ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ + +#endif + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +/* +static uint8_t getSBoxInvert(uint8_t num) +{ + return rsbox[num]; +} +*/ +#define getSBoxInvert(num) (rsbox[(num)]) + +// MixColumns function mixes the columns of the state matrix. +// The method used to multiply may be difficult to understand for the inexperienced. +// Please use the references to gain more information. +static void InvMixColumns(state_t* state) +{ + int i; + uint8_t a, b, c, d; + for (i = 0; i < 4; ++i) + { + a = (*state)[i][0]; + b = (*state)[i][1]; + c = (*state)[i][2]; + d = (*state)[i][3]; + + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } +} + + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void InvSubBytes(state_t* state) +{ + uint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxInvert((*state)[j][i]); + } + } +} + +static void InvShiftRows(state_t* state) +{ + uint8_t temp; + + // Rotate first row 1 columns to right + temp = (*state)[3][1]; + (*state)[3][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[0][1]; + (*state)[0][1] = temp; + + // Rotate second row 2 columns to right + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to right + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[1][3]; + (*state)[1][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[3][3]; + (*state)[3][3] = temp; +} +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +// Cipher is the main function that encrypts the PlainText. +static void Cipher(state_t* state, const uint8_t* RoundKey) +{ + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(0, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr rounds are executed in the loop below. + // Last one without MixColumns() + for (round = 1; ; ++round) + { + SubBytes(state); + ShiftRows(state); + if (round == Nr) { + break; + } + MixColumns(state); + AddRoundKey(round, state, RoundKey); + } + // Add round key to last round + AddRoundKey(Nr, state, RoundKey); +} + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +static void InvCipher(state_t* state, const uint8_t* RoundKey) +{ + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(Nr, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr rounds are executed in the loop below. + // Last one without InvMixColumn() + for (round = (Nr - 1); ; --round) + { + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(round, state, RoundKey); + if (round == 0) { + break; + } + InvMixColumns(state); + } + +} +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +/*****************************************************************************/ +/* Public functions: */ +/*****************************************************************************/ +#if defined(ECB) && (ECB == 1) + + +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) +{ + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher((state_t*)buf, ctx->RoundKey); +} + +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) +{ + // The next function call decrypts the PlainText with the Key using AES algorithm. + InvCipher((state_t*)buf, ctx->RoundKey); +} + + +#endif // #if defined(ECB) && (ECB == 1) + + + + + +#if defined(CBC) && (CBC == 1) + + +static void XorWithIv(uint8_t* buf, const uint8_t* Iv) +{ + uint8_t i; + for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size + { + buf[i] ^= Iv[i]; + } +} + +void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, size_t length) +{ + size_t i; + uint8_t *Iv = ctx->Iv; + for (i = 0; i < length; i += AES_BLOCKLEN) + { + XorWithIv(buf, Iv); + Cipher((state_t*)buf, ctx->RoundKey); + Iv = buf; + buf += AES_BLOCKLEN; + } + /* store Iv in ctx for next call */ + memcpy(ctx->Iv, Iv, AES_BLOCKLEN); +} + +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) +{ + size_t i; + uint8_t storeNextIv[AES_BLOCKLEN]; + for (i = 0; i < length; i += AES_BLOCKLEN) + { + memcpy(storeNextIv, buf, AES_BLOCKLEN); + InvCipher((state_t*)buf, ctx->RoundKey); + XorWithIv(buf, ctx->Iv); + memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); + buf += AES_BLOCKLEN; + } + +} + +#endif // #if defined(CBC) && (CBC == 1) + + + +#if defined(CTR) && (CTR == 1) + +/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) +{ + uint8_t buffer[AES_BLOCKLEN]; + + size_t i; + int bi; + for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) + { + if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ + { + + memcpy(buffer, ctx->Iv, AES_BLOCKLEN); + Cipher((state_t*)buffer,ctx->RoundKey); + + /* Increment Iv and handle overflow */ + for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) + { + /* inc will overflow */ + if (ctx->Iv[bi] == 255) + { + ctx->Iv[bi] = 0; + continue; + } + ctx->Iv[bi] += 1; + break; + } + bi = 0; + } + + buf[i] = (buf[i] ^ buffer[bi]); + } +} + +#endif // #if defined(CTR) && (CTR == 1) + diff --git a/quantum/enc/aes.h b/quantum/enc/aes.h new file mode 100644 index 0000000000..223a2ef92d --- /dev/null +++ b/quantum/enc/aes.h @@ -0,0 +1,91 @@ +#ifndef _AES_H_ +#define _AES_H_ + +#include +#include + +// #define the macros below to 1/0 to enable/disable the mode of operation. +// +// CBC enables AES encryption in CBC-mode of operation. +// CTR enables encryption in counter-mode. +// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously. + +// The #ifndef-guard allows it to be configured before #include'ing or at compile time. +#ifndef CBC + #define CBC 1 +#endif + +#ifndef ECB + #define ECB 1 +#endif + +#ifndef CTR + #define CTR 1 +#endif + + +//#define AES128 1 +//#define AES192 1 +#define AES256 1 + +#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only + +#if defined(AES256) && (AES256 == 1) + #define AES_KEYLEN 32 + #define AES_keyExpSize 240 +#elif defined(AES192) && (AES192 == 1) + #define AES_KEYLEN 24 + #define AES_keyExpSize 208 +#else + #define AES_KEYLEN 16 // Key length in bytes + #define AES_keyExpSize 176 +#endif + +struct AES_ctx +{ + uint8_t RoundKey[AES_keyExpSize]; +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + uint8_t Iv[AES_BLOCKLEN]; +#endif +}; + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); +#endif + +#if defined(ECB) && (ECB == 1) +// buffer size is exactly AES_BLOCKLEN bytes; +// you need only AES_init_ctx as IV is not used in ECB +// NB: ECB is considered insecure for most uses +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); + +#endif // #if defined(ECB) && (ECB == !) + + +#if defined(CBC) && (CBC == 1) +// buffer size MUST be mutile of AES_BLOCKLEN; +// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); + +#endif // #if defined(CBC) && (CBC == 1) + + +#if defined(CTR) && (CTR == 1) + +// Same function for encrypting as for decrypting. +// IV is incremented for every block, and used after encryption as XOR-compliment for output +// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); + +#endif // #if defined(CTR) && (CTR == 1) + + +#endif // _AES_H_ diff --git a/quantum/enc/enc.c b/quantum/enc/enc.c new file mode 100644 index 0000000000..274aaaedb1 --- /dev/null +++ b/quantum/enc/enc.c @@ -0,0 +1,1250 @@ +#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)); + + enc_ctx.state.pw_ready = false; + enc_ctx.state.pw_size = 0; + enc_ctx.state.pw_check_pos = 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: + 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) { + 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; + } + } + 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; + } + } + 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; + } + + 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; + } + } +} + +void enc_read_pw(uint16_t keycode) { + if (!enc_ctx.state.pw_ready) { + if (keycode != KC_ENT) { + enc_ctx.state.pw[enc_ctx.state.pw_size] = keycode; + enc_ctx.state.pw_size++; + } else { + enc_ctx.state.pw_ready = true; + } + } +} + +int enc_read_pw_check(uint16_t keycode) { + if (keycode != KC_ENT) { + enc_ctx.state.pw_check[enc_ctx.state.pw_check_pos] = keycode; + enc_ctx.state.pw_check_pos++; + } else { + if (enc_ctx.state.pw_check_pos != 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) { + return 0; + } else { + return -1; + } + } + 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) { + enc_read_pw(keycode); + return false; + } else { + int ret = enc_read_pw_check(keycode); + if ((ret == 0) && (keycode == KC_ENT)) { + if (initialize_enc(NULL, NULL) != 0) { + enc_switch_mode(ENC_MODE_CLOSED); + } else { + enc_switch_mode(ENC_MODE_OPEN); + } + } + if (ret != 0) { + enc_switch_mode(ENC_MODE_CLOSED); + } + 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; + } + 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_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"; + } + 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; + } + 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 +} diff --git a/quantum/enc/enc.h b/quantum/enc/enc.h new file mode 100644 index 0000000000..dc0891f15c --- /dev/null +++ b/quantum/enc/enc.h @@ -0,0 +1,165 @@ +#pragma once + +#include "quantum.h" + +#include + +#define CBC 1 + +#define ENC_ERR_OK 0x00 +#define ENC_ERR_EMPTY_BUF 0x01 +#define ENC_ERR_NO_CTX 0x02 +#define ENC_ERR_NOT_ALLOWED 0x03 +#define ENC_ERR_INVALID 0x04 +#define ENC_ERR_RETRY 0x05 +#define ENC_ERR_HW_SUPPORT 0x06 +#define ENC_ERR_MORE_DATA 0x07 + +#define ENC_CMD_RESET 0x00 +#define ENC_CMD_ENCRYPT 0x01 +#define ENC_CMD_DECRYPT 0x02 +#define ENC_CMD_MORE_DATA 0x03 +#define ENC_CMD_UNLOCK 0x04 +#define ENC_CMD_LOCK 0x05 +#define ENC_CMD_SET_CFG 0x06 +#define ENC_CMD_GET_MODE 0x07 +#define ENC_CMD_GET_BUFFER 0x08 +#define ENC_CMD_GET_KEYS 0x09 +#define ENC_CMD_GET_BUFSIZE 0x0A +#define ENC_CMD_SET_KEYS 0x0B +#define ENC_CMD_GET_CFG 0x0C +#define ENC_CMD_INITIALIZE 0x0D +#define ENC_CMD_NONE 0x0E +#define ENC_CMD_SET_BUFFER 0x0F + +#define ENC_MODE_CLOSED 0x00 +#define ENC_MODE_OPEN 0x01 +#define ENC_MODE_LOAD 0x02 +#define ENC_MODE_INIT 0x03 + +#define ENC_SUB_MODE_NONE 0x00 +#define ENC_SUB_MODE_SEED 0x01 +#define ENC_SUB_MODE_PASSWORD 0x02 +#define ENC_SUB_MODE_VERIFY_PASSWORD 0x03 +#define ENC_SUB_MODE_REQUEST 0x04 +#define ENC_SUB_MODE_REQUEST_ALLOW 0x05 +#define ENC_SUB_MODE_REQUEST_DENY 0x06 + +#define ENC_CFG_PARANOIA 0x00 +#define ENC_CFG_SECURE 0x01 +#define ENC_CFG_MAX_ERROR 0x02 +#define ENC_CFG_TIMEOUT 0x03 + +#define ENC_FALSE 0x00 +#define ENC_TRUE 0x01 + +#define ENC_EEPROM_SIZE 123 + +#ifdef VIA_ENABLE +# include "via.h" +# define ENC_EEPROM_ADDR (VIA_EEPROM_CUSTOM_CONFIG_ADDR - ENC_EEPROM_SIZE) +#else +# include "eeconfig.h" +# define ENC_EEPROM_ADDR (EECONFIG_SIZE) +#endif + +typedef struct __attribute__((packed)) { + unsigned int max_error:4; + unsigned int error_count:4; + unsigned int paranoia_mode:1; + unsigned int secure_mode:1; + unsigned int timeout:6; + unsigned int initialized:1; + unsigned int reserved:7; +} enc_config_flags_t; + +typedef struct __attribute__((packed)) { + enc_config_flags_t flags; + uint8_t identifier[8]; + uint8_t salt[16]; + uint8_t validate[32]; + uint8_t key_store[64]; +} enc_config_t; + +typedef struct __attribute__((packed)) { + uint32_t seed; + uint8_t key[32]; +} enc_keys_t; + +typedef struct { + uint8_t mode; + uint8_t sub_mode; + uint32_t pw_timeout; + bool pw_timeout_enabled; + uint8_t req_cmd; + uint32_t req_timeout; + bool req_timeout_enabled; +} enc_mode_t; + +typedef struct { + uint16_t pw[32]; + uint16_t pw_check[32]; + uint16_t pw_size; + uint16_t pw_check_pos; + bool pw_ready; + uint32_t seed; + bool seed_ready; + uint32_t pw_timer; + uint32_t req_timer; + bool cfg_ready; +} enc_state_t; + +typedef struct { + enc_mode_t mode; + enc_config_t cnf; + enc_keys_t keys; + enc_state_t state; +} ENC_CTX; + +#define ENC_REQUEST_HEADER_LEN 9 + +#define ENC_RESPONSE_HEADER_POS_SIZE 1 +#define ENC_RESPONSE_HEADER_LEN 3 + +typedef struct __attribute__((packed)) { + uint8_t magic[2]; + uint8_t cmd; + uint16_t size; + uint32_t id; +} enc_request_header_t; + +typedef struct { + uint8_t *data; + uint16_t dsize; + uint16_t dpos; +} enc_data_buffer_t; + +typedef struct { + enc_request_header_t req_header; + enc_data_buffer_t data; + uint8_t req_cmd; + uint32_t req_id; + uint8_t state_cmd; + uint8_t state_cmd_old; + uint8_t *res_data; + uint32_t req_timer; +} enc_request_state_t; + +#define ENC_HID_REQUEST_TIMEOUT 30 + +// Called by QMK core to process ENC-specific keycodes. +bool process_record_enc(uint16_t keycode, keyrecord_t *record); + +// called to allow having config ready instantly +void pre_init_enc(void); +void eeconfig_init_enc(void); + +enc_config_flags_t enc_get_config_flags(void); +void enc_set_config_flags(enc_config_flags_t); +enc_mode_t enc_get_mode(void); +void enc_set_mode(enc_mode_t); + +const char* enc_mode_to_str(uint8_t mode); +const char* enc_sub_mode_to_str(uint8_t mode); +const char* enc_cmd_to_str(uint8_t cmd); +void enc_write_oled(bool invert); diff --git a/quantum/enc/enc_boards/enc_boards.h b/quantum/enc/enc_boards/enc_boards.h new file mode 100644 index 0000000000..2dd06741f9 --- /dev/null +++ b/quantum/enc/enc_boards/enc_boards.h @@ -0,0 +1,14 @@ +#pragma once + +#ifdef ENC_OPTLOCK +# undef ENC_OPTLOCK +#endif + +#if defined(STM32F401xx) || defined(STMF411xx) +# define ENC_OPTLOCK +#endif + +#ifdef ENC_OPTLOCK + void enc_flash_lock(void); + int enc_is_flash_locked(void); +#endif diff --git a/quantum/enc/enc_boards/enc_boards.mk b/quantum/enc/enc_boards/enc_boards.mk new file mode 100644 index 0000000000..80fb2fd905 --- /dev/null +++ b/quantum/enc/enc_boards/enc_boards.mk @@ -0,0 +1,3 @@ +ifneq ($(filter %_STM32F401xC %_STM32F401xE %_STM32F405xG %_STM32F411xE, %_STM32F412xB, $(MCU_SERIES)_$(MCU_LDSCRIPT)),) + SRC += enc_stm32f40xx_stm32f41xx.c +endif diff --git a/quantum/enc/enc_boards/enc_stm32f40xx_stm32f41xx.c b/quantum/enc/enc_boards/enc_stm32f40xx_stm32f41xx.c new file mode 100644 index 0000000000..f77455fbeb --- /dev/null +++ b/quantum/enc/enc_boards/enc_stm32f40xx_stm32f41xx.c @@ -0,0 +1,51 @@ +#include "hal.h" +#include "enc.h" + +#define FLASH_OPTKEY1 0x08192A3B +#define FLASH_OPTKEY2 0x4C5D6E7F + +static inline void OPT_WaitNotBusy(void) { + uint32_t sr = 0; + for (sr = FLASH->SR; sr & FLASH_SR_BSY; sr = FLASH->SR) { + __WFI(); + } +} + +static inline void OPT_Unlock(void) { + OPT_WaitNotBusy(); + if (FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) { + FLASH->OPTKEYR = FLASH_OPTKEY1; + FLASH->OPTKEYR = FLASH_OPTKEY2; + } +} + +static inline void OPT_Lock(void) { + OPT_WaitNotBusy(); + FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK; +} + +static inline void OPT_Set(uint32_t OptionBytes) { + __IO uint32_t *optionBytes = &(FLASH->OPTCR); + if (*optionBytes != OptionBytes) { + OPT_Unlock(); + *optionBytes = OptionBytes; + FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT; + OPT_Lock(); + /*NVIC_SystemReset();*/ + } +} + +bool enc_is_flash_locked(void) { + if (FLASH->OPTCR & FLASH_OPTCR_RDP) { + return ENC_TRUE; + } + return ENC_FALSE; +} + +void enc_flash_lock(void) { + OPT_Unlock(); + FLASH->OPTCR |= FLASH_OPTCR_RDP; + FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT; + OPT_Lock(); + /*NVIC_SystemReset();*/ +} diff --git a/quantum/enc/pbkdf2-sha256.h b/quantum/enc/pbkdf2-sha256.h new file mode 100644 index 0000000000..5f93e4ae39 --- /dev/null +++ b/quantum/enc/pbkdf2-sha256.h @@ -0,0 +1,855 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include +#include +#include + +typedef struct { + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} sha2_context; + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ + | ( (unsigned long) (b)[(i) + 1] << 16 ) \ + | ( (unsigned long) (b)[(i) + 2] << 8 ) \ + | ( (unsigned long) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * SHA-256 context setup + */ +void sha2_starts( sha2_context *ctx, int is224 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->is224 = is224; +} + +static void sha2_process( sha2_context *ctx, const unsigned char data[64] ) +{ + unsigned long temp1, temp2, W[64]; + unsigned long A, B, C, D, E, F, G, H; + + GET_ULONG_BE( W[ 0], data, 0 ); + GET_ULONG_BE( W[ 1], data, 4 ); + GET_ULONG_BE( W[ 2], data, 8 ); + GET_ULONG_BE( W[ 3], data, 12 ); + GET_ULONG_BE( W[ 4], data, 16 ); + GET_ULONG_BE( W[ 5], data, 20 ); + GET_ULONG_BE( W[ 6], data, 24 ); + GET_ULONG_BE( W[ 7], data, 28 ); + GET_ULONG_BE( W[ 8], data, 32 ); + GET_ULONG_BE( W[ 9], data, 36 ); + GET_ULONG_BE( W[10], data, 40 ); + GET_ULONG_BE( W[11], data, 44 ); + GET_ULONG_BE( W[12], data, 48 ); + GET_ULONG_BE( W[13], data, 52 ); + GET_ULONG_BE( W[14], data, 56 ); + GET_ULONG_BE( W[15], data, 60 ); + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define XF0(x,y,z) ((x & y) | (z & (x | y))) +#define XF1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + XF1(e,f,g) + K + x; \ + temp2 = S2(a) + XF0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 ); + P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 ); + P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF ); + P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 ); + P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B ); + P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 ); + P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 ); + P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 ); + P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 ); + P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 ); + P( G, H, A, B, C, D, E, F, W[10], 0x243185BE ); + P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 ); + P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 ); + P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE ); + P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 ); + P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 ); + P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 ); + P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 ); + P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 ); + P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC ); + P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F ); + P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA ); + P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC ); + P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA ); + P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 ); + P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D ); + P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 ); + P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 ); + P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 ); + P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 ); + P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 ); + P( B, C, D, E, F, G, H, A, R(31), 0x14292967 ); + P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 ); + P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 ); + P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC ); + P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 ); + P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 ); + P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB ); + P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E ); + P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 ); + P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 ); + P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B ); + P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 ); + P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 ); + P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 ); + P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 ); + P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 ); + P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 ); + P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 ); + P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 ); + P( G, H, A, B, C, D, E, F, R(50), 0x2748774C ); + P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 ); + P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 ); + P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A ); + P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F ); + P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 ); + P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE ); + P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F ); + P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 ); + P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 ); + P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA ); + P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB ); + P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 ); + P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/* + * SHA-256 process buffer + */ +void sha2_update( sha2_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + unsigned long left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (unsigned long) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (unsigned long) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + sha2_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + sha2_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } +} + +static const unsigned char sha2_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void sha2_finish( sha2_context *ctx, unsigned char output[32] ) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_BE( high, msglen, 0 ); + PUT_ULONG_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha2_update( ctx, (unsigned char *) sha2_padding, padn ); + sha2_update( ctx, msglen, 8 ); + + PUT_ULONG_BE( ctx->state[0], output, 0 ); + PUT_ULONG_BE( ctx->state[1], output, 4 ); + PUT_ULONG_BE( ctx->state[2], output, 8 ); + PUT_ULONG_BE( ctx->state[3], output, 12 ); + PUT_ULONG_BE( ctx->state[4], output, 16 ); + PUT_ULONG_BE( ctx->state[5], output, 20 ); + PUT_ULONG_BE( ctx->state[6], output, 24 ); + + if( ctx->is224 == 0 ) + PUT_ULONG_BE( ctx->state[7], output, 28 ); +} + +/* + * output = SHA-256( input buffer ) + */ +void sha2( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + sha2_context ctx; + + sha2_starts( &ctx, is224 ); + sha2_update( &ctx, input, ilen ); + sha2_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha2_context ) ); +} + +/* + * SHA-256 HMAC context setup + */ +void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, size_t keylen, + int is224 ) +{ + size_t i; + unsigned char sum[32]; + + if( keylen > 64 ) + { + sha2( key, keylen, sum, is224 ); + keylen = ( is224 ) ? 28 : 32; + key = sum; + } + + memset( ctx->ipad, 0x36, 64 ); + memset( ctx->opad, 0x5C, 64 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + sha2_starts( ctx, is224 ); + sha2_update( ctx, ctx->ipad, 64 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * SHA-256 HMAC process buffer + */ +void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, size_t ilen ) +{ + sha2_update( ctx, input, ilen ); +} + +/* + * SHA-256 HMAC final digest + */ +void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] ) +{ + int is224, hlen; + unsigned char tmpbuf[32]; + + is224 = ctx->is224; + hlen = ( is224 == 0 ) ? 32 : 28; + + sha2_finish( ctx, tmpbuf ); + sha2_starts( ctx, is224 ); + sha2_update( ctx, ctx->opad, 64 ); + sha2_update( ctx, tmpbuf, hlen ); + sha2_finish( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * SHA-256 HMAC context reset + */ +void sha2_hmac_reset( sha2_context *ctx ) +{ + sha2_starts( ctx, ctx->is224 ); + sha2_update( ctx, ctx->ipad, 64 ); +} + +/* + * output = HMAC-SHA-256( hmac key, input buffer ) + */ +void sha2_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + sha2_context ctx; + + sha2_hmac_starts( &ctx, key, keylen, is224 ); + sha2_hmac_update( &ctx, input, ilen ); + sha2_hmac_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha2_context ) ); +} + + + + + +#ifndef min +#define min( a, b ) ( ((a) < (b)) ? (a) : (b) ) +#endif + +void PKCS5_PBKDF2_HMAC(unsigned char *password, size_t plen, + unsigned char *salt, size_t slen, + const unsigned long iteration_count, const unsigned long key_length, + unsigned char *output) +{ + sha2_context ctx; + sha2_starts(&ctx, 0); + + // Size of the generated digest + unsigned char md_size = 32; + unsigned char md1[32]; + unsigned char work[32]; + + unsigned long counter = 1; + unsigned long generated_key_length = 0; + while (generated_key_length < key_length) { + // U1 ends up in md1 and work + unsigned char c[4]; + c[0] = (counter >> 24) & 0xff; + c[1] = (counter >> 16) & 0xff; + c[2] = (counter >> 8) & 0xff; + c[3] = (counter >> 0) & 0xff; + + sha2_hmac_starts(&ctx, password, plen, 0); + sha2_hmac_update(&ctx, salt, slen); + sha2_hmac_update(&ctx, c, 4); + sha2_hmac_finish(&ctx, md1); + memcpy(work, md1, md_size); + + unsigned long ic = 1; + for (ic = 1; ic < iteration_count; ic++) { + // U2 ends up in md1 + sha2_hmac_starts(&ctx, password, plen, 0); + sha2_hmac_update(&ctx, md1, md_size); + sha2_hmac_finish(&ctx, md1); + // U1 xor U2 + unsigned long i = 0; + for (i = 0; i < md_size; i++) { + work[i] ^= md1[i]; + } + // and so on until iteration_count + } + + // Copy the generated bytes to the key + unsigned long bytes_to_write = + min((key_length - generated_key_length), md_size); + memcpy(output + generated_key_length, work, bytes_to_write); + generated_key_length += bytes_to_write; + ++counter; + } +} + +#ifdef TEST +/* + * FIPS-180-2 test vectors + */ +static unsigned char sha2_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha2_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha2_test_sum[6][32] = +{ + /* + * SHA-224 test vectors + */ + { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7 }, + { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, + 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, + 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, + 0x52, 0x52, 0x25, 0x25 }, + { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8, + 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B, + 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE, + 0x4E, 0xE7, 0xAD, 0x67 }, + + /* + * SHA-256 test vectors + */ + { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, + { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, + 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, + 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, + 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, + { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, + 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, + 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, + 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 } +}; + +/* + * RFC 4231 test vectors + */ +static unsigned char sha2_hmac_test_key[7][26] = { + {"\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" + "\x0B\x0B\x0B\x0B"}, + {"Jefe"}, + {"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA"}, + {"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19"}, + {"\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" + "\x0C\x0C\x0C\x0C"}, + {""}, /* 0xAA 131 times */ + {""} +}; + +static const int sha2_hmac_test_keylen[7] = { + 20, 4, 20, 25, 20, 131, 131 +}; + +static unsigned char sha2_hmac_test_buf[7][153] = +{ + { "Hi There" }, + { "what do ya want for nothing?" }, + { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, + { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, + { "Test With Truncation" }, + { "Test Using Larger Than Block-Size Key - Hash Key First" }, + { "This is a test using a larger than block-size key " + "and a larger than block-size data. The key needs to " + "be hashed before being used by the HMAC algorithm." } +}; + +static const int sha2_hmac_test_buflen[7] = +{ + 8, 28, 50, 50, 20, 54, 152 +}; + +static const unsigned char sha2_hmac_test_sum[14][32] = +{ + /* + * HMAC-SHA-224 test vectors + */ + { 0x89, 0x6F, 0xB1, 0x12, 0x8A, 0xBB, 0xDF, 0x19, + 0x68, 0x32, 0x10, 0x7C, 0xD4, 0x9D, 0xF3, 0x3F, + 0x47, 0xB4, 0xB1, 0x16, 0x99, 0x12, 0xBA, 0x4F, + 0x53, 0x68, 0x4B, 0x22 }, + { 0xA3, 0x0E, 0x01, 0x09, 0x8B, 0xC6, 0xDB, 0xBF, + 0x45, 0x69, 0x0F, 0x3A, 0x7E, 0x9E, 0x6D, 0x0F, + 0x8B, 0xBE, 0xA2, 0xA3, 0x9E, 0x61, 0x48, 0x00, + 0x8F, 0xD0, 0x5E, 0x44 }, + { 0x7F, 0xB3, 0xCB, 0x35, 0x88, 0xC6, 0xC1, 0xF6, + 0xFF, 0xA9, 0x69, 0x4D, 0x7D, 0x6A, 0xD2, 0x64, + 0x93, 0x65, 0xB0, 0xC1, 0xF6, 0x5D, 0x69, 0xD1, + 0xEC, 0x83, 0x33, 0xEA }, + { 0x6C, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3C, 0xAC, + 0x6A, 0x2A, 0xBC, 0x1B, 0xB3, 0x82, 0x62, 0x7C, + 0xEC, 0x6A, 0x90, 0xD8, 0x6E, 0xFC, 0x01, 0x2D, + 0xE7, 0xAF, 0xEC, 0x5A }, + { 0x0E, 0x2A, 0xEA, 0x68, 0xA9, 0x0C, 0x8D, 0x37, + 0xC9, 0x88, 0xBC, 0xDB, 0x9F, 0xCA, 0x6F, 0xA8 }, + { 0x95, 0xE9, 0xA0, 0xDB, 0x96, 0x20, 0x95, 0xAD, + 0xAE, 0xBE, 0x9B, 0x2D, 0x6F, 0x0D, 0xBC, 0xE2, + 0xD4, 0x99, 0xF1, 0x12, 0xF2, 0xD2, 0xB7, 0x27, + 0x3F, 0xA6, 0x87, 0x0E }, + { 0x3A, 0x85, 0x41, 0x66, 0xAC, 0x5D, 0x9F, 0x02, + 0x3F, 0x54, 0xD5, 0x17, 0xD0, 0xB3, 0x9D, 0xBD, + 0x94, 0x67, 0x70, 0xDB, 0x9C, 0x2B, 0x95, 0xC9, + 0xF6, 0xF5, 0x65, 0xD1 }, + + /* + * HMAC-SHA-256 test vectors + */ + { 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53, + 0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B, + 0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7, + 0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 }, + { 0x5B, 0xDC, 0xC1, 0x46, 0xBF, 0x60, 0x75, 0x4E, + 0x6A, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xC7, + 0x5A, 0x00, 0x3F, 0x08, 0x9D, 0x27, 0x39, 0x83, + 0x9D, 0xEC, 0x58, 0xB9, 0x64, 0xEC, 0x38, 0x43 }, + { 0x77, 0x3E, 0xA9, 0x1E, 0x36, 0x80, 0x0E, 0x46, + 0x85, 0x4D, 0xB8, 0xEB, 0xD0, 0x91, 0x81, 0xA7, + 0x29, 0x59, 0x09, 0x8B, 0x3E, 0xF8, 0xC1, 0x22, + 0xD9, 0x63, 0x55, 0x14, 0xCE, 0xD5, 0x65, 0xFE }, + { 0x82, 0x55, 0x8A, 0x38, 0x9A, 0x44, 0x3C, 0x0E, + 0xA4, 0xCC, 0x81, 0x98, 0x99, 0xF2, 0x08, 0x3A, + 0x85, 0xF0, 0xFA, 0xA3, 0xE5, 0x78, 0xF8, 0x07, + 0x7A, 0x2E, 0x3F, 0xF4, 0x67, 0x29, 0x66, 0x5B }, + { 0xA3, 0xB6, 0x16, 0x74, 0x73, 0x10, 0x0E, 0xE0, + 0x6E, 0x0C, 0x79, 0x6C, 0x29, 0x55, 0x55, 0x2B }, + { 0x60, 0xE4, 0x31, 0x59, 0x1E, 0xE0, 0xB6, 0x7F, + 0x0D, 0x8A, 0x26, 0xAA, 0xCB, 0xF5, 0xB7, 0x7F, + 0x8E, 0x0B, 0xC6, 0x21, 0x37, 0x28, 0xC5, 0x14, + 0x05, 0x46, 0x04, 0x0F, 0x0E, 0xE3, 0x7F, 0x54 }, + { 0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB, + 0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44, + 0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93, + 0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2 } +}; +typedef struct { + char *t; + char *p; + int plen; + char *s; + int slen; + int c; + int dkLen; + char dk[1024]; // Remember to set this to max dkLen +} testvector; + +int do_test(testvector * tv) +{ + printf("Started %s\n", tv->t); + fflush(stdout); + char *key = malloc(tv->dkLen); + if (key == 0) { + return -1; + } + + PKCS5_PBKDF2_HMAC((unsigned char*)tv->p, tv->plen, + (unsigned char*)tv->s, tv->slen, tv->c, + tv->dkLen, (unsigned char*)key); + + if (memcmp(tv->dk, key, tv->dkLen) != 0) { + // Failed + return -1; + } + + return 0; +} + +/* + * Checkup routine + */ +int main() +{ + int verbose = 1; + int i, j, k, buflen; + unsigned char buf[1024]; + unsigned char sha2sum[32]; + sha2_context ctx; + + for (i = 0; i < 6; i++) { + j = i % 3; + k = i < 3; + + if (verbose != 0) + printf(" SHA-%d test #%d: ", 256 - k * 32, j + 1); + + sha2_starts(&ctx, k); + + if (j == 2) { + memset(buf, 'a', buflen = 1000); + + for (j = 0; j < 1000; j++) + sha2_update(&ctx, buf, buflen); + } else + sha2_update(&ctx, sha2_test_buf[j], + sha2_test_buflen[j]); + + sha2_finish(&ctx, sha2sum); + + if (memcmp(sha2sum, sha2_test_sum[i], 32 - k * 4) != 0) { + if (verbose != 0) + printf("failed\n"); + + return (1); + } + + if (verbose != 0) + printf("passed\n"); + } + + if (verbose != 0) + printf("\n"); + + for (i = 0; i < 14; i++) { + j = i % 7; + k = i < 7; + + if (verbose != 0) + printf(" HMAC-SHA-%d test #%d: ", 256 - k * 32, + j + 1); + + if (j == 5 || j == 6) { + memset(buf, '\xAA', buflen = 131); + sha2_hmac_starts(&ctx, buf, buflen, k); + } else + sha2_hmac_starts(&ctx, sha2_hmac_test_key[j], + sha2_hmac_test_keylen[j], k); + + sha2_hmac_update(&ctx, sha2_hmac_test_buf[j], + sha2_hmac_test_buflen[j]); + + sha2_hmac_finish(&ctx, sha2sum); + + buflen = (j == 4) ? 16 : 32 - k * 4; + + if (memcmp(sha2sum, sha2_hmac_test_sum[i], buflen) != 0) { + if (verbose != 0) + printf("failed\n"); + + return (1); + } + + if (verbose != 0) + printf("passed\n"); + } + + if (verbose != 0) + printf("\n"); + + testvector *tv = 0; + int res = 0; + + testvector t1 = { + "Test 1", + "password", 8, "salt", 4, 1, 32, + .dk = { 0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, + 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, + 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, + 0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b } + }; + + tv = &t1; + res = do_test(tv); + if (res != 0) { + printf("%s failed\n", tv->t); + return res; + } + + testvector t2 = { + "Test 2", + "password", 8, "salt", 4, 2, 32, { + 0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3, + 0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0, 0x6d, 0xd0, + 0x2a, 0x30, 0x3f, 0x8e, 0xf3, 0xc2, 0x51, 0xdf, + 0xd6, 0xe2, 0xd8, 0x5a, 0x95, 0x47, 0x4c, 0x43 } + }; + + tv = &t2; + res = do_test(tv); + if (res != 0) { + printf("%s failed\n", tv->t); + return res; + } + + testvector t3 = { + "Test 3", + "password", 8, "salt", 4, 4096, 32, { + 0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, + 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, + 0x96, 0x28, 0x93, 0xa0, 0x01, 0xce, 0x4e, 0x11, + 0xa4, 0x96, 0x38, 0x73, 0xaa, 0x98, 0x13, 0x4a } + }; + + tv = &t3; + res = do_test(tv); + if (res != 0) { + printf("%s failed\n", tv->t); + return res; + } + + testvector t4 = { + "Test 4", + "password", 8, "salt", 4, 16777216, 32, { + 0xcf, 0x81, 0xc6, 0x6f, 0xe8, 0xcf, 0xc0, 0x4d, + 0x1f, 0x31, 0xec, 0xb6, 0x5d, 0xab, 0x40, 0x89, + 0xf7, 0xf1, 0x79, 0xe8, 0x9b, 0x3b, 0x0b, 0xcb, + 0x17, 0xad, 0x10, 0xe3, 0xac, 0x6e, 0xba, 0x46 } + }; + + tv = &t4; + // res = do_test(tv); + if (res != 0) { + printf("%s failed\n", tv->t); + return res; + } + + testvector t5 = { + "Test 5", + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, 4096, 40, { + 0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f, + 0x32, 0xd8, 0x14, 0xb8, 0x11, 0x6e, 0x84, 0xcf, + 0x2b, 0x17, 0x34, 0x7e, 0xbc, 0x18, 0x00, 0x18, + 0x1c, 0x4e, 0x2a, 0x1f, 0xb8, 0xdd, 0x53, 0xe1, + 0xc6, 0x35, 0x51, 0x8c, 0x7d, 0xac, 0x47, 0xe9 } + }; + + tv = &t5; + res = do_test(tv); + if (res != 0) { + printf("%s failed\n", tv->t); + return res; + } + + testvector t6 = { + "Test 6", + "pass\0word", 9, "sa\0lt", 5, 4096, 16, { + 0x89, 0xb6, 0x9d, 0x05, 0x16, 0xf8, 0x29, 0x89, + 0x3c, 0x69, 0x62, 0x26, 0x65, 0x0a, 0x86, 0x87 } + }; + + tv = &t6; + res = do_test(tv); + if (res != 0) { + printf("%s failed\n", tv->t); + return res; + } + + return (0); +} + +#endif diff --git a/quantum/enc/pkcs7_padding.c b/quantum/enc/pkcs7_padding.c new file mode 100644 index 0000000000..d7e6c12403 --- /dev/null +++ b/quantum/enc/pkcs7_padding.c @@ -0,0 +1,56 @@ +#include "pkcs7_padding.h" + +int pkcs7_padding_pad_buffer( uint8_t *buffer, size_t data_length, size_t buffer_size, uint8_t modulus ){ + uint8_t pad_byte = modulus - ( data_length % modulus ) ; + if( data_length + pad_byte > buffer_size ){ + return -pad_byte; + } + int i = 0; + while( i < pad_byte){ + buffer[data_length+i] = pad_byte; + i++; + } + return pad_byte; +} + +int pkcs7_padding_valid( uint8_t *buffer, size_t data_length, size_t buffer_size, uint8_t modulus ){ + uint8_t expected_pad_byte = modulus - ( data_length % modulus ) ; + if( data_length + expected_pad_byte > buffer_size ){ + return 0; + } + int i = 0; + while( i < expected_pad_byte ){ + if( buffer[data_length + i] != expected_pad_byte){ + return 0; + } + i++; + } + return 1; +} + +size_t pkcs7_padding_data_length( uint8_t * buffer, size_t buffer_size, uint8_t modulus ){ + /* test for valid buffer size */ + if( buffer_size % modulus != 0 || + buffer_size < modulus ){ + return 0; + } + uint8_t padding_value; + padding_value = buffer[buffer_size-1]; + /* test for valid padding value */ + if( padding_value < 1 || padding_value > modulus ){ + return 0; + } + /* buffer must be at least padding_value + 1 in size */ + if( buffer_size < padding_value + 1 ){ + return 0; + } + uint8_t count = 1; + buffer_size --; + for( ; count < padding_value ; count++){ + buffer_size --; + if( buffer[buffer_size] != padding_value ){ + return 0; + } + } + return buffer_size; +} diff --git a/quantum/enc/pkcs7_padding.h b/quantum/enc/pkcs7_padding.h new file mode 100644 index 0000000000..b6b9906158 --- /dev/null +++ b/quantum/enc/pkcs7_padding.h @@ -0,0 +1,24 @@ +#ifndef _PKCS7_PADDING_H_ +#define _PKCS7_PADDING_H_ + +#include +#include + +/* Pad a buffer with bytes as defined in PKCS#7 + * Returns the number of pad bytes added, or zero if + * the buffer size is not large enough to hold the correctly padded data + */ +int pkcs7_padding_pad_buffer( uint8_t *buffer, size_t data_length, size_t buffer_size, uint8_t modulus ); + +int pkcs7_padding_valid( uint8_t *buffer, size_t data_length, size_t buffer_size, uint8_t modulus ); + +/* Given a block of pkcs7 padded data, return the actual data length in the block based on the padding applied. + * buffer_size must be a multiple of modulus + * last byte 'x' in buffer must be between 1 and modulus + * buffer_size must be at least x + 1 in size + * last 'x' bytes in buffer must be same as 'x' + * returned size will be buffer_size - 'x' + */ +size_t pkcs7_padding_data_length( uint8_t * buffer, size_t buffer_size, uint8_t modulus ); + +#endif diff --git a/quantum/quantum.c b/quantum/quantum.c index 33121f6b95..617f64aa77 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -260,6 +260,9 @@ bool process_record_quantum(keyrecord_t *record) { #endif #if defined(VIA_ENABLE) process_record_via(keycode, record) && +#endif +#if defined(ENC_ENABLE) + process_record_enc(keycode, record) && #endif process_record_kb(keycode, record) && #if defined(SECURE_ENABLE) diff --git a/quantum/quantum.h b/quantum/quantum.h index 92e1af1c40..79d72b8bfe 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -217,6 +217,10 @@ extern layer_state_t layer_state; # include "via.h" #endif +#ifdef ENC_ENABLE +# include "enc.h" +#endif + #ifdef WPM_ENABLE # include "wpm.h" #endif diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index 40355d799a..452fe75df2 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h @@ -605,6 +605,17 @@ enum quantum_keycodes { CAPS_WORD, +#ifdef ENC_ENABLE + ENC_INIT, + ENC_LOAD, + ENC_CLOSE, + ENC_PASTE, + ENC_KEYSPASTE, + ENC_RESET, + ENC_REQ_ALLOW, + ENC_REQ_DENY, +#endif + // Start of custom keycode range for keyboards and keymaps - always leave at the end SAFE_RANGE }; diff --git a/quantum/split_common/transaction_id_define.h b/quantum/split_common/transaction_id_define.h index 761a8884f4..5026497fbf 100644 --- a/quantum/split_common/transaction_id_define.h +++ b/quantum/split_common/transaction_id_define.h @@ -84,6 +84,14 @@ enum serial_transaction_id { PUT_POINTING_CPI, #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) +#if defined(ENC_ENABLE) && defined(SPLIT_ENC_MODE_ENABLE) + PUT_ENC_MODE, +#endif // defined(ENC_ENABLE) && defined(SPLIT_ENC_MODE_ENABLE) + +#if defined(ENC_ENABLE) && defined(SPLIT_ENC_FLAGS_ENABLE) + PUT_ENC_FLAGS, +#endif // defined(ENC_ENABLE) && defined(SPLIT_ENC_FLAGS_ENABLE) + #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) PUT_RPC_INFO, PUT_RPC_REQ_DATA, diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c index 9e3df534e3..a0ac0b6935 100644 --- a/quantum/split_common/transactions.c +++ b/quantum/split_common/transactions.c @@ -663,6 +663,59 @@ static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t s #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) +//////////////////////////////////////////////////// +// ENC + +#if defined(ENC_ENABLE) && defined(SPLIT_ENC_MODE_ENABLE) + +static bool enc_mode_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { + static uint32_t last_update = 0; + enc_mode_t enc_mode_sync; + enc_mode_sync = enc_get_mode(); + return send_if_data_mismatch(PUT_ENC_MODE, &last_update, &enc_mode_sync, &split_shmem->enc_mode_sync, sizeof(enc_mode_sync)); +} + +static void enc_mode_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { + enc_set_mode(split_shmem->enc_mode_sync); +} + +# define TRANSACTIONS_ENC_MODE_MASTER() TRANSACTION_HANDLER_MASTER(enc_mode) +# define TRANSACTIONS_ENC_MODE_SLAVE() TRANSACTION_HANDLER_SLAVE(enc_mode) +# define TRANSACTIONS_ENC_MODE_REGISTRATIONS [PUT_ENC_MODE] = trans_initiator2target_initializer(enc_mode_sync), + +#else // defined(ENC_ENABLE) && defined(SPLIT_ENC_MODE_ENABLE) + +# define TRANSACTIONS_ENC_MODE_MASTER() +# define TRANSACTIONS_ENC_MODE_SLAVE() +# define TRANSACTIONS_ENC_MODE_REGISTRATIONS + +#endif // defined(ENC_ENABLE) && defined(SPLIT_ENC_MODE_ENABLE) + +#if defined(ENC_ENABLE) && defined(SPLIT_ENC_FLAGS_ENABLE) + +static bool enc_flags_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { + static uint32_t last_update = 0; + enc_config_flags_t enc_flags_sync; + enc_flags_sync = enc_get_config_flags(); + return send_if_data_mismatch(PUT_ENC_FLAGS, &last_update, &enc_flags_sync, &split_shmem->enc_flags_sync, sizeof(enc_flags_sync)); +} + +static void enc_flags_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { + enc_set_config_flags(split_shmem->enc_flags_sync); +} + +# define TRANSACTIONS_ENC_FLAGS_MASTER() TRANSACTION_HANDLER_MASTER(enc_flags) +# define TRANSACTIONS_ENC_FLAGS_SLAVE() TRANSACTION_HANDLER_SLAVE(enc_flags) +# define TRANSACTIONS_ENC_FLAGS_REGISTRATIONS [PUT_ENC_FLAGS] = trans_initiator2target_initializer(enc_flags_sync), + +#else // defined(ENC_ENABLE) && defined(SPLIT_ENC_FLAGS_ENABLE) + +# define TRANSACTIONS_ENC_FLAGS_MASTER() +# define TRANSACTIONS_ENC_FLAGS_SLAVE() +# define TRANSACTIONS_ENC_FLAGS_REGISTRATIONS + +#endif // defined(ENC_ENABLE) && defined(SPLIT_ENC_FLAGS_ENABLE) + //////////////////////////////////////////////////// split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = { diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h index e62679990a..91ad8b0067 100644 --- a/quantum/split_common/transport.h +++ b/quantum/split_common/transport.h @@ -185,6 +185,14 @@ typedef struct _split_shared_memory_t { split_slave_pointing_sync_t pointing; #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) +#if defined(ENC_ENABLE) && defined(SPLIT_ENC_MODE_ENABLE) + enc_mode_t enc_mode_sync; +#endif // defined(ENC_ENABLE) && defined(SPLIT_ENC_MODE_ENABLE) + +#if defined(ENC_ENABLE) && defined(SPLIT_ENC_FLAGS_ENABLE) + enc_config_flags_t enc_flags_sync; +#endif // defined(ENC_ENABLE) && defined(SPLIT_ENC_FLAGS_ENABLE) + #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) rpc_sync_info_t rpc_info; uint8_t rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE]; diff --git a/quantum/via.h b/quantum/via.h index ac29a58902..a303ed14e5 100644 --- a/quantum/via.h +++ b/quantum/via.h @@ -45,10 +45,17 @@ # define VIA_EEPROM_LAYOUT_OPTIONS_DEFAULT 0x00000000 #endif +// If ENC_ENABLE the layout has to be adjusted +// for storing the needed crypto stuff inside the EEPROM +#ifdef ENC_ENABLE +# include "enc.h" +# define VIA_EEPROM_CUSTOM_CONFIG_ADDR (VIA_EEPROM_LAYOUT_OPTIONS_ADDR + VIA_EEPROM_LAYOUT_OPTIONS_SIZE + ENC_EEPROM_SIZE) +#else // The end of the EEPROM memory used by VIA // By default, dynamic keymaps will start at this if there is no // custom config -#define VIA_EEPROM_CUSTOM_CONFIG_ADDR (VIA_EEPROM_LAYOUT_OPTIONS_ADDR + VIA_EEPROM_LAYOUT_OPTIONS_SIZE) +# define VIA_EEPROM_CUSTOM_CONFIG_ADDR (VIA_EEPROM_LAYOUT_OPTIONS_ADDR + VIA_EEPROM_LAYOUT_OPTIONS_SIZE) +#endif #ifndef VIA_EEPROM_CUSTOM_CONFIG_SIZE # define VIA_EEPROM_CUSTOM_CONFIG_SIZE 0