13 changed files with 859 additions and 361 deletions

No files matched your search

+123 -51
View File
@@ -1,23 +1,52 @@
# RED_CRYPTO ver 0.5.0
# RED_CRYPTO ver 0.7.3
## Description
Password manager for (almost) any QMK keyboards.
Supports cryptographic algorithms:
Password manager for (almost) any QMK-compatible keyboards.
There are two versions:
- hard-coded passwords in `keymap.c`, change branch to `hard-coded-storage` or releases
- storing passwords in EEPROM with adding and editing via `RED_MENU`, change branch to `eeprom-storage` or releases
## Alert
> Now red_crypto supports STM32 EEPROM.
>
> Tested on Keychron K9 Pro with STM32L4xx with virtual EEPROM
See chapter about [Memory issue](#memory-issue) and [Memory usage](#memory-usage).
I recommend using at the beginning internal FLASH or EEPROM, because you have some resources not to need external memory. Or you can do not change your passwords, if there are very strong one's.
> Red_crypto will remind you constanly about using internal memory.
### Supports cryptographic algorithms
- [x] Kuznechik (Russian GOST cipher)
- [x] SHA256 (for hashing key)
- [ ] Streebog (for hashing key, Russian GOST hash algorithm)
- [ ] AES256
## Features and plans
### Features and plans
- [x] add read all ASCII-printable symbols for key
- [x] add Kuznechik lib for non 128 bit MCU
- [x] use SHA256 for hashing key to set key length to 32 bytes
- [x] expand stored passwords length from 16 byte to 64
- [x] expand number of stored passwords (manual adding new keys)
- [ ] write new passwords to EEPROM without flashing firmware
- [x] add menu to managing stored passwords
- [x] adding new passwords via menu to EEPROM without flashing firmware
- [x] add feature to edit passwords in EEPROM
- [ ] add feature to backspacing while adding password
- [ ] add feature to name passwords in EEPROM
- [ ] add feature to update master password in EEPROM
- [ ] add feature to count memory usage
- [ ] add feature to see how many passwords you can store
- [ ] add feature to interactive choosing passwords with arrows
- [ ] add support Streebog
- [ ] add CBC mode for Kuznechik, it will increase security
- [ ] add addition procedures for Kuznechik (is it really need?)
- [ ] add support AES256
- [ ] reseach and add KDF algorithm instead of SHA256
## Installation
@@ -41,78 +70,121 @@ include keyboards/<your keyboard>/<path to your keymap folder>/red_crypto/red_cr
#define USE_KUZNECHIK_8
```
If you want use SHA256 of your key to encrypt passwords, define this in `config.h`.
If you want (and if you can) use SHA256 of your key to encrypt passwords, define this in `config.h`.
```c
#define USE_SHA256_KEY
```
Change storage size (default `4`) and maximum password length (default `64`).
Change storage size (default `5`) and maximum password length (default `64`).
```c
#define STORAGE_SIZE 4
#define STORAGE_PASS_LEN 64 // use a multiple of 16, e.g. 16, 32, 64... but don't forget about available memory!
#define INIT_STORAGE_SIZE 5
#define INIT_STORAGE_PASS_LEN 64 // use a multiple of 16, e.g. 16, 32, 64... but don't forget about available memory!
```
5. Encrypt your passwords with chosen algorithm (AES, Kuznechik). Now available only Kuznechik. You can use `CyberChef`.
5. Adding passwords now in menu. Look [Usage](#usage).
> Don't use web version! We are here for security, right?
6. Add new layer or set new keys everywhere you want.
If you've enabled SHA256 for key, choose `SHA2`, then `SHA256` mode and `64` rounds. Hash your key, then copy it to next step.
Choose `GOST Encrypt`, then choose type `GOST R 34.12 (Kuznechik, 2015)`, not `Magma`. Choose mode `ECB`. Now there is no other modes for `Kuznechik`.
> Don't forget IV for GOST
```
94208510C2C001FB01C0C21085209401
```
6. Add your encrypted passwords in **keymap.c**. Now you can encrypt 4 passwords with any length (16, 32, 64, more not tested).
> Keep this information in secret. Even if there are no plaintext.
Chosen parameter `STORAGE_PASS_LEN` must be the same as the number of zeros in this array.
Chosen parameter `STORAGE_SIZE` must be the same as the number of passwords in this array.
```c
const uint8_t encrypted_passwords[STORAGE_SIZE][STORAGE_PASS_LEN] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
};
```
If you want more passwords in storage, you should:
- add keys `RED_PASSX` into `enum red_crypto_keys` in `red_crypto.h`
- add into `crypto_proccess_record_user` handling new keys
7. Add new layer or set new keyes everywhere you want.
- `RED_TEST` - execute test functions of every algorithm with. Available only with `#define TEST_FUNCTIONS_ENABLED` and `COMMAND_ENABLE=yes`. You can see output via `hid_listen`.
- `RED_CRY_M` - execute reading password for encrypted passwords. After entering password, tap this key again. Now, you can use `RED_PASSX` keys.
- `RED_PASSX` - where `X` is number of your password in database. After tapping, keyboard send decrypted password.
- `RED_MENU` - exec menu to change passwords, show them, etc.
- `RED_RNG` - use 32 times function named `tap_random_base64` from QMK. It's for generating random strings. But now random seed is not unique for every keyboard's power on.
- `RED_TEST` - execute test functions of every algorithm with. Available only with `#define TEST_FUNCTIONS_ENABLED` and `COMMAND_ENABLE=yes`. You can see output via `hid_listen`.
8. Copy this string to function **process_record_user** in **keymap.c** before all your code. It uses "switch case" construction inside.
7. Add some code to **keymap.c**.
Copy this function above **process_record_user**. It is initializing EEPROM of STM32.
```c
uint8_t crypto_return = crypto_process_record_user(keycode, event, encrypted_passwords);
if (crypto_return == 1){
uint16_t density=0; // for test
void keyboard_post_init_user(void) {
density=EEPROM_Init();
}
```
Copy this string to at the beginning of function **process_record_user** in **keymap.c**. It uses "switch case" construction inside.
```c
uint8_t crypto_return = crypto_process_record_user(keycode, record);
if (crypto_return == RED_KEY_READ){
return false;
}
```
9. Compile and flash your keyboard.
8. Compile and flash your keyboard.
## Usage
Tap `RED_CRY_M`. Enter password. Tap `RED_CRY_M` again to confirm.
Now you can use `RED_PASSX` to send decrypted passwords.
Tap `RED_CRY_M`. Enter master key. Tap `RED_CRY_M` again to confirm.
Now you can use `RED_PASSX` to send decrypted passwords. And you can use menu via `RED_MENU`.
If you have missed while entering password, just tap `RED_CRY_M` and tap `RED_CRY_M`.
> If you have missed while entering password, just tap `RED_CRY_M` and tap `RED_CRY_M`.
### Adding passwords
You must firstly enter master key to enter in **crypto mode**.
You should open any program with text box (notepad, telegram, html text box). Then tap `RED_MENU` and you will see menu.
Choose `6-Add password` with entering `6`. Enter password, tap `Enter` and `Enter`.
### Changing passwords
Open menu with `RED_MENU`, choose `4-Change password in storage` with entering `4`.
Choose **index** in hex from 0 to F. Now you can change first 16 password.
Enter new password, tap `Enter` and `Enter`.
## Memory usage
To represent the resources that will be spent on the password storage. It is just example calculate.
If you have 10 different password, set 64 byte size for encrypted password, 16 byte size for ecrypted name for each password, you will store:
$10*(64+16)=800b$
i.e. even if you have arduino with 1kb EEPROM, you can store enough passwords.
If you have up to 100.000 rewrite cycles, and if you will change you passwords every month, you will use up the entire resource of memory in:
$\frac{100.000}{10*(64+16)}=\frac{125}{12}=10.4167$
i.e. you can rewrite you passwords for 10 years. But in my calculations not consider the probability of forgetting passwords.
## Memory issue
You have two ways to store passwords:
### FLASH or internal EEPROM
You can use FLASH or internal EEPROM memory to store passwords near with your keymap.
#### Advantages:
- You can use red_crypto without any upgrading of keyboard.
#### Disadvantages:
- You have memory limit. E.g. Arduino ProMicro have 1024 byte EEPROM.
- On STM32 MCUs in most cases you don't have true EEPROM, because it's emulated in FLASH.
- You have limit of re-flashing your firmware. Most likely about 100.000 times, but this number may vary depending on the temperature, manufacturer, and revision. Remember this.
- You don't have access to rewrite passwords without re-flashing firmware. May be you can, but with hard way.
### External EEPROM (or FRAM)
You can use external EEPROM (FRAM) memory with access to rewrite on-the-fly and add new passwords, etc.
#### Advantages:
- You can add new passwords, update old one's, renew master password, etc.
- Up to 1.000.000 rewrite cycles (or up to $10^{14}$ with FRAM).
- Faster access to data (more fast with FRAM).
- CAT24C512 EEPROM has built-in ECC module (Error Correction Code). Don't know how it works, but sounds good.
- You can upgrade memory with adding chips on I2C or SPI bus. Look at docs on your memory chip to know about maximum quantity.
#### Disadvantages:
- You will have to buy a chip and solder it to your MCU's pins. Your MCU must have 2 free pins for I2C support or 4 pins for SPI. Look [QMK docs](https://docs.qmk.fm/drivers/eeprom) to choose EEPROM(FRAM) chip.
## Related projects
+44 -44
View File
@@ -1097,7 +1097,7 @@ void print_rnd_key(WORD key[])
/*********************** TEST FUNCTION DEFINITIONS ***********************/
#ifdef TEST_FUNCTIONS_ENABLED
void print_hex(BYTE str[], int len)
void red_print_hex(BYTE str[], int len)
{
int idx;
@@ -1126,21 +1126,21 @@ int aes_ecb_test(void)
//printf("* ECB mode:\n");
aes_key_setup(key[0], key_schedule, 256);
//printf( "Key : ");
//print_hex(key[0], 32);
//red_print_hex(key[0], 32);
for(idx = 0; idx < 2; idx++) {
aes_encrypt(plaintext[idx], enc_buf, key_schedule, 256);
//printf("\nPlaintext : ");
//print_hex(plaintext[idx], 16);
//red_print_hex(plaintext[idx], 16);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, 16);
//red_print_hex(enc_buf, 16);
pass = pass && !memcmp(enc_buf, ciphertext[idx], 16);
aes_decrypt(ciphertext[idx], enc_buf, key_schedule, 256);
//printf("\nCiphertext : ");
//print_hex(ciphertext[idx], 16);
//red_print_hex(ciphertext[idx], 16);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, 16);
//red_print_hex(enc_buf, 16);
pass = pass && !memcmp(enc_buf, plaintext[idx], 16);
//printf("\n\n");
@@ -1171,26 +1171,26 @@ int aes_cbc_test(void)
aes_key_setup(key[0], key_schedule, 256);
//printf( "Key : ");
//print_hex(key[0], 32);
//red_print_hex(key[0], 32);
//printf("\nIV : ");
//print_hex(iv[0], 16);
//red_print_hex(iv[0], 16);
aes_encrypt_cbc(plaintext[0], 32, enc_buf, key_schedule, 256, iv[0]);
//printf("\nPlaintext : ");
//print_hex(plaintext[0], 32);
//red_print_hex(plaintext[0], 32);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, 32);
//red_print_hex(enc_buf, 32);
//printf("\nCiphertext : ");
//print_hex(ciphertext[0], 32);
//red_print_hex(ciphertext[0], 32);
pass = pass && !memcmp(enc_buf, ciphertext[0], 32);
aes_decrypt_cbc(ciphertext[0], 32, enc_buf, key_schedule, 256, iv[0]);
//printf("\nCiphertext : ");
//print_hex(ciphertext[0], 32);
//red_print_hex(ciphertext[0], 32);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, 32);
//red_print_hex(enc_buf, 32);
//printf("\nPlaintext : ");
//print_hex(plaintext[0], 32);
//red_print_hex(plaintext[0], 32);
pass = pass && !memcmp(enc_buf, plaintext[0], 32);
//printf("\n\n");
@@ -1219,22 +1219,22 @@ int aes_ctr_test(void)
aes_key_setup(key[0], key_schedule, 256);
//printf( "Key : ");
//print_hex(key[0], 32);
//red_print_hex(key[0], 32);
//printf("\nIV : ");
//print_hex(iv[0], 16);
//red_print_hex(iv[0], 16);
aes_encrypt_ctr(plaintext[0], 32, enc_buf, key_schedule, 256, iv[0]);
//printf("\nPlaintext : ");
//print_hex(plaintext[0], 32);
//red_print_hex(plaintext[0], 32);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, 32);
//red_print_hex(enc_buf, 32);
pass = pass && !memcmp(enc_buf, ciphertext[0], 32);
aes_decrypt_ctr(ciphertext[0], 32, enc_buf, key_schedule, 256, iv[0]);
//printf("\nCiphertext : ");
//print_hex(ciphertext[0], 32);
//red_print_hex(ciphertext[0], 32);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, 32);
//red_print_hex(enc_buf, 32);
pass = pass && !memcmp(enc_buf, plaintext[0], 32);
//printf("\n\n");
@@ -1273,70 +1273,70 @@ int aes_ccm_test(void)
//printf("* CCM mode:\n");
//printf("Key : ");
//print_hex(key[0], 16);
//red_print_hex(key[0], 16);
//print_hex(plaintext[0], 4);
//print_hex(assoc[0], 8);
//print_hex(ciphertext[0], 8);
//print_hex(iv[0], 7);
//print_hex(key[0], 16);
//red_print_hex(plaintext[0], 4);
//red_print_hex(assoc[0], 8);
//red_print_hex(ciphertext[0], 8);
//red_print_hex(iv[0], 7);
//red_print_hex(key[0], 16);
aes_encrypt_ccm(plaintext[0], 4, assoc[0], 8, iv[0], 7, enc_buf, &enc_buf_len, 4, key[0], 128);
//printf("\nNONCE : ");
//print_hex(iv[0], 7);
//red_print_hex(iv[0], 7);
//printf("\nAssoc. Data : ");
//print_hex(assoc[0], 8);
//red_print_hex(assoc[0], 8);
//printf("\nPayload : ");
//print_hex(plaintext[0], 4);
//red_print_hex(plaintext[0], 4);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//red_print_hex(enc_buf, enc_buf_len);
pass = pass && !memcmp(enc_buf, ciphertext[0], enc_buf_len);
aes_decrypt_ccm(ciphertext[0], 8, assoc[0], 8, iv[0], 7, enc_buf, &enc_buf_len, 4, &mac_auth, key[0], 128);
//printf("\n-Ciphertext : ");
//print_hex(ciphertext[0], 8);
//red_print_hex(ciphertext[0], 8);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//red_print_hex(enc_buf, enc_buf_len);
//printf("\nAuthenticated: %d ", mac_auth);
pass = pass && !memcmp(enc_buf, plaintext[0], enc_buf_len) && mac_auth;
aes_encrypt_ccm(plaintext[1], 16, assoc[1], 16, iv[1], 8, enc_buf, &enc_buf_len, 6, key[0], 128);
//printf("\n\nNONCE : ");
//print_hex(iv[1], 8);
//red_print_hex(iv[1], 8);
//printf("\nAssoc. Data : ");
//print_hex(assoc[1], 16);
//red_print_hex(assoc[1], 16);
//printf("\nPayload : ");
//print_hex(plaintext[1], 16);
//red_print_hex(plaintext[1], 16);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//red_print_hex(enc_buf, enc_buf_len);
pass = pass && !memcmp(enc_buf, ciphertext[1], enc_buf_len);
aes_decrypt_ccm(ciphertext[1], 22, assoc[1], 16, iv[1], 8, enc_buf, &enc_buf_len, 6, &mac_auth, key[0], 128);
//printf("\n-Ciphertext : ");
//print_hex(ciphertext[1], 22);
//red_print_hex(ciphertext[1], 22);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//red_print_hex(enc_buf, enc_buf_len);
//printf("\nAuthenticated: %d ", mac_auth);
pass = pass && !memcmp(enc_buf, plaintext[1], enc_buf_len) && mac_auth;
aes_encrypt_ccm(plaintext[2], 24, assoc[2], 20, iv[2], 12, enc_buf, &enc_buf_len, 8, key[0], 128);
//printf("\n\nNONCE : ");
//print_hex(iv[2], 12);
//red_print_hex(iv[2], 12);
//printf("\nAssoc. Data : ");
//print_hex(assoc[2], 20);
//red_print_hex(assoc[2], 20);
//printf("\nPayload : ");
//print_hex(plaintext[2], 24);
//red_print_hex(plaintext[2], 24);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//red_print_hex(enc_buf, enc_buf_len);
pass = pass && !memcmp(enc_buf, ciphertext[2], enc_buf_len);
aes_decrypt_ccm(ciphertext[2], 32, assoc[2], 20, iv[2], 12, enc_buf, &enc_buf_len, 8, &mac_auth, key[0], 128);
//printf("\n-Ciphertext : ");
//print_hex(ciphertext[2], 32);
//red_print_hex(ciphertext[2], 32);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//red_print_hex(enc_buf, enc_buf_len);
//printf("\nAuthenticated: %d ", mac_auth);
pass = pass && !memcmp(enc_buf, plaintext[2], enc_buf_len) && mac_auth;
+58 -103
View File
@@ -4,19 +4,20 @@
uint8_t shift_tracker = 0;
void write_keycode(uint8_t up_key, uint8_t low_key, keyrecord_t *record, uint8_t readed_key[], uint8_t *count_char_key) {
uint8_t write_keycode(uint8_t up_key, uint8_t low_key, keyrecord_t *record, uint8_t readed_key[], uint8_t *count_char_key) {
if (record->event.pressed) {
if (shift_tracker == 1) {
shift_tracker = 0;
// shift_tracker = 0;
readed_key[*count_char_key] = up_key;
} else {
readed_key[*count_char_key] = low_key;
}
#ifdef USE_RED_CRY_DEBUG
dprintf("%d", readed_key[*count_char_key]);
dprintf("%d ", readed_key[*count_char_key]);
#endif
*count_char_key = *count_char_key + 1;
}
return RED_KEY_READ;
};
uint8_t kc_to_ascii(uint16_t keycode, keyrecord_t *record, uint8_t readed_key[], uint8_t *count_char_key) {
@@ -25,208 +26,162 @@ uint8_t kc_to_ascii(uint16_t keycode, keyrecord_t *record, uint8_t readed_key[],
if (record->event.pressed) {
shift_tracker = 1;
}
return 1;
else {
shift_tracker = 0;
}
return RED_KEY_READ;
break;
case KC_A:
write_keycode(ASCII_UP_A, ASCII_LOW_A, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_A, ASCII_LOW_A, record, readed_key, count_char_key);
break;
case KC_B:
write_keycode(ASCII_UP_B, ASCII_LOW_B, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_B, ASCII_LOW_B, record, readed_key, count_char_key);
break;
case KC_C:
write_keycode(ASCII_UP_C, ASCII_LOW_C, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_C, ASCII_LOW_C, record, readed_key, count_char_key);
break;
case KC_D:
write_keycode(ASCII_UP_D, ASCII_LOW_D, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_D, ASCII_LOW_D, record, readed_key, count_char_key);
break;
case KC_E:
write_keycode(ASCII_UP_E, ASCII_LOW_E, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_E, ASCII_LOW_E, record, readed_key, count_char_key);
break;
case KC_F:
write_keycode(ASCII_UP_F, ASCII_LOW_F, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_F, ASCII_LOW_F, record, readed_key, count_char_key);
break;
case KC_G:
write_keycode(ASCII_UP_G, ASCII_LOW_G, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_G, ASCII_LOW_G, record, readed_key, count_char_key);
break;
case KC_H:
write_keycode(ASCII_UP_H, ASCII_LOW_H, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_H, ASCII_LOW_H, record, readed_key, count_char_key);
break;
case KC_I:
write_keycode(ASCII_UP_I, ASCII_LOW_I, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_I, ASCII_LOW_I, record, readed_key, count_char_key);
break;
case KC_J:
write_keycode(ASCII_UP_J, ASCII_LOW_J, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_J, ASCII_LOW_J, record, readed_key, count_char_key);
break;
case KC_K:
write_keycode(ASCII_UP_K, ASCII_LOW_K, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_K, ASCII_LOW_K, record, readed_key, count_char_key);
break;
case KC_L:
write_keycode(ASCII_UP_L, ASCII_LOW_L, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_L, ASCII_LOW_L, record, readed_key, count_char_key);
break;
case KC_M:
write_keycode(ASCII_UP_M, ASCII_LOW_M, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_M, ASCII_LOW_M, record, readed_key, count_char_key);
break;
case KC_N:
write_keycode(ASCII_UP_N, ASCII_LOW_N, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_N, ASCII_LOW_N, record, readed_key, count_char_key);
break;
case KC_O:
write_keycode(ASCII_UP_O, ASCII_LOW_O, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_O, ASCII_LOW_O, record, readed_key, count_char_key);
break;
case KC_P:
write_keycode(ASCII_UP_P, ASCII_LOW_P, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_P, ASCII_LOW_P, record, readed_key, count_char_key);
break;
case KC_Q:
write_keycode(ASCII_UP_Q, ASCII_LOW_Q, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_Q, ASCII_LOW_Q, record, readed_key, count_char_key);
break;
case KC_R:
write_keycode(ASCII_UP_R, ASCII_LOW_R, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_R, ASCII_LOW_R, record, readed_key, count_char_key);
break;
case KC_S:
write_keycode(ASCII_UP_S, ASCII_LOW_S, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_S, ASCII_LOW_S, record, readed_key, count_char_key);
break;
case KC_T:
write_keycode(ASCII_UP_T, ASCII_LOW_T, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_T, ASCII_LOW_T, record, readed_key, count_char_key);
break;
case KC_U:
write_keycode(ASCII_UP_U, ASCII_LOW_U, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_U, ASCII_LOW_U, record, readed_key, count_char_key);
break;
case KC_V:
write_keycode(ASCII_UP_V, ASCII_LOW_V, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_V, ASCII_LOW_V, record, readed_key, count_char_key);
break;
case KC_W:
write_keycode(ASCII_UP_W, ASCII_LOW_W, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_W, ASCII_LOW_W, record, readed_key, count_char_key);
break;
case KC_X:
write_keycode(ASCII_UP_X, ASCII_LOW_X, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_X, ASCII_LOW_X, record, readed_key, count_char_key);
break;
case KC_Y:
write_keycode(ASCII_UP_Y, ASCII_LOW_Y, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_Y, ASCII_LOW_Y, record, readed_key, count_char_key);
break;
case KC_Z:
write_keycode(ASCII_UP_Z, ASCII_LOW_Z, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_Z, ASCII_LOW_Z, record, readed_key, count_char_key);
break;
case KC_1:
write_keycode(ASCII_UP_1, ASCII_LOW_1, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_1, ASCII_LOW_1, record, readed_key, count_char_key);
break;
case KC_2:
write_keycode(ASCII_UP_2, ASCII_LOW_2, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_2, ASCII_LOW_2, record, readed_key, count_char_key);
break;
case KC_3:
write_keycode(ASCII_UP_3, ASCII_LOW_3, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_3, ASCII_LOW_3, record, readed_key, count_char_key);
break;
case KC_4:
write_keycode(ASCII_UP_4, ASCII_LOW_4, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_4, ASCII_LOW_4, record, readed_key, count_char_key);
break;
case KC_5:
write_keycode(ASCII_UP_5, ASCII_LOW_5, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_5, ASCII_LOW_5, record, readed_key, count_char_key);
break;
case KC_6:
write_keycode(ASCII_UP_6, ASCII_LOW_6, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_6, ASCII_LOW_6, record, readed_key, count_char_key);
break;
case KC_7:
write_keycode(ASCII_UP_7, ASCII_LOW_7, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_7, ASCII_LOW_7, record, readed_key, count_char_key);
break;
case KC_8:
write_keycode(ASCII_UP_8, ASCII_LOW_8, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_8, ASCII_LOW_8, record, readed_key, count_char_key);
break;
case KC_9:
write_keycode(ASCII_UP_9, ASCII_LOW_9, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_9, ASCII_LOW_9, record, readed_key, count_char_key);
break;
case KC_0:
write_keycode(ASCII_UP_0, ASCII_LOW_0, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_0, ASCII_LOW_0, record, readed_key, count_char_key);
break;
case KC_SPACE:
write_keycode(ASCII_SPACE, ASCII_SPACE, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_SPACE, ASCII_SPACE, record, readed_key, count_char_key);
break;
case KC_MINUS:
write_keycode(ASCII_UP_MINUS, ASCII_LOW_MINUS, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_MINUS, ASCII_LOW_MINUS, record, readed_key, count_char_key);
break;
case KC_EQUAL:
write_keycode(ASCII_UP_EQUAL, ASCII_LOW_EQUAL, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_EQUAL, ASCII_LOW_EQUAL, record, readed_key, count_char_key);
break;
case KC_LEFT_BRACKET:
write_keycode(ASCII_UP_LEFT_BR, ASCII_LOW_LEFT_BR, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_LEFT_BR, ASCII_LOW_LEFT_BR, record, readed_key, count_char_key);
break;
case KC_RIGHT_BRACKET:
write_keycode(ASCII_UP_RIGHT_BR, ASCII_LOW_RIGHT_BR, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_RIGHT_BR, ASCII_LOW_RIGHT_BR, record, readed_key, count_char_key);
break;
case KC_BACKSLASH:
write_keycode(ASCII_UP_BACKSLASH, ASCII_LOW_BACKSLASH, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_BACKSLASH, ASCII_LOW_BACKSLASH, record, readed_key, count_char_key);
break;
case KC_NONUS_HASH:
write_keycode(ASCII_UP_HASH, ASCII_GRAVE, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_HASH, ASCII_GRAVE, record, readed_key, count_char_key);
break;
case KC_SEMICOLON:
write_keycode(ASCII_UP_SEMICOLON, ASCII_LOW_SEMICOLON, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_SEMICOLON, ASCII_LOW_SEMICOLON, record, readed_key, count_char_key);
break;
case KC_QUOTE:
write_keycode(ASCII_UP_QUOTE, ASCII_LOW_QUOTE, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_QUOTE, ASCII_LOW_QUOTE, record, readed_key, count_char_key);
break;
// i am not sure about KC_GRAVE and KC_NONUS_HASH
// need to test
case KC_GRAVE:
write_keycode(ASCII_NON_PRINTABLE, ASCII_GRAVE, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_NON_PRINTABLE, ASCII_GRAVE, record, readed_key, count_char_key);
break;
case KC_COMMA:
write_keycode(ASCII_UP_COMMA, ASCII_LOW_COMMA, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_COMMA, ASCII_LOW_COMMA, record, readed_key, count_char_key);
break;
case KC_DOT:
write_keycode(ASCII_UP_DOT, ASCII_LOW_DOT, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_DOT, ASCII_LOW_DOT, record, readed_key, count_char_key);
break;
case KC_SLASH:
write_keycode(ASCII_UP_SLASH, ASCII_LOW_SLASH, record, readed_key, count_char_key);
return 1;
return write_keycode(ASCII_UP_SLASH, ASCII_LOW_SLASH, record, readed_key, count_char_key);
break;
default:
break;
}
return 0;
return RED_IDLE;
}
+1
View File
@@ -2,6 +2,7 @@
#include QMK_KEYBOARD_H
#include "quantum.h"
#include "red_crypto.h"
#ifndef KC_TO_ASCII_H
# define KC_TO_ASCII_H
+9 -1
View File
@@ -258,12 +258,20 @@ void kuz_decrypt_block(kuz_key_t *key, void *blk)
void print_w128(w128_t *x)
{
int i;
printf("\n");
for (i = 0; i < 16; i++)
printf(" %02X", x->b[i]);
printf("\n");
};
void print_chars_w128(w128_t *x) {
printf("\n");
for (uint8_t i = 0; i < 16; i++) {
if (x->b[i] == 0x00) break;
printf("%c", x->b[i]);
}
printf("\n");
};
/*********************** TEST FUNCTION DEFINITIONS ***********************/
#ifdef TEST_FUNCTIONS_ENABLED
+1
View File
@@ -32,6 +32,7 @@ void kuz_decrypt_block(kuz_key_t *subkeys, void *x);
// utils
void print_w128(w128_t *x);
void print_chars_w128(w128_t *x);
// tests
#ifdef TEST_FUNCTIONS_ENABLED
+217 -125
View File
@@ -2,107 +2,155 @@
#include "red_crypto.h"
uint8_t dec_pass[STORAGE_SIZE][STORAGE_PASS_LEN];
uint8_t eeprom_inited = 0;
uint8_t *master_key; // you can use key any length with SHA256 by defining MASTER_KEY_LEN, kuznechik use only 32byte
uint8_t **decrypted_passwords;
uint8_t *new_pass_enc;
#ifdef USE_SHA256_KEY
uint8_t master_key_hash[32];
#endif
uint8_t count_char_key = 0;
uint8_t crypto_mode = 0;
uint8_t decrypted_mode = 0;
uint8_t red_menu_mode = 0;
void init_dec_pass(void) {
for (uint8_t i = 0; i < STORAGE_SIZE; i++) {
for (uint8_t j = 0; j < STORAGE_PASS_LEN; j++) {
dec_pass[i][j] = 0x00;
void crypto_eeprom_init() {
uint8_t red_var[3] = {'R', 'E', 'D'};
// TODO: don't work with this var,copy it to global var in RAM
// TODO: write code for not emulated EEPROM
// eeconfig_read_user_datablock(enc_pass.raw);
// for (uint8_t i = 0; i < EECONFIG_USER_DATA_SIZE; i++) {
// dprintf("%x ", enc_pass.raw[i]);
// }
red_read_from_storage();
if (enc_pass.init_var[0] == red_var[0] && enc_pass.init_var[1] == red_var[1] && enc_pass.init_var[2] == red_var[2]) { // not empty eeprom
dprintf("Not empty EEPROM\n");
eeprom_inited = 1;
// #undef INIT_STORAGE_SIZE
// #define INIT_STORAGE_SIZE enc_pass.storage_size
// #undef INIT_STORAGE_PASS_LEN
// #define INIT_STORAGE_PASS_LEN enc_pass.storage_pass_len
} else { // empty eeprom
dprintf("Empty EEPROM\n");
eeprom_inited = 0;
enc_pass.init_var[0] = 'R';
enc_pass.init_var[1] = 'E';
enc_pass.init_var[2] = 'D';
enc_pass.version[0] = '0';
enc_pass.version[1] = '7';
enc_pass.version[2] = '3';
enc_pass.memory_usage = 0;
enc_pass.password_count = 0;
enc_pass.storage_size = INIT_STORAGE_SIZE;
enc_pass.storage_pass_len = INIT_STORAGE_PASS_LEN;
for (uint8_t password_index = 0; password_index < enc_pass.storage_size; password_index++) { // must zero bytes in memory
for (uint8_t password_byte = 0; password_byte < enc_pass.storage_pass_len; password_byte++) {
enc_pass.passwords[password_index * enc_pass.storage_pass_len + password_byte] = 0x00;
}
}
// eeconfig_update_user_datablock(enc_pass.raw);
red_write_to_storage();
}
}
// encrypt new password
uint8_t *encrypt_pass_kuzn(const uint8_t *new_pass, const uint8_t new_pass_length, const uint8_t password_index) {
kuz_key_t key;
w128_t x;
new_pass_enc = red_init_array(enc_pass.storage_pass_len, 0x00); // assign zeros to encrypted new password var
// copy new password in decrypted_passwords
if (password_index == 255) {
for (uint8_t byte_index = 0; byte_index < new_pass_length; byte_index++) {
decrypted_passwords[enc_pass.password_count][byte_index] = new_pass[byte_index];
}
} else {
decrypted_passwords[password_index] = red_init_array(enc_pass.storage_pass_len, 0x00);
for (uint8_t byte_index = 0; byte_index < new_pass_length; byte_index++) {
decrypted_passwords[password_index][byte_index] = new_pass[byte_index];
}
}
}
// you can use key any length with SHA256, kuznechik use only 32byte
kuz_init();
// using master_key for encrypting
#ifdef USE_SHA256_KEY
uint8_t readed_key[128] = {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, 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, 0, 0};
kuz_set_encrypt_key(&key, hashing_string(master_key));
#endif
// if you don't have enough FLASH in MCU
#ifndef USE_SHA256_KEY
uint8_t readed_key[32] = {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};
kuz_set_encrypt_key(&key, master_key);
#endif
uint8_t count_char_key = 0;
uint8_t crypto_mode = 0;
void print_chars_w128(w128_t *x) {
for (uint8_t i = 0; i < 16; i++) {
if (x->b[i] == 0x00) break;
dprintf("%c", x->b[i]);
#ifdef USE_RED_CRY_DEBUG
print_w128(&x);
#endif
// encrypting one password
// it will read only blocks with password, empty blocks will not be encrypted!
for (uint8_t block_index = 0; block_index < CEILING(new_pass_length, BLOCK_SIZE); block_index++) {
// reading password's block for encrypting
for (uint8_t byte_index = 0 + block_index * BLOCK_SIZE; byte_index < BLOCK_SIZE + block_index * BLOCK_SIZE; byte_index++) {
x.b[byte_index % BLOCK_SIZE] = new_pass[byte_index];
}
kuz_encrypt_block(&key, &x);
// reading encrypted block to return variable
for (uint8_t byte_index = 0 + block_index * BLOCK_SIZE; byte_index < BLOCK_SIZE + block_index * BLOCK_SIZE; byte_index++) {
new_pass_enc[byte_index + block_index * BLOCK_SIZE] = x.b[byte_index % BLOCK_SIZE];
}
#ifdef USE_RED_CRY_DEBUG
print_w128(&x);
print_chars_w128(&x);
#endif
}
dprintf("\n");
};
void print_chars(uint8_t *c) {
for (uint8_t i = 0; i < 32; i++) {
if (c[i] == 0x00) break;
dprintf("%c", c[i]);
}
dprintf("\n");
};
void print_int(uint8_t *c) {
for (uint8_t i = 0; i < 32; i++) {
dprintf("%d", c[i]);
}
dprintf("\n");
};
void print_hex(uint8_t *h) {
for (uint8_t i = 0; i < 32; i++) {
dprintf("%x ", h[i]);
}
dprintf("\n");
};
size_t min_len(size_t a, size_t b) {
if (a < b)
return a;
else
return b;
return new_pass_enc;
}
void decrypt_pass_kuzn(const uint8_t encrypted_passwords[STORAGE_SIZE][STORAGE_PASS_LEN]) {
// decrypting passwords
void decrypt_pass_kuzn(void) {
kuz_key_t key;
w128_t x;
init_dec_pass();
decrypted_passwords = red_init_array_2d(enc_pass.storage_size, enc_pass.storage_pass_len, 0x00); // clear decrypted passwords
kuz_init();
// for hashing key, like a KDF algorithm
#ifdef USE_SHA256_KEY
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, readed_key, min_len(u_strlen(readed_key), MAX_KEY_LEN));
BYTE result_key[SHA256_BLOCK_SIZE];
sha256_final(&ctx, result_key);
print_hex(result_key);
kuz_set_decrypt_key(&key, result_key);
kuz_set_decrypt_key(&key, hashing_string(master_key));
#endif
// if you don't have enough FLASH in MCU
#ifndef USE_SHA256_KEY
kuz_set_decrypt_key(&key, readed_key);
kuz_set_decrypt_key(&key, master_key);
#endif
for (uint8_t j = 0; j < STORAGE_SIZE; j++) {
// decrypting all passwords in storage
for (uint8_t password_index = 0; password_index < enc_pass.storage_size; password_index++) {
#ifdef USE_RED_CRY_DEBUG
dprintf("decrypted\t=");
#endif
for (uint8_t k = 0; k < STORAGE_PASS_LEN / 16; k++) {
for (uint8_t block_index = 0; block_index < enc_pass.storage_pass_len / BLOCK_SIZE; block_index++) {
uint8_t cnt_zeros = 0;
for (uint8_t z = 0 + k * 16; z < 16 + k * 16; z++) {
if (encrypted_passwords[j][z] == 0x00) {
// checking is this empty block or not
for (uint8_t byte_index = 0 + block_index * BLOCK_SIZE; byte_index < BLOCK_SIZE + block_index * BLOCK_SIZE; byte_index++) {
// if (encrypted_passwords[password_index][byte_index] == 0x00) {
if (enc_pass.passwords[password_index * enc_pass.storage_pass_len + byte_index] == 0x00) {
cnt_zeros++;
} else {
cnt_zeros = 0;
break;
}
}
if (cnt_zeros != 0) break; // if there is zero 8 byte block in password, e.g. password length <32 or <64
if (cnt_zeros == BLOCK_SIZE) break; // if there are BLOCK_SIZE byte zeros block in password, e.g. password length <32 or <64
for (uint8_t i = 0 + k * 16; i < 16 + k * 16; i++) {
x.b[i % 16] = encrypted_passwords[j][i];
// reading password's block for decrypting
for (uint8_t byte_index = 0 + block_index * BLOCK_SIZE; byte_index < BLOCK_SIZE + block_index * BLOCK_SIZE; byte_index++) {
// x.b[byte_index % BLOCK_SIZE] = encrypted_passwords[password_index][byte_index];
x.b[byte_index % BLOCK_SIZE] = enc_pass.passwords[password_index * enc_pass.storage_pass_len + byte_index];
}
// decrypting via Kuznechik
kuz_decrypt_block(&key, &x);
for (uint8_t i = 0 + k * 16; i < 16 + k * 16; i++) {
dec_pass[j][i] = x.b[i % 16];
// writing decrypted password's block
for (uint8_t byte_index = 0 + block_index * BLOCK_SIZE; byte_index < BLOCK_SIZE + block_index * BLOCK_SIZE; byte_index++) {
decrypted_passwords[password_index][byte_index] = x.b[byte_index % BLOCK_SIZE];
}
#ifdef USE_RED_CRY_DEBUG
@@ -113,75 +161,46 @@ void decrypt_pass_kuzn(const uint8_t encrypted_passwords[STORAGE_SIZE][STORAGE_P
}
};
// TODO: add encrypt new passwords with binding on new keys
// and storing all these to EEPROM
// void encrypt_pass_kuzn(){
// kuz_set_encrypt_key(&key,readed_key);
// for (uint8_t i=0; i<16; i++) {
// x.b[i] = pass[i];
// }
// kuz_encrypt_block(&key,&x);
// printf("encrypted\t="); print_w128(&x);
// print_chars_w128(&x);
// }
void send_chars_pass(uint8_t *out) {
for (uint8_t i = 0; i < STORAGE_PASS_LEN && out[i] != 0; i++) {
send_char((char)out[i]);
}
};
uint8_t crypto_process_record_user(uint16_t keycode, keyrecord_t *record, const uint8_t encrypted_passwords[STORAGE_SIZE][STORAGE_PASS_LEN]) {
// function for embedding to "proccess_record_user" for adding crypto features
uint8_t crypto_process_record_user(uint16_t keycode, keyrecord_t *record) {
if (crypto_mode) {
switch (keycode) {
case RED_CRY_M:
if (record->event.pressed) {
#ifdef USE_RED_CRY_DEBUG
print_int(readed_key);
red_print_int(master_key, MASTER_KEY_LEN);
#endif
crypto_mode = 0;
count_char_key = 0;
decrypt_pass_kuzn(encrypted_passwords);
if (eeprom_inited == 1) decrypt_pass_kuzn();
decrypted_mode = 1;
}
break;
default:
// reading key
return kc_to_ascii(keycode, record, readed_key, &count_char_key);
return kc_to_ascii(keycode, record, master_key, &count_char_key);
break;
}
} else {
} else if (decrypted_mode && red_menu_mode) {
uint8_t key_return = draw_red_menu(keycode, record);
if (key_return == RED_MENU_EXIT) {
red_menu_mode = 0;
} else {
return key_return;
}
} else if (decrypted_mode) {
switch (keycode) {
case RED_PASS1:
case RED_RST_EE:
if (record->event.pressed) {
send_chars_pass(dec_pass[0]);
enc_pass.init_var[0] = 0x00;
crypto_eeprom_init();
}
break;
case RED_PASS2:
case RED_CRY_M:
if (record->event.pressed) {
send_chars_pass(dec_pass[1]);
}
break;
case RED_PASS3:
if (record->event.pressed) {
send_chars_pass(dec_pass[2]);
}
break;
case RED_PASS4:
if (record->event.pressed) {
send_chars_pass(dec_pass[3]);
}
break;
// if you want to add more keys for passwords, copy this `case`
// case RED_PASSX: //change X here
// if (record->event.pressed) {
// send_chars_pass(dec_pass[X]); //change X here
// }
// break;
case RED_RNG:
if (record->event.pressed) {
// TODO: change seed
for (uint8_t i = 0; i < 32; i++) {
tap_random_base64();
}
decrypted_mode = 0;
decrypted_passwords = red_init_array_2d(enc_pass.storage_size, enc_pass.storage_pass_len, 0x00); // clear decrypted passwords
master_key = red_init_array(MASTER_KEY_LEN, 0);
}
break;
case RED_TEST:
@@ -193,16 +212,89 @@ uint8_t crypto_process_record_user(uint16_t keycode, keyrecord_t *record, const
}
#endif
break;
case RED_RNG:
if (record->event.pressed) {
// TODO: change seed
for (uint8_t i = 0; i < 32; i++) {
tap_random_base64();
}
}
break;
case RED_MENU:
if (record->event.pressed) {
red_menu_mode = 1; // to enter in menu mode block code above
}
break;
case RED_PASS1:
if (record->event.pressed && enc_pass.password_count >= 1) {
red_send_chars_pass(decrypted_passwords[0]);
}
break;
case RED_PASS2:
if (record->event.pressed && enc_pass.password_count >= 2) {
red_send_chars_pass(decrypted_passwords[1]);
}
break;
case RED_PASS3:
if (record->event.pressed && enc_pass.password_count >= 3) {
red_send_chars_pass(decrypted_passwords[2]);
}
break;
case RED_PASS4:
if (record->event.pressed && enc_pass.password_count >= 4) {
red_send_chars_pass(decrypted_passwords[3]);
}
break;
case RED_PASS5:
if (record->event.pressed && enc_pass.password_count >= 5) {
red_send_chars_pass(decrypted_passwords[4]);
}
break;
case RED_PASS6:
if (record->event.pressed && enc_pass.password_count >= 6) {
red_send_chars_pass(decrypted_passwords[5]);
}
break;
case RED_PASS7:
if (record->event.pressed && enc_pass.password_count >= 7) {
red_send_chars_pass(decrypted_passwords[6]);
}
break;
case RED_PASS8:
if (record->event.pressed && enc_pass.password_count >= 8) {
red_send_chars_pass(decrypted_passwords[7]);
}
break;
case RED_PASS9:
if (record->event.pressed && enc_pass.password_count >= 9) {
red_send_chars_pass(decrypted_passwords[8]);
}
break;
case RED_PASS10:
if (record->event.pressed && enc_pass.password_count >= 10) {
red_send_chars_pass(decrypted_passwords[9]);
}
break;
// if you want to add more keys for passwords, copy this `case` and add new keys in red_crypto.h
// case RED_PASSX: //change X here
// if (record->event.pressed) {
// red_send_chars_pass(decrypted_passwords[X]); //change X here
// }
// break;
}
} else {
// by default
switch (keycode) {
case RED_CRY_M:
if (record->event.pressed) {
crypto_mode = 1;
for (uint8_t i = 0; i < 32; i++) {
readed_key[i] = 0;
}
crypto_eeprom_init();
crypto_mode = 1; // to enter in crypto mode and unlock other keys
// clearing readed key
master_key = red_init_array(MASTER_KEY_LEN, 0);
// dprintf("%d", keycode);
}
break;
}
}
return 0;
return RED_IDLE;
}
+91 -37
View File
@@ -1,60 +1,114 @@
// Author: redlineo, romanov.pd@gmail.com
#ifndef RED_CRYPTO_H
#define RED_CRYPTO_H
#include QMK_KEYBOARD_H
#include "quantum.h"
#ifndef RED_CRYPTO_H
# define RED_CRYPTO_H
# include "kc_to_ascii.h"
// includes of red_crypto
#include "kc_to_ascii.h"
#include "utils.h"
#include "red_menu.h"
// includes for EEPROM, tested on STM32L432xx
#ifdef STM32L432xx
# include "eeprom.h"
# include "eeprom_stm32_defs.h"
# include "eeprom_stm32_l4.h"
#endif
// not tested!!!
// #ifdef USE_RED_KUZNECHIK_128
// #include "kuznechik_128bit.h"
// #endif
# ifdef USE_RED_KUZNECHIK_8
# include "kuznechik_8bit.h"
# ifdef USE_SHA256_KEY
# include "sha256.h"
# endif
#define MASTER_KEY_LEN 32
#ifdef USE_RED_KUZNECHIK_8
# include "kuznechik_8bit.h"
# ifdef USE_SHA256_KEY
# undef MASTER_KEY_LEN
# define MASTER_KEY_LEN 128
# include "sha256.h"
# endif
#endif
# ifdef USE_RED_AES_256
# include "aes.h"
#ifdef USE_RED_AES_256
# include "aes.h"
#endif
#define MAX_KEY_LEN 128
#define BLOCK_SIZE 16
#ifndef INIT_STORAGE_SIZE
# define INIT_STORAGE_SIZE 5
#endif
#ifndef INIT_STORAGE_PASS_LEN
# define INIT_STORAGE_PASS_LEN 64
#endif
#ifdef INIT_STORAGE_PASS_LEN
# if (INIT_STORAGE_PASS_LEN % 16 != 0)
# error "Password length must be multiply of 16 (16,32,64...)"
# endif
#endif
# define MAX_KEY_LEN 128
# ifndef STORAGE_SIZE
# define STORAGE_SIZE 4
# endif
# ifdef STORAGE_PASS_LEN
# if STORAGE_PASS_LEN % 16 != 0
# error Storage password length must be a multiple of 16
# endif
# endif
# ifndef STORAGE_PASS_LEN
# define STORAGE_PASS_LEN 64
# endif
//example for encrypted 64 byte password
// const uint8_t red_enc_pass[STORAGE_SIZE][STORAGE_PASS_LEN] = {
// {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
// };
// example for encrypted 64 byte password
// const uint8_t red_enc_pass[STORAGE_SIZE][STORAGE_PASS_LEN] = {
// {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
// };
enum red_crypto_keys {
RED_CRY_M = SAFE_RANGE + 0x80, // added safe range offset
RED_MENU,
RED_RNG,
RED_TEST,
RED_PASS1, RED_PASS2, RED_PASS3, RED_PASS4, RED_PASS5, RED_PASS6, RED_PASS7, RED_PASS8, RED_PASS9, RED_PASS10, RED_PASS11, RED_PASS12
RED_LOCK, // TODO: add autolock feature
RED_RST_EE, // resetting EEPROM by clearing RED bytes
RED_PASS1,
RED_PASS2,
RED_PASS3,
RED_PASS4,
RED_PASS5,
RED_PASS6,
RED_PASS7,
RED_PASS8,
RED_PASS9,
RED_PASS10,
};
uint8_t crypto_process_record_user(uint16_t keycode, keyrecord_t *record, const uint8_t encrypted_passwords[STORAGE_SIZE][STORAGE_PASS_LEN]);
enum red_crypto_states {
RED_IDLE = 0,
RED_KEY_READ,
RED_MENU_EXIT,
};
// uint8_t storage_size = INIT_STORAGE_SIZE;
// uint8_t storage_pass_len = INIT_STORAGE_PASS_LEN;
#define EEPROM_PASS_OFFSET 3 + 3 + 1 + 1 + 4 + 1
#define STORAGE_SIZE (EEPROM_PASS_OFFSET + INIT_STORAGE_SIZE * INIT_STORAGE_PASS_LEN)
typedef union {
uint8_t raw[STORAGE_SIZE];
struct {
uint8_t init_var[3]; // if in eeprom is bytes "RED", then it's not first flash or first power-on, or in eeprom is old red_crypto
uint8_t version[3]; // red_crypto library version
uint8_t storage_size;
uint8_t storage_pass_len;
uint32_t memory_usage;
uint8_t password_count;
uint8_t passwords[INIT_STORAGE_SIZE * INIT_STORAGE_PASS_LEN];
};
} red_crypto_storage_eeprom;
red_crypto_storage_eeprom enc_pass;
uint8_t crypto_process_record_user(uint16_t keycode, keyrecord_t *record);
uint8_t *encrypt_pass_kuzn(const uint8_t *new_pass, const uint8_t new_pass_length, const uint8_t password_index);
void crypto_eeprom_init(void);
#endif
+2
View File
@@ -5,6 +5,8 @@ SRC += red_crypto/sha256.c
SRC += red_crypto/aes.c
SRC += red_crypto/kuznechik_8bit.c
SRC += red_crypto/kc_to_ascii.c
SRC += red_crypto/utils.c
SRC += red_crypto/red_menu.c
# SRC += red_crypto/kuznechik_128bit.c # you can't include this, because you may not have ARMv8 and upper, check this
# TODO: do something like this:
+174
View File
@@ -0,0 +1,174 @@
#include "red_menu.h"
// clang-format off
enum menu_options {
EXIT,
SHOW_PASS_NAMES,
SHOW_MEMORY_USAGE,
CHANGE_MASTER_KEY,
CHANGE_PASS_IN_STORAGE,
CHANGE_PASS_NAME,
ADD_NEW_PASS,
SAVE_NEW_PASS,
READING_PASS,
READ_USER_CHOICE,
SHOW_MAIN_MENU,
WAIT_PASS_INDEX
};
// clang-format on
uint8_t readed_option[1] = {SHOW_MAIN_MENU};
uint8_t count_readed = 0;
uint8_t return_key = 0;
uint8_t password_index = 255;
uint8_t *enc_pass_new;
uint8_t *readed_key_new;
uint8_t count_char_key_new = 0;
// read new key
uint8_t read_new_key(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case KC_ENTER:
readed_option[0] = SAVE_NEW_PASS;
return RED_KEY_READ;
break;
default:
if (count_char_key_new + 1 == enc_pass.storage_pass_len) {
readed_option[0] = SAVE_NEW_PASS;
send_string("Length limit!\n");
// TODO: done this feature
}
return kc_to_ascii(keycode, record, readed_key_new, &count_char_key_new);
break;
}
return RED_IDLE;
}
// clang-format on
// return values
// 0 idle
// 1 get key input
// 2 exit menu
uint8_t draw_red_menu(uint16_t keycode, keyrecord_t *record) {
switch (readed_option[0]) {
case EXIT:
readed_option[0] = SHOW_MAIN_MENU;
return RED_MENU_EXIT;
break;
case READ_USER_CHOICE: {
return_key = kc_to_ascii(keycode, record, readed_option, &count_readed);
count_readed = 0;
if (readed_option[0] == ASCII_LOW_0) {
readed_option[0] = EXIT;
}
if (readed_option[0] == ASCII_LOW_1) {
readed_option[0] = SHOW_PASS_NAMES;
}
if (readed_option[0] == ASCII_LOW_2) {
readed_option[0] = SHOW_MEMORY_USAGE;
}
if (readed_option[0] == ASCII_LOW_3) {
readed_option[0] = CHANGE_MASTER_KEY;
}
if (readed_option[0] == ASCII_LOW_4) {
readed_option[0] = CHANGE_PASS_IN_STORAGE;
}
if (readed_option[0] == ASCII_LOW_5) {
readed_option[0] = CHANGE_PASS_NAME;
}
if (readed_option[0] == ASCII_LOW_6) {
readed_option[0] = ADD_NEW_PASS;
}
if (return_key == RED_KEY_READ) {
readed_key_new = red_init_array(MAX_KEY_LEN, 0x00); // init or reinit readed keys
count_char_key_new = 0; // init or reinit counted keys
CLEAR_MENU_MACROS;
return RED_KEY_READ;
}
break;
}
case SHOW_PASS_NAMES: // TODO
case SHOW_MEMORY_USAGE: // TODO
case CHANGE_MASTER_KEY: // TODO
case CHANGE_PASS_IN_STORAGE:
send_string("Which one? Write index in hex [0-9a-f]: "); // now you can change first 16 passwords on the fly
// to read more, I need read keys as integers, or bytes
readed_option[0] = WAIT_PASS_INDEX;
// send_string("Which one? [1-");
// send_byte(enc_pass.password_count);
// send_string("]: ");
break;
case WAIT_PASS_INDEX:
return_key = kc_to_ascii(keycode, record, readed_option, &count_readed);
count_readed = 0;
uint8_t pass_ind_upd = 0; // for checking right translation from keycode to num
if (return_key == RED_KEY_READ) {
if (readed_option[0] >= ASCII_LOW_0 && readed_option[0] <= ASCII_LOW_9) {
password_index = readed_option[0] - 0x30;
pass_ind_upd++;
} else if (readed_option[0] >= ASCII_LOW_A && readed_option[0] <= ASCII_LOW_F) {
password_index = readed_option[0] - 0x61 + 10;
pass_ind_upd++;
}
if (pass_ind_upd == 0 || password_index >= enc_pass.password_count) {
send_string("\nWrong index! Try again!\n");
readed_option[0] = CHANGE_PASS_IN_STORAGE;
} else {
readed_option[0] = READING_PASS;
send_string("\nWrite new password. Tap `Enter` for confirm\n");
}
return RED_KEY_READ;
}
break;
case CHANGE_PASS_NAME: // TODO
case SAVE_NEW_PASS:
enc_pass_new = (uint8_t *)malloc(sizeof(uint8_t) * enc_pass.storage_pass_len);
enc_pass_new = encrypt_pass_kuzn(readed_key_new, count_char_key_new, password_index);
count_char_key_new = 0;
if (password_index == 255) {
for (uint8_t new_pass_index = 0; new_pass_index < enc_pass.storage_pass_len; new_pass_index++) {
enc_pass.passwords[enc_pass.password_count * enc_pass.storage_pass_len + new_pass_index] = enc_pass_new[new_pass_index];
}
enc_pass.password_count++;
} else {
for (uint8_t new_pass_index = 0; new_pass_index < enc_pass.storage_pass_len; new_pass_index++) {
enc_pass.passwords[password_index * enc_pass.storage_pass_len + new_pass_index] = enc_pass_new[new_pass_index];
}
}
// eeconfig_update_user_datablock(enc_pass.raw);
red_write_to_storage();
send_string("Successful adding new key on keycode RED_PASS");
if (password_index == 255) {
send_byte(enc_pass.password_count);
} else {
send_byte(password_index);
password_index = 255;
}
send_string("\n");
send_string(SS_DELAY(1000));
CLEAR_MENU_MACROS;
send_string("Press `Enter` ");
readed_option[0] = SHOW_MAIN_MENU;
break;
case READING_PASS:
return read_new_key(keycode, record);
break;
case ADD_NEW_PASS:
if (enc_pass.password_count == enc_pass.storage_size) {
send_string("Limit error\n");
readed_option[0] = SHOW_MAIN_MENU;
} else {
send_string("Write new password. Tap `Enter` for confirm\n");
readed_option[0] = READING_PASS;
}
break;
default: // SHOW_MAIN_MENU
CLEAR_MENU_MACROS;
send_string("RED_CRYPTO MENU:\n0-EXIT\n1-Show password's names\n2-Show memory usage\n3-Change master key\n4-Change password in storage\n5-Change password's name\n6-Add new password\n");
send_string("Choose option(0-6): ");
readed_option[0] = READ_USER_CHOICE;
break;
}
return RED_IDLE;
}
+14
View File
@@ -0,0 +1,14 @@
#include QMK_KEYBOARD_H
#include "quantum.h"
#ifndef RED_MENU_H
# define RED_MENU_H
# include "kc_to_ascii.h"
# include "red_crypto.h"
#define CLEAR_MENU_MACROS send_string(SS_DOWN(X_LCTL) SS_DOWN(X_A) SS_UP(X_LCTL) SS_UP(X_A) SS_TAP(X_BACKSPACE))
uint8_t draw_red_menu(uint16_t keycode, keyrecord_t *record);
#endif
+98
View File
@@ -0,0 +1,98 @@
#include "utils.h"
void red_print_chars(uint8_t *c) {
for (uint8_t i = 0; i < 32; i++) {
if (c[i] == 0x00) break;
dprintf("%c", c[i]);
}
dprintf("\n");
};
void red_print_int(uint8_t *c, uint8_t len) {
for (uint8_t i = 0; i < len; i++) {
dprintf("%d", c[i]);
}
dprintf("\n");
};
void red_print_hex(uint8_t *h) {
for (uint8_t i = 0; i < 32; i++) {
dprintf("%x ", h[i]);
}
dprintf("\n");
};
size_t red_min_len(size_t a, size_t b) {
if (a < b)
return a;
else
return b;
}
void red_send_chars_pass(uint8_t *out) {
for (uint8_t i = 0; i < INIT_STORAGE_PASS_LEN && out[i] != 0; i++) {
send_char((char)out[i]);
}
};
uint8_t *red_init_array(uint8_t len, uint8_t val) {
uint8_t *arr = (uint8_t *)malloc(sizeof(uint8_t) * len);
for (uint8_t i = 0; i < len; i++) {
arr[i] = val;
}
return arr;
}
uint8_t **red_init_array_2d(uint8_t len_row, uint8_t len_col, uint8_t val) {
uint8_t **arr = (uint8_t **)malloc(sizeof(uint8_t *) * len_row);
for (uint8_t i = 0; i < len_row; i++) {
arr[i] = (uint8_t *)malloc(sizeof(uint8_t) * len_col);
for (uint8_t j = 0; j < len_col; j++) {
arr[i][j] = val;
}
}
return arr;
}
// count printable symbols of ASCII in string with safety check of max length
uint8_t red_strlen_printable(uint8_t *str_printable, uint8_t max_len) {
uint8_t result = 0;
while (result < max_len && *str_printable != '\0') {
result++;
str_printable++;
}
return result;
}
#ifdef USE_SHA256_KEY
// hashing string to 32byte with sha256
uint8_t *hashing_string(uint8_t *str_to_hash) {
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, str_to_hash, red_strlen_printable(str_to_hash, MAX_KEY_LEN));
// BYTE result_key[SHA256_BLOCK_SIZE];
BYTE *result_key = red_init_array(SHA256_BLOCK_SIZE, 0x00);
sha256_final(&ctx, result_key);
# ifdef USE_RED_CRY_DEBUG
red_print_hex(result_key);
# endif
return result_key;
}
#endif
// EEPROM utils
void red_write_to_storage(void) {
// uint8_t res = 0;
for (uint16_t raw_index = 0; raw_index < STORAGE_SIZE; raw_index++) {
// res = EEPROM_WriteDataByte(0x0000 + raw_index, enc_pass.raw[raw_index]);
EEPROM_WriteDataByte(0x0040 + raw_index, enc_pass.raw[raw_index]);
}
// return res;
}
void red_read_from_storage(void) {
for (uint16_t raw_index = 0; raw_index < STORAGE_SIZE; raw_index++) {
enc_pass.raw[raw_index] = EEPROM_ReadDataByte(0x0040 + raw_index);
}
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef RED_UTILS_H
#define RED_UTILS_H
#include QMK_KEYBOARD_H
#include "quantum.h"
#include "red_crypto.h"
void red_print_chars(uint8_t *c);
void red_print_int(uint8_t *c, uint8_t len);
void red_print_hex(uint8_t *h);
size_t red_min_len(size_t a, size_t b);
void red_send_chars_pass(uint8_t *out);
uint8_t *hashing_string(uint8_t *str_to_hash);
uint8_t *red_init_array(uint8_t len, uint8_t val);
uint8_t **red_init_array_2d(uint8_t len_row, uint8_t len_col, uint8_t val);
void red_write_to_storage(void);
void red_read_from_storage(void);
#endif