diff --git a/Makefile b/Makefile index 92396f5d2..e97cc71b3 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ ENABLE_MESSENGER := 1 ENABLE_MESSENGER_DELIVERY_NOTIFICATION := 1 ENABLE_MESSENGER_NOTIFICATION := 1 ENABLE_MESSENGER_UART := 0 +ENABLE_ENCRYPTION := 1 ############################################################# @@ -163,6 +164,10 @@ ifeq ($(ENABLE_MESSENGER),1) OBJS += app/messenger.o OBJS += ui/messenger.o endif +ifeq ($(ENABLE_ENCRYPTION),1) + OBJS += external/chacha/chacha.o + OBJS += helper/crypto.o +endif ifeq ($(OS), Windows_NT) TOP := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) @@ -222,7 +227,10 @@ endif CFLAGS = ifeq ($(ENABLE_CLANG),0) - CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c11 -MMD + # Highest optimization settings (possible breaking changes): + CFLAGS += -Oz -mcpu=cortex-m0 -fno-delete-null-pointer-checks -std=c11 -MMD + # Standard settings: + #CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c11 -MMD #CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c99 -MMD #CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=gnu99 -MMD #CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=gnu11 -MMD @@ -374,6 +382,9 @@ endif ifeq ($(ENABLE_MESSENGER_UART),1) CFLAGS += -DENABLE_MESSENGER_UART endif +ifeq ($(ENABLE_ENCRYPTION),1) + CFLAGS += -DENABLE_ENCRYPTION +endif LDFLAGS = ifeq ($(ENABLE_CLANG),0) diff --git a/README.md b/README.md index 5dfee65aa..3d68cf185 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ This repository is a fork of [Egzumer firmare](https://github.com/egzumer/uv-k5-firmware-custom) plus my changes: * `ENABLE_SPECTRUM_CHANNEL_SCAN` this enables spectrum channel scan mode (enter by going into memory mode and press F+5, this allows SUPER fast channel scanning (**4.5x faster than regular scanning**), regular scan of 200 memory channels takes roughly 18 seconds, **spectrum memory scan takes roughly 4 seconds**, if you have less channels stored i.e 50 - the spectrum memory scan will take only **1 second** +* `ENABLE_ENCRYPTION` - ChaCha20 256 bit encryption for the messenger, more info at [Encryption](https://github.com/kamilsss655/uv-k5-firmware-custom/wiki/44-%E2%80%90-Encryption#details) * Fixed AM AGC so **AM demodulation is crystal clear**, no audible clicks, no need for `AM_FIX`. * `RxOff` menu setting offsets the receive frequency by any specified amount in the range of `0-150Mhz` for use with upconverters. Allows to fine tune frequency (in `1kHz` steps) as opposed to other implementations that use hardcoded offsets. (**IMPORTANT: Make sure you set this value to 0 if not using an upconverter, when used for the first time. Otherwise it might load some random offset from EEPROM.**) * `ENABLE_SPECTRUM_COPY_VFO` allowing to exit the spectrum and fine tuning screen with PTT button and copy current peak frequency, modulation, step, bandwidth to VFO. Also entering spectrum will carry these settings from VFO (full integration). Now to enter fine tuning screen in spectrum press MENU button. This allows you to save and respond to the frequencies found much faster. @@ -159,6 +160,7 @@ ENABLE_SPECTRUM_SHOW_CHANNEL_NAME := 1 shows channel number and channel n ENABLE_ULTRA_LOW_POWER_TX := 0 transmits with ultra low power. useful for dev/testing ENABLE_ADJUSTABLE_RX_GAIN_SETTINGS := 1 keeps the rx gain settings set in spectrum mode after exit (otherwise these are always overwritten to default value), this makes much more sense considering that we have a radio with user adjustable gain so why not use it to adjust to current radio conditions, maximum gain allows to greatly increase reception in scan memory channels mode (in this configuration default gain settings are only set at boot and when exiting AM modulation mode to set it to sane value after am fix) ENABLE_SPECTRUM_CHANNEL_SCAN := 1 this enables spectrum channel scan mode (enter by going into memory mode and press F+5, this allows SUPER fast channel scanning (4.5x faster than regular scanning), regular scan of 200 memory channels takes roughly 18 seconds, spectrum memory scan takes roughly 4 seconds, if you have less channels stored i.e 50 - the spectrum memory scan will take only **1 second** +ENABLE_ENCRYPTION := 1 enable ChaCha20 256 bit encryption for messenger ``` diff --git a/app/action.c b/app/action.c index 7acf2b475..dc85d92ae 100644 --- a/app/action.c +++ b/app/action.c @@ -102,42 +102,12 @@ void ACTION_Monitor(void) RADIO_SetupRegisters(true); -#ifdef ENABLE_FMRADIO - if (gFmRadioMode) { - FM_Start(); - gRequestDisplayScreen = DISPLAY_FM; - } - else -#endif gRequestDisplayScreen = gScreenToDisplay; } void ACTION_Scan(bool bRestart) { (void)bRestart; -#ifdef ENABLE_FMRADIO - if (gFmRadioMode) - { - if (gCurrentFunction != FUNCTION_RECEIVE && - gCurrentFunction != FUNCTION_MONITOR && - gCurrentFunction != FUNCTION_TRANSMIT) - { - GUI_SelectNextDisplay(DISPLAY_FM); - - gMonitor = false; - - if (gFM_ScanState != FM_SCAN_OFF) - { - FM_Start(); - -#ifdef ENABLE_VOICE - gAnotherVoiceID = VOICE_ID_SCANNING_STOP; -#endif - } - } - return; - } -#endif if (!SCANNER_IsScanning()) { // not scanning diff --git a/app/app.c b/app/app.c index d68707cb0..a8d8466be 100644 --- a/app/app.c +++ b/app/app.c @@ -915,17 +915,6 @@ void APP_Update(void) } } -#ifdef ENABLE_FMRADIO - if (gScheduleFM && - gFM_ScanState != FM_SCAN_OFF && - gCurrentFunction != FUNCTION_MONITOR && - gCurrentFunction != FUNCTION_RECEIVE && - gCurrentFunction != FUNCTION_TRANSMIT) - { // switch to FM radio mode - FM_Start(); - gScheduleFM = false; - } -#endif #ifdef ENABLE_VOX if (gEeprom.VOX_SWITCH) @@ -1419,9 +1408,9 @@ void APP_TimeSlice500ms(void) if (gReducedService) { - BOARD_ADC_GetBatteryInfo(&gBatteryCurrentVoltage, &gBatteryCurrent); + BOARD_ADC_GetBatteryInfo(&gBatteryCurrentVoltage); - if (gBatteryCurrent > 500 || gBatteryCalibration[3] < gBatteryCurrentVoltage) + if (gBatteryCalibration[3] < gBatteryCurrentVoltage) { #ifdef ENABLE_OVERLAY overlay_FLASH_RebootToBootloader(); @@ -1442,7 +1431,7 @@ void APP_TimeSlice500ms(void) if ((gBatteryCheckCounter & 1) == 0) { - BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryVoltageIndex++], &gBatteryCurrent); + BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryVoltageIndex++]); if (gBatteryVoltageIndex > 3) gBatteryVoltageIndex = 0; BATTERY_GetReadings(true); @@ -1452,16 +1441,12 @@ void APP_TimeSlice500ms(void) // regular display updates (once every 2 sec) - if need be if ((gBatteryCheckCounter & 3) == 0) { - if (gChargingWithTypeC || gSetting_battery_text > 0) + if (gSetting_battery_text > 0) gUpdateStatus = true; - #ifdef ENABLE_SHOW_CHARGE_LEVEL - if (gChargingWithTypeC) - gUpdateDisplay = true; - #endif } #ifdef ENABLE_FMRADIO - if ((gFM_ScanState == FM_SCAN_OFF || gAskToSave) && !gCssBackgroundScan) + if (gAskToSave && !gCssBackgroundScan) #else if (!gCssBackgroundScan) #endif @@ -1893,51 +1878,45 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) } #endif } - else if (Key != KEY_SIDE1 && Key != KEY_SIDE2) { - switch (gScreenToDisplay) { - case DISPLAY_MAIN: + switch (gScreenToDisplay) { + case DISPLAY_MAIN: + if ((Key == KEY_SIDE1 || Key == KEY_SIDE2) && !SCANNER_IsScanning()) + { + ACTION_Handle(Key, bKeyPressed, bKeyHeld); + } + else MAIN_ProcessKeys(Key, bKeyPressed, bKeyHeld); - break; + + break; #ifdef ENABLE_FMRADIO - case DISPLAY_FM: - FM_ProcessKeys(Key, bKeyPressed, bKeyHeld); - break; + case DISPLAY_FM: + FM_ProcessKeys(Key, bKeyPressed, bKeyHeld); + break; #endif - case DISPLAY_MENU: - MENU_ProcessKeys(Key, bKeyPressed, bKeyHeld); + case DISPLAY_MENU: + MENU_ProcessKeys(Key, bKeyPressed, bKeyHeld); + break; + + #ifdef ENABLE_MESSENGER + case DISPLAY_MSG: + MSG_ProcessKeys(Key, bKeyPressed, bKeyHeld); break; - - #ifdef ENABLE_MESSENGER - case DISPLAY_MSG: - MSG_ProcessKeys(Key, bKeyPressed, bKeyHeld); - break; - #endif + #endif - case DISPLAY_SCANNER: - SCANNER_ProcessKeys(Key, bKeyPressed, bKeyHeld); - break; + case DISPLAY_SCANNER: + SCANNER_ProcessKeys(Key, bKeyPressed, bKeyHeld); + break; #ifdef ENABLE_AIRCOPY - case DISPLAY_AIRCOPY: - AIRCOPY_ProcessKeys(Key, bKeyPressed, bKeyHeld); - break; -#endif - case DISPLAY_INVALID: - default: - break; - } - } - else -#ifdef ENABLE_AIRCOPY - if (!SCANNER_IsScanning() && gScreenToDisplay != DISPLAY_AIRCOPY) -#else - if (!SCANNER_IsScanning()) + case DISPLAY_AIRCOPY: + AIRCOPY_ProcessKeys(Key, bKeyPressed, bKeyHeld); + break; #endif - { - ACTION_Handle(Key, bKeyPressed, bKeyHeld); + case DISPLAY_INVALID: + default: + gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; + break; } - else if (!bKeyHeld && bKeyPressed) - gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; } Skip: @@ -1963,6 +1942,7 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) SETTINGS_SaveSettings(); else gFlagSaveSettings = 1; + gRequestSaveSettings = false; gUpdateStatus = true; } diff --git a/app/fm.c b/app/fm.c index 2ea52afe9..5eb56e8a2 100644 --- a/app/fm.c +++ b/app/fm.c @@ -84,15 +84,8 @@ void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) case KEY_EXIT: Key_EXIT(); break; - case KEY_F: - GENERIC_Key_F(bKeyPressed, bKeyHeld); - break; - case KEY_PTT: - GENERIC_Key_PTT(bKeyPressed); - break; default: - if (!bKeyHeld && bKeyPressed) - gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; + gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; break; } } diff --git a/app/generic.c b/app/generic.c index f8a9f2362..13ba098b9 100644 --- a/app/generic.c +++ b/app/generic.c @@ -61,13 +61,9 @@ void GENERIC_Key_F(bool bKeyPressed, bool bKeyHeld) } else // released { - #ifdef ENABLE_FMRADIO - if ((gFmRadioMode || gScreenToDisplay != DISPLAY_MAIN) && gScreenToDisplay != DISPLAY_FM) - return; - #else - if (gScreenToDisplay != DISPLAY_MAIN) - return; - #endif + + if (gScreenToDisplay != DISPLAY_MAIN) + return; gWasFKeyPressed = !gWasFKeyPressed; // toggle F function @@ -90,14 +86,6 @@ void GENERIC_Key_F(bool bKeyPressed, bool bKeyHeld) return; } - #ifdef ENABLE_FMRADIO - if (gFM_ScanState == FM_SCAN_OFF) // not scanning - { - gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; - return; - } - #endif - gBeepToPlay = BEEP_440HZ_500MS; gPttWasReleased = true; diff --git a/app/menu.c b/app/menu.c index b20f810c1..521f69ca6 100644 --- a/app/menu.c +++ b/app/menu.c @@ -485,6 +485,15 @@ void MENU_AcceptSetting(void) break; #endif + #ifdef ENABLE_ENCRYPTION + case MENU_ENC_KEY: + memset(gEeprom.ENC_KEY, 0, sizeof(gEeprom.ENC_KEY)); + memmove(gEeprom.ENC_KEY, edit, sizeof(edit)); + memset(edit, 0, sizeof(edit)); + gUpdateStatus = true; + break; + #endif + case MENU_W_N: gTxVfo->CHANNEL_BANDWIDTH = gSubMenuSelection; gRequestSaveChannel = 1; @@ -1183,7 +1192,13 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; - if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && edit_index >= 0) + if (edit_index >= 0 && ( + UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME + #ifdef ENABLE_ENCRYPTION + || UI_MENU_GetCurrentMenuId() == MENU_ENC_KEY + #endif + )) + { // currently editing the channel name if (edit_index < 10) @@ -1455,15 +1470,40 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld) return; } + #ifdef ENABLE_ENCRYPTION + if (UI_MENU_GetCurrentMenuId() == MENU_ENC_KEY) + { + if (edit_index < 0) + { // enter encryption key edit mode + // pad the encryption key out with '_' + edit_index = strlen(edit); + while (edit_index < 10) + edit[edit_index++] = '_'; + edit[edit_index] = 0; + edit_index = 0; // 'edit_index' is going to be used as the cursor position + + return; + } + else if (edit_index >= 0 && edit_index < 10) + { // editing the encryption key characters + + if (++edit_index < 10) + return; // next char + + // exit, save encryption key + } + } + #endif + if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME) { if (edit_index < 0) { // enter channel name edit mode if (!RADIO_CheckValidChannel(gSubMenuSelection, false, 0)) return; - + SETTINGS_FetchChannelName(edit, gSubMenuSelection); - + // pad the channel name out with '_' edit_index = strlen(edit); while (edit_index < 10) @@ -1505,6 +1545,9 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld) if (UI_MENU_GetCurrentMenuId() == MENU_RESET || UI_MENU_GetCurrentMenuId() == MENU_MEM_CH || UI_MENU_GetCurrentMenuId() == MENU_DEL_CH || + #ifdef ENABLE_ENCRYPTION + UI_MENU_GetCurrentMenuId() == MENU_ENC_KEY || + #endif UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME) { switch (gAskForConfirmation) @@ -1613,10 +1656,19 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction) uint8_t Channel; bool bCheckScanList; - if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && gIsInSubMenu && edit_index >= 0) + if (gIsInSubMenu && + edit_index >= 0 && + ( + UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME + #ifdef ENABLE_ENCRYPTION + || UI_MENU_GetCurrentMenuId() == MENU_ENC_KEY + #endif + ) + ) { // change the character if (bKeyPressed && edit_index < 10 && Direction != 0) { + // TODO: Allow special chars when setting encryption key const char unwanted[] = "$%&!\"':;?^`|{}"; char c = edit[edit_index] + Direction; unsigned int i = 0; @@ -1747,8 +1799,16 @@ void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) MENU_Key_STAR(bKeyPressed, bKeyHeld); break; case KEY_F: - if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && edit_index >= 0) - { // currently editing the channel name + if (edit_index >= 0 && + ( + UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME + #ifdef ENABLE_ENCRYPTION + || UI_MENU_GetCurrentMenuId() == MENU_ENC_KEY + #endif + ) + ) + { // adds space, + // currently editing the channel name or enc_key if (!bKeyHeld && bKeyPressed) { gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; diff --git a/app/messenger.c b/app/messenger.c index 35fef308c..73669dbcf 100644 --- a/app/messenger.c +++ b/app/messenger.c @@ -15,23 +15,20 @@ #include "driver/system.h" #include "app/messenger.h" #include "ui/ui.h" +#ifdef ENABLE_ENCRYPTION + #include "helper/crypto.h" +#endif #if defined(ENABLE_UART) && defined(ENABLE_UART_DEBUG) #include "driver/uart.h" #endif -typedef enum MsgStatus { - READY, - SENDING, - RECEIVING, -} MsgStatus; - const uint8_t MSG_BUTTON_STATE_HELD = 1 << 1; const uint8_t MSG_BUTTON_EVENT_SHORT = 0; const uint8_t MSG_BUTTON_EVENT_LONG = MSG_BUTTON_STATE_HELD; -const uint8_t MAX_MSG_LENGTH = TX_MSG_LENGTH - 1; +const uint8_t MAX_MSG_LENGTH = PAYLOAD_LENGTH - 1; const uint16_t TONE2_FREQ = 0x3065; // 0x2854 @@ -44,16 +41,16 @@ unsigned char numberOfLettersAssignedToKey[9] = { 4, 3, 3, 3, 3, 3, 4, 3, 4 }; char T9TableNum[9][4] = { {'1', '\0', '\0', '\0'}, {'2', '\0', '\0', '\0'}, {'3', '\0', '\0', '\0'}, {'4', '\0', '\0', '\0'}, {'5', '\0', '\0', '\0'}, {'6', '\0', '\0', '\0'}, {'7', '\0', '\0', '\0'}, {'8', '\0', '\0', '\0'}, {'9', '\0', '\0', '\0'} }; unsigned char numberOfNumsAssignedToKey[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; -char cMessage[TX_MSG_LENGTH]; -char lastcMessage[TX_MSG_LENGTH]; -char rxMessage[4][MAX_RX_MSG_LENGTH + 2]; +char cMessage[PAYLOAD_LENGTH]; +char lastcMessage[PAYLOAD_LENGTH]; +char rxMessage[4][PAYLOAD_LENGTH + 2]; unsigned char cIndex = 0; unsigned char prevKey = 0, prevLetter = 0; KeyboardType keyboardType = UPPERCASE; MsgStatus msgStatus = READY; -uint8_t msgFSKBuffer[MSG_HEADER_LENGTH + MAX_RX_MSG_LENGTH]; +union DataPacket dataPacket; uint16_t gErrorsDuringMSG; @@ -77,6 +74,11 @@ void MSG_FSKSendData() { // set the FM deviation level const uint16_t dev_val = BK4819_ReadRegister(BK4819_REG_40); + + // mute the mic + const uint16_t reg30 = BK4819_ReadRegister(BK4819_REG_30); + BK4819_WriteRegister(BK4819_REG_30, reg30 & ~(1u << 2)); + //UART_printf("\n BANDWIDTH : 0x%.4X", dev_val); { uint16_t deviation = 850; @@ -227,7 +229,7 @@ void MSG_FSKSendData() { (0u << 0); // 0 ~ 7 ??? // Set packet length (not including pre-amble and sync bytes that we can't seem to disable) - BK4819_WriteRegister(BK4819_REG_5D, ((MSG_HEADER_LENGTH + MAX_RX_MSG_LENGTH) << 8)); + BK4819_WriteRegister(BK4819_REG_5D, ((sizeof(dataPacket.serializedArray)) << 8)); // REG_5A // @@ -267,12 +269,14 @@ void MSG_FSKSendData() { SYSTEM_DelayMs(100); { // load the entire packet data into the TX FIFO buffer - const uint16_t len_buff = (MSG_HEADER_LENGTH + MAX_RX_MSG_LENGTH); - for (size_t i = 0, j = 0; i < len_buff; i += 2, j++) { - BK4819_WriteRegister(BK4819_REG_5F, (msgFSKBuffer[i + 1] << 8) | msgFSKBuffer[i]); + for (size_t i = 0, j = 0; i < sizeof(dataPacket.serializedArray); i += 2, j++) { + BK4819_WriteRegister(BK4819_REG_5F, (dataPacket.serializedArray[i + 1] << 8) | dataPacket.serializedArray[i]); } } + // clear dataPacket + memset(dataPacket.serializedArray, 0, sizeof(dataPacket.serializedArray));; + // enable FSK TX BK4819_WriteRegister(BK4819_REG_59, (1u << 11) | fsk_reg59); @@ -302,6 +306,9 @@ void MSG_FSKSendData() { // restore FM deviation level BK4819_WriteRegister(BK4819_REG_40, dev_val); + //restore mic mute + BK4819_WriteRegister(BK4819_REG_30, reg30); + // restore TX/RX filtering BK4819_WriteRegister(BK4819_REG_2B, filt_val); @@ -508,7 +515,7 @@ void MSG_EnableRX(const bool enable) { { // packet size .. sync + 14 bytes - size of a single packet - uint16_t size = (MSG_HEADER_LENGTH + MAX_RX_MSG_LENGTH); + uint16_t size = sizeof(dataPacket.serializedArray); // size -= (fsk_reg59 & (1u << 3)) ? 4 : 2; size = (((size + 1) / 2) * 2) + 2; // round up to even, else FSK RX doesn't work BK4819_WriteRegister(BK4819_REG_5D, (size << 8)); @@ -529,7 +536,7 @@ void MSG_EnableRX(const bool enable) { // ----------------------------------------------------- -void moveUP(char (*rxMessages)[MAX_RX_MSG_LENGTH + 2]) { +void moveUP(char (*rxMessages)[PAYLOAD_LENGTH + 2]) { // Shift existing lines up strcpy(rxMessages[0], rxMessages[1]); strcpy(rxMessages[1], rxMessages[2]); @@ -539,34 +546,42 @@ void moveUP(char (*rxMessages)[MAX_RX_MSG_LENGTH + 2]) { memset(rxMessages[3], 0, sizeof(rxMessages[3])); } -void MSG_Send(const char txMessage[TX_MSG_LENGTH], bool bServiceMessage) { +void MSG_SendPacket(union DataPacket packet) { if ( msgStatus != READY ) return; - if ( strlen(txMessage) > 0 && (TX_freq_check(gCurrentVfo->pTX->Frequency) == 0) ) { + if ( strlen(packet.data.payload) > 0 && (TX_freq_check(gCurrentVfo->pTX->Frequency) == 0) ) { msgStatus = SENDING; RADIO_SetVfoState(VFO_STATE_NORMAL); + BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false); BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, true); - memset(msgFSKBuffer, 0, sizeof(msgFSKBuffer)); - - // ? ToDo - // first 20 byte sync, msg type and ID - msgFSKBuffer[0] = 'M'; - msgFSKBuffer[1] = 'S'; - - // next 20 for msg - memcpy(msgFSKBuffer + 2, txMessage, TX_MSG_LENGTH); - - // CRC ? ToDo - - msgFSKBuffer[MAX_RX_MSG_LENGTH - 1] = '\0'; - msgFSKBuffer[MAX_RX_MSG_LENGTH + 0] = 'I'; - msgFSKBuffer[MAX_RX_MSG_LENGTH + 1] = 'D'; - msgFSKBuffer[MAX_RX_MSG_LENGTH + 2] = '0'; - msgFSKBuffer[(MSG_HEADER_LENGTH + MAX_RX_MSG_LENGTH) - 1] = '#'; + memset(dataPacket.serializedArray, 0, sizeof(dataPacket.serializedArray)); + + // later refactor to not use global state but pass dataPacket type everywhere + dataPacket = packet; + #ifdef ENABLE_ENCRYPTION + if(packet.data.header == ENCRYPTED_MESSAGE_PACKET){ + char nonce[NONCE_LENGTH]; + + CRYPTO_Random(nonce, NONCE_LENGTH); + // this is wat happens when we have global state + memcpy(packet.data.nonce, nonce, NONCE_LENGTH); + + CRYPTO_Crypt( + packet.data.payload, + PAYLOAD_LENGTH, + dataPacket.data.payload, + &packet.data.nonce, + gEncryptionKey, + 256 + ); + + memcpy(dataPacket.data.nonce, nonce, sizeof(dataPacket.data.nonce)); + } + #endif BK4819_DisableDTMF(); @@ -583,7 +598,6 @@ void MSG_Send(const char txMessage[TX_MSG_LENGTH], bool bServiceMessage) { SYSTEM_DelayMs(100); - APP_EndTransmission(); // this must be run after end of TX, otherwise radio will still TX transmit without even RED LED on FUNCTION_Select(FUNCTION_FOREGROUND); @@ -593,11 +607,11 @@ void MSG_Send(const char txMessage[TX_MSG_LENGTH], bool bServiceMessage) { BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, false); MSG_EnableRX(true); - if (!bServiceMessage) { + if (packet.data.header != ACK_PACKET) { moveUP(rxMessage); - sprintf(rxMessage[3], "> %s", txMessage); + sprintf(rxMessage[3], "> %s", packet.data.payload); memset(lastcMessage, 0, sizeof(lastcMessage)); - memcpy(lastcMessage, txMessage, TX_MSG_LENGTH); + memcpy(lastcMessage, packet.data.payload, PAYLOAD_LENGTH); cIndex = 0; prevKey = 0; prevLetter = 0; @@ -629,7 +643,7 @@ void MSG_StorePacket(const uint16_t interrupt_bits) { if (rx_sync) { gFSKWriteIndex = 0; - memset(msgFSKBuffer, 0, sizeof(msgFSKBuffer)); + memset(dataPacket.serializedArray, 0, sizeof(dataPacket.serializedArray)); msgStatus = RECEIVING; } @@ -638,10 +652,10 @@ void MSG_StorePacket(const uint16_t interrupt_bits) { const uint16_t count = BK4819_ReadRegister(BK4819_REG_5E) & (7u << 0); // almost full threshold for (uint16_t i = 0; i < count; i++) { const uint16_t word = BK4819_ReadRegister(BK4819_REG_5F); - if (gFSKWriteIndex < sizeof(msgFSKBuffer)) - msgFSKBuffer[gFSKWriteIndex++] = validate_char((word >> 0) & 0xff); - if (gFSKWriteIndex < sizeof(msgFSKBuffer)) - msgFSKBuffer[gFSKWriteIndex++] = validate_char((word >> 8) & 0xff); + if (gFSKWriteIndex < sizeof(dataPacket.serializedArray)) + dataPacket.serializedArray[gFSKWriteIndex++] = (word >> 0) & 0xff; + if (gFSKWriteIndex < sizeof(dataPacket.serializedArray)) + dataPacket.serializedArray[gFSKWriteIndex++] = (word >> 8) & 0xff; } SYSTEM_DelayMs(10); @@ -658,31 +672,40 @@ void MSG_StorePacket(const uint16_t interrupt_bits) { if (gFSKWriteIndex > 2) { - // If there's three 0x1b bytes, then it's a service message - if (msgFSKBuffer[2] == 0x1b && msgFSKBuffer[3] == 0x1b && msgFSKBuffer[4] == 0x1b) { + if (dataPacket.data.header == ACK_PACKET) { #ifdef ENABLE_MESSENGER_DELIVERY_NOTIFICATION - // If the next 4 bytes are "RCVD", then it's a delivery notification - if (msgFSKBuffer[5] == 'R' && msgFSKBuffer[6] == 'C' && msgFSKBuffer[7] == 'V' && msgFSKBuffer[8] == 'D') { - #ifdef ENABLE_MESSENGER_UART - UART_printf("SVC= INVALID_PACKET) { + snprintf(rxMessage[3], PAYLOAD_LENGTH + 2, "ERROR: INVALID PACKET."); } else { - snprintf(rxMessage[3], TX_MSG_LENGTH + 2, "< %s", &msgFSKBuffer[2]); + #ifdef ENABLE_ENCRYPTION + if(dataPacket.data.header == ENCRYPTED_MESSAGE_PACKET) + { + CRYPTO_Crypt(dataPacket.data.payload, + PAYLOAD_LENGTH, + dataPacket.data.payload, + &dataPacket.data.nonce, + gEncryptionKey, + 256); + } + snprintf(rxMessage[3], PAYLOAD_LENGTH + 2, "< %s", dataPacket.data.payload); + #else + snprintf(rxMessage[3], PAYLOAD_LENGTH + 2, "< %s", dataPacket.data.payload); + #endif } #ifdef ENABLE_MESSENGER_UART - UART_printf("SMS<%s\r\n", &msgFSKBuffer[2]); + UART_printf("SMS<%s\r\n", dencryptedTxMessage); #endif if ( gScreenToDisplay != DISPLAY_MSG ) { @@ -701,8 +724,9 @@ void MSG_StorePacket(const uint16_t interrupt_bits) { gFSKWriteIndex = 0; // Transmit a message to the sender that we have received the message (Unless it's a service message) - if (msgFSKBuffer[0] == 'M' && msgFSKBuffer[1] == 'S' && msgFSKBuffer[2] != 0x1b) { - MSG_Send("\x1b\x1b\x1bRCVD ", true); + if (dataPacket.data.header!=ACK_PACKET) { + dataPacket.data.header=ACK_PACKET; + MSG_SendPacket(dataPacket); } } } @@ -780,7 +804,7 @@ void processBackspace() { void MSG_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { uint8_t state = bKeyPressed + 2 * bKeyHeld; - + if (state == MSG_BUTTON_EVENT_SHORT) { switch (Key) @@ -810,14 +834,21 @@ void MSG_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { break; case KEY_UP: memset(cMessage, 0, sizeof(cMessage)); - memcpy(cMessage, lastcMessage, TX_MSG_LENGTH); + memcpy(cMessage, lastcMessage, PAYLOAD_LENGTH); cIndex = strlen(cMessage); break; /*case KEY_DOWN: break;*/ case KEY_MENU: // Send message - MSG_Send(cMessage, false); + memset(dataPacket.serializedArray,0,sizeof(dataPacket.serializedArray)); + #ifdef ENABLE_ENCRYPTION + dataPacket.data.header=ENCRYPTED_MESSAGE_PACKET; + #else + dataPacket.data.header=MESSAGE_PACKET; + #endif + memcpy(dataPacket.data.payload, cMessage, sizeof(dataPacket.data.payload)); + MSG_SendPacket(dataPacket); break; case KEY_EXIT: gRequestDisplayScreen = DISPLAY_MAIN; diff --git a/app/messenger.h b/app/messenger.h index 47f55c7be..bc496e1f5 100644 --- a/app/messenger.h +++ b/app/messenger.h @@ -8,6 +8,11 @@ #include #include "driver/keyboard.h" +enum { + NONCE_LENGTH = 13, + PAYLOAD_LENGTH = 30 +}; + typedef enum KeyboardType { UPPERCASE, LOWERCASE, @@ -15,26 +20,46 @@ typedef enum KeyboardType { END_TYPE_KBRD } KeyboardType; -enum { - TX_MSG_LENGTH = 30, - MSG_HEADER_LENGTH = 20, - MAX_RX_MSG_LENGTH = TX_MSG_LENGTH + 2 -}; -//const uint8_t TX_MSG_LENGTH = 30; -//const uint8_t MAX_RX_MSG_LENGTH = TX_MSG_LENGTH + 2; - extern KeyboardType keyboardType; extern uint16_t gErrorsDuringMSG; -extern char cMessage[TX_MSG_LENGTH]; -extern char rxMessage[4][MAX_RX_MSG_LENGTH + 2]; +extern char cMessage[PAYLOAD_LENGTH]; +extern char rxMessage[4][PAYLOAD_LENGTH + 2]; extern uint8_t hasNewMessage; extern uint8_t keyTickCounter; +typedef enum MsgStatus { + READY, + SENDING, + RECEIVING, +} MsgStatus; + +typedef enum PacketType { + MESSAGE_PACKET = 100u, + ENCRYPTED_MESSAGE_PACKET, + ACK_PACKET, + INVALID_PACKET +} PacketType; + +// Data Packet definition // 2024 kamilsss655 +union DataPacket +{ + struct{ + uint8_t header; + uint8_t payload[PAYLOAD_LENGTH]; + unsigned char nonce[NONCE_LENGTH]; + // uint8_t signature[SIGNATURE_LENGTH]; + } data; + // header + payload + nonce = must be an even number + uint8_t serializedArray[1+PAYLOAD_LENGTH+NONCE_LENGTH]; +}; + + void MSG_EnableRX(const bool enable); void MSG_StorePacket(const uint16_t interrupt_bits); void MSG_Init(); void MSG_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld); -void MSG_Send(const char txMessage[TX_MSG_LENGTH], bool bServiceMessage); +void MSG_SendPacket(union DataPacket packet); +void MSG_FSKSendData(); #endif diff --git a/app/spectrum.c b/app/spectrum.c index 95e1a8205..c1e012a4c 100644 --- a/app/spectrum.c +++ b/app/spectrum.c @@ -793,7 +793,7 @@ static void DrawStatus() { #endif GUI_DisplaySmallest(String, 0, 1, true, true); - BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryCheckCounter++ % 4], &gBatteryCurrent); + BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryCheckCounter++ % 4]); uint16_t voltage = (gBatteryVoltages[0] + gBatteryVoltages[1] + gBatteryVoltages[2] + gBatteryVoltages[3]) / diff --git a/app/uart.c b/app/uart.c index 60cf0b668..b11dd2642 100644 --- a/app/uart.c +++ b/app/uart.c @@ -316,7 +316,7 @@ static void CMD_0529(void) Reply.Header.Size = sizeof(Reply.Data); // Original doesn't actually send current! - BOARD_ADC_GetBatteryInfo(&Reply.Data.Voltage, &Reply.Data.Current); + BOARD_ADC_GetBatteryInfo(&Reply.Data.Voltage); SendReply(&Reply, sizeof(Reply)); } diff --git a/bitmaps.c b/bitmaps.c index 8500def1c..c44dd8c95 100644 --- a/bitmaps.c +++ b/bitmaps.c @@ -105,19 +105,6 @@ const uint8_t BITMAP_BatteryLevel[2] = }; #endif -const uint8_t BITMAP_USB_C[9] = -{ // USB symbol - 0b00000000, - 0b00011100, - 0b00100111, - 0b01000100, - 0b01000100, - 0b01000100, - 0b01000100, - 0b00100111, - 0b00011100 -}; - const uint8_t BITMAP_KeyLock[6] = { // teeny padlock symbol 0b00000000, diff --git a/bitmaps.h b/bitmaps.h index c9c394c0d..5b1367fae 100644 --- a/bitmaps.h +++ b/bitmaps.h @@ -11,8 +11,6 @@ extern const uint8_t BITMAP_RX[8]; extern const uint8_t BITMAP_BatteryLevel[2]; extern const uint8_t BITMAP_BatteryLevel1[17]; -extern const uint8_t BITMAP_USB_C[9]; - extern const uint8_t BITMAP_KeyLock[6]; extern const uint8_t BITMAP_F_Key[6]; diff --git a/board.c b/board.c index 7f249ed46..572aa26c2 100644 --- a/board.c +++ b/board.c @@ -491,12 +491,11 @@ void BOARD_ADC_Init(void) ADC_SoftReset(); } -void BOARD_ADC_GetBatteryInfo(uint16_t *pVoltage, uint16_t *pCurrent) +void BOARD_ADC_GetBatteryInfo(uint16_t *pVoltage) { ADC_Start(); while (!ADC_CheckEndOfConversion(ADC_CH9)) {} *pVoltage = ADC_GetValue(ADC_CH4); - *pCurrent = ADC_GetValue(ADC_CH9); } void BOARD_Init(void) @@ -506,9 +505,6 @@ void BOARD_Init(void) BACKLIGHT_InitHardware(); BOARD_ADC_Init(); ST7565_Init(true); - #ifdef ENABLE_FMRADIO - BK1080_Init(0, false); - #endif CRC_Init(); } @@ -730,18 +726,10 @@ void BOARD_EEPROM_Init(void) att->band = 0xf; } } - - // 0F30..0F3F - EEPROM_ReadBuffer(0x0F30, gCustomAesKey, sizeof(gCustomAesKey)); - bHasCustomAesKey = false; - for (i = 0; i < ARRAY_SIZE(gCustomAesKey); i++) - { - if (gCustomAesKey[i] != 0xFFFFFFFFu) - { - bHasCustomAesKey = true; - return; - } - } + #ifdef ENABLE_ENCRYPTION + // 0F30..0F3F - load encryption key + EEPROM_ReadBuffer(0x0F30, gEeprom.ENC_KEY, sizeof(gEeprom.ENC_KEY)); + #endif #ifdef ENABLE_SPECTRUM_SHOW_CHANNEL_NAME BOARD_gMR_LoadChannels(); @@ -855,7 +843,7 @@ void BOARD_FactoryReset(bool bIsAll) { if ( !(i >= 0x0EE0 && i < 0x0F18) && // ANI ID + DTMF codes - !(i >= 0x0F30 && i < 0x0F50) && // AES KEY + F LOCK + Scramble Enable + !(i >= 0x0F30 && i < 0x0F50) && // ENCRYPTION KEY + F LOCK + Scramble Enable !(i >= 0x1C00 && i < 0x1E00) && // DTMF contacts !(i >= 0x0EB0 && i < 0x0ED0) && // Welcome strings !(i >= 0x0EA0 && i < 0x0EA8) && // Voice Prompt diff --git a/board.h b/board.h index 6247f5c08..9fef7d8b8 100644 --- a/board.h +++ b/board.h @@ -24,7 +24,7 @@ void BOARD_FLASH_Init(void); void BOARD_GPIO_Init(void); void BOARD_PORTCON_Init(void); void BOARD_ADC_Init(void); -void BOARD_ADC_GetBatteryInfo(uint16_t *pVoltage, uint16_t *pCurrent); +void BOARD_ADC_GetBatteryInfo(uint16_t *pVoltage); void BOARD_Init(void); void BOARD_EEPROM_Init(void); void BOARD_EEPROM_LoadCalibration(void); diff --git a/compile-with-docker.sh b/compile-with-docker.sh index 43c480a5c..fe2c0a58c 100755 --- a/compile-with-docker.sh +++ b/compile-with-docker.sh @@ -1,3 +1,5 @@ #!/bin/sh +# first clean images older than 24h, you will run out of disk space one day +docker image prune -a --force --filter "until=24h" docker build -t uvk5 . docker run --rm -v ${PWD}/compiled-firmware:/app/compiled-firmware uvk5 /bin/bash -c "cd /app && make clean && make && cp firmware* compiled-firmware/" diff --git a/docs/UV K5 EEPROM.xlsx b/docs/UV K5 EEPROM.xlsx index a722c21cb..9e1ecf34e 100644 Binary files a/docs/UV K5 EEPROM.xlsx and b/docs/UV K5 EEPROM.xlsx differ diff --git a/external/chacha/chacha.c b/external/chacha/chacha.c new file mode 100644 index 000000000..ac8451d37 --- /dev/null +++ b/external/chacha/chacha.c @@ -0,0 +1,227 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include "chacha.h" + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((unsigned char)(v) & U8C(0xFF)) +#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#if (USE_UNALIGNED == 1) +#define U8TO32_LITTLE(p) \ + (*((uint32_t *)(p))) +#define U32TO8_LITTLE(p, v) \ + do { \ + *((uint32_t *)(p)) = v; \ + } while (0) +#else +#define U8TO32_LITTLE(p) \ + (((uint32_t)((p)[0]) ) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) +#endif + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void +chacha_keysetup(struct chacha_ctx *x,const unsigned char *k,uint32_t kbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void +chacha_ivsetup(struct chacha_ctx *x, const unsigned char *iv, const unsigned char *counter) +{ + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); + //x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); + x->input[13] = U8TO32_LITTLE(iv + 0); + x->input[14] = U8TO32_LITTLE(iv + 4); + x->input[15] = U8TO32_LITTLE(iv + 8); +} + +void +chacha_encrypt_bytes(struct chacha_ctx *x,const unsigned char *m,unsigned char *c,uint32_t bytes) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + unsigned char *ctarget = NULL; + unsigned char tmp[64]; + u_int8_t i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { +#if (USE_MEMCPY == 1) + memcpy(tmp, m, bytes); +#else + for (i = 0;i < bytes;++i) tmp[i] = m[i]; +#endif + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { +#if (USE_MEMCPY == 1) + memcpy(ctarget, c, bytes); +#else + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; +#endif + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} diff --git a/external/chacha/chacha.h b/external/chacha/chacha.h new file mode 100644 index 000000000..3892001d1 --- /dev/null +++ b/external/chacha/chacha.h @@ -0,0 +1,38 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#ifndef CHACHA_H +#define CHACHA_H + +#include +#include +#include +#include + +#define CHACHA_MINKEYLEN 16 +#define CHACHA_NONCELEN 8 +#define CHACHA_CTRLEN 8 +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) +#define CHACHA_BLOCKLEN 64 + +/* use memcpy() to copy blocks of memory (typically faster) */ +#define USE_MEMCPY 1 +/* use unaligned little-endian load/store (can be faster) */ +#define USE_UNALIGNED 0 + +struct chacha_ctx { + uint32_t input[16]; +}; + +void chacha_keysetup(struct chacha_ctx *x, const unsigned char *k, + uint32_t kbits); +void chacha_ivsetup(struct chacha_ctx *x, const unsigned char *iv, + const unsigned char *ctr); +void chacha_encrypt_bytes(struct chacha_ctx *x, const unsigned char *m, + unsigned char *c, uint32_t bytes); + +#endif /* CHACHA_H */ + diff --git a/helper/battery.c b/helper/battery.c index 13f43c13b..ec077babe 100644 --- a/helper/battery.c +++ b/helper/battery.c @@ -26,11 +26,9 @@ uint16_t gBatteryCalibration[6]; uint16_t gBatteryCurrentVoltage; -uint16_t gBatteryCurrent; uint16_t gBatteryVoltages[4]; uint16_t gBatteryVoltageAverage; uint8_t gBatteryDisplayLevel; -bool gChargingWithTypeC; bool gLowBatteryBlink; bool gLowBattery; bool gLowBatteryConfirmed; @@ -123,28 +121,6 @@ void BATTERY_GetReadings(const bool bDisplayBatteryLevel) if ((gScreenToDisplay == DISPLAY_MENU) && UI_MENU_GetCurrentMenuId() == MENU_VOL) gUpdateDisplay = true; - if (gBatteryCurrent < 501) - { - if (gChargingWithTypeC) - { - gUpdateStatus = true; - gUpdateDisplay = true; - } - - gChargingWithTypeC = false; - } - else - { - if (!gChargingWithTypeC) - { - gUpdateStatus = true; - gUpdateDisplay = true; - BACKLIGHT_TurnOn(); - } - - gChargingWithTypeC = true; - } - if (PreviousBatteryLevel != gBatteryDisplayLevel) { if(gBatteryDisplayLevel > 2) @@ -181,42 +157,41 @@ void BATTERY_TimeSlice500ms(void) if (lowBatteryCountdown < lowBatteryPeriod) { - if (lowBatteryCountdown == lowBatteryPeriod-1 && !gChargingWithTypeC && !gLowBatteryConfirmed) + if (lowBatteryCountdown == lowBatteryPeriod-1 && !gLowBatteryConfirmed) AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP); } else { lowBatteryCountdown = 0; - if (!gChargingWithTypeC) - { // not on charge - if(!gLowBatteryConfirmed) { - AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP); + + if(!gLowBatteryConfirmed) { + AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP); #ifdef ENABLE_VOICE - AUDIO_SetVoiceID(0, VOICE_ID_LOW_VOLTAGE); + AUDIO_SetVoiceID(0, VOICE_ID_LOW_VOLTAGE); #endif - } - if (gBatteryDisplayLevel == 0) - { + } + if (gBatteryDisplayLevel == 0) + { #ifdef ENABLE_VOICE - AUDIO_PlaySingleVoice(true); + AUDIO_PlaySingleVoice(true); #endif - gReducedService = true; + gReducedService = true; - //if (gCurrentFunction != FUNCTION_POWER_SAVE) - FUNCTION_Select(FUNCTION_POWER_SAVE); + //if (gCurrentFunction != FUNCTION_POWER_SAVE) + FUNCTION_Select(FUNCTION_POWER_SAVE); - ST7565_HardwareReset(); + ST7565_HardwareReset(); - if (gEeprom.BACKLIGHT_TIME < (ARRAY_SIZE(gSubMenu_BACKLIGHT) - 1)) - BACKLIGHT_TurnOff(); // turn the backlight off - } + if (gEeprom.BACKLIGHT_TIME < (ARRAY_SIZE(gSubMenu_BACKLIGHT) - 1)) + BACKLIGHT_TurnOff(); // turn the backlight off + } #ifdef ENABLE_VOICE - else - AUDIO_PlaySingleVoice(false); + else + AUDIO_PlaySingleVoice(false); #endif - } + } } } diff --git a/helper/battery.h b/helper/battery.h index c951bd96d..f6fa36ae5 100644 --- a/helper/battery.h +++ b/helper/battery.h @@ -22,11 +22,9 @@ extern uint16_t gBatteryCalibration[6]; extern uint16_t gBatteryCurrentVoltage; -extern uint16_t gBatteryCurrent; extern uint16_t gBatteryVoltages[4]; extern uint16_t gBatteryVoltageAverage; extern uint8_t gBatteryDisplayLevel; -extern bool gChargingWithTypeC; extern bool gLowBatteryBlink; extern bool gLowBattery; extern bool gLowBatteryConfirmed; diff --git a/helper/crypto.c b/helper/crypto.c new file mode 100644 index 000000000..ddf905798 --- /dev/null +++ b/helper/crypto.c @@ -0,0 +1,134 @@ +/* Copyright 2024 kamilsss655 + * https://github.com/kamilsss655 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "crypto.h" +#include "external/chacha/chacha.h" +#include "driver/bk4819.h" +#include "driver/systick.h" + +u_int8_t gEncryptionKey[32]; + +// salt used for hashing encryption key from eeprom used for sending packets +// we never actually use the key stored in eeprom directly +// 4 salts for each 8 bytes chunks of the encryption key +static const uint8_t encryptionSalt[4][8] = { + {0xEF, 0x58, 0x0A, 0xC6, 0x12, 0x4A, 0xFA, 0x4F}, + {0xAE, 0x6F, 0x9D, 0x3C, 0xBB, 0x80, 0xAC, 0x4A}, + {0xF3, 0x5E, 0x11, 0x69, 0xC7, 0x97, 0xFB, 0xC6}, + {0x27, 0x4F, 0xB7, 0x1A, 0xA7, 0xE5, 0x77, 0x9C} +}; + +// salt used to display encryption key hash in menu +static const uint8_t displaySalt[32] = { + 0x22, 0xA1, 0xDA, 0x49, 0xA8, 0x22, 0x79, 0xBF, 0x2D, 0x98, 0xDE, 0xA8, 0x4F, 0xC3, 0x23, 0xF3, + 0x65, 0xB9, 0x69, 0x22, 0xB3, 0x6F, 0xB4, 0x59, 0xC7, 0x90, 0x10, 0x70, 0xFA, 0x51, 0xA0, 0x19 +}; + +// Used for both encryption and decryption +void CRYPTO_Crypt(void *input, int input_len, void *output, void *nonce, const void *key, int key_len) +{ + struct chacha_ctx ctx; + + unsigned char keystream[CHACHA_BLOCKLEN]; + + memset(&ctx, 0, sizeof(ctx)); + chacha_keysetup(&ctx, key, key_len); + + // init keystream and generate key + memset(keystream, 0, sizeof(keystream)); + chacha_ivsetup(&ctx, nonce, NULL); + chacha_encrypt_bytes(&ctx, keystream, keystream,sizeof(keystream)); + + // crypt data, only works for input_len <= 32 + for (uint8_t i = 0; i < input_len; i++) { + ((unsigned char *)output)[i] = + ((unsigned char *)input)[i] ^ keystream[32 + i]; + } +} + +// Generate random byte +uint8_t CRYPTO_RandomByte() +{ + uint8_t randByte = 0x00; + uint8_t noise; + for(uint8_t i = 0; i < 8; i++) { + noise = BK4819_ReadRegister(BK4819_REG_65) & 0x007F; + randByte |= (noise & 0x01)<< i; + SYSTICK_DelayUs(979); + } + return randByte; +} + +// Generate random number from the radio noise +void CRYPTO_Random(void *output, int len) +{ + for (uint8_t i = 0; i < len; i++) { + ((unsigned char *)output)[i] = CRYPTO_RandomByte(); + } +} + + +// Generate salted hash +// output is always 8 bytes (64 bits), +// input can be upto 255 bytes +void CRYPTO_HashSalted(const void *input, void *output, const void *salt, int input_len, int salt_len) +{ + union eight_bytes hash; + + // FNV offset basis + hash.u64 = 0xcbf29ce484222325; + // FNV prime + const uint64_t fnvPrime = 0x100000001b3; + + // hash input + for(int i=0; i + +extern uint8_t gEncryptionKey[32]; +static const uint8_t encryptionSalt[4][8]; +static const uint8_t displaySalt[32]; + +union eight_bytes { + uint64_t u64; + uint8_t b8[sizeof(uint64_t)]; +}; + +// Used for both encryption and decryption +void CRYPTO_Crypt(void *input, int input_len, void *output, void *nonce, const void *key, int key_len); +void CRYPTO_Random(void *output, int len); +uint8_t CRYPTO_RandomByte(); +void CRYPTO_DisplayHash(void *input, void *output, int input_len); +void CRYPTO_Generate256BitKey(void *input, void *output, int input_len); +void CRYPTO_HashSalted(const void *input, void *output, const void *salt, int input_len, int salt_len); \ No newline at end of file diff --git a/main.c b/main.c index 120007b90..858b8125a 100644 --- a/main.c +++ b/main.c @@ -79,7 +79,7 @@ void Main(void) memset(gDTMF_String, '-', sizeof(gDTMF_String)); gDTMF_String[sizeof(gDTMF_String) - 1] = 0; - BOARD_ADC_GetBatteryInfo(&gBatteryCurrentVoltage, &gBatteryCurrent); + BOARD_ADC_GetBatteryInfo(&gBatteryCurrentVoltage); BOARD_EEPROM_Init(); @@ -98,7 +98,7 @@ void Main(void) BK4819_SetAGC(gEeprom.RX_AGC!=RX_AGC_OFF); for (i = 0; i < ARRAY_SIZE(gBatteryVoltages); i++) - BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent); + BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i]); BATTERY_GetReadings(false); @@ -140,7 +140,7 @@ void Main(void) gDebounceCounter = 0; } - if (!gChargingWithTypeC && gBatteryDisplayLevel == 0) + if (gBatteryDisplayLevel == 0) { FUNCTION_Select(FUNCTION_POWER_SAVE); diff --git a/misc.c b/misc.c index 6ebc97dfd..2972d5eba 100644 --- a/misc.c +++ b/misc.c @@ -171,9 +171,6 @@ bool gFlagResetVfos; bool gRequestSaveVFO; uint8_t gRequestSaveChannel; bool gRequestSaveSettings; -#ifdef ENABLE_FMRADIO - bool gRequestSaveFM; -#endif bool gFlagPrepareTX; bool gFlagAcceptSetting; @@ -182,9 +179,6 @@ bool gFlagRefreshSetting; bool gFlagSaveVfo; bool gFlagSaveSettings; bool gFlagSaveChannel; -#ifdef ENABLE_FMRADIO - bool gFlagSaveFM; -#endif bool g_CDCSS_Lost; uint8_t gCDCSSCodeType; bool g_CTCSS_Lost; diff --git a/misc.h b/misc.h index eda934e6e..99014cd1b 100644 --- a/misc.h +++ b/misc.h @@ -280,9 +280,6 @@ extern bool gFlagResetVfos; extern bool gRequestSaveVFO; extern uint8_t gRequestSaveChannel; extern bool gRequestSaveSettings; -#ifdef ENABLE_FMRADIO - extern bool gRequestSaveFM; -#endif extern uint8_t gKeypadLocked; extern bool gFlagPrepareTX; @@ -292,9 +289,6 @@ extern bool gFlagRefreshSetting; // refresh menu display extern bool gFlagSaveVfo; extern bool gFlagSaveSettings; extern bool gFlagSaveChannel; -#ifdef ENABLE_FMRADIO - extern bool gFlagSaveFM; -#endif extern bool g_CDCSS_Lost; extern uint8_t gCDCSSCodeType; extern bool g_CTCSS_Lost; @@ -335,9 +329,6 @@ extern uint8_t gFSKWriteIndex; extern volatile bool gNextTimeslice; extern bool gUpdateDisplay; extern bool gF_LOCK; -#ifdef ENABLE_FMRADIO - extern uint8_t gFM_ChannelPosition; -#endif extern uint8_t gShowChPrefix; extern volatile uint8_t gFoundCDCSSCountdown_10ms; extern volatile uint8_t gFoundCTCSSCountdown_10ms; diff --git a/scheduler.c b/scheduler.c index faa16cd82..ca66c71f5 100644 --- a/scheduler.c +++ b/scheduler.c @@ -99,10 +99,10 @@ void SystickHandler(void) DECREMENT_AND_TRIGGER(gCountdownToPlayNextVoice_10ms, gFlagPlayQueuedVoice); #endif - #ifdef ENABLE_FMRADIO - if (gFM_ScanState != FM_SCAN_OFF && gCurrentFunction != FUNCTION_MONITOR) - if (gCurrentFunction != FUNCTION_TRANSMIT && gCurrentFunction != FUNCTION_RECEIVE) - DECREMENT_AND_TRIGGER(gFmPlayCountdown_10ms, gScheduleFM); + #ifdef ENABLE_FMRADIO //gFM_ScanState is never different than FM_SCAN_OFF + // if (gFM_ScanState != FM_SCAN_OFF && gCurrentFunction != FUNCTION_MONITOR) + // if (gCurrentFunction != FUNCTION_TRANSMIT && gCurrentFunction != FUNCTION_RECEIVE) + // DECREMENT_AND_TRIGGER(gFmPlayStandardCountdown_10ms, gScheduleFM); #endif #ifdef ENABLE_VOX diff --git a/settings.c b/settings.c index 1bae89f0d..43f6cb039 100644 --- a/settings.c +++ b/settings.c @@ -26,6 +26,10 @@ #include "settings.h" #include "board.h" +#ifdef ENABLE_ENCRYPTION + #include "helper/crypto.h" +#endif + EEPROM_Config_t gEeprom; void SETTINGS_SaveVfoIndices(void) @@ -176,6 +180,10 @@ void SETTINGS_SaveSettings(void) memcpy(&State[0], &gEeprom.FM_FrequencyPlaying, 2); EEPROM_WriteBuffer(0x0E88, State, true); #endif + + #ifdef ENABLE_ENCRYPTION + SETTINGS_SaveEncryptionKey(); + #endif } void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode) @@ -264,6 +272,16 @@ void SETTINGS_SaveChannelName(uint8_t channel, const char * name) EEPROM_WriteBuffer(0x0F58 + offset, buf + 8, true); } +#ifdef ENABLE_ENCRYPTION +void SETTINGS_SaveEncryptionKey() +{ + EEPROM_WriteBuffer(0x0F30, gEeprom.ENC_KEY, true); + EEPROM_WriteBuffer(0x0F38, gEeprom.ENC_KEY + 8, true); + + CRYPTO_Generate256BitKey(gEeprom.ENC_KEY, gEncryptionKey, sizeof(gEeprom.ENC_KEY)); +} +#endif + void SETTINGS_FetchChannelName(char *s, const int channel) { int i; diff --git a/settings.h b/settings.h index 5f3f83c39..0b5e526f7 100644 --- a/settings.h +++ b/settings.h @@ -154,12 +154,7 @@ typedef struct { uint8_t field8_0xb; #ifdef ENABLE_FMRADIO - uint16_t FM_SelectedFrequency; - uint8_t FM_SelectedChannel; - bool FM_IsMrMode; uint16_t FM_FrequencyPlaying; - uint16_t FM_LowerLimit; - uint16_t FM_UpperLimit; #endif uint8_t SQUELCH_LEVEL; @@ -245,6 +240,9 @@ typedef struct { #ifdef ENABLE_PWRON_PASSWORD uint32_t POWER_ON_PASSWORD; uint8_t PASSWORD_WRONG_ATTEMPTS; +#endif +#ifdef ENABLE_ENCRYPTION + char ENC_KEY[16]; #endif uint16_t VOX1_THRESHOLD; uint16_t VOX0_THRESHOLD; @@ -279,4 +277,7 @@ void SETTINGS_FetchChannelName(char *s, const int channel); void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration); void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep); void SETTINGS_SetVfoFrequency(uint32_t frequency); +#ifdef ENABLE_ENCRYPTION + void SETTINGS_SaveEncryptionKey(); +#endif #endif diff --git a/ui/main.c b/ui/main.c index 84f13f515..e65ea0d16 100644 --- a/ui/main.c +++ b/ui/main.c @@ -708,25 +708,6 @@ void UI_DisplayMain(void) UI_PrintStringSmall(String, 2, 0, 3); } #endif - -#ifdef ENABLE_SHOW_CHARGE_LEVEL - else if (gChargingWithTypeC) - { // charging .. show the battery state - if (gScreenToDisplay != DISPLAY_MAIN -#ifdef ENABLE_DTMF_CALLING - || gDTMF_CallState != DTMF_CALL_STATE_NONE -#endif - ) - return; - - center_line = CENTER_LINE_CHARGE_DATA; - - sprintf(String, "Charge %u.%02uV %u%%", - gBatteryVoltageAverage / 100, gBatteryVoltageAverage % 100, - BATTERY_VoltsToPercent(gBatteryVoltageAverage)); - UI_PrintStringSmall(String, 2, 0, 3); - } -#endif } } diff --git a/ui/menu.c b/ui/menu.c index e81cb1357..fb5c8e9c5 100644 --- a/ui/menu.c +++ b/ui/menu.c @@ -35,6 +35,9 @@ #include "ui/inputbox.h" #include "ui/menu.h" #include "ui/ui.h" +#ifdef ENABLE_ENCRYPTION + #include "helper/crypto.h" +#endif const t_menu_item MenuList[] = { @@ -111,6 +114,9 @@ const t_menu_item MenuList[] = {"RxMode", VOICE_ID_DUAL_STANDBY, MENU_TDR }, #ifdef ENABLE_PWRON_PASSWORD {"Passwd", VOICE_ID_INVALID, MENU_PASSWORD }, // power on password +#endif +#ifdef ENABLE_ENCRYPTION + {"EncKey", VOICE_ID_INVALID, MENU_ENC_KEY }, // encryption key #endif {"Sql", VOICE_ID_SQUELCH, MENU_SQL }, // hidden menu items from here on @@ -721,6 +727,37 @@ void UI_DisplayMenu(void) already_printed = true; break; } + #ifdef ENABLE_ENCRYPTION + case MENU_ENC_KEY: + { + if (!gIsInSubMenu) + { // show placeholder in main menu + strcpy(String, "****"); + UI_PrintString(String, menu_item_x1, menu_item_x2, 2, 8); + } + else + { // show the key being edited + if (edit_index != -1 || gAskForConfirmation) { + UI_PrintString(edit, (menu_item_x1 -2), 0, 2, 8); + // show the cursor + if(edit_index < 10) + UI_PrintString( "^", (menu_item_x1 -2) + (8 * edit_index), 0, 4, 8); + } + else{ + strcpy(String, "hashed value"); + UI_PrintStringSmall(String, 20, 0, 5); + + memset(String, 0, sizeof(String)); + + CRYPTO_DisplayHash(gEeprom.ENC_KEY, String, sizeof(gEeprom.ENC_KEY)); + UI_PrintString(String, (menu_item_x1 -2), 0, 2, 8); + } + } + + already_printed = true; + break; + } + #endif case MENU_SAVE: strcpy(String, gSubMenu_SAVE[gSubMenuSelection]); @@ -957,6 +994,9 @@ void UI_DisplayMenu(void) if ((UI_MENU_GetCurrentMenuId() == MENU_RESET || UI_MENU_GetCurrentMenuId() == MENU_MEM_CH || + #ifdef ENABLE_ENCRYPTION + UI_MENU_GetCurrentMenuId() == MENU_ENC_KEY || + #endif UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME || UI_MENU_GetCurrentMenuId() == MENU_DEL_CH) && gAskForConfirmation) { // display confirmation @@ -969,7 +1009,7 @@ void UI_DisplayMenu(void) void MENU_PrintNotAllowed() { - char String[7]; + char String[8]; strcpy(String, "NOT"); UI_PrintString(String, menu_item_x1, menu_item_x2, 0, 8); strcpy(String, "ALLOWED"); diff --git a/ui/menu.h b/ui/menu.h index 74bf7a2d2..f40cace2b 100644 --- a/ui/menu.h +++ b/ui/menu.h @@ -61,6 +61,9 @@ enum MENU_TDR, #ifdef ENABLE_PWRON_PASSWORD MENU_PASSWORD, +#endif +#ifdef ENABLE_ENCRYPTION + MENU_ENC_KEY, #endif MENU_BEEP, #ifdef ENABLE_VOICE diff --git a/ui/status.c b/ui/status.c index a95e187c8..e960b4077 100644 --- a/ui/status.c +++ b/ui/status.c @@ -182,9 +182,6 @@ void UI_DisplayStatus() unsigned int x2 = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1) - 3; - if (gChargingWithTypeC) - x2 -= sizeof(BITMAP_USB_C); // the radio is on charge - switch (gSetting_battery_text) { default: @@ -215,12 +212,7 @@ void UI_DisplayStatus() } // move to right side of the screen - x = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1) - sizeof(BITMAP_USB_C); - - // USB-C charge indicator - if (gChargingWithTypeC) - memmove(line + x, BITMAP_USB_C, sizeof(BITMAP_USB_C)); - x += sizeof(BITMAP_USB_C); + x = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1); // BATTERY LEVEL indicator UI_DrawBattery(line + x, gBatteryDisplayLevel, gLowBatteryBlink);