Init
This commit is contained in:
151
User/FreeRTOSConfig.h
Normal file
151
User/FreeRTOSConfig.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
FreeRTOS V202112.00
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
#include "debug.h"
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Application specific definitions.
|
||||
*
|
||||
* These definitions should be adjusted for your particular hardware and
|
||||
* application requirements.
|
||||
*
|
||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
*
|
||||
* See http://www.freertos.org/a00110.html.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
/* See https://www.freertos.org/Using-FreeRTOS-on-RISC-V.html */
|
||||
|
||||
/* don't have MTIME */
|
||||
#define configMTIME_BASE_ADDRESS ( 0 )
|
||||
#define configMTIMECMP_BASE_ADDRESS ( 0 )
|
||||
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configCPU_CLOCK_HZ SystemCoreClock
|
||||
#define configTICK_RATE_HZ ( ( TickType_t ) 500 )
|
||||
#define configMAX_PRIORITIES ( 15 )
|
||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 1024 ) /* Can be as low as 60 but some of the demo tasks that use this constant require it to be higher. */
|
||||
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 32 * 1024 ) )
|
||||
#define configMAX_TASK_NAME_LEN ( 16 )
|
||||
#define configUSE_TRACE_FACILITY 0
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 0
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 1
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||
#define configUSE_APPLICATION_TASK_TAG 0
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||
|
||||
/* Co-routine definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||
|
||||
/* Software timer definitions. */
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
||||
#define configTIMER_QUEUE_LENGTH 4
|
||||
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE )
|
||||
|
||||
|
||||
|
||||
/* Set the following definitions to 1 to include the API function, or zero
|
||||
to exclude the API function. */
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskCleanUpResources 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_eTaskGetState 1
|
||||
#define INCLUDE_xTimerPendFunctionCall 1
|
||||
#define INCLUDE_xTaskAbortDelay 1
|
||||
#define INCLUDE_xTaskGetHandle 1
|
||||
#define INCLUDE_xSemaphoreGetMutexHolder 1
|
||||
|
||||
|
||||
/* Normal assert() semantics without relying on the provision of an assert.h
|
||||
header file. */
|
||||
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); printf("err at line %d of file \"%s\". \r\n ",__LINE__,__FILE__); while(1); }
|
||||
|
||||
/* Map to the platform printf function. */
|
||||
#define configPRINT_STRING( pcString ) printf( pcString )
|
||||
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
45
User/ch32v30x_conf.h
Normal file
45
User/ch32v30x_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32v30x_conf.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2021/06/06
|
||||
* Description : Library configuration file.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#ifndef __CH32V30x_CONF_H
|
||||
#define __CH32V30x_CONF_H
|
||||
|
||||
#include "ch32v30x_adc.h"
|
||||
#include "ch32v30x_bkp.h"
|
||||
#include "ch32v30x_can.h"
|
||||
#include "ch32v30x_crc.h"
|
||||
#include "ch32v30x_dac.h"
|
||||
#include "ch32v30x_dbgmcu.h"
|
||||
#include "ch32v30x_dma.h"
|
||||
#include "ch32v30x_exti.h"
|
||||
#include "ch32v30x_flash.h"
|
||||
#include "ch32v30x_fsmc.h"
|
||||
#include "ch32v30x_gpio.h"
|
||||
#include "ch32v30x_i2c.h"
|
||||
#include "ch32v30x_iwdg.h"
|
||||
#include "ch32v30x_pwr.h"
|
||||
#include "ch32v30x_rcc.h"
|
||||
#include "ch32v30x_rtc.h"
|
||||
#include "ch32v30x_sdio.h"
|
||||
#include "ch32v30x_spi.h"
|
||||
#include "ch32v30x_tim.h"
|
||||
#include "ch32v30x_usart.h"
|
||||
#include "ch32v30x_wwdg.h"
|
||||
#include "ch32v30x_it.h"
|
||||
#include "ch32v30x_misc.h"
|
||||
|
||||
|
||||
#endif /* __CH32V30x_CONF_H */
|
||||
|
||||
|
||||
|
||||
|
||||
|
246
User/ch32v30x_it.c
Normal file
246
User/ch32v30x_it.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32v30x_it.c
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2024/03/05
|
||||
* Description : Main Interrupt Service Routines.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#include "ch32v30x_it.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
void NMI_Handler (void) __attribute__ ((interrupt ("WCH-Interrupt-fast")));
|
||||
void HardFault_Handler (void) __attribute__ ((interrupt ("WCH-Interrupt-fast")));
|
||||
|
||||
/*********************************************************************
|
||||
* @fn NMI_Handler
|
||||
*
|
||||
* @brief This function handles NMI exception.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void NMI_Handler (void) {
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t ra;
|
||||
uint32_t t0;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
uint32_t s0;
|
||||
uint32_t s1;
|
||||
uint32_t a0;
|
||||
uint32_t a1;
|
||||
uint32_t a2;
|
||||
uint32_t a3;
|
||||
uint32_t a4;
|
||||
uint32_t a5;
|
||||
uint32_t a6;
|
||||
uint32_t a7;
|
||||
uint32_t s2;
|
||||
uint32_t s3;
|
||||
uint32_t s4;
|
||||
uint32_t s5;
|
||||
uint32_t s6;
|
||||
uint32_t s7;
|
||||
uint32_t s8;
|
||||
uint32_t s9;
|
||||
uint32_t s10;
|
||||
uint32_t s11;
|
||||
uint32_t t3;
|
||||
uint32_t t4;
|
||||
uint32_t t5;
|
||||
uint32_t t6;
|
||||
} HardFaultRegs;
|
||||
|
||||
// Minimal printf over UART
|
||||
void uart_printf (const char *fmt) {
|
||||
while (*fmt) {
|
||||
USART_SendData (USART1, *fmt);
|
||||
while (USART_GetFlagStatus (USART1, USART_FLAG_TXE) == RESET);
|
||||
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_hex32 (unsigned long val) {
|
||||
const char hex[] = "0123456789ABCDEF";
|
||||
USART_SendData (USART1, '0');
|
||||
while (USART_GetFlagStatus (USART1, USART_FLAG_TXE) == RESET);
|
||||
USART_SendData (USART1, 'x');
|
||||
while (USART_GetFlagStatus (USART1, USART_FLAG_TXE) == RESET);
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
USART_SendData (USART1, hex[(val >> (i * 4)) & 0xF]);
|
||||
while (USART_GetFlagStatus (USART1, USART_FLAG_TXE) == RESET);
|
||||
}
|
||||
}
|
||||
|
||||
volatile HardFaultRegs hardfault_regs; // visible in debugger
|
||||
|
||||
/*********************************************************************
|
||||
* @fn HardFault_Handler
|
||||
*
|
||||
* @brief This function handles Hard Fault exception.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void HardFault_Handler (void) {
|
||||
|
||||
uint32_t *sp;
|
||||
__asm volatile ("mv %0, sp"
|
||||
: "=r"(sp)); // get current stack pointer
|
||||
|
||||
// Copy the stacked registers to the volatile struct
|
||||
hardfault_regs.ra = sp[0];
|
||||
hardfault_regs.t0 = sp[1];
|
||||
hardfault_regs.t1 = sp[2];
|
||||
hardfault_regs.t2 = sp[3];
|
||||
hardfault_regs.s0 = sp[4];
|
||||
hardfault_regs.s1 = sp[5];
|
||||
hardfault_regs.a0 = sp[6];
|
||||
hardfault_regs.a1 = sp[7];
|
||||
hardfault_regs.a2 = sp[8];
|
||||
hardfault_regs.a3 = sp[9];
|
||||
hardfault_regs.a4 = sp[10];
|
||||
hardfault_regs.a5 = sp[11];
|
||||
hardfault_regs.a6 = sp[12];
|
||||
hardfault_regs.a7 = sp[13];
|
||||
hardfault_regs.s2 = sp[14];
|
||||
hardfault_regs.s3 = sp[15];
|
||||
hardfault_regs.s4 = sp[16];
|
||||
hardfault_regs.s5 = sp[17];
|
||||
hardfault_regs.s6 = sp[18];
|
||||
hardfault_regs.s7 = sp[19];
|
||||
hardfault_regs.s8 = sp[20];
|
||||
hardfault_regs.s9 = sp[21];
|
||||
hardfault_regs.s10 = sp[22];
|
||||
hardfault_regs.s11 = sp[23];
|
||||
hardfault_regs.t3 = sp[24];
|
||||
hardfault_regs.t4 = sp[25];
|
||||
hardfault_regs.t5 = sp[26];
|
||||
hardfault_regs.t6 = sp[27];
|
||||
|
||||
// Print all registers
|
||||
uart_printf ("HardFault! Registers:\n");
|
||||
|
||||
uart_printf ("RA: ");
|
||||
print_hex32 (hardfault_regs.ra);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("T0: ");
|
||||
print_hex32 (hardfault_regs.t0);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("T1: ");
|
||||
print_hex32 (hardfault_regs.t1);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("T2: ");
|
||||
print_hex32 (hardfault_regs.t2);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S0: ");
|
||||
print_hex32 (hardfault_regs.s0);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S1: ");
|
||||
print_hex32 (hardfault_regs.s1);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("A0: ");
|
||||
print_hex32 (hardfault_regs.a0);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("A1: ");
|
||||
print_hex32 (hardfault_regs.a1);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("A2: ");
|
||||
print_hex32 (hardfault_regs.a2);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("A3: ");
|
||||
print_hex32 (hardfault_regs.a3);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("A4: ");
|
||||
print_hex32 (hardfault_regs.a4);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("A5: ");
|
||||
print_hex32 (hardfault_regs.a5);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("A6: ");
|
||||
print_hex32 (hardfault_regs.a6);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("A7: ");
|
||||
print_hex32 (hardfault_regs.a7);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S2: ");
|
||||
print_hex32 (hardfault_regs.s2);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S3: ");
|
||||
print_hex32 (hardfault_regs.s3);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S4: ");
|
||||
print_hex32 (hardfault_regs.s4);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S5: ");
|
||||
print_hex32 (hardfault_regs.s5);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S6: ");
|
||||
print_hex32 (hardfault_regs.s6);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S7: ");
|
||||
print_hex32 (hardfault_regs.s7);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S8: ");
|
||||
print_hex32 (hardfault_regs.s8);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S9: ");
|
||||
print_hex32 (hardfault_regs.s9);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S10: ");
|
||||
print_hex32 (hardfault_regs.s10);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("S11: ");
|
||||
print_hex32 (hardfault_regs.s11);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("T3: ");
|
||||
print_hex32 (hardfault_regs.t3);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("T4: ");
|
||||
print_hex32 (hardfault_regs.t4);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("T5: ");
|
||||
print_hex32 (hardfault_regs.t5);
|
||||
uart_printf ("\n");
|
||||
|
||||
uart_printf ("T6: ");
|
||||
print_hex32 (hardfault_regs.t6);
|
||||
uart_printf ("\n");
|
||||
Delay_Ms (1000);
|
||||
NVIC_SystemReset();
|
||||
while (1) {
|
||||
}
|
||||
}
|
20
User/ch32v30x_it.h
Normal file
20
User/ch32v30x_it.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32v30x_it.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2021/06/06
|
||||
* Description : This file contains the headers of the interrupt handlers.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#ifndef __CH32V30x_IT_H
|
||||
#define __CH32V30x_IT_H
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#endif /* __CH32V30x_IT_H */
|
||||
|
||||
|
25
User/lib/base64.c
Normal file
25
User/lib/base64.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "base64.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static const char b64_enc_table[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
int base64_encode(const uint8_t *in, size_t ilen, char *out)
|
||||
{
|
||||
size_t out_len = 0;
|
||||
for (size_t i = 0; i < ilen; i += 3) {
|
||||
uint32_t triple = 0;
|
||||
int remain = ilen - i;
|
||||
|
||||
triple |= in[i] << 16;
|
||||
if (remain > 1) triple |= in[i + 1] << 8;
|
||||
if (remain > 2) triple |= in[i + 2];
|
||||
|
||||
out[out_len++] = b64_enc_table[(triple >> 18) & 0x3F];
|
||||
out[out_len++] = b64_enc_table[(triple >> 12) & 0x3F];
|
||||
out[out_len++] = (remain > 1) ? b64_enc_table[(triple >> 6) & 0x3F] : '=';
|
||||
out[out_len++] = (remain > 2) ? b64_enc_table[triple & 0x3F] : '=';
|
||||
}
|
||||
return 0;
|
||||
}
|
7
User/lib/base64.h
Normal file
7
User/lib/base64.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifdef B64_HEADER
|
||||
#define B64_HEADER
|
||||
#include <stddef.h>
|
||||
|
||||
int base64_encode(const uint8_t *in, size_t ilen, char *out);
|
||||
|
||||
#endif
|
417
User/lib/cifra/aes.c
Normal file
417
User/lib/cifra/aes.c
Normal file
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cf_config.h"
|
||||
#include "aes.h"
|
||||
#include "handy.h"
|
||||
#include "bitops.h"
|
||||
#include "tassert.h"
|
||||
|
||||
static const uint8_t S[256] =
|
||||
{
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe,
|
||||
0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4,
|
||||
0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7,
|
||||
0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3,
|
||||
0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09,
|
||||
0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3,
|
||||
0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe,
|
||||
0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92,
|
||||
0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c,
|
||||
0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,
|
||||
0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
|
||||
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2,
|
||||
0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5,
|
||||
0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25,
|
||||
0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86,
|
||||
0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e,
|
||||
0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42,
|
||||
0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
|
||||
static const uint8_t Rcon[11] =
|
||||
{
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
|
||||
};
|
||||
|
||||
#ifdef INLINE_FUNCS
|
||||
static inline uint32_t word4(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3)
|
||||
{
|
||||
return b0 << 24 | b1 << 16 | b2 << 8 | b3;
|
||||
}
|
||||
|
||||
static inline uint8_t byte(uint32_t w, unsigned x)
|
||||
{
|
||||
/* nb. bytes are numbered 0 (leftmost, top)
|
||||
* to 3 (rightmost). */
|
||||
x = 3 - x;
|
||||
return (w >> (x * 8)) & 0xff;
|
||||
}
|
||||
|
||||
static uint32_t round_constant(uint32_t i)
|
||||
{
|
||||
return Rcon[i] << 24;
|
||||
}
|
||||
|
||||
static uint32_t rot_word(uint32_t w)
|
||||
{
|
||||
/* Takes
|
||||
* word [a0,a1,a2,a3]
|
||||
* returns
|
||||
* word [a1,a2,a3,a0]
|
||||
*
|
||||
*/
|
||||
return rotl32(w, 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define word4(a, b, c, d) (((uint32_t)(a) << 24) | ((uint32_t)(b) << 16) | ((uint32_t)(c) << 8) | (d))
|
||||
#define byte(w, x) ((w >> ((3 - (x)) << 3)) & 0xff)
|
||||
#define round_constant(i) ((uint32_t)(Rcon[i]) << 24)
|
||||
#define rot_word(w) rotl32((w), 8)
|
||||
|
||||
static uint32_t sub_word(uint32_t w, const uint8_t *sbox)
|
||||
{
|
||||
uint8_t a = byte(w, 0),
|
||||
b = byte(w, 1),
|
||||
c = byte(w, 2),
|
||||
d = byte(w, 3);
|
||||
#if CF_CACHE_SIDE_CHANNEL_PROTECTION
|
||||
select_u8x4(&a, &b, &c, &d, sbox, 256);
|
||||
#else
|
||||
a = sbox[a];
|
||||
b = sbox[b];
|
||||
c = sbox[c];
|
||||
d = sbox[d];
|
||||
#endif
|
||||
return word4(a, b, c, d);
|
||||
}
|
||||
|
||||
static void aes_schedule(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
|
||||
{
|
||||
size_t i,
|
||||
nb = AES_BLOCKSZ / 4,
|
||||
nk = nkey / 4,
|
||||
n = nb * (ctx->rounds + 1);
|
||||
uint32_t *w = ctx->ks;
|
||||
|
||||
/* First words are just the key. */
|
||||
for (i = 0; i < nk; i++)
|
||||
{
|
||||
w[i] = read32_be(key + i * 4);
|
||||
}
|
||||
|
||||
uint32_t i_div_nk = 1;
|
||||
uint32_t i_mod_nk = 0;
|
||||
|
||||
for (; i < n; i++, i_mod_nk++)
|
||||
{
|
||||
uint32_t temp = w[i - 1];
|
||||
|
||||
if (i_mod_nk == nk)
|
||||
{
|
||||
i_div_nk++;
|
||||
i_mod_nk = 0;
|
||||
}
|
||||
|
||||
if (i_mod_nk == 0)
|
||||
temp = sub_word(rot_word(temp), S) ^ round_constant(i_div_nk);
|
||||
else if (nk > 6 && i_mod_nk == 4)
|
||||
temp = sub_word(temp, S);
|
||||
|
||||
w[i] = w[i - nk] ^ temp;
|
||||
}
|
||||
}
|
||||
|
||||
void cf_aes_init(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
|
||||
{
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
|
||||
switch (nkey)
|
||||
{
|
||||
#if CF_AES_MAXROUNDS >= AES128_ROUNDS
|
||||
case 16:
|
||||
ctx->rounds = AES128_ROUNDS;
|
||||
aes_schedule(ctx, key, nkey);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if CF_AES_MAXROUNDS >= AES192_ROUNDS
|
||||
case 24:
|
||||
ctx->rounds = AES192_ROUNDS;
|
||||
aes_schedule(ctx, key, nkey);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if CF_AES_MAXROUNDS >= AES256_ROUNDS
|
||||
case 32:
|
||||
ctx->rounds = AES256_ROUNDS;
|
||||
aes_schedule(ctx, key, nkey);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void add_round_key(uint32_t state[4], const uint32_t rk[4])
|
||||
{
|
||||
state[0] ^= rk[0];
|
||||
state[1] ^= rk[1];
|
||||
state[2] ^= rk[2];
|
||||
state[3] ^= rk[3];
|
||||
}
|
||||
|
||||
static void sub_block(uint32_t state[4])
|
||||
{
|
||||
state[0] = sub_word(state[0], S);
|
||||
state[1] = sub_word(state[1], S);
|
||||
state[2] = sub_word(state[2], S);
|
||||
state[3] = sub_word(state[3], S);
|
||||
}
|
||||
|
||||
static void shift_rows(uint32_t state[4])
|
||||
{
|
||||
uint32_t u, v, x, y;
|
||||
|
||||
u = word4(byte(state[0], 0),
|
||||
byte(state[1], 1),
|
||||
byte(state[2], 2),
|
||||
byte(state[3], 3));
|
||||
|
||||
v = word4(byte(state[1], 0),
|
||||
byte(state[2], 1),
|
||||
byte(state[3], 2),
|
||||
byte(state[0], 3));
|
||||
|
||||
x = word4(byte(state[2], 0),
|
||||
byte(state[3], 1),
|
||||
byte(state[0], 2),
|
||||
byte(state[1], 3));
|
||||
|
||||
y = word4(byte(state[3], 0),
|
||||
byte(state[0], 1),
|
||||
byte(state[1], 2),
|
||||
byte(state[2], 3));
|
||||
|
||||
state[0] = u;
|
||||
state[1] = v;
|
||||
state[2] = x;
|
||||
state[3] = y;
|
||||
}
|
||||
|
||||
static uint32_t gf_poly_mul2(uint32_t x)
|
||||
{
|
||||
return
|
||||
((x & 0x7f7f7f7f) << 1) ^
|
||||
(((x & 0x80808080) >> 7) * 0x1b);
|
||||
}
|
||||
|
||||
static uint32_t mix_column(uint32_t x)
|
||||
{
|
||||
uint32_t x2 = gf_poly_mul2(x);
|
||||
return x2 ^ rotr32(x ^ x2, 24) ^ rotr32(x, 16) ^ rotr32(x, 8);
|
||||
}
|
||||
|
||||
static void mix_columns(uint32_t state[4])
|
||||
{
|
||||
state[0] = mix_column(state[0]);
|
||||
state[1] = mix_column(state[1]);
|
||||
state[2] = mix_column(state[2]);
|
||||
state[3] = mix_column(state[3]);
|
||||
}
|
||||
|
||||
void cf_aes_encrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
assert(ctx->rounds == AES128_ROUNDS ||
|
||||
ctx->rounds == AES192_ROUNDS ||
|
||||
ctx->rounds == AES256_ROUNDS);
|
||||
|
||||
uint32_t state[4] = {
|
||||
read32_be(in + 0),
|
||||
read32_be(in + 4),
|
||||
read32_be(in + 8),
|
||||
read32_be(in + 12)
|
||||
};
|
||||
|
||||
const uint32_t *round_keys = ctx->ks;
|
||||
add_round_key(state, round_keys);
|
||||
round_keys += 4;
|
||||
|
||||
for (uint32_t round = 1; round < ctx->rounds; round++)
|
||||
{
|
||||
sub_block(state);
|
||||
shift_rows(state);
|
||||
mix_columns(state);
|
||||
add_round_key(state, round_keys);
|
||||
round_keys += 4;
|
||||
}
|
||||
|
||||
sub_block(state);
|
||||
shift_rows(state);
|
||||
add_round_key(state, round_keys);
|
||||
|
||||
write32_be(state[0], out + 0);
|
||||
write32_be(state[1], out + 4);
|
||||
write32_be(state[2], out + 8);
|
||||
write32_be(state[3], out + 12);
|
||||
}
|
||||
|
||||
#if CF_AES_ENCRYPT_ONLY == 0
|
||||
static const uint8_t S_inv[256] =
|
||||
{
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81,
|
||||
0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e,
|
||||
0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23,
|
||||
0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66,
|
||||
0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72,
|
||||
0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65,
|
||||
0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46,
|
||||
0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
|
||||
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca,
|
||||
0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91,
|
||||
0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,
|
||||
0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
|
||||
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f,
|
||||
0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2,
|
||||
0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8,
|
||||
0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93,
|
||||
0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb,
|
||||
0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6,
|
||||
0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
static void inv_sub_block(uint32_t state[4])
|
||||
{
|
||||
state[0] = sub_word(state[0], S_inv);
|
||||
state[1] = sub_word(state[1], S_inv);
|
||||
state[2] = sub_word(state[2], S_inv);
|
||||
state[3] = sub_word(state[3], S_inv);
|
||||
}
|
||||
|
||||
static void inv_shift_rows(uint32_t state[4])
|
||||
{
|
||||
uint32_t u, v, x, y;
|
||||
|
||||
u = word4(byte(state[0], 0),
|
||||
byte(state[3], 1),
|
||||
byte(state[2], 2),
|
||||
byte(state[1], 3));
|
||||
|
||||
v = word4(byte(state[1], 0),
|
||||
byte(state[0], 1),
|
||||
byte(state[3], 2),
|
||||
byte(state[2], 3));
|
||||
|
||||
x = word4(byte(state[2], 0),
|
||||
byte(state[1], 1),
|
||||
byte(state[0], 2),
|
||||
byte(state[3], 3));
|
||||
|
||||
y = word4(byte(state[3], 0),
|
||||
byte(state[2], 1),
|
||||
byte(state[1], 2),
|
||||
byte(state[0], 3));
|
||||
|
||||
state[0] = u;
|
||||
state[1] = v;
|
||||
state[2] = x;
|
||||
state[3] = y;
|
||||
}
|
||||
|
||||
static uint32_t inv_mix_column(uint32_t x)
|
||||
{
|
||||
uint32_t x2 = gf_poly_mul2(x),
|
||||
x4 = gf_poly_mul2(x2),
|
||||
x9 = x ^ gf_poly_mul2(x4),
|
||||
x11 = x2 ^ x9,
|
||||
x13 = x4 ^ x9;
|
||||
|
||||
return x ^ x2 ^ x13 ^ rotr32(x11, 24) ^ rotr32(x13, 16) ^ rotr32(x9, 8);
|
||||
}
|
||||
|
||||
static void inv_mix_columns(uint32_t state[4])
|
||||
{
|
||||
state[0] = inv_mix_column(state[0]);
|
||||
state[1] = inv_mix_column(state[1]);
|
||||
state[2] = inv_mix_column(state[2]);
|
||||
state[3] = inv_mix_column(state[3]);
|
||||
}
|
||||
|
||||
void cf_aes_decrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
assert(ctx->rounds == AES128_ROUNDS ||
|
||||
ctx->rounds == AES192_ROUNDS ||
|
||||
ctx->rounds == AES256_ROUNDS);
|
||||
|
||||
uint32_t state[4] = {
|
||||
read32_be(in + 0),
|
||||
read32_be(in + 4),
|
||||
read32_be(in + 8),
|
||||
read32_be(in + 12)
|
||||
};
|
||||
|
||||
const uint32_t *round_keys = &ctx->ks[ctx->rounds << 2];
|
||||
add_round_key(state, round_keys);
|
||||
round_keys -= 4;
|
||||
|
||||
for (uint32_t round = ctx->rounds - 1; round != 0; round--)
|
||||
{
|
||||
inv_shift_rows(state);
|
||||
inv_sub_block(state);
|
||||
add_round_key(state, round_keys);
|
||||
inv_mix_columns(state);
|
||||
round_keys -= 4;
|
||||
}
|
||||
|
||||
inv_shift_rows(state);
|
||||
inv_sub_block(state);
|
||||
add_round_key(state, round_keys);
|
||||
|
||||
write32_be(state[0], out + 0);
|
||||
write32_be(state[1], out + 4);
|
||||
write32_be(state[2], out + 8);
|
||||
write32_be(state[3], out + 12);
|
||||
}
|
||||
#else
|
||||
void cf_aes_decrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
void cf_aes_finish(cf_aes_context *ctx)
|
||||
{
|
||||
mem_clean(ctx, sizeof *ctx);
|
||||
}
|
||||
|
||||
const cf_prp cf_aes = {
|
||||
.blocksz = AES_BLOCKSZ,
|
||||
.encrypt = (cf_prp_block) cf_aes_encrypt,
|
||||
.decrypt = (cf_prp_block) cf_aes_decrypt
|
||||
};
|
||||
|
152
User/lib/cifra/aes.h
Normal file
152
User/lib/cifra/aes.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The AES block cipher
|
||||
* ====================
|
||||
*
|
||||
* This is a small, simple implementation of AES. Key expansion is done
|
||||
* first, filling in a :c:type:`cf_aes_context`. Then encryption and
|
||||
* decryption can be performed as desired.
|
||||
*
|
||||
* Usually you don't want to use AES directly; you should use it via
|
||||
* a :doc:`block cipher mode <modes>`.
|
||||
*/
|
||||
|
||||
#ifndef AES_H
|
||||
#define AES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "prp.h"
|
||||
|
||||
/* .. c:macro:: AES_BLOCKSZ
|
||||
* AES has a 128-bit block size. This quantity is in bytes.
|
||||
*/
|
||||
#define AES_BLOCKSZ 16
|
||||
|
||||
/* --- Size configuration --- */
|
||||
|
||||
/* .. c:macro:: AES128_ROUNDS
|
||||
* .. c:macro:: AES192_ROUNDS
|
||||
* .. c:macro:: AES256_ROUNDS
|
||||
*
|
||||
* Round counts for different key sizes.
|
||||
*/
|
||||
#define AES128_ROUNDS 10
|
||||
#define AES192_ROUNDS 12
|
||||
#define AES256_ROUNDS 14
|
||||
|
||||
/* .. c:macro:: CF_AES_MAXROUNDS
|
||||
*
|
||||
* You can reduce the maximum number of rounds this implementation
|
||||
* supports. This reduces the storage needed by :c:type:`cf_aes_context`.
|
||||
*
|
||||
* The default is :c:macro:`AES256_ROUNDS` and is good for all key
|
||||
* sizes.
|
||||
*/
|
||||
#ifndef CF_AES_MAXROUNDS
|
||||
# define CF_AES_MAXROUNDS AES256_ROUNDS
|
||||
#endif
|
||||
|
||||
/* .. c:macro:: CF_AES_ENCRYPT_ONLY
|
||||
*
|
||||
* Define this to 1 if you don't need to decrypt anything.
|
||||
* This saves space. :c:func:`cf_aes_decrypt` calls `abort(3)`.
|
||||
*/
|
||||
#ifndef CF_AES_ENCRYPT_ONLY
|
||||
# define CF_AES_ENCRYPT_ONLY 0
|
||||
#endif
|
||||
|
||||
/* .. c:type:: cf_aes_context
|
||||
* This type represents an expanded AES key. Create one
|
||||
* using :c:func:`cf_aes_init`, make use of one using
|
||||
* :c:func:`cf_aes_encrypt` or :c:func:`cf_aes_decrypt`.
|
||||
*
|
||||
* The contents of this structure are equivalent to the
|
||||
* original key material. You should clean the
|
||||
* contents of this structure with :c:func:`cf_aes_finish`
|
||||
* when you're done.
|
||||
*
|
||||
* .. c:member:: cf_aes_context.rounds
|
||||
*
|
||||
* Number of rounds to use, set by :c:func:`cf_aes_init`.
|
||||
*
|
||||
* This depends on the original key size, and will be
|
||||
* :c:macro:`AES128_ROUNDS`, :c:macro:`AES192_ROUNDS` or
|
||||
* :c:macro:`AES256_ROUNDS`.
|
||||
*
|
||||
* .. c:member:: cf_aes_context.ks
|
||||
*
|
||||
* Expanded key material. Filled in by :c:func:`cf_aes_init`.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t rounds;
|
||||
uint32_t ks[AES_BLOCKSZ / 4 * (CF_AES_MAXROUNDS + 1)];
|
||||
} cf_aes_context;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* This function does AES key expansion. It destroys
|
||||
* existing contents of :c:data:`ctx`.
|
||||
*
|
||||
* :param ctx: expanded key context, filled in by this function.
|
||||
* :param key: pointer to key material, of :c:data:`nkey` bytes.
|
||||
* :param nkey: length of key material. Must be `16`, `24` or `32`.
|
||||
*/
|
||||
extern void cf_aes_init(cf_aes_context *ctx,
|
||||
const uint8_t *key,
|
||||
size_t nkey);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Encrypts the given block, from :c:data:`in` to :c:data:`out`.
|
||||
* These may alias.
|
||||
*
|
||||
* Fails at runtime if :c:data:`ctx` is invalid.
|
||||
*
|
||||
* :param ctx: expanded key context
|
||||
* :param in: input block (read)
|
||||
* :param out: output block (written)
|
||||
*/
|
||||
extern void cf_aes_encrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Decrypts the given block, from :c:data:`in` to :c:data:`out`.
|
||||
* These may alias.
|
||||
*
|
||||
* Fails at runtime if :c:data:`ctx` is invalid.
|
||||
*
|
||||
* :param ctx: expanded key context
|
||||
* :param in: input block (read)
|
||||
* :param out: output block (written)
|
||||
*/
|
||||
extern void cf_aes_decrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Erase scheduled key material.
|
||||
*
|
||||
* Call this when you're done to erase the round keys. */
|
||||
extern void cf_aes_finish(cf_aes_context *ctx);
|
||||
|
||||
/* .. c:var:: const cf_prp cf_aes
|
||||
* Abstract interface to AES. See :c:type:`cf_prp` for
|
||||
* more information. */
|
||||
extern const cf_prp cf_aes;
|
||||
|
||||
#endif
|
294
User/lib/cifra/bitops.h
Normal file
294
User/lib/cifra/bitops.h
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef BITOPS_H
|
||||
#define BITOPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Assorted bitwise and common operations used in ciphers. */
|
||||
|
||||
/** Circularly rotate right x by n bits.
|
||||
* 0 > n > 32. */
|
||||
static inline uint32_t rotr32(uint32_t x, unsigned n)
|
||||
{
|
||||
return (x >> n) | (x << (32 - n));
|
||||
}
|
||||
|
||||
/** Circularly rotate left x by n bits.
|
||||
* 0 > n > 32. */
|
||||
static inline uint32_t rotl32(uint32_t x, unsigned n)
|
||||
{
|
||||
return (x << n) | (x >> (32 - n));
|
||||
}
|
||||
|
||||
/** Circularly rotate right x by n bits.
|
||||
* 0 > n > 64. */
|
||||
static inline uint64_t rotr64(uint64_t x, unsigned n)
|
||||
{
|
||||
return (x >> n) | (x << (64 - n));
|
||||
}
|
||||
|
||||
/** Circularly rotate left x by n bits.
|
||||
* 0 > n > 64. */
|
||||
static inline uint64_t rotl64(uint64_t x, unsigned n)
|
||||
{
|
||||
return (x << n) | (x >> (64 - n));
|
||||
}
|
||||
|
||||
/** Read 4 bytes from buf, as a 32-bit big endian quantity. */
|
||||
static inline uint32_t read32_be(const uint8_t buf[4])
|
||||
{
|
||||
return (buf[0] << 24) |
|
||||
(buf[1] << 16) |
|
||||
(buf[2] << 8) |
|
||||
(buf[3]);
|
||||
}
|
||||
|
||||
/** Read 4 bytes from buf, as a 32-bit little endian quantity. */
|
||||
static inline uint32_t read32_le(const uint8_t buf[4])
|
||||
{
|
||||
return (buf[3] << 24) |
|
||||
(buf[2] << 16) |
|
||||
(buf[1] << 8) |
|
||||
(buf[0]);
|
||||
}
|
||||
|
||||
/** Read 8 bytes from buf, as a 64-bit big endian quantity. */
|
||||
static inline uint64_t read64_be(const uint8_t buf[8])
|
||||
{
|
||||
uint32_t hi = read32_be(buf),
|
||||
lo = read32_be(buf + 4);
|
||||
return ((uint64_t)hi) << 32 |
|
||||
lo;
|
||||
}
|
||||
|
||||
/** Read 8 bytes from buf, as a 64-bit little endian quantity. */
|
||||
static inline uint64_t read64_le(const uint8_t buf[8])
|
||||
{
|
||||
uint32_t hi = read32_le(buf + 4),
|
||||
lo = read32_le(buf);
|
||||
return ((uint64_t)hi) << 32 |
|
||||
lo;
|
||||
}
|
||||
|
||||
/** Encode v as a 32-bit big endian quantity into buf. */
|
||||
static inline void write32_be(uint32_t v, uint8_t buf[4])
|
||||
{
|
||||
*buf++ = (v >> 24) & 0xff;
|
||||
*buf++ = (v >> 16) & 0xff;
|
||||
*buf++ = (v >> 8) & 0xff;
|
||||
*buf = v & 0xff;
|
||||
}
|
||||
|
||||
/** Encode v as a 32-bit little endian quantity into buf. */
|
||||
static inline void write32_le(uint32_t v, uint8_t buf[4])
|
||||
{
|
||||
*buf++ = v & 0xff;
|
||||
*buf++ = (v >> 8) & 0xff;
|
||||
*buf++ = (v >> 16) & 0xff;
|
||||
*buf = (v >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/** Encode v as a 64-bit big endian quantity into buf. */
|
||||
static inline void write64_be(uint64_t v, uint8_t buf[8])
|
||||
{
|
||||
*buf++ = (v >> 56) & 0xff;
|
||||
*buf++ = (v >> 48) & 0xff;
|
||||
*buf++ = (v >> 40) & 0xff;
|
||||
*buf++ = (v >> 32) & 0xff;
|
||||
*buf++ = (v >> 24) & 0xff;
|
||||
*buf++ = (v >> 16) & 0xff;
|
||||
*buf++ = (v >> 8) & 0xff;
|
||||
*buf = v & 0xff;
|
||||
}
|
||||
|
||||
/** Encode v as a 64-bit little endian quantity into buf. */
|
||||
static inline void write64_le(uint64_t v, uint8_t buf[8])
|
||||
{
|
||||
*buf++ = v & 0xff;
|
||||
*buf++ = (v >> 8) & 0xff;
|
||||
*buf++ = (v >> 16) & 0xff;
|
||||
*buf++ = (v >> 24) & 0xff;
|
||||
*buf++ = (v >> 32) & 0xff;
|
||||
*buf++ = (v >> 40) & 0xff;
|
||||
*buf++ = (v >> 48) & 0xff;
|
||||
*buf = (v >> 56) & 0xff;
|
||||
}
|
||||
|
||||
/** out = in ^ b8.
|
||||
* out and in may alias. */
|
||||
static inline void xor_b8(uint8_t *out, const uint8_t *in, uint8_t b8, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
out[i] = in[i] ^ b8;
|
||||
}
|
||||
|
||||
/** out = x ^ y.
|
||||
* out, x and y may alias. */
|
||||
static inline void xor_bb(uint8_t *out, const uint8_t *x, const uint8_t *y, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
out[i] = x[i] ^ y[i];
|
||||
}
|
||||
|
||||
/* out ^= x
|
||||
* out and x may alias. */
|
||||
static inline void xor_words(uint32_t *out, const uint32_t *x, size_t nwords)
|
||||
{
|
||||
for (size_t i = 0; i < nwords; i++)
|
||||
out[i] ^= x[i];
|
||||
}
|
||||
|
||||
/** Produce 0xffffffff if x == y, zero otherwise, without branching. */
|
||||
static inline uint32_t mask_u32(uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t diff = x ^ y;
|
||||
uint32_t diff_is_zero = ~diff & (diff - 1);
|
||||
return - (diff_is_zero >> 31);
|
||||
}
|
||||
|
||||
/** Product 0xff if x == y, zero otherwise, without branching. */
|
||||
static inline uint8_t mask_u8(uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t diff = x ^ y;
|
||||
uint8_t diff_is_zero = ~diff & (diff - 1);
|
||||
return - (diff_is_zero >> 7);
|
||||
}
|
||||
|
||||
/** Select the ith entry from the given table of n values, in a side channel-silent
|
||||
* way. */
|
||||
static inline uint32_t select_u32(uint32_t i, volatile const uint32_t *tab, uint32_t n)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
|
||||
for (uint32_t ii = 0; ii < n; ii++)
|
||||
{
|
||||
uint32_t mask = mask_u32(i, ii);
|
||||
r = (r & ~mask) | (tab[ii] & mask);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Select the ith entry from the given table of n values, in a side channel-silent
|
||||
* way. */
|
||||
static inline uint8_t select_u8(uint32_t i, volatile const uint8_t *tab, uint32_t n)
|
||||
{
|
||||
uint8_t r = 0;
|
||||
|
||||
for (uint32_t ii = 0; ii < n; ii++)
|
||||
{
|
||||
uint8_t mask = mask_u8(i, ii);
|
||||
r = (r & ~mask) | (tab[ii] & mask);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Select the ath, bth, cth and dth entries from the given table of n values,
|
||||
* placing the results into a, b, c and d. */
|
||||
static inline void select_u8x4(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d,
|
||||
volatile const uint8_t *tab, uint32_t n)
|
||||
{
|
||||
uint8_t ra = 0,
|
||||
rb = 0,
|
||||
rc = 0,
|
||||
rd = 0;
|
||||
uint8_t mask;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
uint8_t item = tab[i];
|
||||
|
||||
mask = mask_u8(*a, i); ra = (ra & ~mask) | (item & mask);
|
||||
mask = mask_u8(*b, i); rb = (rb & ~mask) | (item & mask);
|
||||
mask = mask_u8(*c, i); rc = (rc & ~mask) | (item & mask);
|
||||
mask = mask_u8(*d, i); rd = (rd & ~mask) | (item & mask);
|
||||
}
|
||||
|
||||
*a = ra;
|
||||
*b = rb;
|
||||
*c = rc;
|
||||
*d = rd;
|
||||
}
|
||||
|
||||
/** out ^= if0 or if1, depending on the value of bit. */
|
||||
static inline void select_xor128(uint32_t out[4],
|
||||
const uint32_t if0[4],
|
||||
const uint32_t if1[4],
|
||||
uint8_t bit)
|
||||
{
|
||||
uint32_t mask1 = mask_u32(bit, 1);
|
||||
uint32_t mask0 = ~mask1;
|
||||
|
||||
out[0] ^= (if0[0] & mask0) | (if1[0] & mask1);
|
||||
out[1] ^= (if0[1] & mask0) | (if1[1] & mask1);
|
||||
out[2] ^= (if0[2] & mask0) | (if1[2] & mask1);
|
||||
out[3] ^= (if0[3] & mask0) | (if1[3] & mask1);
|
||||
}
|
||||
|
||||
/** Increments the integer stored at v (of non-zero length len)
|
||||
* with the least significant byte first. */
|
||||
static inline void incr_le(uint8_t *v, size_t len)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (1)
|
||||
{
|
||||
if (++v[i] != 0)
|
||||
return;
|
||||
i++;
|
||||
if (i == len)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Increments the integer stored at v (of non-zero length len)
|
||||
* with the most significant byte last. */
|
||||
static inline void incr_be(uint8_t *v, size_t len)
|
||||
{
|
||||
len--;
|
||||
while (1)
|
||||
{
|
||||
if (++v[len] != 0)
|
||||
return;
|
||||
if (len == 0)
|
||||
return;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
/** Copies len bytes from in to out, with in shifted left by offset bits
|
||||
* to the right. */
|
||||
static inline void copy_bytes_unaligned(uint8_t *out, const uint8_t *in, size_t len, uint8_t offset)
|
||||
{
|
||||
uint8_t byte_off = offset / 8;
|
||||
uint8_t bit_off = offset & 7;
|
||||
uint8_t rmask = (1 << bit_off) - 1;
|
||||
uint8_t lmask = ~rmask;
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
out[i] = (in[i + byte_off] << bit_off) & lmask;
|
||||
out[i] |= (in[i + byte_off + 1] >> (8 - bit_off)) & rmask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t count_trailing_zeroes(uint32_t x)
|
||||
{
|
||||
return (uint32_t) __builtin_ctzl(x);
|
||||
}
|
||||
|
||||
#endif
|
195
User/lib/cifra/blockwise.c
Normal file
195
User/lib/cifra/blockwise.c
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include "blockwise.h"
|
||||
#include "bitops.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock,
|
||||
const void *inp, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx)
|
||||
{
|
||||
cf_blockwise_accumulate_final(partial, npartial, nblock,
|
||||
inp, nbytes,
|
||||
process, process, ctx);
|
||||
}
|
||||
|
||||
void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock,
|
||||
const void *inp, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
cf_blockwise_in_fn process_final,
|
||||
void *ctx)
|
||||
{
|
||||
const uint8_t *bufin = inp;
|
||||
assert(partial && *npartial < nblock);
|
||||
assert(inp || !nbytes);
|
||||
assert(process && ctx);
|
||||
|
||||
/* If we have partial data, copy in to buffer. */
|
||||
if (*npartial && nbytes)
|
||||
{
|
||||
size_t space = nblock - *npartial;
|
||||
size_t taken = MIN(space, nbytes);
|
||||
|
||||
memcpy(partial + *npartial, bufin, taken);
|
||||
|
||||
bufin += taken;
|
||||
nbytes -= taken;
|
||||
*npartial += taken;
|
||||
|
||||
/* If that gives us a full block, process it. */
|
||||
if (*npartial == nblock)
|
||||
{
|
||||
if (nbytes == 0)
|
||||
process_final(ctx, partial);
|
||||
else
|
||||
process(ctx, partial);
|
||||
*npartial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* now nbytes < nblock or *npartial == 0. */
|
||||
|
||||
/* If we have a full block of data, process it directly. */
|
||||
while (nbytes >= nblock)
|
||||
{
|
||||
/* Partial buffer must be empty, or we're ignoring extant data */
|
||||
assert(*npartial == 0);
|
||||
|
||||
if (nbytes == nblock)
|
||||
process_final(ctx, bufin);
|
||||
else
|
||||
process(ctx, bufin);
|
||||
bufin += nblock;
|
||||
nbytes -= nblock;
|
||||
}
|
||||
|
||||
/* Finally, if we have remaining data, buffer it. */
|
||||
while (nbytes)
|
||||
{
|
||||
size_t space = nblock - *npartial;
|
||||
size_t taken = MIN(space, nbytes);
|
||||
|
||||
memcpy(partial + *npartial, bufin, taken);
|
||||
|
||||
bufin += taken;
|
||||
nbytes -= taken;
|
||||
*npartial += taken;
|
||||
|
||||
/* If we started with *npartial, we must have copied it
|
||||
* in first. */
|
||||
assert(*npartial < nblock);
|
||||
}
|
||||
}
|
||||
|
||||
void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock,
|
||||
const void *inp, void *outp, size_t nbytes,
|
||||
cf_blockwise_out_fn process, void *ctx)
|
||||
{
|
||||
const uint8_t *inb = inp;
|
||||
uint8_t *outb = outp;
|
||||
|
||||
assert(partial && *npartial < nblock);
|
||||
assert(inp || !nbytes);
|
||||
assert(process && ctx);
|
||||
|
||||
while (nbytes)
|
||||
{
|
||||
/* If we're out of material, and need more, produce a block. */
|
||||
if (*npartial == 0)
|
||||
{
|
||||
process(ctx, partial);
|
||||
*npartial = nblock;
|
||||
}
|
||||
|
||||
size_t offset = nblock - *npartial;
|
||||
size_t taken = MIN(*npartial, nbytes);
|
||||
xor_bb(outb, inb, partial + offset, taken);
|
||||
*npartial -= taken;
|
||||
nbytes -= taken;
|
||||
outb += taken;
|
||||
inb += taken;
|
||||
}
|
||||
}
|
||||
|
||||
void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
uint8_t byte, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx)
|
||||
{
|
||||
/* only memset the whole of the block once */
|
||||
int filled = 0;
|
||||
|
||||
while (nbytes)
|
||||
{
|
||||
size_t start = *npartial;
|
||||
size_t count = MIN(nbytes, nblock - start);
|
||||
|
||||
if (!filled)
|
||||
memset(partial + start, byte, count);
|
||||
|
||||
if (start == 0 && count == nblock)
|
||||
filled = 1;
|
||||
|
||||
if (start + count == nblock)
|
||||
{
|
||||
process(ctx, partial);
|
||||
*npartial = 0;
|
||||
} else {
|
||||
*npartial += count;
|
||||
}
|
||||
|
||||
nbytes -= count;
|
||||
}
|
||||
}
|
||||
|
||||
void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
|
||||
size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx)
|
||||
{
|
||||
|
||||
switch (nbytes)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: fbyte ^= lbyte;
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
|
||||
break;
|
||||
case 2:
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
|
||||
break;
|
||||
default:
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
|
||||
|
||||
/* If the middle and last bytes differ, then process the last byte separately.
|
||||
* Otherwise, just extend the middle block size. */
|
||||
if (lbyte != mbyte)
|
||||
{
|
||||
cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 2, process, ctx);
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
|
||||
} else {
|
||||
cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 1, process, ctx);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
147
User/lib/cifra/blockwise.h
Normal file
147
User/lib/cifra/blockwise.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef BLOCKWISE_H
|
||||
#define BLOCKWISE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Processing function for cf_blockwise_accumulate. */
|
||||
typedef void (*cf_blockwise_in_fn)(void *ctx, const uint8_t *data);
|
||||
|
||||
/* Processing function for cf_blockwise_xor. */
|
||||
typedef void (*cf_blockwise_out_fn)(void *ctx, uint8_t *data);
|
||||
|
||||
/* This function manages the common abstraction of accumulating input in
|
||||
* a buffer, and processing it when a full block is available.
|
||||
*
|
||||
* partial is the buffer (maintained by the caller)
|
||||
* on entry, npartial is the currently valid count of used bytes on
|
||||
* the front of partial.
|
||||
* on exit, npartial is updated to reflect the status of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* input is the new data to process, of length nbytes.
|
||||
* process is the processing function, passed ctx and a pointer
|
||||
* to the data to process (always exactly nblock bytes long!)
|
||||
* which may not neccessarily be the same as partial.
|
||||
*/
|
||||
void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
const void *input, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx);
|
||||
|
||||
/* This function manages the common abstraction of accumulating input in
|
||||
* a buffer, and processing it when a full block is available.
|
||||
* This version supports calling a different processing function for
|
||||
* the last block.
|
||||
*
|
||||
* partial is the buffer (maintained by the caller)
|
||||
* on entry, npartial is the currently valid count of used bytes on
|
||||
* the front of partial.
|
||||
* on exit, npartial is updated to reflect the status of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* input is the new data to process, of length nbytes.
|
||||
* process is the processing function, passed ctx and a pointer
|
||||
* to the data to process (always exactly nblock bytes long!)
|
||||
* which may not neccessarily be the same as partial.
|
||||
* process_final is called last (but may not be called at all if
|
||||
* all input is buffered).
|
||||
*/
|
||||
void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
const void *input, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
cf_blockwise_in_fn process_final,
|
||||
void *ctx);
|
||||
|
||||
/* This function manages XORing an input stream with a keystream
|
||||
* to produce an output stream. The keystream is produced in blocks
|
||||
* (ala a block cipher in counter mode).
|
||||
*
|
||||
* partial is the keystream buffer (maintained by the caller)
|
||||
* on entry, *npartial is the currently valid count of bytes in partial:
|
||||
* unused bytes are at the *end*. So *npartial = 4 means the last four
|
||||
* bytes of partial are usable as keystream.
|
||||
* on exit, npartial is updated to reflect the new state of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* input is the new data to process, of length nbytes.
|
||||
* output is where to write input xored with the keystream -- also length
|
||||
* nbytes.
|
||||
* process is the processing function, passed ctx and partial which it
|
||||
* should fill with fresh key stream.
|
||||
*/
|
||||
void cf_blockwise_xor(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
const void *input, void *output, size_t nbytes,
|
||||
cf_blockwise_out_fn newblock,
|
||||
void *ctx);
|
||||
|
||||
/* This function processes a single byte a number of times. It's useful
|
||||
* for padding, and more efficient than calling cf_blockwise_accumulate
|
||||
* a bunch of times.
|
||||
*
|
||||
* partial is the buffer (maintained by the caller)
|
||||
* on entry, npartial is the currently valid count of used bytes on
|
||||
* the front of partial.
|
||||
* on exit, npartial is updated to reflect the status of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* process is the processing function, passed ctx and a pointer
|
||||
* to the data to process (always exactly nblock bytes long!)
|
||||
* which may not neccessarily be the same as partial.
|
||||
* byte is the byte to process, nbytes times.
|
||||
*/
|
||||
void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
uint8_t byte, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx);
|
||||
|
||||
/* This function attempts to process patterns of bytes common in
|
||||
* block cipher padding.
|
||||
*
|
||||
* This takes three bytes:
|
||||
* - a first byte, fbyte,
|
||||
* - a middle byte, mbyte,
|
||||
* - a last byte, lbyte.
|
||||
*
|
||||
* If nbytes is zero, nothing happens.
|
||||
* If nbytes is one, the byte fbyte ^ lbyte is processed.
|
||||
* If nbytes is two, the fbyte then lbyte are processed.
|
||||
* If nbytes is three or more, fbyte, then one or more mbytes, then fbyte
|
||||
* is processed.
|
||||
*
|
||||
* partial is the buffer (maintained by the caller)
|
||||
* on entry, npartial is the currently valid count of used bytes on
|
||||
* the front of partial.
|
||||
* on exit, npartial is updated to reflect the status of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* process is the processing function, passed ctx and a pointer
|
||||
* to the data to process (always exactly nblock bytes long!)
|
||||
* which may not neccessarily be the same as partial.
|
||||
*/
|
||||
void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
|
||||
size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx);
|
||||
|
||||
#endif
|
59
User/lib/cifra/cf_config.h
Normal file
59
User/lib/cifra/cf_config.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef CF_CONFIG_H
|
||||
#define CF_CONFIG_H
|
||||
|
||||
/**
|
||||
* Library configuration
|
||||
* =====================
|
||||
*/
|
||||
|
||||
/* .. c:macro:: CF_SIDE_CHANNEL_PROTECTION
|
||||
* Define this as 1 if you need all available side channel protections.
|
||||
* **This option may alter the ABI**.
|
||||
*
|
||||
* This has a non-trivial performance penalty. Where a
|
||||
* side-channel free option is cheap or free (like checking
|
||||
* a MAC) this is always done in a side-channel free way.
|
||||
*
|
||||
* The default is **on** for all available protections.
|
||||
*/
|
||||
#ifndef CF_SIDE_CHANNEL_PROTECTION
|
||||
# define CF_SIDE_CHANNEL_PROTECTION 1
|
||||
#endif
|
||||
|
||||
/* .. c:macro:: CF_TIME_SIDE_CHANNEL_PROTECTION
|
||||
* Define this as 1 if you need timing/branch prediction side channel
|
||||
* protection.
|
||||
*
|
||||
* You probably want this. The default is on. */
|
||||
#ifndef CF_TIME_SIDE_CHANNEL_PROTECTION
|
||||
# define CF_TIME_SIDE_CHANNEL_PROTECTION CF_SIDE_CHANNEL_PROTECTION
|
||||
#endif
|
||||
|
||||
/* .. c:macro:: CF_CACHE_SIDE_CHANNEL_PROTECTION
|
||||
* Define this as 1 if you need cache side channel protection.
|
||||
*
|
||||
* If you have a microcontroller with no cache, you can turn this off
|
||||
* without negative effects.
|
||||
*
|
||||
* The default is on. This will have some performance impact,
|
||||
* especially on AES.
|
||||
*/
|
||||
#ifndef CF_CACHE_SIDE_CHANNEL_PROTECTION
|
||||
# define CF_CACHE_SIDE_CHANNEL_PROTECTION CF_SIDE_CHANNEL_PROTECTION
|
||||
#endif
|
||||
|
||||
#endif
|
28
User/lib/cifra/chash.c
Normal file
28
User/lib/cifra/chash.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include "chash.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
|
||||
void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out)
|
||||
{
|
||||
cf_chash_ctx ctx;
|
||||
assert(h);
|
||||
h->init(&ctx);
|
||||
h->update(&ctx, m, nm);
|
||||
h->digest(&ctx, out);
|
||||
mem_clean(&ctx, sizeof ctx);
|
||||
}
|
||||
|
137
User/lib/cifra/chash.h
Normal file
137
User/lib/cifra/chash.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef CHASH_H
|
||||
#define CHASH_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* General hash function description
|
||||
* =================================
|
||||
* This allows us to make use of hash functions without depending
|
||||
* on a specific one. This is useful in implementing, for example,
|
||||
* :doc:`HMAC <hmac>`.
|
||||
*/
|
||||
|
||||
/* .. c:type:: cf_chash_init
|
||||
* Hashing initialisation function type.
|
||||
*
|
||||
* Functions of this type should initialise the context in preparation
|
||||
* for hashing a message with `cf_chash_update` functions.
|
||||
*
|
||||
* :rtype: void
|
||||
* :param ctx: hash function-specific context structure.
|
||||
*/
|
||||
typedef void (*cf_chash_init)(void *ctx);
|
||||
|
||||
/* .. c:type:: cf_chash_update
|
||||
* Hashing data processing function type.
|
||||
*
|
||||
* Functions of this type hash `count` bytes of data at `data`,
|
||||
* updating the contents of `ctx`.
|
||||
*
|
||||
* :rtype: void
|
||||
* :param ctx: hash function-specific context structure.
|
||||
* :param data: input data to hash.
|
||||
* :param count: number of bytes to hash.
|
||||
*/
|
||||
typedef void (*cf_chash_update)(void *ctx, const void *data, size_t count);
|
||||
|
||||
/* .. c:type:: cf_chash_digest
|
||||
* Hashing completion function type.
|
||||
*
|
||||
* Functions of this type complete a hashing operation,
|
||||
* writing :c:member:`cf_chash.hashsz` bytes to `hash`.
|
||||
*
|
||||
* This function does not change `ctx` -- any padding which needs doing
|
||||
* must be done seperately (in a copy of `ctx`, say).
|
||||
*
|
||||
* This means you can interlave `_update` and `_digest` calls to
|
||||
* learn `H(A)` and `H(A || B)` without hashing `A` twice.
|
||||
*
|
||||
* :rtype: void
|
||||
* :param ctx: hash function-specific context structure.
|
||||
* :param hash: location to write hash result.
|
||||
*/
|
||||
typedef void (*cf_chash_digest)(const void *ctx, uint8_t *hash);
|
||||
|
||||
/* .. c:type:: cf_chash
|
||||
* This type describes an incremental hash function in an abstract way.
|
||||
*
|
||||
* .. c:member:: cf_chash.hashsz
|
||||
* The hash function's output, in bytes.
|
||||
*
|
||||
* .. c:member:: cf_chash.blocksz
|
||||
* The hash function's internal block size, in bytes.
|
||||
*
|
||||
* .. c:member:: cf_chash.init
|
||||
* Context initialisation function.
|
||||
*
|
||||
* .. c:member:: cf_chash:update
|
||||
* Data processing function.
|
||||
*
|
||||
* .. c:member:: cf_chash:digest
|
||||
* Completion function.
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
size_t hashsz;
|
||||
size_t blocksz;
|
||||
|
||||
cf_chash_init init;
|
||||
cf_chash_update update;
|
||||
cf_chash_digest digest;
|
||||
} cf_chash;
|
||||
|
||||
/* .. c:macro:: CF_CHASH_MAXCTX
|
||||
* The maximum size of a :c:type:`cf_chash_ctx`. This allows
|
||||
* use to put a structure in automatic storage that can
|
||||
* store working data for any supported hash function. */
|
||||
#define CF_CHASH_MAXCTX 390
|
||||
|
||||
/* .. c:macro:: CF_CHASH_MAXBLK
|
||||
* Maximum hash function block size (in bytes). */
|
||||
#define CF_CHASH_MAXBLK 128
|
||||
|
||||
/* .. c:macro:: CF_MAXHASH
|
||||
* Maximum hash function output (in bytes). */
|
||||
#define CF_MAXHASH 64
|
||||
|
||||
/* .. c:type:: cf_chash_ctx
|
||||
* A type usable with any `cf_chash` as a context. */
|
||||
typedef union
|
||||
{
|
||||
uint8_t ctx[CF_CHASH_MAXCTX];
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} cf_chash_ctx;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* One shot hashing: `out = h(m)`.
|
||||
*
|
||||
* Using the hash function `h`, `nm` bytes at `m` are hashed and `h->hashsz` bytes
|
||||
* of result is written to the buffer `out`.
|
||||
*
|
||||
* :param h: hash function description.
|
||||
* :param m: message buffer.
|
||||
* :param nm: message length.
|
||||
* :param out: hash result buffer (written).
|
||||
*/
|
||||
void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out);
|
||||
|
||||
#endif
|
86
User/lib/cifra/handy.h
Normal file
86
User/lib/cifra/handy.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef HANDY_H
|
||||
#define HANDY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Handy CPP defines and C inline functions.
|
||||
*/
|
||||
|
||||
/* Evaluates to the number of items in array-type variable arr. */
|
||||
#define ARRAYCOUNT(arr) (sizeof arr / sizeof arr[0])
|
||||
|
||||
/* Normal MIN/MAX macros. Evaluate argument expressions only once. */
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) \
|
||||
({ typeof (x) __x = (x); \
|
||||
typeof (y) __y = (y); \
|
||||
__x < __y ? __x : __y; })
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) \
|
||||
({ typeof (x) __x = (x); \
|
||||
typeof (y) __y = (y); \
|
||||
__x > __y ? __x : __y; })
|
||||
#endif
|
||||
|
||||
/* Swap two values. Uses GCC type inference magic. */
|
||||
#ifndef SWAP
|
||||
#define SWAP(x, y) \
|
||||
do { \
|
||||
typeof (x) __tmp = (x); \
|
||||
(x) = (y); \
|
||||
(y) = __tmp; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/** Stringify its argument. */
|
||||
#define STRINGIFY(x) STRINGIFY_(x)
|
||||
#define STRINGIFY_(x) #x
|
||||
|
||||
/* Error handling macros.
|
||||
*
|
||||
* These expect a zero = success, non-zero = error convention.
|
||||
*/
|
||||
|
||||
/** Error: return.
|
||||
*
|
||||
* If the expression fails, return the error from this function. */
|
||||
#define ER(expr) do { typeof (expr) err_ = (expr); if (err_) return err_; } while (0)
|
||||
|
||||
/** Error: goto.
|
||||
*
|
||||
* If the expression fails, goto x_err. Assumes defn of label
|
||||
* x_err and 'error_type err'. */
|
||||
#define EG(expr) do { err = (expr); if (err) goto x_err; } while (0)
|
||||
|
||||
/** Like memset(ptr, 0, len), but not allowed to be removed by
|
||||
* compilers. */
|
||||
static inline void mem_clean(volatile void *v, size_t len)
|
||||
{
|
||||
if (len)
|
||||
{
|
||||
memset((void *) v, 0, len);
|
||||
(void) *((volatile uint8_t *) v);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns 1 if len bytes at va equal len bytes at vb, 0 if they do not.
|
||||
* Does not leak length of common prefix through timing. */
|
||||
static inline unsigned mem_eq(const void *va, const void *vb, size_t len)
|
||||
{
|
||||
const volatile uint8_t *a = va;
|
||||
const volatile uint8_t *b = vb;
|
||||
uint8_t diff = 0;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
diff |= *a++ ^ *b++;
|
||||
}
|
||||
|
||||
return !diff;
|
||||
}
|
||||
|
||||
#endif
|
106
User/lib/cifra/hmac.c
Normal file
106
User/lib/cifra/hmac.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include "hmac.h"
|
||||
#include "chash.h"
|
||||
#include "bitops.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void cf_hmac_init(cf_hmac_ctx *ctx,
|
||||
const cf_chash *hash,
|
||||
const uint8_t *key, size_t nkey)
|
||||
{
|
||||
assert(ctx);
|
||||
assert(hash);
|
||||
|
||||
mem_clean(ctx, sizeof *ctx);
|
||||
ctx->hash = hash;
|
||||
|
||||
/* Prepare key: */
|
||||
uint8_t k[CF_CHASH_MAXBLK];
|
||||
|
||||
/* Shorten long keys. */
|
||||
if (nkey > hash->blocksz)
|
||||
{
|
||||
/* Standard doesn't cover case where blocksz < hashsz.
|
||||
* FIPS186-1 seems to want to append a negative number of zero bytes.
|
||||
* In any case, we only have a k buffer of CF_CHASH_MAXBLK! */
|
||||
assert(hash->hashsz <= hash->blocksz);
|
||||
|
||||
cf_hash(hash, key, nkey, k);
|
||||
key = k;
|
||||
nkey = hash->hashsz;
|
||||
}
|
||||
|
||||
/* Right zero-pad short keys. */
|
||||
if (k != key)
|
||||
memcpy(k, key, nkey);
|
||||
if (hash->blocksz > nkey)
|
||||
memset(k + nkey, 0, hash->blocksz - nkey);
|
||||
|
||||
/* Start inner hash computation */
|
||||
uint8_t blk[CF_CHASH_MAXBLK];
|
||||
|
||||
xor_b8(blk, k, 0x36, hash->blocksz);
|
||||
hash->init(&ctx->inner);
|
||||
hash->update(&ctx->inner, blk, hash->blocksz);
|
||||
|
||||
/* And outer. */
|
||||
xor_b8(blk, k, 0x5c, hash->blocksz);
|
||||
hash->init(&ctx->outer);
|
||||
hash->update(&ctx->outer, blk, hash->blocksz);
|
||||
|
||||
mem_clean(blk, sizeof blk);
|
||||
mem_clean(k, sizeof k);
|
||||
}
|
||||
|
||||
void cf_hmac_update(cf_hmac_ctx *ctx, const void *data, size_t ndata)
|
||||
{
|
||||
assert(ctx && ctx->hash);
|
||||
|
||||
ctx->hash->update(&ctx->inner, data, ndata);
|
||||
}
|
||||
|
||||
void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out)
|
||||
{
|
||||
assert(ctx && ctx->hash);
|
||||
assert(out);
|
||||
|
||||
uint8_t innerh[CF_MAXHASH];
|
||||
ctx->hash->digest(&ctx->inner, innerh);
|
||||
|
||||
ctx->hash->update(&ctx->outer, innerh, ctx->hash->hashsz);
|
||||
ctx->hash->digest(&ctx->outer, out);
|
||||
|
||||
mem_clean(ctx, sizeof *ctx);
|
||||
}
|
||||
|
||||
void cf_hmac(const uint8_t *key, size_t nkey,
|
||||
const uint8_t *msg, size_t nmsg,
|
||||
uint8_t *out,
|
||||
const cf_chash *hash)
|
||||
{
|
||||
cf_hmac_ctx ctx;
|
||||
|
||||
assert(out);
|
||||
assert(hash);
|
||||
|
||||
cf_hmac_init(&ctx, hash, key, nkey);
|
||||
cf_hmac_update(&ctx, msg, nmsg);
|
||||
cf_hmac_finish(&ctx, out);
|
||||
}
|
||||
|
78
User/lib/cifra/hmac.h
Normal file
78
User/lib/cifra/hmac.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef HMAC_H
|
||||
#define HMAC_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chash.h"
|
||||
|
||||
/**
|
||||
* HMAC
|
||||
* ====
|
||||
* This is a one-shot and incremental interface to computing
|
||||
* HMAC with any hash function.
|
||||
*
|
||||
* (Note: HMAC with SHA3 is possible, but is probably not a
|
||||
* sensible thing to want.)
|
||||
*/
|
||||
|
||||
/* .. c:type:: cf_hmac_ctx
|
||||
* HMAC incremental interface context.
|
||||
*
|
||||
* .. c:member:: cf_hmac_ctx.hash
|
||||
* Hash function description.
|
||||
*
|
||||
* .. c:member:: cf_hmac_ctx.inner
|
||||
* Inner hash computation.
|
||||
*
|
||||
* .. c:member:: cf_hmac_ctx.outer
|
||||
* Outer hash computation.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const cf_chash *hash;
|
||||
cf_chash_ctx inner;
|
||||
cf_chash_ctx outer;
|
||||
} cf_hmac_ctx;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Set up ctx for computing a HMAC using the given hash and key. */
|
||||
void cf_hmac_init(cf_hmac_ctx *ctx,
|
||||
const cf_chash *hash,
|
||||
const uint8_t *key, size_t nkey);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Input data. */
|
||||
void cf_hmac_update(cf_hmac_ctx *ctx,
|
||||
const void *data, size_t ndata);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finish and compute HMAC.
|
||||
* `ctx->hash->hashsz` bytes are written to `out`. */
|
||||
void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* One shot interface: compute `HMAC_hash(key, msg)`, writing the
|
||||
* answer (which is `hash->hashsz` long) to `out`.
|
||||
*
|
||||
* This function does not fail. */
|
||||
void cf_hmac(const uint8_t *key, size_t nkey,
|
||||
const uint8_t *msg, size_t nmsg,
|
||||
uint8_t *out,
|
||||
const cf_chash *hash);
|
||||
|
||||
#endif
|
64
User/lib/cifra/prp.h
Normal file
64
User/lib/cifra/prp.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef PRP_H
|
||||
#define PRP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* General block cipher description
|
||||
* ================================
|
||||
* This allows us to implement block cipher modes which can work
|
||||
* with different block ciphers.
|
||||
*/
|
||||
|
||||
/* .. c:type:: cf_prp_block
|
||||
* Block processing function type.
|
||||
*
|
||||
* The `in` and `out` blocks may alias.
|
||||
*
|
||||
* :rtype: void
|
||||
* :param ctx: block cipher-specific context object.
|
||||
* :param in: input block.
|
||||
* :param out: output block.
|
||||
*/
|
||||
typedef void (*cf_prp_block)(void *ctx, const uint8_t *in, uint8_t *out);
|
||||
|
||||
/* .. c:type:: cf_prp
|
||||
* Describes an PRP in a general way.
|
||||
*
|
||||
* .. c:member:: cf_prp.blocksz
|
||||
* Block size in bytes. Must be no more than :c:macro:`CF_MAXBLOCK`.
|
||||
*
|
||||
* .. c:member:: cf_prp.encrypt
|
||||
* Block encryption function.
|
||||
*
|
||||
* .. c:member:: cf_prp.decrypt
|
||||
* Block decryption function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
size_t blocksz;
|
||||
cf_prp_block encrypt;
|
||||
cf_prp_block decrypt;
|
||||
} cf_prp;
|
||||
|
||||
/* .. c:macro:: CF_MAXBLOCK
|
||||
* The maximum block cipher blocksize we support, in bytes.
|
||||
*/
|
||||
#define CF_MAXBLOCK 16
|
||||
|
||||
#endif
|
235
User/lib/cifra/sha2.h
Normal file
235
User/lib/cifra/sha2.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef SHA2_H
|
||||
#define SHA2_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chash.h"
|
||||
|
||||
/**
|
||||
* SHA224/SHA256
|
||||
* =============
|
||||
*/
|
||||
|
||||
/* .. c:macro:: CF_SHA224_HASHSZ
|
||||
* The output size of SHA224: 28 bytes. */
|
||||
#define CF_SHA224_HASHSZ 28
|
||||
|
||||
/* .. c:macro:: CF_SHA224_BLOCKSZ
|
||||
* The block size of SHA224: 64 bytes. */
|
||||
#define CF_SHA224_BLOCKSZ 64
|
||||
|
||||
/* .. c:macro:: CF_SHA256_HASHSZ
|
||||
* The output size of SHA256: 32 bytes. */
|
||||
#define CF_SHA256_HASHSZ 32
|
||||
|
||||
/* .. c:macro:: CF_SHA256_BLOCKSZ
|
||||
* The block size of SHA256: 64 bytes. */
|
||||
#define CF_SHA256_BLOCKSZ 64
|
||||
|
||||
/* .. c:type:: cf_sha256_context
|
||||
* Incremental SHA256 hashing context.
|
||||
*
|
||||
* .. c:member:: cf_sha256_context.H
|
||||
* Intermediate values.
|
||||
*
|
||||
* .. c:member:: cf_sha256_context.partial
|
||||
* Unprocessed input.
|
||||
*
|
||||
* .. c:member:: cf_sha256_context.npartial
|
||||
* Number of bytes of unprocessed input.
|
||||
*
|
||||
* .. c:member:: cf_sha256_context.blocks
|
||||
* Number of full blocks processed.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t H[8]; /* State. */
|
||||
uint8_t partial[CF_SHA256_BLOCKSZ]; /* Partial block of input. */
|
||||
uint32_t blocks; /* Number of full blocks processed into H. */
|
||||
size_t npartial; /* Number of bytes in prefix of partial. */
|
||||
} cf_sha256_context;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Sets up `ctx` ready to hash a new message.
|
||||
*/
|
||||
extern void cf_sha256_init(cf_sha256_context *ctx);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
|
||||
* a full block.
|
||||
*/
|
||||
extern void cf_sha256_update(cf_sha256_context *ctx, const void *data, size_t nbytes);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA256_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This leaves `ctx` unchanged.
|
||||
*/
|
||||
extern void cf_sha256_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA256_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha256_digest`.
|
||||
*/
|
||||
extern void cf_sha256_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Sets up `ctx` ready to hash a new message.
|
||||
*
|
||||
* nb. SHA224 uses SHA256's underlying types.
|
||||
*/
|
||||
extern void cf_sha224_init(cf_sha256_context *ctx);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
|
||||
* a full block.
|
||||
*/
|
||||
extern void cf_sha224_update(cf_sha256_context *ctx, const void *data, size_t nbytes);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA224_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This leaves `ctx` unchanged.
|
||||
*/
|
||||
extern void cf_sha224_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA224_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha224_digest`.
|
||||
*/
|
||||
extern void cf_sha224_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ]);
|
||||
|
||||
/* .. c:var:: cf_sha224
|
||||
* Abstract interface to SHA224. See :c:type:`cf_chash` for more information.
|
||||
*/
|
||||
extern const cf_chash cf_sha224;
|
||||
|
||||
/* .. c:var:: cf_sha256
|
||||
* Abstract interface to SHA256. See :c:type:`cf_chash` for more information.
|
||||
*/
|
||||
extern const cf_chash cf_sha256;
|
||||
|
||||
/**
|
||||
* SHA384/SHA512
|
||||
* =============
|
||||
*/
|
||||
|
||||
/* .. c:macro:: CF_SHA384_HASHSZ
|
||||
* The output size of SHA384: 48 bytes. */
|
||||
#define CF_SHA384_HASHSZ 48
|
||||
|
||||
/* .. c:macro:: CF_SHA384_BLOCKSZ
|
||||
* The block size of SHA384: 128 bytes. */
|
||||
#define CF_SHA384_BLOCKSZ 128
|
||||
|
||||
/* .. c:macro:: CF_SHA512_HASHSZ
|
||||
* The output size of SHA512: 64 bytes. */
|
||||
#define CF_SHA512_HASHSZ 64
|
||||
|
||||
/* .. c:macro:: CF_SHA512_BLOCKSZ
|
||||
* The block size of SHA512: 128 bytes. */
|
||||
#define CF_SHA512_BLOCKSZ 128
|
||||
|
||||
/* .. c:type:: cf_sha512_context
|
||||
* Incremental SHA512 hashing context.
|
||||
*
|
||||
* .. c:member:: cf_sha512_context.H
|
||||
* Intermediate values.
|
||||
*
|
||||
* .. c:member:: cf_sha512_context.partial
|
||||
* Unprocessed input.
|
||||
*
|
||||
* .. c:member:: cf_sha512_context.npartial
|
||||
* Number of bytes of unprocessed input.
|
||||
*
|
||||
* .. c:member:: cf_sha512_context.blocks
|
||||
* Number of full blocks processed.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint64_t H[8];
|
||||
uint8_t partial[CF_SHA512_BLOCKSZ];
|
||||
uint32_t blocks;
|
||||
size_t npartial;
|
||||
} cf_sha512_context;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Sets up `ctx` ready to hash a new message.
|
||||
*/
|
||||
extern void cf_sha512_init(cf_sha512_context *ctx);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
|
||||
* a full block.
|
||||
*/
|
||||
extern void cf_sha512_update(cf_sha512_context *ctx, const void *data, size_t nbytes);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA512_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This leaves `ctx` unchanged.
|
||||
*/
|
||||
extern void cf_sha512_digest(const cf_sha512_context *ctx, uint8_t hash[CF_SHA512_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA512_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha512_digest`.
|
||||
*/
|
||||
extern void cf_sha512_digest_final(cf_sha512_context *ctx, uint8_t hash[CF_SHA512_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Sets up `ctx` ready to hash a new message.
|
||||
*
|
||||
* nb. SHA384 uses SHA512's underlying types.
|
||||
*/
|
||||
extern void cf_sha384_init(cf_sha512_context *ctx);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
|
||||
* a full block.
|
||||
*/
|
||||
extern void cf_sha384_update(cf_sha512_context *ctx, const void *data, size_t nbytes);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA384_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This leaves `ctx` unchanged.
|
||||
*/
|
||||
extern void cf_sha384_digest(const cf_sha512_context *ctx, uint8_t hash[CF_SHA384_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA384_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha384_digest`.
|
||||
*/
|
||||
extern void cf_sha384_digest_final(cf_sha512_context *ctx, uint8_t hash[CF_SHA384_HASHSZ]);
|
||||
|
||||
/* .. c:var:: cf_sha384
|
||||
* Abstract interface to SHA384. See :c:type:`cf_chash` for more information.
|
||||
*/
|
||||
extern const cf_chash cf_sha384;
|
||||
|
||||
/* .. c:var:: cf_sha512
|
||||
* Abstract interface to SHA512. See :c:type:`cf_chash` for more information.
|
||||
*/
|
||||
extern const cf_chash cf_sha512;
|
||||
|
||||
#endif
|
231
User/lib/cifra/sha256.c
Normal file
231
User/lib/cifra/sha256.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sha2.h"
|
||||
#include "blockwise.h"
|
||||
#include "bitops.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
|
||||
static const uint32_t K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
# define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
# define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
# define BSIG0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
|
||||
# define BSIG1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
|
||||
# define SSIG0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
|
||||
# define SSIG1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
|
||||
|
||||
void cf_sha256_init(cf_sha256_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
ctx->H[0] = 0x6a09e667;
|
||||
ctx->H[1] = 0xbb67ae85;
|
||||
ctx->H[2] = 0x3c6ef372;
|
||||
ctx->H[3] = 0xa54ff53a;
|
||||
ctx->H[4] = 0x510e527f;
|
||||
ctx->H[5] = 0x9b05688c;
|
||||
ctx->H[6] = 0x1f83d9ab;
|
||||
ctx->H[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
void cf_sha224_init(cf_sha256_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
ctx->H[0] = 0xc1059ed8;
|
||||
ctx->H[1] = 0x367cd507;
|
||||
ctx->H[2] = 0x3070dd17;
|
||||
ctx->H[3] = 0xf70e5939;
|
||||
ctx->H[4] = 0xffc00b31;
|
||||
ctx->H[5] = 0x68581511;
|
||||
ctx->H[6] = 0x64f98fa7;
|
||||
ctx->H[7] = 0xbefa4fa4;
|
||||
}
|
||||
|
||||
static void sha256_update_block(void *vctx, const uint8_t *inp)
|
||||
{
|
||||
cf_sha256_context *ctx = vctx;
|
||||
|
||||
/* This is a 16-word window into the whole W array. */
|
||||
uint32_t W[16];
|
||||
|
||||
uint32_t a = ctx->H[0],
|
||||
b = ctx->H[1],
|
||||
c = ctx->H[2],
|
||||
d = ctx->H[3],
|
||||
e = ctx->H[4],
|
||||
f = ctx->H[5],
|
||||
g = ctx->H[6],
|
||||
h = ctx->H[7],
|
||||
Wt;
|
||||
|
||||
for (size_t t = 0; t < 64; t++)
|
||||
{
|
||||
/* For W[0..16] we process the input into W.
|
||||
* For W[16..64] we compute the next W value:
|
||||
*
|
||||
* W[t] = SSIG1(W[t - 2]) + W[t - 7] + SSIG0(W[t - 15]) + W[t - 16];
|
||||
*
|
||||
* But all W indices are reduced mod 16 into our window.
|
||||
*/
|
||||
if (t < 16)
|
||||
{
|
||||
W[t] = Wt = read32_be(inp);
|
||||
inp += 4;
|
||||
} else {
|
||||
Wt = SSIG1(W[(t - 2) % 16]) +
|
||||
W[(t - 7) % 16] +
|
||||
SSIG0(W[(t - 15) % 16]) +
|
||||
W[(t - 16) % 16];
|
||||
W[t % 16] = Wt;
|
||||
}
|
||||
|
||||
uint32_t T1 = h + BSIG1(e) + CH(e, f, g) + K[t] + Wt;
|
||||
uint32_t T2 = BSIG0(a) + MAJ(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
}
|
||||
|
||||
ctx->H[0] += a;
|
||||
ctx->H[1] += b;
|
||||
ctx->H[2] += c;
|
||||
ctx->H[3] += d;
|
||||
ctx->H[4] += e;
|
||||
ctx->H[5] += f;
|
||||
ctx->H[6] += g;
|
||||
ctx->H[7] += h;
|
||||
|
||||
ctx->blocks++;
|
||||
}
|
||||
|
||||
void cf_sha256_update(cf_sha256_context *ctx, const void *data, size_t nbytes)
|
||||
{
|
||||
cf_blockwise_accumulate(ctx->partial, &ctx->npartial, sizeof ctx->partial,
|
||||
data, nbytes,
|
||||
sha256_update_block, ctx);
|
||||
}
|
||||
|
||||
void cf_sha224_update(cf_sha256_context *ctx, const void *data, size_t nbytes)
|
||||
{
|
||||
cf_sha256_update(ctx, data, nbytes);
|
||||
}
|
||||
|
||||
void cf_sha256_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ])
|
||||
{
|
||||
/* We copy the context, so the finalisation doesn't effect the caller's
|
||||
* context. This means the caller can do:
|
||||
*
|
||||
* x = init()
|
||||
* x.update('hello')
|
||||
* h1 = x.digest()
|
||||
* x.update(' world')
|
||||
* h2 = x.digest()
|
||||
*
|
||||
* to get h1 = H('hello') and h2 = H('hello world')
|
||||
*
|
||||
* This wouldn't work if we applied MD-padding to *ctx.
|
||||
*/
|
||||
|
||||
cf_sha256_context ours = *ctx;
|
||||
cf_sha256_digest_final(&ours, hash);
|
||||
}
|
||||
|
||||
void cf_sha256_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ])
|
||||
{
|
||||
uint64_t digested_bytes = ctx->blocks;
|
||||
digested_bytes = digested_bytes * CF_SHA256_BLOCKSZ + ctx->npartial;
|
||||
uint64_t digested_bits = digested_bytes * 8;
|
||||
|
||||
size_t padbytes = CF_SHA256_BLOCKSZ - ((digested_bytes + 8) % CF_SHA256_BLOCKSZ);
|
||||
|
||||
/* Hash 0x80 00 ... block first. */
|
||||
cf_blockwise_acc_pad(ctx->partial, &ctx->npartial, sizeof ctx->partial,
|
||||
0x80, 0x00, 0x00, padbytes,
|
||||
sha256_update_block, ctx);
|
||||
|
||||
/* Now hash length. */
|
||||
uint8_t buf[8];
|
||||
write64_be(digested_bits, buf);
|
||||
cf_sha256_update(ctx, buf, 8);
|
||||
|
||||
/* We ought to have got our padding calculation right! */
|
||||
assert(ctx->npartial == 0);
|
||||
|
||||
write32_be(ctx->H[0], hash + 0);
|
||||
write32_be(ctx->H[1], hash + 4);
|
||||
write32_be(ctx->H[2], hash + 8);
|
||||
write32_be(ctx->H[3], hash + 12);
|
||||
write32_be(ctx->H[4], hash + 16);
|
||||
write32_be(ctx->H[5], hash + 20);
|
||||
write32_be(ctx->H[6], hash + 24);
|
||||
write32_be(ctx->H[7], hash + 28);
|
||||
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
}
|
||||
|
||||
void cf_sha224_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ])
|
||||
{
|
||||
uint8_t full[CF_SHA256_HASHSZ];
|
||||
cf_sha256_digest(ctx, full);
|
||||
memcpy(hash, full, CF_SHA224_HASHSZ);
|
||||
}
|
||||
|
||||
void cf_sha224_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ])
|
||||
{
|
||||
uint8_t full[CF_SHA256_HASHSZ];
|
||||
cf_sha256_digest_final(ctx, full);
|
||||
memcpy(hash, full, CF_SHA224_HASHSZ);
|
||||
}
|
||||
|
||||
const cf_chash cf_sha224 = {
|
||||
.hashsz = CF_SHA224_HASHSZ,
|
||||
.blocksz = CF_SHA256_BLOCKSZ,
|
||||
.init = (cf_chash_init) cf_sha224_init,
|
||||
.update = (cf_chash_update) cf_sha224_update,
|
||||
.digest = (cf_chash_digest) cf_sha224_digest
|
||||
};
|
||||
|
||||
const cf_chash cf_sha256 = {
|
||||
.hashsz = CF_SHA256_HASHSZ,
|
||||
.blocksz = CF_SHA256_BLOCKSZ,
|
||||
.init = (cf_chash_init) cf_sha256_init,
|
||||
.update = (cf_chash_update) cf_sha256_update,
|
||||
.digest = (cf_chash_digest) cf_sha256_digest
|
||||
};
|
||||
|
32
User/lib/cifra/tassert.h
Normal file
32
User/lib/cifra/tassert.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef TASSERT_H
|
||||
#define TASSERT_H
|
||||
|
||||
/* Tiny assert
|
||||
* -----------
|
||||
*
|
||||
* This is an assert(3) definition which doesn't include any
|
||||
* strings, but just branches to abort(3) on failure.
|
||||
*/
|
||||
|
||||
#ifndef FULL_FAT_ASSERT
|
||||
# include <stdlib.h>
|
||||
# define assert(expr) do { if (!(expr)) abort(); } while (0)
|
||||
#else
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#endif
|
26
User/lib/config.c
Normal file
26
User/lib/config.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "config.h"
|
||||
#include "ch32v30x_flash.h"
|
||||
|
||||
PersistentData_t persistent;
|
||||
|
||||
void loadConfig() {
|
||||
memcpy (&persistent, FLASH_USER_PAGE_ADDR, sizeof (persistent));
|
||||
uint32_t crcSum = *((uint32_t *)(((uint8_t *)&persistent) + (sizeof (persistent) - 2)));
|
||||
memset ((((uint8_t *)&persistent) + (sizeof (persistent) - sizeof(crcSum))), 0, 4);
|
||||
CRC_ResetDR();
|
||||
uint32_t currentSum = CRC_CalcBlockCRC ((uint32_t *)&persistent, sizeof (persistent) - 2);
|
||||
|
||||
if (currentSum != crcSum) {
|
||||
memset (&persistent, 0, sizeof (persistent));
|
||||
}
|
||||
}
|
||||
|
||||
void saveConfig() {
|
||||
CRC_ResetDR();
|
||||
uint32_t currentSum = CRC_CalcBlockCRC ((uint32_t *)&persistent, sizeof (persistent) - 2);
|
||||
memcpy ((((uint8_t *)&persistent) + (sizeof (persistent) - sizeof(currentSum))), (uint8_t *)currentSum, 4);
|
||||
FLASH_Unlock();
|
||||
FLASH_ErasePage_Fast (1919);
|
||||
FLASH_ProgramPage_Fast (1919, (uint32_t *)&persistent);
|
||||
FLASH_Lock();
|
||||
}
|
22
User/lib/config.h
Normal file
22
User/lib/config.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef CONFIG_HEADER
|
||||
#define CONFIG_HEADER
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
|
||||
#define FLASH_USER_PAGE_ADDR ((const void *)(0x08077F00))
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic; // e.g. 0xDEADBEEF
|
||||
uint8_t privkey[32]; // Ed25519 private
|
||||
uint8_t pubkey[32]; // Ed25519 public
|
||||
uint8_t config[128]; // user config
|
||||
char nodeName[20];
|
||||
uint8_t extra[40];
|
||||
uint32_t crc32; // integrity check
|
||||
} PersistentData_t;
|
||||
|
||||
extern PersistentData_t persistent;
|
||||
|
||||
void saveConfig();
|
||||
void loadConfig();
|
||||
#endif
|
536
User/lib/monocypher/monocypher-ed25519.c
Normal file
536
User/lib/monocypher/monocypher-ed25519.c
Normal file
@@ -0,0 +1,536 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#include "monocypher-ed25519.h"
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#endif
|
||||
|
||||
/////////////////
|
||||
/// Utilities ///
|
||||
/////////////////
|
||||
#define FOR(i, min, max) for (size_t i = min; i < max; i++)
|
||||
#define COPY(dst, src, size) FOR (_i_, 0, size) (dst)[_i_] = (src)[_i_]
|
||||
#define ZERO(buf, size) FOR (_i_, 0, size) (buf)[_i_] = 0
|
||||
#define WIPE_CTX(ctx) crypto_wipe (ctx, sizeof (*(ctx)))
|
||||
#define WIPE_BUFFER(buffer) crypto_wipe (buffer, sizeof (buffer))
|
||||
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
|
||||
typedef uint8_t u8;
|
||||
typedef uint64_t u64;
|
||||
|
||||
// Returns the smallest positive integer y such that
|
||||
// (x + y) % pow_2 == 0
|
||||
// Basically, it's how many bytes we need to add to "align" x.
|
||||
// Only works when pow_2 is a power of 2.
|
||||
// Note: we use ~x+1 instead of -x to avoid compiler warnings
|
||||
static size_t align (size_t x, size_t pow_2) {
|
||||
return (~x + 1) & (pow_2 - 1);
|
||||
}
|
||||
|
||||
static u64 load64_be (const u8 s[8]) {
|
||||
return ((u64)s[0] << 56) | ((u64)s[1] << 48) | ((u64)s[2] << 40) | ((u64)s[3] << 32) | ((u64)s[4] << 24) | ((u64)s[5] << 16) | ((u64)s[6] << 8) | (u64)s[7];
|
||||
}
|
||||
|
||||
static void store64_be (u8 out[8], u64 in) {
|
||||
out[0] = (in >> 56) & 0xff;
|
||||
out[1] = (in >> 48) & 0xff;
|
||||
out[2] = (in >> 40) & 0xff;
|
||||
out[3] = (in >> 32) & 0xff;
|
||||
out[4] = (in >> 24) & 0xff;
|
||||
out[5] = (in >> 16) & 0xff;
|
||||
out[6] = (in >> 8) & 0xff;
|
||||
out[7] = in & 0xff;
|
||||
}
|
||||
|
||||
static void load64_be_buf (u64 *dst, const u8 *src, size_t size) {
|
||||
FOR (i, 0, size) { dst[i] = load64_be (src + i * 8); }
|
||||
}
|
||||
|
||||
///////////////
|
||||
/// SHA 512 ///
|
||||
///////////////
|
||||
static u64 rot (u64 x, int c) { return (x >> c) | (x << (64 - c)); }
|
||||
|
||||
static u64 ch (u64 x, u64 y, u64 z) { return (x & y) ^ (~x & z); }
|
||||
|
||||
static u64 maj (u64 x, u64 y, u64 z) { return (x & y) ^ (x & z) ^ (y & z); }
|
||||
|
||||
static u64 big_sigma0 (u64 x) { return rot (x, 28) ^ rot (x, 34) ^ rot (x, 39); }
|
||||
|
||||
static u64 big_sigma1 (u64 x) { return rot (x, 14) ^ rot (x, 18) ^ rot (x, 41); }
|
||||
|
||||
static u64 lit_sigma0 (u64 x) { return rot (x, 1) ^ rot (x, 8) ^ (x >> 7); }
|
||||
|
||||
static u64 lit_sigma1 (u64 x) { return rot (x, 19) ^ rot (x, 61) ^ (x >> 6); }
|
||||
|
||||
static const u64 K[80] = {
|
||||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
|
||||
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
|
||||
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
|
||||
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
|
||||
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
|
||||
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
|
||||
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
|
||||
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
|
||||
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
|
||||
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
|
||||
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
|
||||
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
|
||||
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
|
||||
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
|
||||
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
|
||||
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
|
||||
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
|
||||
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
|
||||
|
||||
static void sha512_compress (crypto_sha512_ctx *ctx) {
|
||||
u64 a = ctx->hash[0];
|
||||
u64 b = ctx->hash[1];
|
||||
u64 c = ctx->hash[2];
|
||||
u64 d = ctx->hash[3];
|
||||
u64 e = ctx->hash[4];
|
||||
u64 f = ctx->hash[5];
|
||||
u64 g = ctx->hash[6];
|
||||
u64 h = ctx->hash[7];
|
||||
|
||||
FOR (j, 0, 16) {
|
||||
u64 in = K[j] + ctx->input[j];
|
||||
u64 t1 = big_sigma1 (e) + ch (e, f, g) + h + in;
|
||||
u64 t2 = big_sigma0 (a) + maj (a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
size_t i16 = 0;
|
||||
FOR (i, 1, 5) {
|
||||
i16 += 16;
|
||||
FOR (j, 0, 16) {
|
||||
ctx->input[j] += lit_sigma1 (ctx->input[(j - 2) & 15]);
|
||||
ctx->input[j] += lit_sigma0 (ctx->input[(j - 15) & 15]);
|
||||
ctx->input[j] += ctx->input[(j - 7) & 15];
|
||||
u64 in = K[i16 + j] + ctx->input[j];
|
||||
u64 t1 = big_sigma1 (e) + ch (e, f, g) + h + in;
|
||||
u64 t2 = big_sigma0 (a) + maj (a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->hash[0] += a;
|
||||
ctx->hash[1] += b;
|
||||
ctx->hash[2] += c;
|
||||
ctx->hash[3] += d;
|
||||
ctx->hash[4] += e;
|
||||
ctx->hash[5] += f;
|
||||
ctx->hash[6] += g;
|
||||
ctx->hash[7] += h;
|
||||
}
|
||||
|
||||
// Write 1 input byte
|
||||
static void sha512_set_input (crypto_sha512_ctx *ctx, u8 input) {
|
||||
size_t word = ctx->input_idx >> 3;
|
||||
size_t byte = ctx->input_idx & 7;
|
||||
ctx->input[word] |= (u64)input << (8 * (7 - byte));
|
||||
}
|
||||
|
||||
// Increment a 128-bit "word".
|
||||
static void sha512_incr (u64 x[2], u64 y) {
|
||||
x[1] += y;
|
||||
if (x[1] < y) {
|
||||
x[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_init (crypto_sha512_ctx *ctx) {
|
||||
ctx->hash[0] = 0x6a09e667f3bcc908;
|
||||
ctx->hash[1] = 0xbb67ae8584caa73b;
|
||||
ctx->hash[2] = 0x3c6ef372fe94f82b;
|
||||
ctx->hash[3] = 0xa54ff53a5f1d36f1;
|
||||
ctx->hash[4] = 0x510e527fade682d1;
|
||||
ctx->hash[5] = 0x9b05688c2b3e6c1f;
|
||||
ctx->hash[6] = 0x1f83d9abfb41bd6b;
|
||||
ctx->hash[7] = 0x5be0cd19137e2179;
|
||||
ctx->input_size[0] = 0;
|
||||
ctx->input_size[1] = 0;
|
||||
ctx->input_idx = 0;
|
||||
ZERO (ctx->input, 16);
|
||||
}
|
||||
|
||||
void crypto_sha512_update (crypto_sha512_ctx *ctx,
|
||||
const u8 *message, size_t message_size) {
|
||||
// Avoid undefined NULL pointer increments with empty messages
|
||||
if (message_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Align ourselves with word boundaries
|
||||
if ((ctx->input_idx & 7) != 0) {
|
||||
size_t nb_bytes = MIN (align (ctx->input_idx, 8), message_size);
|
||||
FOR (i, 0, nb_bytes) {
|
||||
sha512_set_input (ctx, message[i]);
|
||||
ctx->input_idx++;
|
||||
}
|
||||
message += nb_bytes;
|
||||
message_size -= nb_bytes;
|
||||
}
|
||||
|
||||
// Align ourselves with block boundaries
|
||||
if ((ctx->input_idx & 127) != 0) {
|
||||
size_t nb_words = MIN (align (ctx->input_idx, 128), message_size) >> 3;
|
||||
load64_be_buf (ctx->input + (ctx->input_idx >> 3), message, nb_words);
|
||||
ctx->input_idx += nb_words << 3;
|
||||
message += nb_words << 3;
|
||||
message_size -= nb_words << 3;
|
||||
}
|
||||
|
||||
// Compress block if needed
|
||||
if (ctx->input_idx == 128) {
|
||||
sha512_incr (ctx->input_size, 1024); // size is in bits
|
||||
sha512_compress (ctx);
|
||||
ctx->input_idx = 0;
|
||||
ZERO (ctx->input, 16);
|
||||
}
|
||||
|
||||
// Process the message block by block
|
||||
FOR (i, 0, message_size >> 7) { // number of blocks
|
||||
load64_be_buf (ctx->input, message, 16);
|
||||
sha512_incr (ctx->input_size, 1024); // size is in bits
|
||||
sha512_compress (ctx);
|
||||
ctx->input_idx = 0;
|
||||
ZERO (ctx->input, 16);
|
||||
message += 128;
|
||||
}
|
||||
message_size &= 127;
|
||||
|
||||
if (message_size != 0) {
|
||||
// Remaining words
|
||||
size_t nb_words = message_size >> 3;
|
||||
load64_be_buf (ctx->input, message, nb_words);
|
||||
ctx->input_idx += nb_words << 3;
|
||||
message += nb_words << 3;
|
||||
message_size -= nb_words << 3;
|
||||
|
||||
// Remaining bytes
|
||||
FOR (i, 0, message_size) {
|
||||
sha512_set_input (ctx, message[i]);
|
||||
ctx->input_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_final (crypto_sha512_ctx *ctx, u8 hash[64]) {
|
||||
// Add padding bit
|
||||
if (ctx->input_idx == 0) {
|
||||
ZERO (ctx->input, 16);
|
||||
}
|
||||
sha512_set_input (ctx, 128);
|
||||
|
||||
// Update size
|
||||
sha512_incr (ctx->input_size, ctx->input_idx * 8);
|
||||
|
||||
// Compress penultimate block (if any)
|
||||
if (ctx->input_idx > 111) {
|
||||
sha512_compress (ctx);
|
||||
ZERO (ctx->input, 14);
|
||||
}
|
||||
// Compress last block
|
||||
ctx->input[14] = ctx->input_size[0];
|
||||
ctx->input[15] = ctx->input_size[1];
|
||||
sha512_compress (ctx);
|
||||
|
||||
// Copy hash to output (big endian)
|
||||
FOR (i, 0, 8) {
|
||||
store64_be (hash + i * 8, ctx->hash[i]);
|
||||
}
|
||||
|
||||
WIPE_CTX (ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512 (u8 hash[64], const u8 *message, size_t message_size) {
|
||||
crypto_sha512_ctx ctx;
|
||||
crypto_sha512_init (&ctx);
|
||||
crypto_sha512_update (&ctx, message, message_size);
|
||||
crypto_sha512_final (&ctx, hash);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// HMAC SHA 512 ///
|
||||
////////////////////
|
||||
void crypto_sha512_hmac_init (crypto_sha512_hmac_ctx *ctx,
|
||||
const u8 *key, size_t key_size) {
|
||||
// hash key if it is too long
|
||||
if (key_size > 128) {
|
||||
crypto_sha512 (ctx->key, key, key_size);
|
||||
key = ctx->key;
|
||||
key_size = 64;
|
||||
}
|
||||
// Compute inner key: padded key XOR 0x36
|
||||
FOR (i, 0, key_size) { ctx->key[i] = key[i] ^ 0x36; }
|
||||
FOR (i, key_size, 128) { ctx->key[i] = 0x36; }
|
||||
// Start computing inner hash
|
||||
crypto_sha512_init (&ctx->ctx);
|
||||
crypto_sha512_update (&ctx->ctx, ctx->key, 128);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac_update (crypto_sha512_hmac_ctx *ctx,
|
||||
const u8 *message, size_t message_size) {
|
||||
crypto_sha512_update (&ctx->ctx, message, message_size);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac_final (crypto_sha512_hmac_ctx *ctx, u8 hmac[64]) {
|
||||
// Finish computing inner hash
|
||||
crypto_sha512_final (&ctx->ctx, hmac);
|
||||
// Compute outer key: padded key XOR 0x5c
|
||||
FOR (i, 0, 128) {
|
||||
ctx->key[i] ^= 0x36 ^ 0x5c;
|
||||
}
|
||||
// Compute outer hash
|
||||
crypto_sha512_init (&ctx->ctx);
|
||||
crypto_sha512_update (&ctx->ctx, ctx->key, 128);
|
||||
crypto_sha512_update (&ctx->ctx, hmac, 64);
|
||||
crypto_sha512_final (&ctx->ctx, hmac); // outer hash
|
||||
WIPE_CTX (ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac (u8 hmac[64], const u8 *key, size_t key_size,
|
||||
const u8 *message, size_t message_size) {
|
||||
crypto_sha512_hmac_ctx ctx;
|
||||
crypto_sha512_hmac_init (&ctx, key, key_size);
|
||||
crypto_sha512_hmac_update (&ctx, message, message_size);
|
||||
crypto_sha512_hmac_final (&ctx, hmac);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// HKDF SHA 512 ///
|
||||
////////////////////
|
||||
void crypto_sha512_hkdf_expand (u8 *okm, size_t okm_size,
|
||||
const u8 *prk, size_t prk_size,
|
||||
const u8 *info, size_t info_size) {
|
||||
int not_first = 0;
|
||||
u8 ctr = 1;
|
||||
u8 blk[64];
|
||||
|
||||
while (okm_size > 0) {
|
||||
size_t out_size = MIN (okm_size, sizeof (blk));
|
||||
|
||||
crypto_sha512_hmac_ctx ctx;
|
||||
crypto_sha512_hmac_init (&ctx, prk, prk_size);
|
||||
if (not_first) {
|
||||
// For some reason HKDF uses some kind of CBC mode.
|
||||
// For some reason CTR mode alone wasn't enough.
|
||||
// Like what, they didn't trust HMAC in 2010? Really??
|
||||
crypto_sha512_hmac_update (&ctx, blk, sizeof (blk));
|
||||
}
|
||||
crypto_sha512_hmac_update (&ctx, info, info_size);
|
||||
crypto_sha512_hmac_update (&ctx, &ctr, 1);
|
||||
crypto_sha512_hmac_final (&ctx, blk);
|
||||
|
||||
COPY (okm, blk, out_size);
|
||||
|
||||
not_first = 1;
|
||||
okm += out_size;
|
||||
okm_size -= out_size;
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_hkdf (u8 *okm, size_t okm_size,
|
||||
const u8 *ikm, size_t ikm_size,
|
||||
const u8 *salt, size_t salt_size,
|
||||
const u8 *info, size_t info_size) {
|
||||
// Extract
|
||||
u8 prk[64];
|
||||
crypto_sha512_hmac (prk, salt, salt_size, ikm, ikm_size);
|
||||
|
||||
// Expand
|
||||
crypto_sha512_hkdf_expand (okm, okm_size, prk, sizeof (prk), info, info_size);
|
||||
}
|
||||
|
||||
///////////////
|
||||
/// Ed25519 ///
|
||||
///////////////
|
||||
void crypto_ed25519_key_pair (u8 secret_key[64], u8 public_key[32], u8 seed[32]) {
|
||||
u8 a[64];
|
||||
COPY (a, seed, 32); // a[ 0..31] = seed
|
||||
crypto_wipe (seed, 32);
|
||||
COPY (secret_key, a, 32); // secret key = seed
|
||||
crypto_sha512 (a, a, 32); // a[ 0..31] = scalar
|
||||
crypto_eddsa_trim_scalar (a, a); // a[ 0..31] = trimmed scalar
|
||||
crypto_eddsa_scalarbase (public_key, a); // public key = [trimmed scalar]B
|
||||
COPY (secret_key + 32, public_key, 32); // secret key includes public half
|
||||
WIPE_BUFFER (a);
|
||||
}
|
||||
|
||||
static void hash_reduce (u8 h[32],
|
||||
const u8 *a, size_t a_size,
|
||||
const u8 *b, size_t b_size,
|
||||
const u8 *c, size_t c_size,
|
||||
const u8 *d, size_t d_size) {
|
||||
u8 hash[64];
|
||||
crypto_sha512_ctx ctx;
|
||||
crypto_sha512_init (&ctx);
|
||||
crypto_sha512_update (&ctx, a, a_size);
|
||||
crypto_sha512_update (&ctx, b, b_size);
|
||||
crypto_sha512_update (&ctx, c, c_size);
|
||||
crypto_sha512_update (&ctx, d, d_size);
|
||||
crypto_sha512_final (&ctx, hash);
|
||||
crypto_eddsa_reduce (h, hash);
|
||||
}
|
||||
|
||||
static void ed25519_dom_sign (u8 signature[64], const u8 secret_key[32],
|
||||
const u8 *dom, size_t dom_size,
|
||||
const u8 *message, size_t message_size) {
|
||||
u8 a[64]; // secret scalar and prefix
|
||||
u8 r[32]; // secret deterministic "random" nonce
|
||||
u8 h[32]; // publically verifiable hash of the message (not wiped)
|
||||
u8 R[32]; // first half of the signature (allows overlapping inputs)
|
||||
const u8 *pk = secret_key + 32;
|
||||
|
||||
crypto_sha512 (a, secret_key, 32);
|
||||
crypto_eddsa_trim_scalar (a, a);
|
||||
hash_reduce (r, dom, dom_size, a + 32, 32, message, message_size, 0, 0);
|
||||
crypto_eddsa_scalarbase (R, r);
|
||||
hash_reduce (h, dom, dom_size, R, 32, pk, 32, message, message_size);
|
||||
COPY (signature, R, 32);
|
||||
crypto_eddsa_mul_add (signature + 32, h, a, r);
|
||||
|
||||
WIPE_BUFFER (a);
|
||||
WIPE_BUFFER (r);
|
||||
}
|
||||
// Meshcore-parity Ed25519 signing (non-standard, do NOT use outside Meshcore networks)
|
||||
static void ed25519_meshcore_sign(u8 signature[64],
|
||||
const u8 priv_seed[32], // secret seed (32 bytes)
|
||||
const u8 pub_key[32], // public key (32 bytes)
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
u8 a[64]; // secret scalar and prefix (same buffer as Monocypher)
|
||||
u8 r[32]; // nonce scalar
|
||||
u8 h[32]; // challenge scalar
|
||||
u8 R[32]; // encoded R
|
||||
|
||||
// 1. Derive scalar a (clamped) and prefix (discarded here, Meshcore doesn<73><6E>t use it)
|
||||
crypto_sha512(a, priv_seed, 32); // hash the seed
|
||||
crypto_eddsa_trim_scalar(a, a); // clamp scalar a
|
||||
|
||||
// 2. Derive nonce r = H(public_key || message) instead of H(prefix || message)
|
||||
hash_reduce(r, 0, 0, pub_key, 32, message, message_size, 0, 0);
|
||||
|
||||
// 3. R = r * basepoint
|
||||
crypto_eddsa_scalarbase(R, r);
|
||||
|
||||
// 4. h = H(R || public_key || message)
|
||||
hash_reduce(h, 0, 0, R, 32, pub_key, 32, message, message_size);
|
||||
|
||||
// 5. signature = R || (h*a + r)
|
||||
COPY(signature, R, 32);
|
||||
crypto_eddsa_mul_add(signature + 32, h, a, r);
|
||||
|
||||
// wipe secrets
|
||||
WIPE_BUFFER(a);
|
||||
WIPE_BUFFER(r);
|
||||
}
|
||||
|
||||
void crypto_ed25519_meshcore_sign(u8 signature[64],
|
||||
const u8 priv_seed[32],
|
||||
const u8 pub_key[32],
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
ed25519_meshcore_sign(signature, priv_seed, pub_key, message, message_size);
|
||||
}
|
||||
|
||||
|
||||
void crypto_ed25519_sign (u8 signature[64], const u8 secret_key[64],
|
||||
const u8 *message, size_t message_size) {
|
||||
ed25519_dom_sign (signature, secret_key, 0, 0, message, message_size);
|
||||
}
|
||||
|
||||
int crypto_ed25519_check (const u8 signature[64], const u8 public_key[32],
|
||||
const u8 *msg, size_t msg_size) {
|
||||
u8 h_ram[32];
|
||||
hash_reduce (h_ram, signature, 32, public_key, 32, msg, msg_size, 0, 0);
|
||||
return crypto_eddsa_check_equation (signature, public_key, h_ram);
|
||||
}
|
||||
|
||||
static const u8 domain[34] = "SigEd25519 no Ed25519 collisions\1";
|
||||
|
||||
void crypto_ed25519_ph_sign (uint8_t signature[64], const uint8_t secret_key[64],
|
||||
const uint8_t message_hash[64]) {
|
||||
ed25519_dom_sign (signature, secret_key, domain, sizeof (domain),
|
||||
message_hash, 64);
|
||||
}
|
||||
|
||||
int crypto_ed25519_ph_check (const uint8_t sig[64], const uint8_t pk[32],
|
||||
const uint8_t msg_hash[64]) {
|
||||
u8 h_ram[32];
|
||||
hash_reduce (h_ram, domain, sizeof (domain), sig, 32, pk, 32, msg_hash, 64);
|
||||
return crypto_eddsa_check_equation (sig, pk, h_ram);
|
||||
}
|
||||
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
}
|
||||
#endif
|
144
User/lib/monocypher/monocypher-ed25519.h
Normal file
144
User/lib/monocypher/monocypher-ed25519.h
Normal file
@@ -0,0 +1,144 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#ifndef ED25519_H
|
||||
#define ED25519_H
|
||||
|
||||
#include "monocypher.h"
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#elif defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
////////////////////////
|
||||
/// Type definitions ///
|
||||
////////////////////////
|
||||
|
||||
// Do not rely on the size or content on any of those types,
|
||||
// they may change without notice.
|
||||
typedef struct {
|
||||
uint64_t hash[8];
|
||||
uint64_t input[16];
|
||||
uint64_t input_size[2];
|
||||
size_t input_idx;
|
||||
} crypto_sha512_ctx;
|
||||
|
||||
typedef struct {
|
||||
uint8_t key[128];
|
||||
crypto_sha512_ctx ctx;
|
||||
} crypto_sha512_hmac_ctx;
|
||||
|
||||
void crypto_ed25519_meshcore_sign (uint8_t signature[64],
|
||||
const uint8_t priv_seed[32],
|
||||
const uint8_t pub_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512
|
||||
// -------
|
||||
void crypto_sha512_init (crypto_sha512_ctx *ctx);
|
||||
void crypto_sha512_update (crypto_sha512_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]);
|
||||
void crypto_sha512 (uint8_t hash[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512 HMAC
|
||||
// ------------
|
||||
void crypto_sha512_hmac_init (crypto_sha512_hmac_ctx *ctx,
|
||||
const uint8_t *key, size_t key_size);
|
||||
void crypto_sha512_hmac_update (crypto_sha512_hmac_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_sha512_hmac_final (crypto_sha512_hmac_ctx *ctx, uint8_t hmac[64]);
|
||||
void crypto_sha512_hmac (uint8_t hmac[64],
|
||||
const uint8_t *key, size_t key_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512 HKDF
|
||||
// ------------
|
||||
void crypto_sha512_hkdf_expand (uint8_t *okm, size_t okm_size,
|
||||
const uint8_t *prk, size_t prk_size,
|
||||
const uint8_t *info, size_t info_size);
|
||||
void crypto_sha512_hkdf (uint8_t *okm, size_t okm_size,
|
||||
const uint8_t *ikm, size_t ikm_size,
|
||||
const uint8_t *salt, size_t salt_size,
|
||||
const uint8_t *info, size_t info_size);
|
||||
|
||||
// Ed25519
|
||||
// -------
|
||||
// Signatures (EdDSA with curve25519 + SHA-512)
|
||||
// --------------------------------------------
|
||||
void crypto_ed25519_key_pair (uint8_t secret_key[64],
|
||||
uint8_t public_key[32],
|
||||
uint8_t seed[32]);
|
||||
void crypto_ed25519_sign (uint8_t signature[64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
int crypto_ed25519_check (const uint8_t signature[64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Pre-hash variants
|
||||
void crypto_ed25519_ph_sign (uint8_t signature[64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t message_hash[64]);
|
||||
int crypto_ed25519_ph_check (const uint8_t signature[64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t message_hash[64]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ED25519_H
|
2956
User/lib/monocypher/monocypher.c
Normal file
2956
User/lib/monocypher/monocypher.c
Normal file
File diff suppressed because it is too large
Load Diff
321
User/lib/monocypher/monocypher.h
Normal file
321
User/lib/monocypher/monocypher.h
Normal file
@@ -0,0 +1,321 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#ifndef MONOCYPHER_H
|
||||
#define MONOCYPHER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#elif defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Constant time comparisons
|
||||
// -------------------------
|
||||
|
||||
// Return 0 if a and b are equal, -1 otherwise
|
||||
int crypto_verify16(const uint8_t a[16], const uint8_t b[16]);
|
||||
int crypto_verify32(const uint8_t a[32], const uint8_t b[32]);
|
||||
int crypto_verify64(const uint8_t a[64], const uint8_t b[64]);
|
||||
|
||||
|
||||
// Erase sensitive data
|
||||
// --------------------
|
||||
void crypto_wipe(void *secret, size_t size);
|
||||
|
||||
|
||||
// Authenticated encryption
|
||||
// ------------------------
|
||||
void crypto_aead_lock(uint8_t *cipher_text,
|
||||
uint8_t mac [16],
|
||||
const uint8_t key [32],
|
||||
const uint8_t nonce[24],
|
||||
const uint8_t *ad, size_t ad_size,
|
||||
const uint8_t *plain_text, size_t text_size);
|
||||
int crypto_aead_unlock(uint8_t *plain_text,
|
||||
const uint8_t mac [16],
|
||||
const uint8_t key [32],
|
||||
const uint8_t nonce[24],
|
||||
const uint8_t *ad, size_t ad_size,
|
||||
const uint8_t *cipher_text, size_t text_size);
|
||||
|
||||
// Authenticated stream
|
||||
// --------------------
|
||||
typedef struct {
|
||||
uint64_t counter;
|
||||
uint8_t key[32];
|
||||
uint8_t nonce[8];
|
||||
} crypto_aead_ctx;
|
||||
|
||||
void crypto_aead_init_x(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[24]);
|
||||
void crypto_aead_init_djb(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[8]);
|
||||
void crypto_aead_init_ietf(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[12]);
|
||||
|
||||
void crypto_aead_write(crypto_aead_ctx *ctx,
|
||||
uint8_t *cipher_text,
|
||||
uint8_t mac[16],
|
||||
const uint8_t *ad , size_t ad_size,
|
||||
const uint8_t *plain_text, size_t text_size);
|
||||
int crypto_aead_read(crypto_aead_ctx *ctx,
|
||||
uint8_t *plain_text,
|
||||
const uint8_t mac[16],
|
||||
const uint8_t *ad , size_t ad_size,
|
||||
const uint8_t *cipher_text, size_t text_size);
|
||||
|
||||
|
||||
// General purpose hash (BLAKE2b)
|
||||
// ------------------------------
|
||||
|
||||
// Direct interface
|
||||
void crypto_blake2b(uint8_t *hash, size_t hash_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
void crypto_blake2b_keyed(uint8_t *hash, size_t hash_size,
|
||||
const uint8_t *key, size_t key_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Incremental interface
|
||||
typedef struct {
|
||||
// Do not rely on the size or contents of this type,
|
||||
// for they may change without notice.
|
||||
uint64_t hash[8];
|
||||
uint64_t input_offset[2];
|
||||
uint64_t input[16];
|
||||
size_t input_idx;
|
||||
size_t hash_size;
|
||||
} crypto_blake2b_ctx;
|
||||
|
||||
void crypto_blake2b_init(crypto_blake2b_ctx *ctx, size_t hash_size);
|
||||
void crypto_blake2b_keyed_init(crypto_blake2b_ctx *ctx, size_t hash_size,
|
||||
const uint8_t *key, size_t key_size);
|
||||
void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_blake2b_final(crypto_blake2b_ctx *ctx, uint8_t *hash);
|
||||
|
||||
|
||||
// Password key derivation (Argon2)
|
||||
// --------------------------------
|
||||
#define CRYPTO_ARGON2_D 0
|
||||
#define CRYPTO_ARGON2_I 1
|
||||
#define CRYPTO_ARGON2_ID 2
|
||||
|
||||
typedef struct {
|
||||
uint32_t algorithm; // Argon2d, Argon2i, Argon2id
|
||||
uint32_t nb_blocks; // memory hardness, >= 8 * nb_lanes
|
||||
uint32_t nb_passes; // CPU hardness, >= 1 (>= 3 recommended for Argon2i)
|
||||
uint32_t nb_lanes; // parallelism level (single threaded anyway)
|
||||
} crypto_argon2_config;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *pass;
|
||||
const uint8_t *salt;
|
||||
uint32_t pass_size;
|
||||
uint32_t salt_size; // 16 bytes recommended
|
||||
} crypto_argon2_inputs;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *key; // may be NULL if no key
|
||||
const uint8_t *ad; // may be NULL if no additional data
|
||||
uint32_t key_size; // 0 if no key (32 bytes recommended otherwise)
|
||||
uint32_t ad_size; // 0 if no additional data
|
||||
} crypto_argon2_extras;
|
||||
|
||||
extern const crypto_argon2_extras crypto_argon2_no_extras;
|
||||
|
||||
void crypto_argon2(uint8_t *hash, uint32_t hash_size, void *work_area,
|
||||
crypto_argon2_config config,
|
||||
crypto_argon2_inputs inputs,
|
||||
crypto_argon2_extras extras);
|
||||
|
||||
|
||||
// Key exchange (X-25519)
|
||||
// ----------------------
|
||||
|
||||
// Shared secrets are not quite random.
|
||||
// Hash them to derive an actual shared key.
|
||||
void crypto_x25519_public_key(uint8_t public_key[32],
|
||||
const uint8_t secret_key[32]);
|
||||
void crypto_x25519(uint8_t raw_shared_secret[32],
|
||||
const uint8_t your_secret_key [32],
|
||||
const uint8_t their_public_key [32]);
|
||||
|
||||
// Conversion to EdDSA
|
||||
void crypto_x25519_to_eddsa(uint8_t eddsa[32], const uint8_t x25519[32]);
|
||||
|
||||
// scalar "division"
|
||||
// Used for OPRF. Be aware that exponential blinding is less secure
|
||||
// than Diffie-Hellman key exchange.
|
||||
void crypto_x25519_inverse(uint8_t blind_salt [32],
|
||||
const uint8_t private_key[32],
|
||||
const uint8_t curve_point[32]);
|
||||
|
||||
// "Dirty" versions of x25519_public_key().
|
||||
// Use with crypto_elligator_rev().
|
||||
// Leaks 3 bits of the private key.
|
||||
void crypto_x25519_dirty_small(uint8_t pk[32], const uint8_t sk[32]);
|
||||
void crypto_x25519_dirty_fast (uint8_t pk[32], const uint8_t sk[32]);
|
||||
|
||||
|
||||
// Signatures
|
||||
// ----------
|
||||
|
||||
// EdDSA with curve25519 + BLAKE2b
|
||||
void crypto_eddsa_key_pair(uint8_t secret_key[64],
|
||||
uint8_t public_key[32],
|
||||
uint8_t seed[32]);
|
||||
void crypto_eddsa_sign(uint8_t signature [64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
int crypto_eddsa_check(const uint8_t signature [64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Conversion to X25519
|
||||
void crypto_eddsa_to_x25519(uint8_t x25519[32], const uint8_t eddsa[32]);
|
||||
|
||||
// EdDSA building blocks
|
||||
void crypto_eddsa_trim_scalar(uint8_t out[32], const uint8_t in[32]);
|
||||
void crypto_eddsa_reduce(uint8_t reduced[32], const uint8_t expanded[64]);
|
||||
void crypto_eddsa_mul_add(uint8_t r[32],
|
||||
const uint8_t a[32],
|
||||
const uint8_t b[32],
|
||||
const uint8_t c[32]);
|
||||
void crypto_eddsa_scalarbase(uint8_t point[32], const uint8_t scalar[32]);
|
||||
int crypto_eddsa_check_equation(const uint8_t signature[64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t h_ram[32]);
|
||||
|
||||
|
||||
// Chacha20
|
||||
// --------
|
||||
|
||||
// Specialised hash.
|
||||
// Used to hash X25519 shared secrets.
|
||||
void crypto_chacha20_h(uint8_t out[32],
|
||||
const uint8_t key[32],
|
||||
const uint8_t in [16]);
|
||||
|
||||
// Unauthenticated stream cipher.
|
||||
// Don't forget to add authentication.
|
||||
uint64_t crypto_chacha20_djb(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[8],
|
||||
uint64_t ctr);
|
||||
uint32_t crypto_chacha20_ietf(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[12],
|
||||
uint32_t ctr);
|
||||
uint64_t crypto_chacha20_x(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[24],
|
||||
uint64_t ctr);
|
||||
|
||||
|
||||
// Poly 1305
|
||||
// ---------
|
||||
|
||||
// This is a *one time* authenticator.
|
||||
// Disclosing the mac reveals the key.
|
||||
// See crypto_lock() on how to use it properly.
|
||||
|
||||
// Direct interface
|
||||
void crypto_poly1305(uint8_t mac[16],
|
||||
const uint8_t *message, size_t message_size,
|
||||
const uint8_t key[32]);
|
||||
|
||||
// Incremental interface
|
||||
typedef struct {
|
||||
// Do not rely on the size or contents of this type,
|
||||
// for they may change without notice.
|
||||
uint8_t c[16]; // chunk of the message
|
||||
size_t c_idx; // How many bytes are there in the chunk.
|
||||
uint32_t r [4]; // constant multiplier (from the secret key)
|
||||
uint32_t pad[4]; // random number added at the end (from the secret key)
|
||||
uint32_t h [5]; // accumulated hash
|
||||
} crypto_poly1305_ctx;
|
||||
|
||||
void crypto_poly1305_init (crypto_poly1305_ctx *ctx, const uint8_t key[32]);
|
||||
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_poly1305_final (crypto_poly1305_ctx *ctx, uint8_t mac[16]);
|
||||
|
||||
|
||||
// Elligator 2
|
||||
// -----------
|
||||
|
||||
// Elligator mappings proper
|
||||
void crypto_elligator_map(uint8_t curve [32], const uint8_t hidden[32]);
|
||||
int crypto_elligator_rev(uint8_t hidden[32], const uint8_t curve [32],
|
||||
uint8_t tweak);
|
||||
|
||||
// Easy to use key pair generation
|
||||
void crypto_elligator_key_pair(uint8_t hidden[32], uint8_t secret_key[32],
|
||||
uint8_t seed[32]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MONOCYPHER_H
|
255
User/lib/rtc/rtc.c
Normal file
255
User/lib/rtc/rtc.c
Normal file
@@ -0,0 +1,255 @@
|
||||
#include "stdint.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "rtc.h"
|
||||
|
||||
_calendar_obj calendar;
|
||||
|
||||
|
||||
uint8_t const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
|
||||
const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_NVIC_Config
|
||||
*
|
||||
* @brief Initializes RTC Int.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void RTC_NVIC_Config (void) {
|
||||
NVIC_InitTypeDef NVIC_InitStructure = {0};
|
||||
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init (&NVIC_InitStructure);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn Is_Leap_Year
|
||||
*
|
||||
* @brief Judging whether it is a leap year.
|
||||
*
|
||||
* @param year
|
||||
*
|
||||
* @return 1 - Yes
|
||||
* 0 - No
|
||||
*/
|
||||
uint8_t Is_Leap_Year (u16 year) {
|
||||
if (year % 4 == 0) {
|
||||
if (year % 100 == 0) {
|
||||
if (year % 400 == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
} else
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Set
|
||||
*
|
||||
* @brief Set Time.
|
||||
*
|
||||
* @param Struct of _calendar_obj
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) {
|
||||
u16 t;
|
||||
u32 seccount = 0;
|
||||
if (syear < 1970 || syear > 2099)
|
||||
return 1;
|
||||
for (t = 1970; t < syear; t++) {
|
||||
if (Is_Leap_Year (t))
|
||||
seccount += 31622400;
|
||||
else
|
||||
seccount += 31536000;
|
||||
}
|
||||
smon -= 1;
|
||||
for (t = 0; t < smon; t++) {
|
||||
seccount += (u32)mon_table[t] * 86400;
|
||||
if (Is_Leap_Year (syear) && t == 1)
|
||||
seccount += 86400;
|
||||
}
|
||||
seccount += (u32)(sday - 1) * 86400;
|
||||
seccount += (u32)hour * 3600;
|
||||
seccount += (u32)min * 60;
|
||||
seccount += sec;
|
||||
|
||||
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
|
||||
PWR_BackupAccessCmd (ENABLE);
|
||||
RTC_SetCounter (seccount);
|
||||
RTC_WaitForLastTask();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Alarm_Set
|
||||
*
|
||||
* @brief Set Alarm Time.
|
||||
*
|
||||
* @param Struct of _calendar_obj
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Alarm_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) {
|
||||
u16 t;
|
||||
u32 seccount = 0;
|
||||
if (syear < 1970 || syear > 2099)
|
||||
return 1;
|
||||
for (t = 1970; t < syear; t++) {
|
||||
if (Is_Leap_Year (t))
|
||||
seccount += 31622400;
|
||||
else
|
||||
seccount += 31536000;
|
||||
}
|
||||
smon -= 1;
|
||||
for (t = 0; t < smon; t++) {
|
||||
seccount += (u32)mon_table[t] * 86400;
|
||||
if (Is_Leap_Year (syear) && t == 1)
|
||||
seccount += 86400;
|
||||
}
|
||||
seccount += (u32)(sday - 1) * 86400;
|
||||
seccount += (u32)hour * 3600;
|
||||
seccount += (u32)min * 60;
|
||||
seccount += sec;
|
||||
|
||||
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
|
||||
PWR_BackupAccessCmd (ENABLE);
|
||||
RTC_SetAlarm (seccount);
|
||||
RTC_WaitForLastTask();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Get_Week
|
||||
*
|
||||
* @brief Get the current day of the week.
|
||||
*
|
||||
* @param year/month/day
|
||||
*
|
||||
* @return week
|
||||
*/
|
||||
uint8_t RTC_Get_Week (u16 year, uint8_t month, uint8_t day) {
|
||||
u16 temp2;
|
||||
uint8_t yearH, yearL;
|
||||
|
||||
yearH = year / 100;
|
||||
yearL = year % 100;
|
||||
if (yearH > 19)
|
||||
yearL += 100;
|
||||
temp2 = yearL + yearL / 4;
|
||||
temp2 = temp2 % 7;
|
||||
temp2 = temp2 + day + table_week[month - 1];
|
||||
if (yearL % 4 == 0 && month < 3)
|
||||
temp2--;
|
||||
return (temp2 % 7);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Get
|
||||
*
|
||||
* @brief Get current time.
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Get (void) {
|
||||
static u16 daycnt = 0;
|
||||
u32 timecount = 0;
|
||||
u32 temp = 0;
|
||||
u16 temp1 = 0;
|
||||
timecount = RTC_GetCounter();
|
||||
temp = timecount / 86400;
|
||||
if (daycnt != temp) {
|
||||
daycnt = temp;
|
||||
temp1 = 1970;
|
||||
while (temp >= 365) {
|
||||
if (Is_Leap_Year (temp1)) {
|
||||
if (temp >= 366)
|
||||
temp -= 366;
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} else
|
||||
temp -= 365;
|
||||
temp1++;
|
||||
}
|
||||
calendar.w_year = temp1;
|
||||
temp1 = 0;
|
||||
while (temp >= 28) {
|
||||
if (Is_Leap_Year (calendar.w_year) && temp1 == 1) {
|
||||
if (temp >= 29)
|
||||
temp -= 29;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
if (temp >= mon_table[temp1])
|
||||
temp -= mon_table[temp1];
|
||||
else
|
||||
break;
|
||||
}
|
||||
temp1++;
|
||||
}
|
||||
calendar.w_month = temp1 + 1;
|
||||
calendar.w_date = temp + 1;
|
||||
}
|
||||
temp = timecount % 86400;
|
||||
calendar.hour = temp / 3600;
|
||||
calendar.min = (temp % 3600) / 60;
|
||||
calendar.sec = (temp % 3600) % 60;
|
||||
calendar.week = RTC_Get_Week (calendar.w_year, calendar.w_month, calendar.w_date);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Init
|
||||
*
|
||||
* @brief Initializes RTC collection.
|
||||
*
|
||||
* @return 1 - Init Fail
|
||||
* 0 - Init Success
|
||||
*/
|
||||
uint8_t RTC_Init (void) {
|
||||
uint8_t temp = 0;
|
||||
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
|
||||
PWR_BackupAccessCmd (ENABLE);
|
||||
RTC_ClearITPendingBit (RTC_IT_ALR);
|
||||
RTC_ClearITPendingBit (RTC_IT_SEC);
|
||||
|
||||
/* Is it the first configuration */
|
||||
|
||||
BKP_DeInit();
|
||||
RCC_LSEConfig (RCC_LSE_ON);
|
||||
while (RCC_GetFlagStatus (RCC_FLAG_LSERDY) == RESET && temp < 250) {
|
||||
temp++;
|
||||
vTaskDelay (pdMS_TO_TICKS (20));
|
||||
}
|
||||
if (temp >= 250)
|
||||
return 1;
|
||||
RCC_RTCCLKConfig (RCC_RTCCLKSource_LSE);
|
||||
RCC_RTCCLKCmd (ENABLE);
|
||||
RTC_WaitForLastTask();
|
||||
RTC_WaitForSynchro();
|
||||
RTC_ITConfig (RTC_IT_SEC, DISABLE);
|
||||
RTC_ITConfig (RTC_IT_ALR, DISABLE);
|
||||
RTC_ITConfig (RTC_IT_OW, DISABLE);
|
||||
RTC_WaitForLastTask();
|
||||
RTC_EnterConfigMode();
|
||||
RTC_SetPrescaler (32767);
|
||||
RTC_WaitForLastTask();
|
||||
RTC_Set (2025, 9, 7, 11, 33, 30); /* Setup Time */
|
||||
RTC_ExitConfigMode();
|
||||
BKP_WriteBackupRegister (BKP_DR1, 0XA1A1);
|
||||
|
||||
RTC_NVIC_Config();
|
||||
RTC_Get();
|
||||
|
||||
return 0;
|
||||
}
|
95
User/lib/rtc/rtc.h
Normal file
95
User/lib/rtc/rtc.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "stdint.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint8_t hour;
|
||||
volatile uint8_t min;
|
||||
volatile uint8_t sec;
|
||||
|
||||
volatile uint16_t w_year;
|
||||
volatile uint8_t w_month;
|
||||
volatile uint8_t w_date;
|
||||
volatile uint8_t week;
|
||||
} _calendar_obj;
|
||||
|
||||
extern _calendar_obj calendar;
|
||||
|
||||
|
||||
extern uint8_t const table_week[12];
|
||||
extern const uint8_t mon_table[12];
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_NVIC_Config
|
||||
*
|
||||
* @brief Initializes RTC Int.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void RTC_NVIC_Config (void);
|
||||
/*********************************************************************
|
||||
* @fn Is_Leap_Year
|
||||
*
|
||||
* @brief Judging whether it is a leap year.
|
||||
*
|
||||
* @param year
|
||||
*
|
||||
* @return 1 - Yes
|
||||
* 0 - No
|
||||
*/
|
||||
uint8_t Is_Leap_Year (u16 year);
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Set
|
||||
*
|
||||
* @brief Set Time.
|
||||
*
|
||||
* @param Struct of _calendar_obj
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) ;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Alarm_Set
|
||||
*
|
||||
* @brief Set Alarm Time.
|
||||
*
|
||||
* @param Struct of _calendar_obj
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Alarm_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) ;
|
||||
/*********************************************************************
|
||||
* @fn RTC_Get_Week
|
||||
*
|
||||
* @brief Get the current day of the week.
|
||||
*
|
||||
* @param year/month/day
|
||||
*
|
||||
* @return week
|
||||
*/
|
||||
uint8_t RTC_Get_Week (u16 year, uint8_t month, uint8_t day) ;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Get
|
||||
*
|
||||
* @brief Get current time.
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Get (void) ;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Init
|
||||
*
|
||||
* @brief Initializes RTC collection.
|
||||
*
|
||||
* @return 1 - Init Fail
|
||||
* 0 - Init Success
|
||||
*/
|
||||
uint8_t RTC_Init (void);
|
229
User/main.c
Normal file
229
User/main.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : main.c
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2021/06/06
|
||||
* Description : Main program body.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
*@Note
|
||||
*task1 and task2 alternate printing
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "sx1262.h"
|
||||
#include "util/log.h"
|
||||
#include "string.h"
|
||||
#include "meshcore/meshcore.h"
|
||||
#include "lib/base64.h"
|
||||
#include "lib/config.h"
|
||||
#include "lib/rtc/rtc.h"
|
||||
|
||||
#define TAG "MeshCore"
|
||||
|
||||
/* Global define */
|
||||
#define TASK1_TASK_PRIO 5
|
||||
#define TASK1_STK_SIZE 2048
|
||||
|
||||
uint8_t publKey[32] = {0x73, 0x78, 0x46, 0x76, 0x87, 0x3c, 0x9f, 0xeb, 0x00, 0x95, 0x05, 0xba, 0xdd, 0x3a, 0x4b, 0x33, 0xc8, 0xf5, 0x88, 0xa3, 0x8f, 0xaa, 0x30, 0x85, 0x3b, 0x91, 0xe6, 0xde, 0x97, 0x8c, 0xf1, 0xb2};
|
||||
uint8_t privKey[32] = {0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20, 0x8a, 0x27, 0xca, 0x33, 0x85, 0xa5, 0x3b, 0x7d, 0x88, 0xce, 0x92, 0x23, 0xc4, 0x40, 0xc3, 0xac};
|
||||
|
||||
/* Global Variable */
|
||||
TaskHandle_t Task1Task_Handler;
|
||||
TaskHandle_t Task2Task_Handler;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn task1_task
|
||||
*
|
||||
* @brief task1 program.
|
||||
*
|
||||
* @param *pvParameters - Parameters point of task1
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
|
||||
uint8_t bufIn[256];
|
||||
|
||||
void task2_task (void *pvParameters) {
|
||||
RTC_Init();
|
||||
while (1) {
|
||||
// char tempBuf[180];
|
||||
// vTaskDelay (pdMS_TO_TICKS (10000));
|
||||
// snprintf (tempBuf, 180, "BRN RISCV: SySTick is %d", xTaskGetTickCount());
|
||||
// makeSendGroupMessage (tempBuf, 1);
|
||||
vTaskDelay (pdMS_TO_TICKS (10000));
|
||||
memcpy (persistent.privkey, privKey, 32);
|
||||
memcpy (persistent.pubkey, publKey, 32);
|
||||
strcpy (persistent.nodeName, "BRN RiscV");
|
||||
sendAdvert();
|
||||
vTaskDelay (pdMS_TO_TICKS (20000));
|
||||
}
|
||||
}
|
||||
|
||||
void task1_task (void *pvParameters) {
|
||||
//loadConfig();
|
||||
const int64_t interval_ms = 10; // 10 ms
|
||||
int64_t start_time, end_time, elapsed;
|
||||
|
||||
ESP_LOGW (TAG, "LoraInit");
|
||||
LoRaInit();
|
||||
int8_t txPowerInDbm = 20;
|
||||
uint32_t frequencyInHz = 869618000;
|
||||
|
||||
ESP_LOGW (TAG, "Enable TCXO");
|
||||
float tcxoVoltage = 2.2; // ebyte
|
||||
// float tcxoVoltage = 1.8; // heltec
|
||||
char useRegulatorLDO = 1;
|
||||
|
||||
LoRaDebugPrint (0);
|
||||
ESP_LOGW (TAG, "Starting lora");
|
||||
uint16_t loraBeginStat = LoRaBegin (frequencyInHz, txPowerInDbm, tcxoVoltage, useRegulatorLDO);
|
||||
if (loraBeginStat != 0) {
|
||||
ESP_LOGE (TAG, "Does not recognize the module");
|
||||
while (1) {
|
||||
vTaskDelay (pdMS_TO_TICKS (1000));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t spreadingFactor = 8;
|
||||
uint8_t bandwidth = SX126X_LORA_BW_62_5;
|
||||
uint8_t codingRate = SX126X_LORA_CR_4_8;
|
||||
uint16_t preambleLength = 16;
|
||||
char crcOn = 1;
|
||||
char invertIrq = 0;
|
||||
|
||||
LoRaConfig (spreadingFactor, bandwidth, codingRate, preambleLength, 0, crcOn,
|
||||
invertIrq);
|
||||
|
||||
|
||||
while (1) {
|
||||
start_time = xTaskGetTickCount();
|
||||
|
||||
uint8_t rxLen = LoRaReceive (bufIn, sizeof (bufIn));
|
||||
if (rxLen > 0) {
|
||||
// ESP_LOGI (TAG, "%d byte packet received", rxLen);
|
||||
|
||||
int8_t rssi, snr;
|
||||
GetPacketStatus (&rssi, &snr);
|
||||
ESP_LOGI (TAG, "rssi=%d[dBm] snr=%d[dB]", rssi, snr);
|
||||
|
||||
FrameStruct frame = decodeFrame (bufIn, rxLen);
|
||||
|
||||
printFrameHeader (frame);
|
||||
|
||||
unsigned char checkSumBuf[10];
|
||||
AdvertisementPayload advert;
|
||||
GroupTextMessage msg;
|
||||
|
||||
switch (frame.header & PAYLOAD_TYPE_MASK) {
|
||||
case PAYLOAD_TYPE_REQ:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RESPONSE:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TXT_MSG:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ACK:
|
||||
memset (checkSumBuf, 0, sizeof (checkSumBuf));
|
||||
base64_encode (frame.payload, 4, checkSumBuf);
|
||||
printf ("Checksum: %s\n", checkSumBuf);
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ADVERT:
|
||||
advert = decodeAdvertisement (frame);
|
||||
printAdvertisement (advert);
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_TXT:
|
||||
msg = decodeGroupMessage (frame);
|
||||
printGroupMessage (msg);
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_DATA:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ANON_REQ:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_PATH:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TRACE:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_MULTIPART:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RAW_CUSTOM:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int lost = GetPacketLost();
|
||||
if (lost != 0) {
|
||||
ESP_LOGW (TAG, "%d packets lost", lost);
|
||||
}
|
||||
|
||||
end_time = xTaskGetTickCount();
|
||||
elapsed = end_time - start_time;
|
||||
|
||||
if (elapsed < (interval_ms / 2)) {
|
||||
vTaskDelay (pdMS_TO_TICKS ((interval_ms - elapsed)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vApplicationStackOverflowHook (TaskHandle_t xTask, char *pcTaskName) {
|
||||
printf ("stackoverflow");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn main
|
||||
*
|
||||
* @brief ; program.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
|
||||
int main (void) {
|
||||
|
||||
NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2);
|
||||
SystemCoreClockUpdate();
|
||||
Delay_Init();
|
||||
USART_Printf_Init (115200);
|
||||
|
||||
printf ("SystemClk:%d\r\n", SystemCoreClock);
|
||||
printf ("ChipID:%08x\r\n", DBGMCU_GetCHIPID());
|
||||
printf ("FreeRTOS Kernel Version:%s\r\n", tskKERNEL_VERSION_NUMBER);
|
||||
|
||||
xTaskCreate ((TaskFunction_t)task1_task,
|
||||
(const char *)"task1",
|
||||
(uint16_t)TASK1_STK_SIZE,
|
||||
(void *)NULL,
|
||||
(UBaseType_t)TASK1_TASK_PRIO,
|
||||
(TaskHandle_t *)&Task1Task_Handler);
|
||||
|
||||
xTaskCreate ((TaskFunction_t)task2_task,
|
||||
(const char *)"task2",
|
||||
(uint16_t)1024,
|
||||
(void *)NULL,
|
||||
(UBaseType_t)TASK1_TASK_PRIO,
|
||||
(TaskHandle_t *)&Task2Task_Handler);
|
||||
|
||||
|
||||
vTaskStartScheduler();
|
||||
|
||||
while (1) {
|
||||
printf ("shouldn't run at here!!\n");
|
||||
}
|
||||
}
|
547
User/meshcore/meshcore.c
Normal file
547
User/meshcore/meshcore.c
Normal file
@@ -0,0 +1,547 @@
|
||||
#include "meshcore.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "lib/monocypher/monocypher-ed25519.h"
|
||||
#include "task.h"
|
||||
#include "lib/base64.h"
|
||||
#include "lib/cifra/aes.h"
|
||||
#include "lib/cifra/sha2.h"
|
||||
#include "lib/cifra/hmac.h"
|
||||
#include "lib/config.h"
|
||||
|
||||
#define AESKeyCount 8
|
||||
|
||||
const uint8_t aesKeys[AESKeyCount][17] = {
|
||||
{0x11, 0x8b, 0x33, 0x87, 0xe9, 0xc5,
|
||||
0xcd, 0xea, 0x6a, 0xc9, 0xe5, 0xed,
|
||||
0xba, 0xa1, 0x15, 0xcd, 0x72},
|
||||
|
||||
{0x0a, 0x44, 0x81, 0xda, 0x0e, 0x4e,
|
||||
0x03, 0xc4, 0x9e, 0x84, 0x77, 0x25,
|
||||
0xd8, 0x3a, 0x93, 0xbf, 0x80}
|
||||
};
|
||||
|
||||
#define TAG "MeshCore"
|
||||
|
||||
// requires at least a 256 byte data
|
||||
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen) {
|
||||
hexdump ("RxDump", data, dataLen);
|
||||
FrameStruct frame;
|
||||
memset (&frame, 0, sizeof (frame));
|
||||
unsigned char index = 0;
|
||||
frame.header = data[index++];
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
memcpy (frame.transportCodes, data + index, 4);
|
||||
index += 4;
|
||||
}
|
||||
frame.pathLen = data[index++];
|
||||
|
||||
memcpy (frame.path, data + index, frame.pathLen);
|
||||
index += frame.pathLen;
|
||||
frame.payloadLen = dataLen - index;
|
||||
memcpy (frame.payload, data + index, frame.payloadLen);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
int aes_encrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
if (ilen % 16 != 0)
|
||||
return -1;
|
||||
|
||||
cf_aes_context ctx;
|
||||
cf_aes_init (&ctx, key, 16);
|
||||
|
||||
for (size_t i = 0; i < ilen; i += 16) {
|
||||
cf_aes_encrypt (&ctx, input + i, output + i);
|
||||
}
|
||||
|
||||
cf_aes_finish (&ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aes_decrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
if (ilen % 16 != 0)
|
||||
return -1;
|
||||
|
||||
cf_aes_context ctx;
|
||||
cf_aes_init (&ctx, key, 16);
|
||||
|
||||
for (size_t i = 0; i < ilen; i += 16) {
|
||||
cf_aes_decrypt (&ctx, input + i, output + i);
|
||||
}
|
||||
|
||||
|
||||
cf_aes_finish (&ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HMAC-SHA256
|
||||
int hmac_sha256 (const uint8_t *key, size_t keylen,
|
||||
const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
cf_hmac_ctx ctx;
|
||||
cf_hmac_init (&ctx, &cf_sha256, key, keylen);
|
||||
cf_hmac_update (&ctx, input, ilen);
|
||||
cf_hmac_finish (&ctx, output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Verify MAC + Decrypt
|
||||
#define KEY_SIZE 16 // AES-128
|
||||
|
||||
int encrypt_then_mac (const uint8_t *aes_key,
|
||||
const uint8_t *plaintext, size_t plen,
|
||||
uint8_t *output, size_t *olen) {
|
||||
if (plen == 0)
|
||||
return -1;
|
||||
|
||||
// ciphertext will go right after HMAC
|
||||
uint8_t *ciphertext = output + HMAC_SIZE;
|
||||
|
||||
// encrypt plaintext
|
||||
aes_encrypt_ecb (aes_key, plaintext, plen, ciphertext);
|
||||
|
||||
// compute HMAC over ciphertext
|
||||
uint8_t mac[32]; // full SHA-256
|
||||
hmac_sha256 (aes_key, KEY_SIZE, ciphertext, plen, mac);
|
||||
|
||||
// copy only HMAC_SIZE bytes of MAC
|
||||
memcpy (output, mac, HMAC_SIZE);
|
||||
|
||||
// return total length = HMAC + ciphertext
|
||||
*olen = HMAC_SIZE + plen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *plaintext) {
|
||||
if (ilen <= HMAC_SIZE)
|
||||
return -1;
|
||||
|
||||
const uint8_t *mac = input;
|
||||
const uint8_t *ciphertext = input + HMAC_SIZE;
|
||||
size_t clen = ilen - HMAC_SIZE;
|
||||
|
||||
uint8_t calc_mac[32]; // full SHA-256
|
||||
hmac_sha256 (aes_key, KEY_SIZE, ciphertext, clen, calc_mac);
|
||||
|
||||
if (memcmp (mac, calc_mac, HMAC_SIZE) != 0)
|
||||
return -2;
|
||||
|
||||
return aes_decrypt_ecb (aes_key, ciphertext, clen, plaintext);
|
||||
}
|
||||
|
||||
void hexdump (const char *label, const uint8_t *data, size_t len) {
|
||||
if (label)
|
||||
printf ("%s (len=%zu):\n", label, len);
|
||||
|
||||
for (size_t i = 0; i < len; i += 16) {
|
||||
printf ("%04zx ", i); // offset
|
||||
for (size_t j = 0; j < 16; j++) {
|
||||
if (i + j < len)
|
||||
printf ("%02X ", data[i + j]);
|
||||
else
|
||||
printf (" "); // pad spacing
|
||||
}
|
||||
printf (" ");
|
||||
for (size_t j = 0; j < 16 && i + j < len; j++) {
|
||||
uint8_t c = data[i + j];
|
||||
printf ("%c", isprint (c) ? c : '.');
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// EncryptedPayloadStruct decodeEncryptedPayload(FrameStruct frame) {
|
||||
// EncryptedPayloadStruct enc;
|
||||
// memset(&enc, 0, sizeof(enc));
|
||||
// if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
|
||||
// return enc;
|
||||
// }
|
||||
// unsigned char index = 0;
|
||||
// enc.destinationHash = frame.payload[index++];
|
||||
// enc.sourceHash = frame.payload[index++];
|
||||
|
||||
|
||||
// index = 0;
|
||||
|
||||
// memcpy(&msg.timestamp, tmp + index, 4);
|
||||
// index += 4;
|
||||
// msg.flags = tmp[index++];
|
||||
|
||||
// memcpy(msg.text, tmp + index, plaintextLen - index);
|
||||
// return end;
|
||||
// }
|
||||
|
||||
GroupTextMessage decodeGroupMessage (FrameStruct frame) {
|
||||
GroupTextMessage msg;
|
||||
memset (&msg, 0, sizeof (msg));
|
||||
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
|
||||
ESP_LOGW (TAG, "Not a group text");
|
||||
return msg;
|
||||
}
|
||||
unsigned char index = 0;
|
||||
msg.channelHash = frame.payload[index++];
|
||||
unsigned char tmp[184];
|
||||
|
||||
|
||||
unsigned char decrypted = 0;
|
||||
for (unsigned char i = 0; i < AESKeyCount; i++) {
|
||||
|
||||
if (msg.channelHash != aesKeys[i][0]) {
|
||||
ESP_LOGW (TAG, "Hash %d does not equal %d", aesKeys[i][0], msg.channelHash);
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGW (TAG, "Hash does equal %d", msg.channelHash);
|
||||
|
||||
if (mac_then_decrypt (aesKeys[i] + 1, frame.payload + index, frame.payloadLen - index, tmp) != 0) {
|
||||
ESP_LOGW (TAG, "HMAC failed on grouphash key %d not matching %d", aesKeys[i][0], msg.channelHash);
|
||||
continue;
|
||||
}
|
||||
hexdump ("RxDumpDec", tmp, frame.payloadLen - index);
|
||||
decrypted = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!decrypted) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
unsigned char plaintextLen = frame.payloadLen - index;
|
||||
index = 0;
|
||||
|
||||
ESP_LOGI (TAG, "Starting memcpy");
|
||||
vTaskDelay (pdMS_TO_TICKS (10));
|
||||
memcpy (&msg.timestamp, tmp + index, 4);
|
||||
index += 4;
|
||||
msg.flags = tmp[index++];
|
||||
|
||||
memcpy (msg.text, tmp + index, plaintextLen - index);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void printGroupMessage (GroupTextMessage msg) {
|
||||
printf ("Message with channel hash %d, flags %d: %s\n", msg.channelHash,
|
||||
msg.flags, msg.text);
|
||||
}
|
||||
|
||||
AdvertisementPayload decodeAdvertisement (FrameStruct frame) {
|
||||
AdvertisementPayload advert;
|
||||
memset (&advert, 0, sizeof (advert));
|
||||
|
||||
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_ADVERT) {
|
||||
return advert;
|
||||
}
|
||||
|
||||
unsigned char index = 0;
|
||||
|
||||
memcpy (advert.pubKey, frame.payload + index, 32);
|
||||
index += 32;
|
||||
|
||||
memcpy (&advert.timestamp, frame.payload + index, 4);
|
||||
index += 4;
|
||||
|
||||
memcpy (advert.signature, frame.payload + index, 64);
|
||||
index += 64;
|
||||
|
||||
advert.dataFlags = frame.payload[index++];
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (&advert.latitude, frame.payload + index, 4);
|
||||
index += 4;
|
||||
memcpy (&advert.longitude, frame.payload + index, 4);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy (&advert.rfu1, frame.payload + index, 2);
|
||||
index += 2;
|
||||
}
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy (&advert.rfu2, frame.payload + index, 2);
|
||||
index += 2;
|
||||
}
|
||||
memcpy (advert.nodeName, frame.payload + index, frame.payloadLen - index);
|
||||
advert.nodeName[frame.payloadLen - index] = 0;
|
||||
|
||||
return advert;
|
||||
}
|
||||
|
||||
void printAdvertisement (AdvertisementPayload advert) {
|
||||
unsigned char keyBuf[50];
|
||||
unsigned char sigBuf[90];
|
||||
memset (keyBuf, 0, sizeof (keyBuf));
|
||||
memset (sigBuf, 0, sizeof (sigBuf));
|
||||
base64_encode (advert.pubKey, 32, keyBuf);
|
||||
base64_encode (advert.signature, 64, sigBuf);
|
||||
|
||||
printf ("%s on %ld with type %s on %s location %ld %ld, public key %s and "
|
||||
"signature %s\n",
|
||||
advert.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME ? advert.nodeName
|
||||
: "nameless node",
|
||||
advert.timestamp,
|
||||
(advert.dataFlags & 0x07) == 0x04
|
||||
? "sensor"
|
||||
: ((advert.dataFlags & 0x07) == 0x03
|
||||
? "room server"
|
||||
: ((advert.dataFlags & 0x07) == 0x02 ? "repeater"
|
||||
: "chat node")),
|
||||
advert.dataFlags & 0x80 ? "known" : "unknown", advert.latitude,
|
||||
advert.longitude, keyBuf, sigBuf);
|
||||
}
|
||||
|
||||
void printFrameHeader (FrameStruct frame) {
|
||||
switch (frame.header & ROUTE_TYPE_MASK) {
|
||||
case ROUTE_TYPE_TRANSPORT_FLOOD:
|
||||
printf ("transport flood");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_FLOOD:
|
||||
printf ("flood");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_DIRECT:
|
||||
printf ("direct");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_TRANSPORT_DIRECT:
|
||||
printf ("transport direct");
|
||||
break;
|
||||
}
|
||||
|
||||
printf (", payload type is ");
|
||||
|
||||
switch (frame.header & PAYLOAD_TYPE_MASK) {
|
||||
case PAYLOAD_TYPE_REQ:
|
||||
printf ("request");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RESPONSE:
|
||||
printf ("response");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TXT_MSG:
|
||||
printf ("text message");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ACK:
|
||||
printf ("acknowledgement");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ADVERT:
|
||||
printf ("advert");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_TXT:
|
||||
printf ("group text");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_DATA:
|
||||
printf ("group data");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ANON_REQ:
|
||||
printf ("anon request");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_PATH:
|
||||
printf ("path");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TRACE:
|
||||
printf ("trace");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_MULTIPART:
|
||||
printf ("multipart");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RAW_CUSTOM:
|
||||
printf ("raw");
|
||||
break;
|
||||
}
|
||||
char version[2];
|
||||
version[0] = (frame.header >> 6) + '0';
|
||||
version[1] = 0;
|
||||
|
||||
printf (", payload version is %s ", version);
|
||||
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
printf ("Transport codes: %d %d\n", *((uint16_t *)frame.transportCodes),
|
||||
*((uint16_t *)&(frame.transportCodes[2])));
|
||||
}
|
||||
printf ("Path is %d nodes long", frame.pathLen);
|
||||
|
||||
for (uint8_t pathIndex = 0; pathIndex < frame.pathLen; pathIndex++) {
|
||||
printf ("node %d - %02X, ", pathIndex, frame.path[pathIndex]);
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
void sendFrame (FrameStruct frame) {
|
||||
uint8_t txBuf[256];
|
||||
size_t offset = 0;
|
||||
|
||||
txBuf[offset++] = frame.header;
|
||||
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
memcpy (txBuf + offset, frame.transportCodes, 4);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
if (frame.pathLen > 64) {
|
||||
frame.pathLen = 64;
|
||||
}
|
||||
|
||||
txBuf[offset++] = frame.pathLen;
|
||||
|
||||
memcpy (txBuf + offset, frame.path, frame.pathLen);
|
||||
offset += frame.pathLen;
|
||||
|
||||
uint16_t maxPayloadLen = 256 - offset;
|
||||
|
||||
uint16_t payloadLen = frame.payloadLen > maxPayloadLen ? maxPayloadLen : frame.payloadLen;
|
||||
|
||||
memcpy (txBuf + offset, frame.payload, payloadLen);
|
||||
offset += payloadLen;
|
||||
|
||||
hexdump ("TxDump", txBuf, offset);
|
||||
LoRaSend (txBuf, offset, SX126x_TXMODE_SYNC);
|
||||
}
|
||||
|
||||
void sendGroupMessage (GroupTextMessage msg) {
|
||||
|
||||
msg.channelHash = aesKeys[msg.keyIndex][0];
|
||||
|
||||
msg.flags = 0;
|
||||
msg.timestamp = RTC_GetCounter();
|
||||
|
||||
FrameStruct frame;
|
||||
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_GRP_TXT | PAYLOAD_VERSION_0;
|
||||
frame.pathLen = 0;
|
||||
size_t offset = 0;
|
||||
memset (frame.payload, 0, sizeof (frame.payload));
|
||||
frame.payload[offset++] = msg.channelHash;
|
||||
|
||||
uint8_t cipherBuf[176];
|
||||
size_t offset2 = 0;
|
||||
memcpy (cipherBuf, (const void *)&(msg.timestamp), 4);
|
||||
offset2 += 4;
|
||||
cipherBuf[offset2++] = msg.flags;
|
||||
size_t textSize = offset2 + strlen ((const char *)msg.text);
|
||||
if (textSize > 175) {
|
||||
textSize = 175;
|
||||
}
|
||||
memcpy (cipherBuf + offset2, msg.text, textSize);
|
||||
offset2 += textSize;
|
||||
|
||||
offset2 = (((offset2 / 16) + 1) * 16);
|
||||
|
||||
size_t olen = 0;
|
||||
hexdump ("TxDumpDec", cipherBuf, offset2);
|
||||
encrypt_then_mac (&(aesKeys[msg.keyIndex][1]), cipherBuf, offset2, &(frame.payload[offset]), &olen);
|
||||
|
||||
frame.payloadLen = olen + 1;
|
||||
|
||||
sendFrame (frame);
|
||||
return;
|
||||
}
|
||||
|
||||
void makeSendGroupMessage (char *txt, uint8_t keyIndex) {
|
||||
GroupTextMessage msg;
|
||||
strcpy ((char *)msg.text, txt);
|
||||
msg.keyIndex = keyIndex;
|
||||
sendGroupMessage (msg);
|
||||
return;
|
||||
}
|
||||
|
||||
void sendAdvert() {
|
||||
AdvertisementPayload ad;
|
||||
memcpy (ad.pubKey, persistent.pubkey, sizeof (ad.pubKey));
|
||||
ad.dataFlags = ADVERTISEMENT_FLAG_IS_CHAT_NODE | ADVERTISEMENT_FLAG_HAS_NAME;
|
||||
strcpy (ad.nodeName, persistent.nodeName);
|
||||
ad.timestamp = RTC_GetCounter();
|
||||
|
||||
// 1. Build app_data exactly like AdvertDataBuilder::encodeTo
|
||||
uint8_t app_data[40];
|
||||
size_t app_len = 0;
|
||||
|
||||
app_data[app_len++] = ad.dataFlags;
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (app_data + app_len, &ad.latitude, sizeof (ad.latitude));
|
||||
app_len += sizeof (ad.latitude);
|
||||
memcpy (app_data + app_len, &ad.longitude, sizeof (ad.longitude));
|
||||
app_len += sizeof (ad.longitude);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy (app_data + app_len, &ad.rfu1, sizeof (ad.rfu1));
|
||||
app_len += sizeof (ad.rfu1);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy (app_data + app_len, &ad.rfu2, sizeof (ad.rfu2));
|
||||
app_len += sizeof (ad.rfu2);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME) {
|
||||
size_t nodenameLen = strlen (ad.nodeName);
|
||||
memcpy (app_data + app_len, ad.nodeName, nodenameLen);
|
||||
app_len += nodenameLen;
|
||||
}
|
||||
|
||||
// 2. Reserve frame and build payload header
|
||||
FrameStruct frame;
|
||||
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_ADVERT | PAYLOAD_VERSION_0;
|
||||
|
||||
size_t offset = 0;
|
||||
memcpy (frame.payload + offset, ad.pubKey, sizeof (ad.pubKey));
|
||||
offset += sizeof (ad.pubKey);
|
||||
|
||||
memcpy (frame.payload + offset, &ad.timestamp, sizeof (ad.timestamp));
|
||||
offset += sizeof (ad.timestamp);
|
||||
|
||||
// reserve signature space
|
||||
uint8_t *signature_pos = frame.payload + offset;
|
||||
offset += 64;
|
||||
|
||||
// append app_data after signature
|
||||
memcpy (frame.payload + offset, app_data, app_len);
|
||||
offset += app_len;
|
||||
|
||||
// 3. Sign pubKey + timestamp + app_data
|
||||
uint8_t message[76];
|
||||
size_t msg_len = 0;
|
||||
memcpy (message + msg_len, ad.pubKey, sizeof (ad.pubKey));
|
||||
msg_len += sizeof (ad.pubKey);
|
||||
memcpy (message + msg_len, &ad.timestamp, sizeof (ad.timestamp));
|
||||
msg_len += sizeof (ad.timestamp);
|
||||
memcpy (message + msg_len, app_data, app_len);
|
||||
msg_len += app_len;
|
||||
|
||||
crypto_ed25519_meshcore_sign (signature_pos, persistent.privkey, persistent.pubkey, message, msg_len);
|
||||
|
||||
hexdump ("Complete advert", frame.payload, offset);
|
||||
|
||||
hexdump ("Public key", ad.pubKey, 32);
|
||||
|
||||
hexdump ("Signature", signature_pos, 64);
|
||||
|
||||
hexdump ("Timestamp", &ad.timestamp, 4);
|
||||
|
||||
hexdump ("NodeName", ad.nodeName, 20);
|
||||
|
||||
hexdump ("Appdata", app_data, app_len);
|
||||
|
||||
// 5. Set payload length and send
|
||||
frame.payloadLen = offset;
|
||||
frame.pathLen = 0;
|
||||
sendFrame (frame);
|
||||
}
|
61
User/meshcore/meshcore.h
Normal file
61
User/meshcore/meshcore.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef MESHCORE_HEADER
|
||||
#define MESHCORE_HEADER
|
||||
|
||||
#include "packetstructs.h"
|
||||
#include "string.h"
|
||||
#include "sx1262.h"
|
||||
#include "lib/cifra/aes.h"
|
||||
#include "lib/cifra/sha2.h"
|
||||
#include "lib/cifra/hmac.h"
|
||||
#include "lib/base64.h"
|
||||
#include "util/log.h"
|
||||
#include <ctype.h>
|
||||
#include "stdio.h"
|
||||
|
||||
// requires at least a 256 byte data
|
||||
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen);
|
||||
|
||||
#define KEY_SIZE 16 // 128-bit AES
|
||||
#define HMAC_SIZE 2 // SHA256 output size
|
||||
|
||||
int aes_encrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output);
|
||||
|
||||
// AES-ECB decrypt (same as Arduino's aes.decryptBlock)
|
||||
int aes_decrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output);
|
||||
|
||||
// HMAC-SHA256
|
||||
int hmac_sha256 (const uint8_t *key, size_t keylen, const uint8_t *input,
|
||||
size_t ilen, uint8_t *output);
|
||||
|
||||
// Verify MAC + Decrypt
|
||||
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *plaintext);
|
||||
|
||||
void hexdump (const char *label, const uint8_t *data, size_t len);
|
||||
|
||||
#define AESKeyCount 8
|
||||
|
||||
// EncryptedPayloadStruct decodeEncryptedPayload(FrameStruct frame);
|
||||
|
||||
GroupTextMessage decodeGroupMessage (FrameStruct frame);
|
||||
|
||||
void printGroupMessage (GroupTextMessage msg);
|
||||
|
||||
AdvertisementPayload decodeAdvertisement (FrameStruct frame);
|
||||
|
||||
void printAdvertisement (AdvertisementPayload advert);
|
||||
|
||||
void printFrameHeader (FrameStruct frame);
|
||||
|
||||
#define AESKeyCount 8
|
||||
|
||||
extern const uint8_t aesKeys[AESKeyCount][17];
|
||||
|
||||
void sendFrame (FrameStruct frame);
|
||||
void sendGroupMessage (GroupTextMessage msg);
|
||||
void makeSendGroupMessage (char *txt, uint8_t keyIndex);
|
||||
void sendAdvert();
|
||||
|
||||
#endif
|
120
User/meshcore/packetstructs.h
Normal file
120
User/meshcore/packetstructs.h
Normal file
@@ -0,0 +1,120 @@
|
||||
#ifndef PACKETSTRUCTS_FILE
|
||||
#define PACKETSTRUCTS_FILE
|
||||
|
||||
#include <stdint.h>
|
||||
#define ROUTE_TYPE_MASK 0x03
|
||||
#define PAYLOAD_TYPE_MASK 0x3C
|
||||
#define PAYLOAD_VERSION_MASK 0xC0
|
||||
|
||||
typedef enum RouteType {
|
||||
ROUTE_TYPE_TRANSPORT_FLOOD = 0x00,
|
||||
ROUTE_TYPE_FLOOD = 0x01,
|
||||
ROUTE_TYPE_DIRECT = 0x02,
|
||||
ROUTE_TYPE_TRANSPORT_DIRECT = 0x03,
|
||||
} RouteType;
|
||||
|
||||
|
||||
typedef enum PayloadType {
|
||||
PAYLOAD_TYPE_REQ = 0x00 << 2,
|
||||
PAYLOAD_TYPE_RESPONSE = 0x01 << 2,
|
||||
PAYLOAD_TYPE_TXT_MSG = 0x02 << 2,
|
||||
PAYLOAD_TYPE_ACK = 0x03 << 2,
|
||||
PAYLOAD_TYPE_ADVERT = 0x04 << 2,
|
||||
PAYLOAD_TYPE_GRP_TXT = 0x05 << 2,
|
||||
PAYLOAD_TYPE_GRP_DATA = 0x06 << 2,
|
||||
PAYLOAD_TYPE_ANON_REQ = 0x07 << 2,
|
||||
PAYLOAD_TYPE_PATH = 0x08 << 2,
|
||||
PAYLOAD_TYPE_TRACE = 0x09 << 2,
|
||||
PAYLOAD_TYPE_MULTIPART = 0x0A << 2,
|
||||
PAYLOAD_TYPE_RAW_CUSTOM = 0x0F << 2,
|
||||
} PayloadType;
|
||||
|
||||
|
||||
typedef enum PayloadVersion {
|
||||
PAYLOAD_VERSION_0 = 0 << 6,
|
||||
PAYLOAD_VERSION_1 = 1 << 6,
|
||||
PAYLOAD_VERSION_2 = 2 << 6,
|
||||
PAYLOAD_VERSION_3 = 3 << 6,
|
||||
} PayloadVersion;
|
||||
|
||||
|
||||
typedef struct FrameStruct {
|
||||
unsigned char header;
|
||||
unsigned char transportCodes[4];
|
||||
unsigned char pathLen;
|
||||
unsigned char path[64];
|
||||
unsigned char payloadLen;
|
||||
unsigned char payload[184];
|
||||
} FrameStruct;
|
||||
|
||||
typedef enum RequestType {
|
||||
REQUEST_GET_STATS = 0x01,
|
||||
REQUEST_KEEPALIVE = 0x02,
|
||||
REQUEST_GET_TELEMETRY_DATA = 0x03,
|
||||
REQUEST_GET_MIN_MAX_AVG = 0x04,
|
||||
REQUEST_GET_ACCESS_LIST = 0x05,
|
||||
} RequestType;
|
||||
|
||||
|
||||
typedef struct EncryptedPayloadStruct {
|
||||
FrameStruct rawFrame;
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
unsigned char payload[180];
|
||||
} EncryptedPayloadStruct;
|
||||
|
||||
typedef enum AdvertisementPayloadFlags {
|
||||
ADVERTISEMENT_FLAG_IS_CHAT_NODE = 0x01,
|
||||
ADVERTISEMENT_FLAG_IS_REAPEATER = 0x02,
|
||||
ADVERTISEMENT_FLAG_IS_ROOM_SERVER = 0x03,
|
||||
ADVERTISEMENT_FLAG_IS_SENSOR = 0x04,
|
||||
ADVERTISEMENT_FLAG_HAS_LOCATION = 0x10,
|
||||
ADVERTISEMENT_FLAG_RFU1 = 0x20,
|
||||
ADVERTISEMENT_FLAG_RFU2 = 0x40,
|
||||
ADVERTISEMENT_FLAG_HAS_NAME = 0x80,
|
||||
} AdvertisementPayloadFlags;
|
||||
|
||||
typedef struct AdvertisementPayload {
|
||||
unsigned char pubKey[32];
|
||||
int32_t timestamp;
|
||||
unsigned char signature[64];
|
||||
unsigned char dataFlags;
|
||||
int32_t latitude;
|
||||
int32_t longitude;
|
||||
int16_t rfu1;
|
||||
int16_t rfu2;
|
||||
char nodeName[128];
|
||||
|
||||
} AdvertisementPayload;
|
||||
|
||||
typedef struct ReturnedPathPayload {
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
unsigned char pathLen;
|
||||
|
||||
} ReturnedPathPayload;
|
||||
|
||||
typedef struct RequestPayload {
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
} RequestPayload;
|
||||
|
||||
typedef struct ResponsePayload {
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
} ResponsePayload;
|
||||
|
||||
typedef struct PlainTextMessagePayload {
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
} PlainTextMessagePayload;
|
||||
|
||||
typedef struct GroupTextMessage {
|
||||
unsigned char channelHash;
|
||||
unsigned char keyIndex;
|
||||
int32_t timestamp;
|
||||
unsigned char flags;
|
||||
unsigned char text[190];
|
||||
} GroupTextMessage;
|
||||
|
||||
#endif
|
863
User/sx1262.c
Normal file
863
User/sx1262.c
Normal file
@@ -0,0 +1,863 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "sx1262.h"
|
||||
#include "util/log.h"
|
||||
#define TAG "SX1262"
|
||||
|
||||
// Global Stuff
|
||||
static uint8_t PacketParams[6];
|
||||
static char txActive;
|
||||
static int txLost = 0;
|
||||
static char debugPrint;
|
||||
|
||||
// Arduino compatible macros
|
||||
#define delayMicroseconds(us) esp_rom_delay_us (us)
|
||||
#define delay(ms) esp_rom_delay_us (ms * 1000)
|
||||
|
||||
void LoRaError (int error) {
|
||||
if (debugPrint) {
|
||||
ESP_LOGE (TAG, "LoRaErrorDefault=%d", error);
|
||||
}
|
||||
while (1) {
|
||||
vTaskDelay (1);
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaInit (void) {
|
||||
|
||||
txActive = 0;
|
||||
debugPrint = 0;
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||
SPI_InitTypeDef SPI_InitStructure = {0};
|
||||
|
||||
|
||||
// RCC_AHBPeriphClockCmd (RCC_AHBPeriph_SDIO, ENABLE);
|
||||
RCC_APB1PeriphClockCmd (RCC_APB1Periph_USART2 | RCC_APB1Periph_I2C2, ENABLE);
|
||||
|
||||
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOE | RCC_APB2Periph_SPI1, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init (GPIOA, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init (GPIOA, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init (GPIOA, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init (GPIOA, &GPIO_InitStructure);
|
||||
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init (GPIOE, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init (GPIOE, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init (GPIOE, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init (GPIOE, &GPIO_InitStructure);
|
||||
|
||||
|
||||
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
||||
|
||||
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
|
||||
|
||||
|
||||
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
|
||||
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
|
||||
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
|
||||
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
|
||||
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
|
||||
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
|
||||
SPI_InitStructure.SPI_CRCPolynomial = 7;
|
||||
SPI_Init (SPI1, &SPI_InitStructure);
|
||||
|
||||
GPIO_WriteBit (GPIOE, GPIO_Pin_3, 1);
|
||||
|
||||
SPI_Cmd (SPI1, ENABLE);
|
||||
}
|
||||
|
||||
void spi_write_byte (uint8_t *DataOut, size_t DataLength) {
|
||||
spi_read_byte (NULL, DataOut, DataLength);
|
||||
}
|
||||
|
||||
// Full-duplex transfer: TX and RX buffers
|
||||
void spi_read_byte (uint8_t *rx, const uint8_t *tx, size_t len) {
|
||||
GPIO_WriteBit (GPIOA, GPIO_Pin_4, 0);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t out = tx ? tx[i] : 0xFF;
|
||||
|
||||
// Wait TX ready
|
||||
while (SPI_I2S_GetFlagStatus (SPI1, SPI_I2S_FLAG_TXE) == RESET);
|
||||
if (debugPrint) {
|
||||
printf ("Sent %02X over spi.\n", out);
|
||||
}
|
||||
SPI_I2S_SendData (SPI1, out);
|
||||
// Wait RX ready
|
||||
|
||||
while (SPI_I2S_GetFlagStatus (SPI1, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
|
||||
uint8_t in = (uint8_t)SPI_I2S_ReceiveData (SPI1);
|
||||
if (debugPrint) {
|
||||
printf ("Got %02X over spi.\n", in);
|
||||
}
|
||||
if (rx)
|
||||
rx[i] = in;
|
||||
}
|
||||
GPIO_WriteBit (GPIOA, GPIO_Pin_4, 1);
|
||||
}
|
||||
|
||||
int16_t LoRaBegin (uint32_t frequencyInHz, int8_t txPowerInDbm, float tcxoVoltage, char useRegulatorLDO) {
|
||||
if (txPowerInDbm > 22) {
|
||||
txPowerInDbm = 22;
|
||||
}
|
||||
if (txPowerInDbm < -3) {
|
||||
txPowerInDbm = -3;
|
||||
}
|
||||
|
||||
ResetLora();
|
||||
|
||||
uint8_t wk[2];
|
||||
ReadRegister (SX126X_REG_LORA_SYNC_WORD_MSB, wk, 2); // 0x0740
|
||||
uint16_t syncWord = (wk[0] << 8) + wk[1];
|
||||
ESP_LOGI (TAG, "syncWord=0x%x", syncWord);
|
||||
if (syncWord != SX126X_SYNC_WORD_PUBLIC && syncWord != SX126X_SYNC_WORD_PRIVATE) {
|
||||
ESP_LOGE (TAG, "SX126x error, maybe no SPI connection");
|
||||
return ERR_INVALID_MODE;
|
||||
}
|
||||
|
||||
ESP_LOGI (TAG, "SX126x installed");
|
||||
SetStandby (SX126X_STANDBY_RC);
|
||||
|
||||
SetDio2AsRfSwitchCtrl (1);
|
||||
ESP_LOGI (TAG, "tcxoVoltage=%f", tcxoVoltage);
|
||||
// set TCXO control, if requested
|
||||
if (tcxoVoltage > 0.0) {
|
||||
SetDio3AsTcxoCtrl (tcxoVoltage, RADIO_TCXO_SETUP_TIME); // Configure the radio to use a TCXO controlled by DIO3
|
||||
}
|
||||
|
||||
Calibrate (SX126X_CALIBRATE_IMAGE_ON | SX126X_CALIBRATE_ADC_BULK_P_ON | SX126X_CALIBRATE_ADC_BULK_N_ON | SX126X_CALIBRATE_ADC_PULSE_ON | SX126X_CALIBRATE_PLL_ON | SX126X_CALIBRATE_RC13M_ON | SX126X_CALIBRATE_RC64K_ON);
|
||||
|
||||
ESP_LOGI (TAG, "useRegulatorLDO=%d", useRegulatorLDO);
|
||||
if (useRegulatorLDO) {
|
||||
SetRegulatorMode (SX126X_REGULATOR_LDO); // set regulator mode: LDO
|
||||
} else {
|
||||
SetRegulatorMode (SX126X_REGULATOR_DC_DC); // set regulator mode: DC-DC
|
||||
}
|
||||
|
||||
SetBufferBaseAddress (0, 0);
|
||||
SetPaConfig (0x04, 0x07, 0x00, 0x01); // PA Optimal Settings +22 dBm
|
||||
SetOvercurrentProtection (60.0); // current max 60mA for the whole device
|
||||
SetPowerConfig (txPowerInDbm, SX126X_PA_RAMP_200U); // 0 fuer Empfaenger
|
||||
SetRfFrequency (frequencyInHz);
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
void FixInvertedIQ (uint8_t iqConfig) {
|
||||
// fixes IQ configuration for inverted IQ
|
||||
// see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.4 for details
|
||||
// When exchanging LoRa packets with inverted IQ polarity, some packet losses may be observed for longer packets.
|
||||
// Workaround: Bit 2 at address 0x0736 must be set to:
|
||||
// “0” when using inverted IQ polarity (see the SetPacketParam(...) command)
|
||||
// “1” when using standard IQ polarity
|
||||
|
||||
// read current IQ configuration
|
||||
uint8_t iqConfigCurrent = 0;
|
||||
ReadRegister (SX126X_REG_IQ_POLARITY_SETUP, &iqConfigCurrent, 1); // 0x0736
|
||||
|
||||
// set correct IQ configuration
|
||||
// if(iqConfig == SX126X_LORA_IQ_STANDARD) {
|
||||
if (iqConfig == SX126X_LORA_IQ_INVERTED) {
|
||||
iqConfigCurrent &= 0xFB; // using inverted IQ polarity
|
||||
} else {
|
||||
iqConfigCurrent |= 0x04; // using standard IQ polarity
|
||||
}
|
||||
|
||||
// update with the new value
|
||||
WriteRegister (SX126X_REG_IQ_POLARITY_SETUP, &iqConfigCurrent, 1); // 0x0736
|
||||
}
|
||||
|
||||
void LoRaConfig (uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate, uint16_t preambleLength, uint8_t payloadLen, char crcOn, char invertIrq) {
|
||||
SetStopRxTimerOnPreambleDetect (0);
|
||||
SetLoRaSymbNumTimeout (0);
|
||||
SetPacketType (SX126X_PACKET_TYPE_LORA); // SX126x.ModulationParams.PacketType : MODEM_LORA
|
||||
uint8_t ldro = 0; // LowDataRateOptimize OFF
|
||||
SetModulationParams (spreadingFactor, bandwidth, codingRate, ldro);
|
||||
|
||||
PacketParams[0] = (preambleLength >> 8) & 0xFF;
|
||||
PacketParams[1] = preambleLength;
|
||||
if (payloadLen) {
|
||||
PacketParams[2] = 0x01; // Fixed length packet (implicit header)
|
||||
PacketParams[3] = payloadLen;
|
||||
} else {
|
||||
PacketParams[2] = 0x00; // Variable length packet (explicit header)
|
||||
PacketParams[3] = 0xFF;
|
||||
}
|
||||
|
||||
if (crcOn)
|
||||
PacketParams[4] = SX126X_LORA_CRC_ON;
|
||||
else
|
||||
PacketParams[4] = SX126X_LORA_CRC_OFF;
|
||||
|
||||
if (invertIrq)
|
||||
PacketParams[5] = 0x01; // Inverted LoRa I and Q signals setup
|
||||
else
|
||||
PacketParams[5] = 0x00; // Standard LoRa I and Q signals setup
|
||||
|
||||
// fixes IQ configuration for inverted IQ
|
||||
FixInvertedIQ (PacketParams[5]);
|
||||
|
||||
WriteCommand (SX126X_CMD_SET_PACKET_PARAMS, PacketParams, 6); // 0x8C
|
||||
|
||||
// Do not use DIO interruptst
|
||||
SetDioIrqParams (SX126X_IRQ_ALL, // all interrupts enabled
|
||||
SX126X_IRQ_NONE, // interrupts on DIO1
|
||||
SX126X_IRQ_NONE, // interrupts on DIO2
|
||||
SX126X_IRQ_NONE // interrupts on DIO3
|
||||
);
|
||||
|
||||
|
||||
ESP_LOGI (TAG, "Almost done setting LoRa");
|
||||
// Receive state no receive timeoout
|
||||
SetRx (0xFFFFFF);
|
||||
}
|
||||
|
||||
void LoRaDebugPrint (char enable) {
|
||||
debugPrint = enable;
|
||||
}
|
||||
|
||||
uint8_t LoRaReceive (uint8_t *pData, int16_t len) {
|
||||
uint8_t rxLen = 0;
|
||||
uint16_t irqRegs = GetIrqStatus();
|
||||
// uint8_t status = GetStatus();
|
||||
|
||||
if (irqRegs & SX126X_IRQ_RX_DONE) {
|
||||
// ClearIrqStatus(SX126X_IRQ_RX_DONE);
|
||||
ClearIrqStatus (SX126X_IRQ_ALL);
|
||||
rxLen = ReadBuffer (pData, len);
|
||||
}
|
||||
|
||||
return rxLen;
|
||||
}
|
||||
|
||||
char LoRaSend (uint8_t *pData, int16_t len, uint8_t mode) {
|
||||
uint16_t irqStatus;
|
||||
char rv = 0;
|
||||
|
||||
if (txActive == 0) {
|
||||
txActive = 1;
|
||||
if (PacketParams[2] == 0x00) { // Variable length packet (explicit header)
|
||||
PacketParams[3] = len;
|
||||
}
|
||||
WriteCommand (SX126X_CMD_SET_PACKET_PARAMS, PacketParams, 6); // 0x8C
|
||||
|
||||
// ClearIrqStatus(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT);
|
||||
ClearIrqStatus (SX126X_IRQ_ALL);
|
||||
|
||||
WriteBuffer (pData, len);
|
||||
SetTx (5000);
|
||||
|
||||
if (mode & SX126x_TXMODE_SYNC) {
|
||||
irqStatus = GetIrqStatus();
|
||||
while ((!(irqStatus & SX126X_IRQ_TX_DONE)) && (!(irqStatus & SX126X_IRQ_TIMEOUT))) {
|
||||
vTaskDelay (1);
|
||||
irqStatus = GetIrqStatus();
|
||||
}
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "irqStatus=0x%x", irqStatus);
|
||||
if (irqStatus & SX126X_IRQ_TX_DONE) {
|
||||
ESP_LOGI (TAG, "SX126X_IRQ_TX_DONE");
|
||||
}
|
||||
if (irqStatus & SX126X_IRQ_TIMEOUT) {
|
||||
ESP_LOGI (TAG, "SX126X_IRQ_TIMEOUT");
|
||||
}
|
||||
}
|
||||
txActive = 0;
|
||||
|
||||
SetRx (0xFFFFFF);
|
||||
|
||||
if (irqStatus & SX126X_IRQ_TX_DONE) {
|
||||
rv = 1;
|
||||
}
|
||||
} else {
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "Send rv=0x%x", rv);
|
||||
}
|
||||
if (rv == 0)
|
||||
txLost++;
|
||||
return rv;
|
||||
}
|
||||
|
||||
char ReceiveMode (void) {
|
||||
uint16_t irq;
|
||||
char rv = 0;
|
||||
|
||||
if (txActive == 0) {
|
||||
rv = 1;
|
||||
} else {
|
||||
irq = GetIrqStatus();
|
||||
if (irq & (SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT)) {
|
||||
SetRx (0xFFFFFF);
|
||||
txActive = 0;
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void GetPacketStatus (int8_t *rssiPacket, int8_t *snrPacket) {
|
||||
uint8_t buf[4];
|
||||
ReadCommand (SX126X_CMD_GET_PACKET_STATUS, buf, 4); // 0x14
|
||||
*rssiPacket = (buf[3] >> 1) * -1;
|
||||
(buf[2] < 128) ? (*snrPacket = buf[2] >> 2) : (*snrPacket = ((buf[2] - 256) >> 2));
|
||||
}
|
||||
|
||||
void SetTxPower (int8_t txPowerInDbm) {
|
||||
SetPowerConfig (txPowerInDbm, SX126X_PA_RAMP_200U);
|
||||
}
|
||||
|
||||
void ResetLora (void) {
|
||||
vTaskDelay (pdMS_TO_TICKS (10));
|
||||
GPIO_WriteBit (GPIOE, GPIO_Pin_3, 0);
|
||||
vTaskDelay (pdMS_TO_TICKS (20));
|
||||
GPIO_WriteBit (GPIOE, GPIO_Pin_3, 1);
|
||||
ESP_LOGW (TAG, "Waiting for idle");
|
||||
vTaskDelay (pdMS_TO_TICKS (10));
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
WaitForIdle (BUSY_WAIT, "Reset", 1);
|
||||
}
|
||||
|
||||
void Wakeup (void) {
|
||||
GetStatus();
|
||||
}
|
||||
|
||||
void SetStandby (uint8_t mode) {
|
||||
uint8_t data = mode;
|
||||
WriteCommand (SX126X_CMD_SET_STANDBY, &data, 1); // 0x80
|
||||
}
|
||||
|
||||
uint8_t GetStatus (void) {
|
||||
uint8_t rv;
|
||||
ReadCommand (SX126X_CMD_GET_STATUS, &rv, 1); // 0xC0
|
||||
return rv;
|
||||
}
|
||||
|
||||
void SetDio3AsTcxoCtrl (float voltage, uint32_t delay) {
|
||||
uint8_t buf[4];
|
||||
|
||||
// buf[0] = tcxoVoltage & 0x07;
|
||||
if (fabs (voltage - 1.6) <= 0.001) {
|
||||
buf[0] = SX126X_DIO3_OUTPUT_1_6;
|
||||
} else if (fabs (voltage - 1.7) <= 0.001) {
|
||||
buf[0] = SX126X_DIO3_OUTPUT_1_7;
|
||||
} else if (fabs (voltage - 1.8) <= 0.001) {
|
||||
buf[0] = SX126X_DIO3_OUTPUT_1_8;
|
||||
} else if (fabs (voltage - 2.2) <= 0.001) {
|
||||
buf[0] = SX126X_DIO3_OUTPUT_2_2;
|
||||
} else if (fabs (voltage - 2.4) <= 0.001) {
|
||||
buf[0] = SX126X_DIO3_OUTPUT_2_4;
|
||||
} else if (fabs (voltage - 2.7) <= 0.001) {
|
||||
buf[0] = SX126X_DIO3_OUTPUT_2_7;
|
||||
} else if (fabs (voltage - 3.0) <= 0.001) {
|
||||
buf[0] = SX126X_DIO3_OUTPUT_3_0;
|
||||
} else {
|
||||
buf[0] = SX126X_DIO3_OUTPUT_3_3;
|
||||
}
|
||||
|
||||
uint32_t delayValue = (float)delay / 15.625;
|
||||
buf[1] = (uint8_t)((delayValue >> 16) & 0xFF);
|
||||
buf[2] = (uint8_t)((delayValue >> 8) & 0xFF);
|
||||
buf[3] = (uint8_t)(delayValue & 0xFF);
|
||||
|
||||
WriteCommand (SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, buf, 4); // 0x97
|
||||
}
|
||||
|
||||
void Calibrate (uint8_t calibParam) {
|
||||
uint8_t data = calibParam;
|
||||
WriteCommand (SX126X_CMD_CALIBRATE, &data, 1); // 0x89
|
||||
}
|
||||
|
||||
void SetDio2AsRfSwitchCtrl (uint8_t enable) {
|
||||
uint8_t data = enable;
|
||||
WriteCommand (SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1); // 0x9D
|
||||
}
|
||||
|
||||
void SetRfFrequency (uint32_t frequency) {
|
||||
uint8_t buf[4];
|
||||
uint32_t freq = 0;
|
||||
|
||||
CalibrateImage (frequency);
|
||||
|
||||
freq = (uint32_t)((double)frequency / (double)FREQ_STEP);
|
||||
buf[0] = (uint8_t)((freq >> 24) & 0xFF);
|
||||
buf[1] = (uint8_t)((freq >> 16) & 0xFF);
|
||||
buf[2] = (uint8_t)((freq >> 8) & 0xFF);
|
||||
buf[3] = (uint8_t)(freq & 0xFF);
|
||||
WriteCommand (SX126X_CMD_SET_RF_FREQUENCY, buf, 4); // 0x86
|
||||
}
|
||||
|
||||
void CalibrateImage (uint32_t frequency) {
|
||||
uint8_t calFreq[2];
|
||||
|
||||
if (frequency > 900000000) {
|
||||
calFreq[0] = 0xE1;
|
||||
calFreq[1] = 0xE9;
|
||||
} else if (frequency > 850000000) {
|
||||
calFreq[0] = 0xD7;
|
||||
calFreq[1] = 0xDB;
|
||||
} else if (frequency > 770000000) {
|
||||
calFreq[0] = 0xC1;
|
||||
calFreq[1] = 0xC5;
|
||||
} else if (frequency > 460000000) {
|
||||
calFreq[0] = 0x75;
|
||||
calFreq[1] = 0x81;
|
||||
} else if (frequency > 425000000) {
|
||||
calFreq[0] = 0x6B;
|
||||
calFreq[1] = 0x6F;
|
||||
}
|
||||
WriteCommand (SX126X_CMD_CALIBRATE_IMAGE, calFreq, 2); // 0x98
|
||||
}
|
||||
|
||||
void SetRegulatorMode (uint8_t mode) {
|
||||
uint8_t data = mode;
|
||||
WriteCommand (SX126X_CMD_SET_REGULATOR_MODE, &data, 1); // 0x96
|
||||
}
|
||||
|
||||
void SetBufferBaseAddress (uint8_t txBaseAddress, uint8_t rxBaseAddress) {
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = txBaseAddress;
|
||||
buf[1] = rxBaseAddress;
|
||||
WriteCommand (SX126X_CMD_SET_BUFFER_BASE_ADDRESS, buf, 2); // 0x8F
|
||||
}
|
||||
|
||||
void SetPowerConfig (int8_t power, uint8_t rampTime) {
|
||||
uint8_t buf[2];
|
||||
|
||||
if (power > 22) {
|
||||
power = 22;
|
||||
} else if (power < -3) {
|
||||
power = -3;
|
||||
}
|
||||
|
||||
buf[0] = power;
|
||||
buf[1] = (uint8_t)rampTime;
|
||||
WriteCommand (SX126X_CMD_SET_TX_PARAMS, buf, 2); // 0x8E
|
||||
}
|
||||
|
||||
void SetPaConfig (uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut) {
|
||||
uint8_t buf[4];
|
||||
|
||||
buf[0] = paDutyCycle;
|
||||
buf[1] = hpMax;
|
||||
buf[2] = deviceSel;
|
||||
buf[3] = paLut;
|
||||
WriteCommand (SX126X_CMD_SET_PA_CONFIG, buf, 4); // 0x95
|
||||
}
|
||||
|
||||
void SetOvercurrentProtection (float currentLimit) {
|
||||
if ((currentLimit >= 0.0) && (currentLimit <= 140.0)) {
|
||||
uint8_t buf[1];
|
||||
buf[0] = (uint8_t)(currentLimit / 2.5);
|
||||
WriteRegister (SX126X_REG_OCP_CONFIGURATION, buf, 1); // 0x08E7
|
||||
}
|
||||
}
|
||||
|
||||
void SetSyncWord (int16_t sync) {
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = (uint8_t)((sync >> 8) & 0x00FF);
|
||||
buf[1] = (uint8_t)(sync & 0x00FF);
|
||||
WriteRegister (SX126X_REG_LORA_SYNC_WORD_MSB, buf, 2); // 0x0740
|
||||
}
|
||||
|
||||
void SetDioIrqParams (uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
|
||||
uint8_t buf[8];
|
||||
|
||||
buf[0] = (uint8_t)((irqMask >> 8) & 0x00FF);
|
||||
buf[1] = (uint8_t)(irqMask & 0x00FF);
|
||||
buf[2] = (uint8_t)((dio1Mask >> 8) & 0x00FF);
|
||||
buf[3] = (uint8_t)(dio1Mask & 0x00FF);
|
||||
buf[4] = (uint8_t)((dio2Mask >> 8) & 0x00FF);
|
||||
buf[5] = (uint8_t)(dio2Mask & 0x00FF);
|
||||
buf[6] = (uint8_t)((dio3Mask >> 8) & 0x00FF);
|
||||
buf[7] = (uint8_t)(dio3Mask & 0x00FF);
|
||||
WriteCommand (SX126X_CMD_SET_DIO_IRQ_PARAMS, buf, 8); // 0x08
|
||||
}
|
||||
|
||||
void SetStopRxTimerOnPreambleDetect (char enable) {
|
||||
ESP_LOGI (TAG, "SetStopRxTimerOnPreambleDetect enable=%d", enable);
|
||||
// uint8_t data = (uint8_t)enable;
|
||||
uint8_t data = 0;
|
||||
if (enable)
|
||||
data = 1;
|
||||
WriteCommand (SX126X_CMD_STOP_TIMER_ON_PREAMBLE, &data, 1); // 0x9F
|
||||
}
|
||||
|
||||
void SetLoRaSymbNumTimeout (uint8_t SymbNum) {
|
||||
uint8_t data = SymbNum;
|
||||
WriteCommand (SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT, &data, 1); // 0xA0
|
||||
}
|
||||
|
||||
void SetPacketType (uint8_t packetType) {
|
||||
uint8_t data = packetType;
|
||||
WriteCommand (SX126X_CMD_SET_PACKET_TYPE, &data, 1); // 0x01
|
||||
}
|
||||
|
||||
void SetModulationParams (uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate, uint8_t lowDataRateOptimize) {
|
||||
uint8_t data[4];
|
||||
// currently only LoRa supported
|
||||
data[0] = spreadingFactor;
|
||||
data[1] = bandwidth;
|
||||
data[2] = codingRate;
|
||||
data[3] = lowDataRateOptimize;
|
||||
WriteCommand (SX126X_CMD_SET_MODULATION_PARAMS, data, 4); // 0x8B
|
||||
}
|
||||
|
||||
void SetCadParams (uint8_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, uint8_t cadExitMode, uint32_t cadTimeout) {
|
||||
uint8_t data[7];
|
||||
data[0] = cadSymbolNum;
|
||||
data[1] = cadDetPeak;
|
||||
data[2] = cadDetMin;
|
||||
data[3] = cadExitMode;
|
||||
data[4] = (uint8_t)((cadTimeout >> 16) & 0xFF);
|
||||
data[5] = (uint8_t)((cadTimeout >> 8) & 0xFF);
|
||||
data[6] = (uint8_t)(cadTimeout & 0xFF);
|
||||
WriteCommand (SX126X_CMD_SET_CAD_PARAMS, data, 7); // 0x88
|
||||
}
|
||||
|
||||
void SetCad() {
|
||||
uint8_t data = 0;
|
||||
WriteCommand (SX126X_CMD_SET_CAD, &data, 0); // 0xC5
|
||||
}
|
||||
|
||||
uint16_t GetIrqStatus (void) {
|
||||
uint8_t data[3];
|
||||
ReadCommand (SX126X_CMD_GET_IRQ_STATUS, data, 3); // 0x12
|
||||
return (data[1] << 8) | data[2];
|
||||
}
|
||||
|
||||
void ClearIrqStatus (uint16_t irq) {
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = (uint8_t)(((uint16_t)irq >> 8) & 0x00FF);
|
||||
buf[1] = (uint8_t)((uint16_t)irq & 0x00FF);
|
||||
WriteCommand (SX126X_CMD_CLEAR_IRQ_STATUS, buf, 2); // 0x02
|
||||
}
|
||||
|
||||
void SetRx (uint32_t timeout) {
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "----- SetRx timeout=%d", timeout);
|
||||
}
|
||||
SetStandby (SX126X_STANDBY_RC);
|
||||
uint8_t buf[3];
|
||||
buf[0] = (uint8_t)((timeout >> 16) & 0xFF);
|
||||
buf[1] = (uint8_t)((timeout >> 8) & 0xFF);
|
||||
buf[2] = (uint8_t)(timeout & 0xFF);
|
||||
WriteCommand (SX126X_CMD_SET_RX, buf, 3); // 0x82
|
||||
|
||||
for (int retry = 0; retry < 10; retry++) {
|
||||
if ((GetStatus() & 0x70) == 0x50)
|
||||
break;
|
||||
vTaskDelay (pdMS_TO_TICKS (1));
|
||||
}
|
||||
if ((GetStatus() & 0x70) != 0x50) {
|
||||
ESP_LOGE (TAG, "SetRx Illegal Status");
|
||||
LoRaError (ERR_INVALID_SETRX_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
void SetTx (uint32_t timeoutInMs) {
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "----- SetTx timeoutInMs=%d", timeoutInMs);
|
||||
}
|
||||
SetStandby (SX126X_STANDBY_RC);
|
||||
uint8_t buf[3];
|
||||
uint32_t tout = timeoutInMs;
|
||||
if (timeoutInMs != 0) {
|
||||
uint32_t timeoutInUs = timeoutInMs * 1000;
|
||||
tout = (uint32_t)(timeoutInUs / 0.015625);
|
||||
}
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "SetTx timeoutInMs=%d" " tout=%d", timeoutInMs, tout);
|
||||
}
|
||||
buf[0] = (uint8_t)((tout >> 16) & 0xFF);
|
||||
buf[1] = (uint8_t)((tout >> 8) & 0xFF);
|
||||
buf[2] = (uint8_t)(tout & 0xFF);
|
||||
WriteCommand (SX126X_CMD_SET_TX, buf, 3); // 0x83
|
||||
|
||||
for (int retry = 0; retry < 10; retry++) {
|
||||
if ((GetStatus() & 0x70) == 0x60)
|
||||
break;
|
||||
vTaskDelay (1);
|
||||
}
|
||||
if ((GetStatus() & 0x70) != 0x60) {
|
||||
ESP_LOGE (TAG, "SetTx Illegal Status");
|
||||
LoRaError (ERR_INVALID_SETTX_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
int GetPacketLost() {
|
||||
return txLost;
|
||||
}
|
||||
|
||||
uint8_t GetRssiInst() {
|
||||
uint8_t buf[2];
|
||||
ReadCommand (SX126X_CMD_GET_RSSI_INST, buf, 2); // 0x15
|
||||
return buf[1];
|
||||
}
|
||||
|
||||
void GetRxBufferStatus (uint8_t *payloadLength, uint8_t *rxStartBufferPointer) {
|
||||
uint8_t buf[3];
|
||||
ReadCommand (SX126X_CMD_GET_RX_BUFFER_STATUS, buf, 3); // 0x13
|
||||
*payloadLength = buf[1];
|
||||
*rxStartBufferPointer = buf[2];
|
||||
}
|
||||
|
||||
void WaitForIdleBegin (unsigned long timeout, char *text) {
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
char stop = 0;
|
||||
for (int retry = 0; retry < 10; retry++) {
|
||||
if (retry == 9)
|
||||
stop = 1;
|
||||
char ret = WaitForIdle (BUSY_WAIT, text, stop);
|
||||
if (ret == 1)
|
||||
break;
|
||||
ESP_LOGW (TAG, "WaitForIdle fail retry=%d", retry);
|
||||
vTaskDelay (pdMS_TO_TICKS (10));
|
||||
}
|
||||
}
|
||||
|
||||
char WaitForIdle (unsigned long timeout, char *text, char stop) {
|
||||
char ret = 1;
|
||||
TickType_t start = xTaskGetTickCount();
|
||||
vTaskDelay (pdMS_TO_TICKS (1));
|
||||
while (xTaskGetTickCount() - start < (timeout / portTICK_PERIOD_MS)) {
|
||||
if (GPIO_ReadInputDataBit (GPIOE, GPIO_Pin_1) == 0)
|
||||
break;
|
||||
vTaskDelay (pdMS_TO_TICKS (1));
|
||||
}
|
||||
|
||||
if (GPIO_ReadInputDataBit (GPIOE, GPIO_Pin_1)) {
|
||||
if (stop) {
|
||||
ESP_LOGE (TAG, "WaitForIdle Timeout text=%s timeout=%lu start=%d", text, timeout, start);
|
||||
LoRaError (ERR_IDLE_TIMEOUT);
|
||||
} else {
|
||||
ESP_LOGW (TAG, "WaitForIdle Timeout text=%s timeout=%lu start=%d", text, timeout, start);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t ReadBuffer (uint8_t *rxData, int16_t rxDataLen) {
|
||||
uint8_t offset = 0;
|
||||
uint8_t payloadLength = 0;
|
||||
GetRxBufferStatus (&payloadLength, &offset);
|
||||
if (payloadLength > rxDataLen) {
|
||||
ESP_LOGW (TAG, "ReadBuffer rxDataLen too small. payloadLength=%d rxDataLen=%d", payloadLength, rxDataLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
WaitForIdle (BUSY_WAIT, "start ReadBuffer", 1);
|
||||
|
||||
// start transfer
|
||||
uint8_t *buf;
|
||||
buf = malloc (payloadLength + 3);
|
||||
if (buf != NULL) {
|
||||
buf[0] = SX126X_CMD_READ_BUFFER; // 0x1E
|
||||
buf[1] = offset; // offset in rx fifo
|
||||
buf[2] = SX126X_CMD_NOP;
|
||||
memset (&buf[3], SX126X_CMD_NOP, payloadLength);
|
||||
spi_read_byte (buf, buf, payloadLength + 3);
|
||||
memcpy (rxData, &buf[3], payloadLength);
|
||||
free (buf);
|
||||
} else {
|
||||
ESP_LOGE (TAG, "ReadBuffer malloc fail");
|
||||
payloadLength = 0;
|
||||
}
|
||||
|
||||
// wait for BUSY to go low
|
||||
WaitForIdle (BUSY_WAIT, "end ReadBuffer", 0);
|
||||
|
||||
return payloadLength;
|
||||
}
|
||||
|
||||
void WriteBuffer (uint8_t *txData, int16_t txDataLen) {
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
WaitForIdle (BUSY_WAIT, "start WriteBuffer", 1);
|
||||
|
||||
// start transfer
|
||||
uint8_t *buf;
|
||||
buf = malloc (txDataLen + 2);
|
||||
if (buf != NULL) {
|
||||
buf[0] = SX126X_CMD_WRITE_BUFFER; // 0x0E
|
||||
buf[1] = 0; // offset in tx fifo
|
||||
memcpy (&buf[2], txData, txDataLen);
|
||||
spi_write_byte (buf, txDataLen + 2);
|
||||
free (buf);
|
||||
} else {
|
||||
ESP_LOGE (TAG, "WriteBuffer malloc fail");
|
||||
}
|
||||
|
||||
// wait for BUSY to go low
|
||||
WaitForIdle (BUSY_WAIT, "end WriteBuffer", 0);
|
||||
}
|
||||
|
||||
void WriteRegister (uint16_t reg, uint8_t *data, uint8_t numBytes) {
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
WaitForIdle (BUSY_WAIT, "start WriteRegister", 1);
|
||||
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "WriteRegister: REG=0x%02x", reg);
|
||||
for (uint8_t n = 0; n < numBytes; n++) {
|
||||
ESP_LOGI (TAG, "DataOut:%02x ", data[n]);
|
||||
}
|
||||
}
|
||||
|
||||
// start transfer
|
||||
uint8_t buf[16];
|
||||
buf[0] = SX126X_CMD_WRITE_REGISTER;
|
||||
buf[1] = (reg & 0xFF00) >> 8;
|
||||
buf[2] = reg & 0xff;
|
||||
memcpy (&buf[3], data, numBytes);
|
||||
spi_write_byte (buf, 3 + numBytes);
|
||||
|
||||
// wait for BUSY to go low
|
||||
WaitForIdle (BUSY_WAIT, "end WriteRegister", 0);
|
||||
}
|
||||
|
||||
void ReadRegister (uint16_t reg, uint8_t *data, uint8_t numBytes) {
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
WaitForIdle (BUSY_WAIT, "start ReadRegister", 1);
|
||||
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "ReadRegister: REG=0x%02x", reg);
|
||||
}
|
||||
|
||||
// start transfer
|
||||
uint8_t buf[16];
|
||||
uint8_t buf2[16];
|
||||
memset (buf, SX126X_CMD_NOP, sizeof (buf));
|
||||
memset (buf2, SX126X_CMD_NOP, sizeof (buf2));
|
||||
buf[0] = SX126X_CMD_READ_REGISTER;
|
||||
buf[1] = (reg & 0xFF00) >> 8;
|
||||
buf[2] = reg & 0xff;
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "Reading bytes");
|
||||
}
|
||||
|
||||
spi_read_byte (buf2, buf, 4 + numBytes);
|
||||
ESP_LOGI (TAG, "read a byte");
|
||||
memcpy (data, &buf2[4], numBytes);
|
||||
if (debugPrint) {
|
||||
for (uint8_t n = 0; n < numBytes; n++) {
|
||||
ESP_LOGI (TAG, "DataIn:%02x ", data[n]);
|
||||
}
|
||||
}
|
||||
|
||||
// wait for BUSY to go low
|
||||
WaitForIdle (BUSY_WAIT, "end ReadRegister", 0);
|
||||
}
|
||||
|
||||
// WriteCommand with retry
|
||||
void WriteCommand (uint8_t cmd, uint8_t *data, uint8_t numBytes) {
|
||||
uint8_t status;
|
||||
for (int retry = 1; retry < 10; retry++) {
|
||||
status = WriteCommand2 (cmd, data, numBytes);
|
||||
if (debugPrint) {
|
||||
ESP_LOGD (TAG, "status=%02x", status);
|
||||
}
|
||||
if (status == 0)
|
||||
break;
|
||||
ESP_LOGW (TAG, "WriteCommand2 status=%02x retry=%d", status, retry);
|
||||
}
|
||||
if (status != 0) {
|
||||
ESP_LOGE (TAG, "SPI Transaction error:0x%02x", status);
|
||||
LoRaError (ERR_SPI_TRANSACTION);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t WriteCommand2 (uint8_t cmd, uint8_t *data, uint8_t numBytes) {
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
WaitForIdle (BUSY_WAIT, "start WriteCommand2", 1);
|
||||
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "WriteCommand: CMD=0x%02x", cmd);
|
||||
}
|
||||
|
||||
// start transfer
|
||||
uint8_t buf[16];
|
||||
buf[0] = cmd;
|
||||
memcpy (&buf[1], data, numBytes);
|
||||
spi_read_byte (buf, buf, numBytes + 1);
|
||||
|
||||
uint8_t status = 0;
|
||||
uint8_t cmd_status = buf[1] & 0xe;
|
||||
|
||||
switch (cmd_status) {
|
||||
case SX126X_STATUS_CMD_TIMEOUT:
|
||||
case SX126X_STATUS_CMD_INVALID:
|
||||
case SX126X_STATUS_CMD_FAILED:
|
||||
status = cmd_status;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
case 7:
|
||||
status = SX126X_STATUS_SPI_FAILED;
|
||||
break;
|
||||
// default: break; // success
|
||||
}
|
||||
|
||||
// wait for BUSY to go low
|
||||
WaitForIdle (BUSY_WAIT, "end WriteCommand2", 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
void ReadCommand (uint8_t cmd, uint8_t *data, uint8_t numBytes) {
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
WaitForIdleBegin (BUSY_WAIT, "start ReadCommand");
|
||||
|
||||
if (debugPrint) {
|
||||
ESP_LOGI (TAG, "ReadCommand: CMD=0x%02x", cmd);
|
||||
}
|
||||
|
||||
// start transfer
|
||||
uint8_t buf[16];
|
||||
memset (buf, SX126X_CMD_NOP, sizeof (buf));
|
||||
buf[0] = cmd;
|
||||
spi_read_byte (buf, buf, 1 + numBytes);
|
||||
if (data != NULL && numBytes)
|
||||
memcpy (data, &buf[1], numBytes);
|
||||
|
||||
// wait for BUSY to go low
|
||||
vTaskDelay (1);
|
||||
WaitForIdle (BUSY_WAIT, "end ReadCommand", 0);
|
||||
}
|
433
User/sx1262.h
Normal file
433
User/sx1262.h
Normal file
@@ -0,0 +1,433 @@
|
||||
#ifndef _RA01S_H
|
||||
#define _RA01S_H
|
||||
|
||||
//return values
|
||||
#define ERR_NONE 0
|
||||
#define ERR_PACKET_TOO_LONG 1
|
||||
#define ERR_UNKNOWN 2
|
||||
#define ERR_TX_TIMEOUT 3
|
||||
#define ERR_RX_TIMEOUT 4
|
||||
#define ERR_CRC_MISMATCH 5
|
||||
#define ERR_WRONG_MODEM 6
|
||||
#define ERR_INVALID_BANDWIDTH 7
|
||||
#define ERR_INVALID_SPREADING_FACTOR 8
|
||||
#define ERR_INVALID_CODING_RATE 9
|
||||
#define ERR_INVALID_FREQUENCY_DEVIATION 10
|
||||
#define ERR_INVALID_BIT_RATE 11
|
||||
#define ERR_INVALID_RX_BANDWIDTH 12
|
||||
#define ERR_INVALID_DATA_SHAPING 13
|
||||
#define ERR_INVALID_SYNC_WORD 14
|
||||
#define ERR_INVALID_OUTPUT_POWER 15
|
||||
#define ERR_INVALID_MODE 16
|
||||
#define ERR_INVALID_TRANCEIVER 17
|
||||
#define ERR_INVALID_SETRX_STATE 18
|
||||
#define ERR_INVALID_SETTX_STATE 19
|
||||
#define ERR_IDLE_TIMEOUT 20
|
||||
#define ERR_SPI_TRANSACTION 21
|
||||
|
||||
// SX126X physical layer properties
|
||||
#define XTAL_FREQ ( double )32000000
|
||||
#define FREQ_DIV ( double )pow( 2.0, 25.0 )
|
||||
#define FREQ_STEP ( double )( XTAL_FREQ / FREQ_DIV )
|
||||
|
||||
#define LOW 0
|
||||
#define HIGH 1
|
||||
#define BUSY_WAIT 5000
|
||||
|
||||
// SX126X Model
|
||||
#define SX1261_TRANCEIVER 0x01
|
||||
#define SX1262_TRANCEIVER 0x02
|
||||
#define SX1268_TRANCEIVER 0x08
|
||||
|
||||
// SX126X SPI commands
|
||||
// operational modes commands
|
||||
#define SX126X_CMD_NOP 0x00
|
||||
#define SX126X_CMD_SET_SLEEP 0x84
|
||||
#define SX126X_CMD_SET_STANDBY 0x80
|
||||
#define SX126X_CMD_SET_FS 0xC1
|
||||
#define SX126X_CMD_SET_TX 0x83
|
||||
#define SX126X_CMD_SET_RX 0x82
|
||||
#define SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F
|
||||
#define SX126X_CMD_SET_RX_DUTY_CYCLE 0x94
|
||||
#define SX126X_CMD_SET_CAD 0xC5
|
||||
#define SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1
|
||||
#define SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2
|
||||
#define SX126X_CMD_SET_REGULATOR_MODE 0x96
|
||||
#define SX126X_CMD_CALIBRATE 0x89
|
||||
#define SX126X_CMD_CALIBRATE_IMAGE 0x98
|
||||
#define SX126X_CMD_SET_PA_CONFIG 0x95
|
||||
#define SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93
|
||||
|
||||
// register and buffer access commands
|
||||
#define SX126X_CMD_WRITE_REGISTER 0x0D
|
||||
#define SX126X_CMD_READ_REGISTER 0x1D
|
||||
#define SX126X_CMD_WRITE_BUFFER 0x0E
|
||||
#define SX126X_CMD_READ_BUFFER 0x1E
|
||||
|
||||
// DIO and IRQ control
|
||||
#define SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08
|
||||
#define SX126X_CMD_GET_IRQ_STATUS 0x12
|
||||
#define SX126X_CMD_CLEAR_IRQ_STATUS 0x02
|
||||
#define SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D
|
||||
#define SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97
|
||||
|
||||
// RF, modulation and packet commands
|
||||
#define SX126X_CMD_SET_RF_FREQUENCY 0x86
|
||||
#define SX126X_CMD_SET_PACKET_TYPE 0x8A
|
||||
#define SX126X_CMD_GET_PACKET_TYPE 0x11
|
||||
#define SX126X_CMD_SET_TX_PARAMS 0x8E
|
||||
#define SX126X_CMD_SET_MODULATION_PARAMS 0x8B
|
||||
#define SX126X_CMD_SET_PACKET_PARAMS 0x8C
|
||||
#define SX126X_CMD_SET_CAD_PARAMS 0x88
|
||||
#define SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F
|
||||
#define SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0
|
||||
|
||||
#define SX126X_PA_CONFIG_SX1261 0x01
|
||||
#define SX126X_PA_CONFIG_SX1262 0x00
|
||||
|
||||
// status commands
|
||||
#define SX126X_CMD_GET_STATUS 0xC0
|
||||
#define SX126X_CMD_GET_RSSI_INST 0x15
|
||||
#define SX126X_CMD_GET_RX_BUFFER_STATUS 0x13
|
||||
#define SX126X_CMD_GET_PACKET_STATUS 0x14
|
||||
#define SX126X_CMD_GET_DEVICE_ERRORS 0x17
|
||||
#define SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07
|
||||
#define SX126X_CMD_GET_STATS 0x10
|
||||
#define SX126X_CMD_RESET_STATS 0x00
|
||||
|
||||
|
||||
// SX126X register map
|
||||
#define SX126X_REG_HOPPING_ENABLE 0x0385
|
||||
#define SX126X_REG_PACKECT_LENGTH 0x0386
|
||||
#define SX126X_REG_NB_HOPPING_BLOCKS 0x0387
|
||||
#define SX126X_REG_NB_SYMBOLS0 0x0388
|
||||
#define SX126X_REG_FREQ0 0x038A
|
||||
#define SX126X_REG_NB_SYMBOLS15 0x03E2
|
||||
#define SX126X_REG_FREQ15 0x03E4
|
||||
#define SX126X_REG_DIOX_OUTPUT_ENABLE 0x0580
|
||||
#define SX126X_REG_DIOX_INPUT_ENABLE 0x0583
|
||||
#define SX126X_REG_DIOX_PILL_UP_CONTROL 0x0584
|
||||
#define SX126X_REG_DIOX_PULL_DOWN_CONTROL 0x0585
|
||||
#define SX126X_REG_WHITENING_INITIAL_MSB 0x06B8
|
||||
#define SX126X_REG_WHITENING_INITIAL_LSB 0x06B9
|
||||
#define SX126X_REG_CRC_INITIAL_MSB 0x06BC
|
||||
#define SX126X_REG_CRC_INITIAL_LSB 0x06BD
|
||||
#define SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE
|
||||
#define SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF
|
||||
#define SX126X_REG_SYNC_WORD_0 0x06C0
|
||||
#define SX126X_REG_SYNC_WORD_1 0x06C1
|
||||
#define SX126X_REG_SYNC_WORD_2 0x06C2
|
||||
#define SX126X_REG_SYNC_WORD_3 0x06C3
|
||||
#define SX126X_REG_SYNC_WORD_4 0x06C4
|
||||
#define SX126X_REG_SYNC_WORD_5 0x06C5
|
||||
#define SX126X_REG_SYNC_WORD_6 0x06C6
|
||||
#define SX126X_REG_SYNC_WORD_7 0x06C7
|
||||
#define SX126X_REG_NODE_ADDRESS 0x06CD
|
||||
#define SX126X_REG_BROADCAST_ADDRESS 0x06CE
|
||||
#define SX126X_REG_IQ_POLARITY_SETUP 0x0736
|
||||
#define SX126X_REG_LORA_SYNC_WORD_MSB 0x0740
|
||||
#define SX126X_REG_LORA_SYNC_WORD_LSB 0x0741
|
||||
#define SX126X_REG_RANDOM_NUMBER_0 0x0819
|
||||
#define SX126X_REG_RANDOM_NUMBER_1 0x081A
|
||||
#define SX126X_REG_RANDOM_NUMBER_2 0x081B
|
||||
#define SX126X_REG_RANDOM_NUMBER_3 0x081C
|
||||
#define SX126X_REG_TX_MODULETION 0x0889
|
||||
#define SX126X_REG_RX_GAIN 0x08AC
|
||||
#define SX126X_REG_TX_CLAMP_CONFIG 0x08D8
|
||||
#define SX126X_REG_OCP_CONFIGURATION 0x08E7
|
||||
#define SX126X_REG_RTC_CONTROL 0x0902
|
||||
#define SX126X_REG_XTA_TRIM 0x0911
|
||||
#define SX126X_REG_XTB_TRIM 0x0912
|
||||
#define SX126X_REG_DIO3_OUTPUT_VOLTAGE_CONTROL 0x0920
|
||||
#define SX126X_REG_EVENT_MASK 0x0944
|
||||
|
||||
|
||||
// SX126X SPI command variables
|
||||
//SX126X_CMD_SET_SLEEP
|
||||
#define SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default)
|
||||
#define SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained
|
||||
#define SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled
|
||||
#define SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled
|
||||
|
||||
//SX126X_CMD_SET_STANDBY
|
||||
#define SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator
|
||||
#define SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator
|
||||
|
||||
//SX126X_CMD_SET_RX
|
||||
#define SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode)
|
||||
#define SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode)
|
||||
|
||||
//SX126X_CMD_STOP_TIMER_ON_PREAMBLE
|
||||
#define SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default)
|
||||
#define SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection
|
||||
|
||||
//SX126X_CMD_SET_REGULATOR_MODE
|
||||
#define SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default)
|
||||
#define SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC
|
||||
|
||||
//SX126X_CMD_CALIBRATE
|
||||
#define SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled
|
||||
#define SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled
|
||||
#define SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled
|
||||
#define SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled
|
||||
#define SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled
|
||||
#define SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled
|
||||
#define SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled
|
||||
#define SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled
|
||||
#define SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled
|
||||
#define SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled
|
||||
#define SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled
|
||||
#define SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled
|
||||
#define SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled
|
||||
#define SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled
|
||||
|
||||
//SX126X_CMD_CALIBRATE_IMAGE
|
||||
#define SX126X_CAL_IMG_430_MHZ_1 0x6B
|
||||
#define SX126X_CAL_IMG_430_MHZ_2 0x6F
|
||||
#define SX126X_CAL_IMG_470_MHZ_1 0x75
|
||||
#define SX126X_CAL_IMG_470_MHZ_2 0x81
|
||||
#define SX126X_CAL_IMG_779_MHZ_1 0xC1
|
||||
#define SX126X_CAL_IMG_779_MHZ_2 0xC5
|
||||
#define SX126X_CAL_IMG_863_MHZ_1 0xD7
|
||||
#define SX126X_CAL_IMG_863_MHZ_2 0xDB
|
||||
#define SX126X_CAL_IMG_902_MHZ_1 0xE1
|
||||
#define SX126X_CAL_IMG_902_MHZ_2 0xE9
|
||||
|
||||
//SX126X_CMD_SET_PA_CONFIG
|
||||
#define SX126X_PA_CONFIG_HP_MAX 0x07
|
||||
#define SX126X_PA_CONFIG_SX1268 0x01
|
||||
#define SX126X_PA_CONFIG_PA_LUT 0x01
|
||||
|
||||
//SX126X_CMD_SET_RX_TX_FALLBACK_MODE
|
||||
#define SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode
|
||||
#define SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator
|
||||
#define SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default)
|
||||
|
||||
//SX126X_CMD_SET_DIO_IRQ_PARAMS
|
||||
#define SX126X_IRQ_TIMEOUT 0b1000000000 // 9 9 Rx or Tx timeout
|
||||
#define SX126X_IRQ_CAD_DETECTED 0b0100000000 // 8 8 channel activity detected
|
||||
#define SX126X_IRQ_CAD_DONE 0b0010000000 // 7 7 channel activity detection finished
|
||||
#define SX126X_IRQ_CRC_ERR 0b0001000000 // 6 6 wrong CRC received
|
||||
#define SX126X_IRQ_HEADER_ERR 0b0000100000 // 5 5 LoRa header CRC error
|
||||
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
|
||||
#define SX126X_IRQ_SYNC_WORD_VALID 0b0000001000 // 3 3 valid sync word detected
|
||||
#define SX126X_IRQ_PREAMBLE_DETECTED 0b0000000100 // 2 2 preamble detected
|
||||
#define SX126X_IRQ_RX_DONE 0b0000000010 // 1 1 packet received
|
||||
#define SX126X_IRQ_TX_DONE 0b0000000001 // 0 0 packet transmission completed
|
||||
#define SX126X_IRQ_ALL 0b1111111111 // 9 0 all interrupts
|
||||
#define SX126X_IRQ_NONE 0b0000000000 // 9 0 no interrupts
|
||||
|
||||
//SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL
|
||||
#define SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ
|
||||
#define SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control
|
||||
|
||||
//SX126X_CMD_SET_DIO3_AS_TCXO_CTRL
|
||||
#define SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V
|
||||
#define SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V
|
||||
#define SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V
|
||||
#define SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V
|
||||
#define SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V
|
||||
#define SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V
|
||||
#define SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V
|
||||
#define SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V
|
||||
|
||||
//Radio complete Wake-up Time with TCXO stabilisation time
|
||||
#define RADIO_TCXO_SETUP_TIME 5000 // [us]
|
||||
|
||||
//SX126X_CMD_SET_PACKET_TYPE
|
||||
#define SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK
|
||||
#define SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa
|
||||
|
||||
//SX126X_CMD_SET_TX_PARAMS
|
||||
#define SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us
|
||||
#define SX126X_PA_RAMP_20U 0x01 // 7 0 20 us
|
||||
#define SX126X_PA_RAMP_40U 0x02 // 7 0 40 us
|
||||
#define SX126X_PA_RAMP_80U 0x03 // 7 0 80 us
|
||||
#define SX126X_PA_RAMP_200U 0x04 // 7 0 200 us
|
||||
#define SX126X_PA_RAMP_800U 0x05 // 7 0 800 us
|
||||
#define SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us
|
||||
#define SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us
|
||||
|
||||
//SX126X_CMD_SET_MODULATION_PARAMS
|
||||
#define SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none
|
||||
#define SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3
|
||||
#define SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5
|
||||
#define SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7
|
||||
#define SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1
|
||||
#define SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz
|
||||
#define SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz
|
||||
#define SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz
|
||||
#define SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz
|
||||
#define SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz
|
||||
#define SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz
|
||||
#define SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz
|
||||
#define SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz
|
||||
#define SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz
|
||||
#define SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz
|
||||
#define SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz
|
||||
#define SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz
|
||||
#define SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz
|
||||
#define SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz
|
||||
#define SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz
|
||||
#define SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz
|
||||
#define SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz
|
||||
#define SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz
|
||||
#define SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz
|
||||
#define SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz
|
||||
#define SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz
|
||||
#define SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz
|
||||
#define SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz
|
||||
#define SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz
|
||||
#define SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz
|
||||
#define SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz
|
||||
#define SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz
|
||||
#define SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz
|
||||
#define SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz
|
||||
#define SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz
|
||||
#define SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz
|
||||
#define SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5
|
||||
#define SX126X_LORA_CR_4_6 0x02 // 7 0 4/6
|
||||
#define SX126X_LORA_CR_4_7 0x03 // 7 0 4/7
|
||||
#define SX126X_LORA_CR_4_8 0x04 // 7 0 4/8
|
||||
#define SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled
|
||||
#define SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled
|
||||
|
||||
//SX126X_CMD_SET_PACKET_PARAMS
|
||||
#define SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled
|
||||
#define SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits
|
||||
#define SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits
|
||||
#define SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits
|
||||
#define SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits
|
||||
#define SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled
|
||||
#define SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only
|
||||
#define SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast
|
||||
#define SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides)
|
||||
#define SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet)
|
||||
#define SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled
|
||||
#define SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte
|
||||
#define SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte
|
||||
#define SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted
|
||||
#define SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted
|
||||
#define SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled
|
||||
#define SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled
|
||||
#define SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit
|
||||
#define SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit
|
||||
#define SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled
|
||||
#define SX126X_LORA_CRC_ON 0x01 // 7 0 enabled
|
||||
#define SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard
|
||||
#define SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted
|
||||
|
||||
//SX126X_CMD_SET_CAD_PARAMS
|
||||
#define SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1
|
||||
#define SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2
|
||||
#define SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4
|
||||
#define SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8
|
||||
#define SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16
|
||||
#define SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode
|
||||
#define SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected
|
||||
|
||||
//SX126X_CMD_GET_STATUS
|
||||
#define SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC
|
||||
#define SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC
|
||||
#define SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS
|
||||
#define SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX
|
||||
#define SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX
|
||||
#define SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved
|
||||
#define SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out
|
||||
#define SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command
|
||||
#define SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute
|
||||
#define SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done
|
||||
#define SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed
|
||||
|
||||
//SX126X_CMD_GET_PACKET_STATUS
|
||||
#define SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error
|
||||
#define SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error
|
||||
#define SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error
|
||||
#define SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error
|
||||
#define SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error
|
||||
#define SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error
|
||||
#define SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received
|
||||
#define SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent
|
||||
|
||||
//SX126X_CMD_GET_DEVICE_ERRORS
|
||||
#define SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed
|
||||
#define SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock
|
||||
#define SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start
|
||||
#define SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed
|
||||
#define SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed
|
||||
#define SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed
|
||||
#define SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed
|
||||
#define SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed
|
||||
|
||||
|
||||
// SX126X SPI register variables
|
||||
//SX126X_REG_LORA_SYNC_WORD_MSB + LSB
|
||||
//#define SX126X_SYNC_WORD_PUBLIC 0x3444
|
||||
#define SX126X_SYNC_WORD_PUBLIC 0x24B4 //meshtastic
|
||||
#define SX126X_SYNC_WORD_PRIVATE 0x1424
|
||||
|
||||
#define SX126x_TXMODE_ASYNC 0x01
|
||||
#define SX126x_TXMODE_SYNC 0x02
|
||||
#define SX126x_TXMODE_BACK2RX 0x04
|
||||
|
||||
// Public function
|
||||
void LoRaInit(void);
|
||||
int16_t LoRaBegin(uint32_t frequencyInHz, int8_t txPowerInDbm, float tcxoVoltage, char useRegulatorLDO);
|
||||
void LoRaConfig(uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate, uint16_t preambleLength, uint8_t payloadLen, char crcOn, char invertIrq);
|
||||
uint8_t LoRaReceive(uint8_t *pData, int16_t len);
|
||||
char LoRaSend(uint8_t *pData, int16_t len, uint8_t mode);
|
||||
void LoRaDebugPrint(char enable);
|
||||
|
||||
// Private function
|
||||
void spi_write_byte(uint8_t* Dataout, size_t DataLength );
|
||||
void spi_read_byte(uint8_t *rx, const uint8_t *tx, size_t len);
|
||||
uint8_t spi_transfer(uint8_t address);
|
||||
|
||||
char ReceiveMode(void);
|
||||
void GetPacketStatus(int8_t *rssiPacket, int8_t *snrPacket);
|
||||
void SetTxPower(int8_t txPowerInDbm);
|
||||
|
||||
void FixInvertedIQ(uint8_t iqConfig);
|
||||
void SetDio3AsTcxoCtrl(float voltage, uint32_t delay);
|
||||
void SetDio2AsRfSwitchCtrl(uint8_t enable);
|
||||
void ResetLora(void);
|
||||
void SetStandby(uint8_t mode);
|
||||
void SetRfFrequency(uint32_t frequency);
|
||||
void Calibrate(uint8_t calibParam);
|
||||
void CalibrateImage(uint32_t frequency);
|
||||
void SetRegulatorMode(uint8_t mode);
|
||||
void SetBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress);
|
||||
void SetPowerConfig(int8_t power, uint8_t rampTime);
|
||||
void SetOvercurrentProtection(float currentLimit);
|
||||
void SetSyncWord(int16_t sync);
|
||||
void SetPaConfig(uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut);
|
||||
void SetDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask);
|
||||
void SetStopRxTimerOnPreambleDetect(char enable);
|
||||
void SetLoRaSymbNumTimeout(uint8_t SymbNum);
|
||||
void SetPacketType(uint8_t packetType);
|
||||
void SetModulationParams(uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate, uint8_t lowDataRateOptimize);
|
||||
void SetCadParams(uint8_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, uint8_t cadExitMode, uint32_t cadTimeout);
|
||||
void SetCad();
|
||||
uint8_t GetStatus(void);
|
||||
uint16_t GetIrqStatus(void);
|
||||
void ClearIrqStatus(uint16_t irq);
|
||||
void SetRx(uint32_t timeout);
|
||||
void SetTx(uint32_t timeoutInMs);
|
||||
int GetPacketLost();
|
||||
uint8_t GetRssiInst();
|
||||
void GetRxBufferStatus(uint8_t *payloadLength, uint8_t *rxStartBufferPointer);
|
||||
void Wakeup(void);
|
||||
void WaitForIdleBegin(unsigned long timeout, char *text);
|
||||
char WaitForIdle(unsigned long timeout, char *text, char stop);
|
||||
uint8_t ReadBuffer(uint8_t *rxData, int16_t rxDataLen);
|
||||
void WriteBuffer(uint8_t *txData, int16_t txDataLen);
|
||||
void WriteRegister(uint16_t reg, uint8_t* data, uint8_t numBytes);
|
||||
void ReadRegister(uint16_t reg, uint8_t* data, uint8_t numBytes);
|
||||
void WriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes);
|
||||
uint8_t WriteCommand2(uint8_t cmd, uint8_t* data, uint8_t numBytes);
|
||||
void ReadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes);
|
||||
void SPItransfer(uint8_t cmd, char write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, char waitForBusy);
|
||||
void LoRaError(int error);
|
||||
|
||||
|
||||
#endif
|
1036
User/system_ch32v30x.c
Normal file
1036
User/system_ch32v30x.c
Normal file
File diff suppressed because it is too large
Load Diff
32
User/system_ch32v30x.h
Normal file
32
User/system_ch32v30x.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : system_ch32v30x.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2021/06/06
|
||||
* Description : CH32V30x Device Peripheral Access Layer System Header File.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#ifndef __SYSTEM_CH32V30x_H
|
||||
#define __SYSTEM_CH32V30x_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */
|
||||
|
||||
/* System_Exported_Functions */
|
||||
extern void SystemInit(void);
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__CH32V30x_SYSTEM_H */
|
||||
|
||||
|
||||
|
20
User/util/log.h
Normal file
20
User/util/log.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef LOGGER_HEADER
|
||||
#define LOGGER_HEADER
|
||||
|
||||
// Define log levels
|
||||
#define LOG_ERROR "E"
|
||||
#define LOG_WARN "W"
|
||||
#define LOG_INFO "I"
|
||||
#define LOG_DEBUG "D"
|
||||
|
||||
// Define a generic log macro
|
||||
#define LOG_PRINT(level, tag, fmt, ...) \
|
||||
printf("[%s] %s: " fmt "\r\n", level, tag, ##__VA_ARGS__)
|
||||
|
||||
// Define ESP-like shortcuts
|
||||
#define ESP_LOGE(tag, fmt, ...) LOG_PRINT(LOG_ERROR, tag, fmt, ##__VA_ARGS__)
|
||||
#define ESP_LOGW(tag, fmt, ...) LOG_PRINT(LOG_WARN, tag, fmt, ##__VA_ARGS__)
|
||||
#define ESP_LOGI(tag, fmt, ...) LOG_PRINT(LOG_INFO, tag, fmt, ##__VA_ARGS__)
|
||||
#define ESP_LOGD(tag, fmt, ...) LOG_PRINT(LOG_DEBUG, tag, fmt, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user