Browse Source
- Fixed ACK section parsing (elm_cnt and till offset) - Fixed payload section to include seq number in packet - Fixed assembly trigger condition (last_delivered_id+1==seq) - Crypto: Added nonce transmission in encrypted packets - Crypto: Fixed nonce generation with usec timestamp - Reduced debug verbosity in connection handling - Added unknown section type handlingnodeinfo-routing-update
22 changed files with 224265 additions and 48 deletions
@ -0,0 +1,33 @@ |
|||||||
|
Using built-in specs. |
||||||
|
COLLECT_GCC=gcc |
||||||
|
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper |
||||||
|
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa |
||||||
|
OFFLOAD_TARGET_DEFAULT=1 |
||||||
|
Target: x86_64-linux-gnu |
||||||
|
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-fG75Ri/gcc-13-13.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-fG75Ri/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 |
||||||
|
Thread model: posix |
||||||
|
Supported LTO compression algorithms: zlib zstd |
||||||
|
gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04) |
||||||
|
COLLECT_GCC_OPTIONS='-I' '../src' '-I' '../lib' '-I' '../tinycrypt/lib/include' '-I' '../tinycrypt/lib/source' '-g' '-O2' '-v' '-o' 'test_ll_queue_fixed' '-mtune=generic' '-march=x86-64' '-dumpdir' 'test_ll_queue_fixed-' |
||||||
|
/usr/libexec/gcc/x86_64-linux-gnu/13/cc1 -quiet -v -I ../src -I ../lib -I ../tinycrypt/lib/include -I ../tinycrypt/lib/source -imultiarch x86_64-linux-gnu test_ll_queue_fixed.c -D_FORTIFY_SOURCE=3 -quiet -dumpdir test_ll_queue_fixed- -dumpbase test_ll_queue_fixed.c -dumpbase-ext .c -mtune=generic -march=x86-64 -g -O2 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccZX9kaj.s |
||||||
|
GNU C17 (Ubuntu 13.3.0-6ubuntu2~24.04) version 13.3.0 (x86_64-linux-gnu) |
||||||
|
compiled by GNU C version 13.3.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP |
||||||
|
|
||||||
|
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 |
||||||
|
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" |
||||||
|
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu" |
||||||
|
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed" |
||||||
|
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include" |
||||||
|
ignoring nonexistent directory "../src" |
||||||
|
ignoring nonexistent directory "../lib" |
||||||
|
ignoring nonexistent directory "../tinycrypt/lib/include" |
||||||
|
ignoring nonexistent directory "../tinycrypt/lib/source" |
||||||
|
#include "..." search starts here: |
||||||
|
#include <...> search starts here: |
||||||
|
/usr/lib/gcc/x86_64-linux-gnu/13/include |
||||||
|
/usr/local/include |
||||||
|
/usr/include/x86_64-linux-gnu |
||||||
|
/usr/include |
||||||
|
End of search list. |
||||||
|
cc1: fatal error: test_ll_queue_fixed.c: Нет такого файла или каталога |
||||||
|
compilation terminated. |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
#include "lib/ll_queue.h" |
||||||
|
#include "lib/u_async.h" |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
int id; |
||||||
|
char name[32]; |
||||||
|
int value; |
||||||
|
} test_data_t; |
||||||
|
|
||||||
|
int main() { |
||||||
|
struct UASYNC* ua = uasync_create(); |
||||||
|
struct ll_queue* q = queue_new(ua, 0); |
||||||
|
|
||||||
|
/* Create test data */ |
||||||
|
test_data_t* data1 = (test_data_t*)queue_data_new(sizeof(test_data_t)); |
||||||
|
data1->id = 1; |
||||||
|
strcpy(data1->name, "test1"); |
||||||
|
data1->value = 100; |
||||||
|
|
||||||
|
printf("Created data: id=%d, name=%s, value=%d\n", data1->id, data1->name, data1->value); |
||||||
|
printf("Data pointer: %p\n", data1); |
||||||
|
|
||||||
|
/* Put data into queue */ |
||||||
|
queue_data_put(q, data1, data1->id); |
||||||
|
printf("After put: queue count = %d\n", queue_entry_count(q)); |
||||||
|
|
||||||
|
/* Get data from queue */ |
||||||
|
test_data_t* retrieved = (test_data_t*)queue_data_get(q); |
||||||
|
printf("Retrieved pointer: %p\n", retrieved); |
||||||
|
printf("Retrieved data: id=%d, name=%s, value=%d\n", retrieved->id, retrieved->name, retrieved->value); |
||||||
|
|
||||||
|
queue_free(q); |
||||||
|
uasync_destroy(ua, 0); |
||||||
|
return 0; |
||||||
|
} |
||||||
@ -0,0 +1,369 @@ |
|||||||
|
/* sc_lib.c - Secure Channel library implementation using TinyCrypt */ |
||||||
|
|
||||||
|
#include "secure_channel.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/ecc.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/ecc_dh.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/aes.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/ccm_mode.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/constants.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/ecc_platform_specific.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/sha256.h" |
||||||
|
#include <string.h> |
||||||
|
#include <stddef.h> |
||||||
|
#include <sys/types.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <sys/time.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
// Simple debug macros
|
||||||
|
#define DEBUG_CATEGORY_CRYPTO 1 |
||||||
|
#define DEBUG_ERROR(category, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__) |
||||||
|
#define DEBUG_INFO(category, fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__) |
||||||
|
#include <stdio.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include "crc32.h" |
||||||
|
|
||||||
|
static const struct uECC_Curve_t *curve = NULL; |
||||||
|
static uint8_t sc_urandom_seed[8] = {0}; |
||||||
|
static int sc_urandom_initialized = 0; |
||||||
|
|
||||||
|
static void sc_init_random_seed(void) |
||||||
|
{ |
||||||
|
int fd = open("/dev/urandom", O_RDONLY); |
||||||
|
if (fd >= 0) { |
||||||
|
ssize_t ret = read(fd, sc_urandom_seed, 8); |
||||||
|
close(fd); |
||||||
|
if (ret == 8) { |
||||||
|
sc_urandom_initialized = 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static int sc_rng(uint8_t *dest, unsigned size) |
||||||
|
{ |
||||||
|
int fd = open("/dev/urandom", O_RDONLY); |
||||||
|
if (fd < 0) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
ssize_t ret = read(fd, dest, size); |
||||||
|
close(fd); |
||||||
|
if (ret != size) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* Mix in PID and microtime for additional entropy */ |
||||||
|
pid_t pid = getpid(); |
||||||
|
struct timeval tv; |
||||||
|
gettimeofday(&tv, NULL); |
||||||
|
|
||||||
|
for (unsigned i = 0; i < size; i++) { |
||||||
|
dest[i] ^= ((pid >> (i % (sizeof(pid) * 8))) & 0xFF); |
||||||
|
dest[i] ^= ((tv.tv_sec >> (i % (sizeof(tv.tv_sec) * 8))) & 0xFF); |
||||||
|
dest[i] ^= ((tv.tv_usec >> (i % (sizeof(tv.tv_usec) * 8))) & 0xFF); |
||||||
|
} |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
static int sc_validate_key(const uint8_t *public_key) |
||||||
|
{ |
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
int result = uECC_valid_public_key(public_key, curve); |
||||||
|
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_validate_key: uECC_valid_public_key returned %d", result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_generate_keypair(struct SC_MYKEYS *pk) |
||||||
|
{ |
||||||
|
if (!pk) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
|
||||||
|
/* Set custom RNG function */ |
||||||
|
uECC_set_rng(sc_rng); |
||||||
|
|
||||||
|
if (!uECC_make_key(pk->public_key, pk->private_key, curve)) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
// Конвертация hex строки в бинарный формат
|
||||||
|
static int hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len) { |
||||||
|
if (!hex_str || !binary || strlen(hex_str) != binary_len * 2) return -1; |
||||||
|
|
||||||
|
for (size_t i = 0; i < binary_len; i++) { |
||||||
|
unsigned int byte; |
||||||
|
if (sscanf(hex_str + i * 2, "%2x", &byte) != 1) return -1; |
||||||
|
binary[i] = (uint8_t)byte; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, const char *private_key) { |
||||||
|
if (!mykeys || !public_key || !private_key) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: invalid arguments"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
|
||||||
|
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: public_key len=%zu, private_key len=%zu",
|
||||||
|
strlen(public_key), strlen(private_key)); |
||||||
|
|
||||||
|
/* Convert hex to binary first */ |
||||||
|
if (hex_to_binary(public_key, mykeys->public_key, SC_PUBKEY_SIZE)) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: failed to convert public key from hex"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
if (hex_to_binary(private_key, mykeys->private_key, SC_PRIVKEY_SIZE)) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: failed to convert private key from hex"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
/* Validate the converted binary public key */ |
||||||
|
if (sc_validate_key(mykeys->public_key) != 0) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: public key validation failed"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: keys initialized successfully"); |
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_init_ctx(sc_context_t *ctx, struct SC_MYKEYS *mykeys) { |
||||||
|
|
||||||
|
ctx->pk=mykeys; |
||||||
|
ctx->initialized = 1; |
||||||
|
ctx->peer_key_set = 0; |
||||||
|
ctx->session_ready = 0; |
||||||
|
ctx->tx_counter = 0; |
||||||
|
ctx->rx_counter = 0; |
||||||
|
|
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key_h, int mode) { |
||||||
|
uint8_t shared_secret[SC_SHARED_SECRET_SIZE]; |
||||||
|
uint8_t peer_public_key[SC_PUBKEY_SIZE]; |
||||||
|
|
||||||
|
if (mode) { |
||||||
|
if (hex_to_binary(peer_public_key_h, peer_public_key, SC_PUBKEY_SIZE)) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid hex key format"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
} |
||||||
|
else memcpy(peer_public_key, peer_public_key_h, SC_PUBKEY_SIZE); |
||||||
|
|
||||||
|
if (!ctx) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid ctx"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!ctx->initialized) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: ctx not initialized"); |
||||||
|
return SC_ERR_NOT_INITIALIZED; |
||||||
|
} |
||||||
|
|
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
|
||||||
|
/* Validate peer public key */ |
||||||
|
if (sc_validate_key(peer_public_key) != 0) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid key"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
/* Compute shared secret using ECDH */ |
||||||
|
if (!ctx->pk) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: no private key"); |
||||||
|
return SC_ERR_NOT_INITIALIZED; |
||||||
|
} |
||||||
|
if (!uECC_shared_secret(peer_public_key, ctx->pk->private_key, |
||||||
|
shared_secret, curve)) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: shared secret error"); |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Derive session key from shared secret (simple copy for demo) */ |
||||||
|
memcpy(ctx->session_key, shared_secret, SC_SESSION_KEY_SIZE); |
||||||
|
|
||||||
|
/* Store peer public key */ |
||||||
|
memcpy(ctx->peer_public_key, peer_public_key, SC_PUBKEY_SIZE); |
||||||
|
ctx->peer_key_set = 1; |
||||||
|
|
||||||
|
ctx->session_ready = 1; |
||||||
|
|
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
// Новая функция для генерации nonce с микросекундами
|
||||||
|
static void generate_nonce_with_timer(uint8_t *nonce) { |
||||||
|
struct timeval tv; |
||||||
|
gettimeofday(&tv, NULL); |
||||||
|
uint32_t usec = (uint32_t)tv.tv_usec; |
||||||
|
|
||||||
|
// Поместить usec в первые 4 байта (little-endian)
|
||||||
|
nonce[0] = usec & 0xFF; |
||||||
|
nonce[1] = (usec >> 8) & 0xFF; |
||||||
|
nonce[2] = (usec >> 16) & 0xFF; |
||||||
|
nonce[3] = (usec >> 24) & 0xFF; |
||||||
|
|
||||||
|
// Заполнить оставшиеся 9 байт случайными данными
|
||||||
|
sc_rng(nonce + 4, SC_NONCE_SIZE - 4); |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len) { |
||||||
|
uint8_t nonce[SC_NONCE_SIZE]; |
||||||
|
uint8_t plaintext_with_crc[plaintext_len + SC_CRC32_SIZE]; |
||||||
|
size_t total_plaintext_len = plaintext_len + SC_CRC32_SIZE; |
||||||
|
uint8_t combined_output[total_plaintext_len + SC_TAG_SIZE]; |
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
struct tc_ccm_mode_struct ccm_state; |
||||||
|
|
||||||
|
if (!ctx || !plaintext || !ciphertext || !ciphertext_len) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!ctx->session_ready) { |
||||||
|
return SC_ERR_NOT_INITIALIZED; |
||||||
|
} |
||||||
|
|
||||||
|
if (plaintext_len == 0) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
/* Добавляем CRC32 к данным */ |
||||||
|
memcpy(plaintext_with_crc, plaintext, plaintext_len); |
||||||
|
uint32_t crc = crc32_calc(plaintext, plaintext_len); |
||||||
|
plaintext_with_crc[plaintext_len] = (crc >> 0) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 1] = (crc >> 8) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 2] = (crc >> 16) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 3] = (crc >> 24) & 0xFF; |
||||||
|
|
||||||
|
/* Генерируем nonce с таймером */ |
||||||
|
generate_nonce_with_timer(nonce); |
||||||
|
|
||||||
|
/* Initialize AES key schedule */ |
||||||
|
if (tc_aes128_set_encrypt_key(&sched, ctx->session_key) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Configure CCM mode */ |
||||||
|
if (tc_ccm_config(&ccm_state, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Encrypt and generate tag */ |
||||||
|
if (tc_ccm_generation_encryption(combined_output, sizeof(combined_output), |
||||||
|
NULL, 0, /* no associated data */ |
||||||
|
plaintext_with_crc, total_plaintext_len, |
||||||
|
&ccm_state) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Copy nonce + ciphertext + tag to output buffer */ |
||||||
|
memcpy(ciphertext, nonce, SC_NONCE_SIZE); |
||||||
|
memcpy(ciphertext + SC_NONCE_SIZE, combined_output, total_plaintext_len + SC_TAG_SIZE); |
||||||
|
*ciphertext_len = SC_NONCE_SIZE + total_plaintext_len + SC_TAG_SIZE; |
||||||
|
|
||||||
|
ctx->tx_counter++; |
||||||
|
|
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_decrypt(sc_context_t *ctx, |
||||||
|
const uint8_t *ciphertext, |
||||||
|
size_t ciphertext_len, |
||||||
|
uint8_t *plaintext, |
||||||
|
size_t *plaintext_len) |
||||||
|
{ |
||||||
|
uint8_t nonce[SC_NONCE_SIZE]; |
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
struct tc_ccm_mode_struct ccm_state; |
||||||
|
size_t total_plaintext_len = ciphertext_len - SC_NONCE_SIZE - SC_TAG_SIZE; |
||||||
|
uint8_t plaintext_with_crc[total_plaintext_len]; |
||||||
|
|
||||||
|
if (!ctx || !ciphertext || !plaintext || !plaintext_len) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!ctx->session_ready) { |
||||||
|
return SC_ERR_NOT_INITIALIZED; |
||||||
|
} |
||||||
|
|
||||||
|
if (ciphertext_len < SC_NONCE_SIZE + SC_TAG_SIZE + SC_CRC32_SIZE) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
/* Извлекаем nonce из начала ciphertext */ |
||||||
|
memcpy(nonce, ciphertext, SC_NONCE_SIZE); |
||||||
|
|
||||||
|
/* Ciphertext для расшифровки начинается после nonce */ |
||||||
|
const uint8_t *encrypted_data = ciphertext + SC_NONCE_SIZE; |
||||||
|
size_t encrypted_len = ciphertext_len - SC_NONCE_SIZE; |
||||||
|
|
||||||
|
/* Initialize AES key schedule */ |
||||||
|
if (tc_aes128_set_encrypt_key(&sched, ctx->session_key) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Configure CCM mode с извлечённым nonce */ |
||||||
|
if (tc_ccm_config(&ccm_state, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Decrypt and verify tag */ |
||||||
|
if (tc_ccm_decryption_verification(plaintext_with_crc, total_plaintext_len, |
||||||
|
NULL, 0, /* no associated data */ |
||||||
|
encrypted_data, encrypted_len, |
||||||
|
&ccm_state) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_AUTH_FAILED; |
||||||
|
} |
||||||
|
|
||||||
|
/* Проверяем CRC32 */ |
||||||
|
size_t data_len = total_plaintext_len - SC_CRC32_SIZE; |
||||||
|
uint32_t expected_crc = crc32_calc(plaintext_with_crc, data_len); |
||||||
|
uint32_t received_crc = (plaintext_with_crc[data_len] << 0) | |
||||||
|
(plaintext_with_crc[data_len + 1] << 8) | |
||||||
|
(plaintext_with_crc[data_len + 2] << 16) | |
||||||
|
(plaintext_with_crc[data_len + 3] << 24); |
||||||
|
|
||||||
|
if (expected_crc != received_crc) { |
||||||
|
return SC_ERR_CRC_FAILED; |
||||||
|
} |
||||||
|
|
||||||
|
/* Копируем данные без CRC32 */ |
||||||
|
memcpy(plaintext, plaintext_with_crc, data_len); |
||||||
|
*plaintext_len = data_len; |
||||||
|
|
||||||
|
ctx->rx_counter++; |
||||||
|
|
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_compute_public_key_from_private(const uint8_t *private_key, uint8_t *public_key) { |
||||||
|
if (!private_key || !public_key) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!uECC_compute_public_key(private_key, public_key, curve)) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
return SC_OK; |
||||||
|
} |
||||||
@ -0,0 +1,388 @@ |
|||||||
|
/* sc_lib.c - Secure Channel library implementation using TinyCrypt */ |
||||||
|
|
||||||
|
#include "secure_channel.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/ecc.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/ecc_dh.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/aes.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/ccm_mode.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/constants.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/ecc_platform_specific.h" |
||||||
|
#include "../tinycrypt/lib/include/tinycrypt/sha256.h" |
||||||
|
#include <string.h> |
||||||
|
#include <stddef.h> |
||||||
|
#include <sys/types.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <sys/time.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
// Simple debug macros |
||||||
|
#define DEBUG_CATEGORY_CRYPTO 1 |
||||||
|
#define DEBUG_ERROR(category, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__) |
||||||
|
#define DEBUG_INFO(category, fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__) |
||||||
|
#include <stdio.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include "crc32.h" |
||||||
|
|
||||||
|
static const struct uECC_Curve_t *curve = NULL; |
||||||
|
static uint8_t sc_urandom_seed[8] = {0}; |
||||||
|
static int sc_urandom_initialized = 0; |
||||||
|
|
||||||
|
static void sc_init_random_seed(void) |
||||||
|
{ |
||||||
|
int fd = open("/dev/urandom", O_RDONLY); |
||||||
|
if (fd >= 0) { |
||||||
|
ssize_t ret = read(fd, sc_urandom_seed, 8); |
||||||
|
close(fd); |
||||||
|
if (ret == 8) { |
||||||
|
sc_urandom_initialized = 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static int sc_rng(uint8_t *dest, unsigned size) |
||||||
|
{ |
||||||
|
int fd = open("/dev/urandom", O_RDONLY); |
||||||
|
if (fd < 0) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
ssize_t ret = read(fd, dest, size); |
||||||
|
close(fd); |
||||||
|
if (ret != size) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* Mix in PID and microtime for additional entropy */ |
||||||
|
pid_t pid = getpid(); |
||||||
|
struct timeval tv; |
||||||
|
gettimeofday(&tv, NULL); |
||||||
|
|
||||||
|
for (unsigned i = 0; i < size; i++) { |
||||||
|
dest[i] ^= ((pid >> (i % (sizeof(pid) * 8))) & 0xFF); |
||||||
|
dest[i] ^= ((tv.tv_sec >> (i % (sizeof(tv.tv_sec) * 8))) & 0xFF); |
||||||
|
dest[i] ^= ((tv.tv_usec >> (i % (sizeof(tv.tv_usec) * 8))) & 0xFF); |
||||||
|
} |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
static int sc_validate_key(const uint8_t *public_key) |
||||||
|
{ |
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
int result = uECC_valid_public_key(public_key, curve); |
||||||
|
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_validate_key: uECC_valid_public_key returned %d", result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_generate_keypair(struct SC_MYKEYS *pk) |
||||||
|
{ |
||||||
|
if (!pk) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
|
||||||
|
/* Set custom RNG function */ |
||||||
|
uECC_set_rng(sc_rng); |
||||||
|
|
||||||
|
if (!uECC_make_key(pk->public_key, pk->private_key, curve)) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
// Конвертация hex строки в бинарный формат |
||||||
|
static int hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len) { |
||||||
|
if (!hex_str || !binary || strlen(hex_str) != binary_len * 2) return -1; |
||||||
|
|
||||||
|
for (size_t i = 0; i < binary_len; i++) { |
||||||
|
unsigned int byte; |
||||||
|
if (sscanf(hex_str + i * 2, "%2x", &byte) != 1) return -1; |
||||||
|
binary[i] = (uint8_t)byte; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, const char *private_key) { |
||||||
|
if (!mykeys || !public_key || !private_key) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: invalid arguments"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
|
||||||
|
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: public_key len=%zu, private_key len=%zu", |
||||||
|
strlen(public_key), strlen(private_key)); |
||||||
|
|
||||||
|
/* Convert hex to binary first */ |
||||||
|
if (hex_to_binary(public_key, mykeys->public_key, SC_PUBKEY_SIZE)) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: failed to convert public key from hex"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
if (hex_to_binary(private_key, mykeys->private_key, SC_PRIVKEY_SIZE)) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: failed to convert private key from hex"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
/* Validate the converted binary public key */ |
||||||
|
if (sc_validate_key(mykeys->public_key) != 0) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: public key validation failed"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: keys initialized successfully"); |
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_init_ctx(sc_context_t *ctx, struct SC_MYKEYS *mykeys) { |
||||||
|
|
||||||
|
ctx->pk=mykeys; |
||||||
|
ctx->initialized = 1; |
||||||
|
ctx->peer_key_set = 0; |
||||||
|
ctx->session_ready = 0; |
||||||
|
ctx->tx_counter = 0; |
||||||
|
ctx->rx_counter = 0; |
||||||
|
|
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key_h, int mode) { |
||||||
|
uint8_t shared_secret[SC_SHARED_SECRET_SIZE]; |
||||||
|
uint8_t peer_public_key[SC_PUBKEY_SIZE]; |
||||||
|
|
||||||
|
if (mode) { |
||||||
|
if (hex_to_binary(peer_public_key_h, peer_public_key, SC_PUBKEY_SIZE)) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid hex key format"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
} |
||||||
|
else memcpy(peer_public_key, peer_public_key_h, SC_PUBKEY_SIZE); |
||||||
|
|
||||||
|
if (!ctx) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid ctx"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!ctx->initialized) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: ctx not initialized"); |
||||||
|
return SC_ERR_NOT_INITIALIZED; |
||||||
|
} |
||||||
|
|
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
|
||||||
|
/* Validate peer public key */ |
||||||
|
if (sc_validate_key(peer_public_key) != 0) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid key"); |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
/* Compute shared secret using ECDH */ |
||||||
|
if (!ctx->pk) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: no private key"); |
||||||
|
return SC_ERR_NOT_INITIALIZED; |
||||||
|
} |
||||||
|
if (!uECC_shared_secret(peer_public_key, ctx->pk->private_key, |
||||||
|
shared_secret, curve)) { |
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: shared secret error"); |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Derive session key from shared secret (simple copy for demo) */ |
||||||
|
memcpy(ctx->session_key, shared_secret, SC_SESSION_KEY_SIZE); |
||||||
|
|
||||||
|
/* Store peer public key */ |
||||||
|
memcpy(ctx->peer_public_key, peer_public_key, SC_PUBKEY_SIZE); |
||||||
|
ctx->peer_key_set = 1; |
||||||
|
|
||||||
|
ctx->session_ready = 1; |
||||||
|
|
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static void sc_build_nonce(uint64_t counter, uint8_t *nonce_out) |
||||||
|
{ |
||||||
|
struct tc_sha256_state_struct sha_ctx; |
||||||
|
uint8_t hash[32]; |
||||||
|
struct timeval tv; |
||||||
|
uint8_t data[8 + 8 + 4]; |
||||||
|
|
||||||
|
if (!sc_urandom_initialized) { |
||||||
|
sc_init_random_seed(); |
||||||
|
} |
||||||
|
|
||||||
|
gettimeofday(&tv, NULL); |
||||||
|
|
||||||
|
memcpy(data, sc_urandom_seed, 8); |
||||||
|
data[8] = (counter >> 0) & 0xFF; |
||||||
|
data[9] = (counter >> 8) & 0xFF; |
||||||
|
data[10] = (counter >> 16) & 0xFF; |
||||||
|
data[11] = (counter >> 24) & 0xFF; |
||||||
|
data[12] = (counter >> 32) & 0xFF; |
||||||
|
data[13] = (counter >> 40) & 0xFF; |
||||||
|
data[14] = (counter >> 48) & 0xFF; |
||||||
|
data[15] = (counter >> 56) & 0xFF; |
||||||
|
data[16] = (tv.tv_sec >> 0) & 0xFF; |
||||||
|
data[17] = (tv.tv_sec >> 8) & 0xFF; |
||||||
|
data[18] = (tv.tv_sec >> 16) & 0xFF; |
||||||
|
data[19] = (tv.tv_sec >> 24) & 0xFF; |
||||||
|
|
||||||
|
tc_sha256_init(&sha_ctx); |
||||||
|
tc_sha256_update(&sha_ctx, data, 20); |
||||||
|
tc_sha256_final(hash, &sha_ctx); |
||||||
|
|
||||||
|
memcpy(nonce_out, hash, SC_NONCE_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_encrypt(sc_context_t *ctx, |
||||||
|
const uint8_t *plaintext, |
||||||
|
size_t plaintext_len, |
||||||
|
uint8_t *ciphertext, |
||||||
|
size_t *ciphertext_len) |
||||||
|
{ |
||||||
|
uint8_t nonce[SC_NONCE_SIZE]; |
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
struct tc_ccm_mode_struct ccm_state; |
||||||
|
size_t total_plaintext_len = plaintext_len + SC_CRC32_SIZE; |
||||||
|
uint8_t plaintext_with_crc[total_plaintext_len]; |
||||||
|
uint8_t combined_output[total_plaintext_len + SC_TAG_SIZE]; |
||||||
|
|
||||||
|
if (!ctx || !plaintext || !ciphertext || !ciphertext_len) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!ctx->session_ready) { |
||||||
|
return SC_ERR_NOT_INITIALIZED; |
||||||
|
} |
||||||
|
|
||||||
|
if (plaintext_len == 0) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
/* Добавляем CRC32 к данным */ |
||||||
|
memcpy(plaintext_with_crc, plaintext, plaintext_len); |
||||||
|
uint32_t crc = crc32_calc(plaintext, plaintext_len); |
||||||
|
plaintext_with_crc[plaintext_len] = (crc >> 0) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 1] = (crc >> 8) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 2] = (crc >> 16) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 3] = (crc >> 24) & 0xFF; |
||||||
|
|
||||||
|
/* Initialize AES key schedule */ |
||||||
|
if (tc_aes128_set_encrypt_key(&sched, ctx->session_key) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Build nonce from counter */ |
||||||
|
sc_build_nonce(ctx->tx_counter, nonce); |
||||||
|
|
||||||
|
/* Configure CCM mode */ |
||||||
|
if (tc_ccm_config(&ccm_state, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Encrypt and generate tag */ |
||||||
|
if (tc_ccm_generation_encryption(combined_output, sizeof(combined_output), |
||||||
|
NULL, 0, /* no associated data */ |
||||||
|
plaintext_with_crc, total_plaintext_len, |
||||||
|
&ccm_state) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Copy ciphertext + tag to output buffer */ |
||||||
|
memcpy(ciphertext, combined_output, total_plaintext_len + SC_TAG_SIZE); |
||||||
|
*ciphertext_len = total_plaintext_len + SC_TAG_SIZE; |
||||||
|
|
||||||
|
ctx->tx_counter++; |
||||||
|
|
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_decrypt(sc_context_t *ctx, |
||||||
|
const uint8_t *ciphertext, |
||||||
|
size_t ciphertext_len, |
||||||
|
uint8_t *plaintext, |
||||||
|
size_t *plaintext_len) |
||||||
|
{ |
||||||
|
uint8_t nonce[SC_NONCE_SIZE]; |
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
struct tc_ccm_mode_struct ccm_state; |
||||||
|
TCCcmMode_t c = &ccm_state; |
||||||
|
size_t total_plaintext_len = ciphertext_len - SC_TAG_SIZE; |
||||||
|
uint8_t plaintext_with_crc[total_plaintext_len]; |
||||||
|
|
||||||
|
if (!ctx || !ciphertext || !plaintext || !plaintext_len) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!ctx->session_ready) { |
||||||
|
return SC_ERR_NOT_INITIALIZED; |
||||||
|
} |
||||||
|
|
||||||
|
if (ciphertext_len < SC_TAG_SIZE + SC_CRC32_SIZE) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
/* Initialize AES key schedule */ |
||||||
|
if (tc_aes128_set_encrypt_key(&sched, ctx->session_key) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Build nonce from counter */ |
||||||
|
sc_build_nonce(ctx->rx_counter, nonce); |
||||||
|
|
||||||
|
/* Configure CCM mode */ |
||||||
|
if (tc_ccm_config(c, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
|
||||||
|
/* Decrypt and verify tag */ |
||||||
|
if (tc_ccm_decryption_verification(plaintext_with_crc, total_plaintext_len, |
||||||
|
NULL, 0, /* no associated data */ |
||||||
|
ciphertext, ciphertext_len, |
||||||
|
c) != TC_CRYPTO_SUCCESS) { |
||||||
|
return SC_ERR_AUTH_FAILED; |
||||||
|
} |
||||||
|
|
||||||
|
/* Проверяем CRC32 */ |
||||||
|
size_t data_len = total_plaintext_len - SC_CRC32_SIZE; |
||||||
|
uint32_t expected_crc = crc32_calc(plaintext_with_crc, data_len); |
||||||
|
uint32_t received_crc = (plaintext_with_crc[data_len] << 0) | |
||||||
|
(plaintext_with_crc[data_len + 1] << 8) | |
||||||
|
(plaintext_with_crc[data_len + 2] << 16) | |
||||||
|
(plaintext_with_crc[data_len + 3] << 24); |
||||||
|
|
||||||
|
if (expected_crc != received_crc) { |
||||||
|
return SC_ERR_CRC_FAILED; |
||||||
|
} |
||||||
|
|
||||||
|
/* Копируем данные без CRC32 */ |
||||||
|
memcpy(plaintext, plaintext_with_crc, data_len); |
||||||
|
*plaintext_len = data_len; |
||||||
|
|
||||||
|
ctx->rx_counter++; |
||||||
|
|
||||||
|
return SC_OK; |
||||||
|
} |
||||||
|
|
||||||
|
sc_status_t sc_compute_public_key_from_private(const uint8_t *private_key, uint8_t *public_key) { |
||||||
|
if (!private_key || !public_key) { |
||||||
|
return SC_ERR_INVALID_ARG; |
||||||
|
} |
||||||
|
|
||||||
|
if (!curve) { |
||||||
|
curve = uECC_secp256r1(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!uECC_compute_public_key(private_key, public_key, curve)) { |
||||||
|
return SC_ERR_CRYPTO; |
||||||
|
} |
||||||
|
return SC_OK; |
||||||
|
} |
||||||
@ -0,0 +1,68 @@ |
|||||||
|
// secure_channel.h |
||||||
|
#ifndef SECURE_CHANNEL_H |
||||||
|
#define SECURE_CHANNEL_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stddef.h> |
||||||
|
|
||||||
|
// Размеры ключей |
||||||
|
#define SC_PRIVKEY_SIZE 32 |
||||||
|
#define SC_PUBKEY_SIZE 64 |
||||||
|
#define SC_HASH_SIZE 32 |
||||||
|
#define SC_NONCE_SIZE 13 // CCM requires exactly 13 bytes |
||||||
|
#define SC_SHARED_SECRET_SIZE SC_HASH_SIZE |
||||||
|
#define SC_SESSION_KEY_SIZE 16 |
||||||
|
#define SC_TAG_SIZE 8 |
||||||
|
#define SC_CRC32_SIZE 4 |
||||||
|
|
||||||
|
// Коды возврата |
||||||
|
#define SC_OK 0 |
||||||
|
#define SC_ERR_INVALID_ARG -1 |
||||||
|
#define SC_ERR_CRYPTO -2 |
||||||
|
#define SC_ERR_NOT_INITIALIZED -3 |
||||||
|
#define SC_ERR_AUTH_FAILED -4 |
||||||
|
#define SC_ERR_CRC_FAILED -5 |
||||||
|
|
||||||
|
#define SC_PEER_PUBKEY_BIN 0 |
||||||
|
#define SC_PEER_PUBKEY_HEX 1 |
||||||
|
|
||||||
|
// Типы |
||||||
|
typedef int sc_status_t; |
||||||
|
typedef struct secure_channel sc_context_t; |
||||||
|
|
||||||
|
struct SC_MYKEYS { |
||||||
|
/* Локальные ключи */ |
||||||
|
uint8_t private_key[SC_PRIVKEY_SIZE]; |
||||||
|
uint8_t public_key[SC_PUBKEY_SIZE]; |
||||||
|
}; |
||||||
|
|
||||||
|
// Контекст защищенного канала |
||||||
|
struct secure_channel { |
||||||
|
struct SC_MYKEYS* pk; |
||||||
|
/* Ключи пира (после key exchange) */ |
||||||
|
uint8_t peer_public_key[SC_PUBKEY_SIZE]; |
||||||
|
uint8_t session_key[SC_SESSION_KEY_SIZE]; /* Derived session key */ |
||||||
|
|
||||||
|
/* Nonces для отправки и приема */ |
||||||
|
uint8_t send_nonce[SC_NONCE_SIZE]; |
||||||
|
uint8_t recv_nonce[SC_NONCE_SIZE]; |
||||||
|
|
||||||
|
uint8_t initialized; |
||||||
|
uint8_t peer_key_set; |
||||||
|
uint8_t session_ready; |
||||||
|
uint64_t tx_counter; |
||||||
|
uint64_t rx_counter; |
||||||
|
}; |
||||||
|
|
||||||
|
// Функции инициализации |
||||||
|
sc_status_t sc_init_ctx(sc_context_t *ctx, struct SC_MYKEYS *mykeys); |
||||||
|
sc_status_t sc_generate_keypair(struct SC_MYKEYS *keys); |
||||||
|
sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, const char *private_key); |
||||||
|
sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key, int mode);// mode: 0-bin 1-hex key format |
||||||
|
sc_status_t sc_compute_public_key_from_private(const uint8_t *private_key, uint8_t *public_key); |
||||||
|
|
||||||
|
// Криптографические операции |
||||||
|
sc_status_t sc_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len); |
||||||
|
sc_status_t sc_decrypt(sc_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t *plaintext_len); |
||||||
|
|
||||||
|
#endif // SECURE_CHANNEL_H |
||||||
Binary file not shown.
@ -0,0 +1,45 @@ |
|||||||
|
#include "../lib/ll_queue.h" |
||||||
|
#include "../lib/u_async.h" |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
int id; |
||||||
|
char name[32]; |
||||||
|
int value; |
||||||
|
} test_data_t; |
||||||
|
|
||||||
|
int main() { |
||||||
|
struct UASYNC* ua = uasync_create(); |
||||||
|
struct ll_queue* q = queue_new(ua, 0); |
||||||
|
|
||||||
|
/* Create test data */ |
||||||
|
test_data_t* data1 = (test_data_t*)queue_data_new(sizeof(test_data_t)); |
||||||
|
printf("queue_data_new returned: %p\n", data1); |
||||||
|
|
||||||
|
data1->id = 1; |
||||||
|
strcpy(data1->name, "test1"); |
||||||
|
data1->value = 100; |
||||||
|
|
||||||
|
printf("Created data: id=%d, name=%s, value=%d\n", data1->id, data1->name, data1->value); |
||||||
|
printf("Data pointer: %p\n", data1); |
||||||
|
|
||||||
|
/* Put data into queue */ |
||||||
|
int put_result = queue_data_put(q, data1, data1->id); |
||||||
|
printf("queue_data_put returned: %d\n", put_result); |
||||||
|
printf("After put: queue count = %d\n", queue_entry_count(q)); |
||||||
|
|
||||||
|
/* Get data from queue */ |
||||||
|
test_data_t* retrieved = (test_data_t*)queue_data_get(q); |
||||||
|
printf("Retrieved pointer: %p\n", retrieved); |
||||||
|
if (retrieved) { |
||||||
|
printf("Retrieved data: id=%d, name=%s, value=%d\n", retrieved->id, retrieved->name, retrieved->value); |
||||||
|
} else { |
||||||
|
printf("Retrieved NULL!\n"); |
||||||
|
} |
||||||
|
|
||||||
|
queue_free(q); |
||||||
|
uasync_destroy(ua, 0); |
||||||
|
return 0; |
||||||
|
} |
||||||
@ -0,0 +1,78 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
""" |
||||||
|
Script to replace queue_data patterns with macros in test_ll_queue.c |
||||||
|
""" |
||||||
|
|
||||||
|
import re |
||||||
|
|
||||||
|
with open('test_ll_queue.c', 'r') as f: |
||||||
|
content = f.read() |
||||||
|
|
||||||
|
# Pattern 1: test_data_t* var = (test_data_t*)queue_data_new(sizeof(test_data_t)); |
||||||
|
# Replace with: Q_NEW(var); |
||||||
|
content = re.sub( |
||||||
|
r'test_data_t\* (\w+) = \(test_data_t\*\)queue_data_new\(sizeof\(test_data_t\)\);', |
||||||
|
r'Q_NEW(\1);', |
||||||
|
content |
||||||
|
) |
||||||
|
|
||||||
|
# Pattern 2: test_data_t* var = (test_data_t*)queue_data_new_from_pool(pool); |
||||||
|
# Replace with: Q_NEW_POOL(var, pool); |
||||||
|
content = re.sub( |
||||||
|
r'test_data_t\* (\w+) = \(test_data_t\*\)queue_data_new_from_pool\(([^)]+)\);', |
||||||
|
r'Q_NEW_POOL(\1, \2);', |
||||||
|
content |
||||||
|
) |
||||||
|
|
||||||
|
# Pattern 3: test_data_t* var = (test_data_t*)queue_data_get(q); |
||||||
|
# Replace with: Q_GET(q, var); |
||||||
|
content = re.sub( |
||||||
|
r'test_data_t\* (\w+) = \(test_data_t\*\)queue_data_get\(([^)]+)\);', |
||||||
|
r'Q_GET(\2, \1);', |
||||||
|
content |
||||||
|
) |
||||||
|
|
||||||
|
# Pattern 4: queue_data_put(q, var, var->id) |
||||||
|
# Replace with: Q_PUT(q, var) |
||||||
|
content = re.sub( |
||||||
|
r'queue_data_put\(([^,]+), ([^,]+), \2->id\)', |
||||||
|
r'Q_PUT(\1, \2)', |
||||||
|
content |
||||||
|
) |
||||||
|
|
||||||
|
# Pattern 5: queue_data_put_first(q, var, var->id) |
||||||
|
# Replace with: Q_PUT_FIRST(q, var) |
||||||
|
content = re.sub( |
||||||
|
r'queue_data_put_first\(([^,]+), ([^,]+), \2->id\)', |
||||||
|
r'Q_PUT_FIRST(\1, \2)', |
||||||
|
content |
||||||
|
) |
||||||
|
|
||||||
|
# Pattern 6: queue_data_free(var); |
||||||
|
# Replace with: Q_FREE(var); |
||||||
|
content = re.sub( |
||||||
|
r'queue_data_free\((\w+)\);', |
||||||
|
r'Q_FREE(\1);', |
||||||
|
content |
||||||
|
) |
||||||
|
|
||||||
|
# Pattern 7: test_data_t* var = (test_data_t*)queue_find_data_by_id(q, id); |
||||||
|
# Replace with: Q_FIND(q, id, var); |
||||||
|
content = re.sub( |
||||||
|
r'test_data_t\* (\w+) = \(test_data_t\*\)queue_find_data_by_id\(([^,]+), ([^)]+)\);', |
||||||
|
r'Q_FIND(\2, \3, \1);', |
||||||
|
content |
||||||
|
) |
||||||
|
|
||||||
|
# Pattern 8: queue_remove_data(q, var) |
||||||
|
# Replace with: Q_REMOVE(q, var) |
||||||
|
content = re.sub( |
||||||
|
r'queue_remove_data\(([^,]+), ([^)]+)\)', |
||||||
|
r'Q_REMOVE(\1, \2)', |
||||||
|
content |
||||||
|
) |
||||||
|
|
||||||
|
with open('test_ll_queue.c', 'w') as f: |
||||||
|
f.write(content) |
||||||
|
|
||||||
|
print("All patterns replaced successfully!") |
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,40 @@ |
|||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
int a; |
||||||
|
int b; |
||||||
|
int ref_count; |
||||||
|
uint8_t data[0]; |
||||||
|
} test_struct; |
||||||
|
|
||||||
|
int main() { |
||||||
|
test_struct* entry = malloc(sizeof(test_struct) + 100); |
||||||
|
entry->a = 1; |
||||||
|
entry->b = 2; |
||||||
|
entry->ref_count = 3; |
||||||
|
|
||||||
|
void* data_ptr = entry->data; // or (void*)(entry + 1)
|
||||||
|
|
||||||
|
printf("entry pointer: %p\n", entry); |
||||||
|
printf("data pointer: %p\n", data_ptr); |
||||||
|
printf("sizeof(test_struct): %zu\n", sizeof(test_struct)); |
||||||
|
printf("difference in bytes: %ld\n", (char*)data_ptr - (char*)entry); |
||||||
|
|
||||||
|
// Test different ways to convert back
|
||||||
|
test_struct* back1 = (test_struct*)((char*)data_ptr - sizeof(test_struct)); |
||||||
|
test_struct* back2 = (test_struct*)data_ptr - 1; |
||||||
|
test_struct* back3 = (test_struct*)data_ptr - 0; |
||||||
|
|
||||||
|
printf("back1 (char* subtraction): %p\n", back1); |
||||||
|
printf("back2 (pointer - 1): %p\n", back2); |
||||||
|
printf("back3 (pointer - 0): %p\n", back3); |
||||||
|
|
||||||
|
printf("back1 ref_count: %d\n", back1->ref_count); |
||||||
|
printf("back2 ref_count: %d\n", back2->ref_count); |
||||||
|
printf("back3 ref_count: %d\n", back3->ref_count); |
||||||
|
|
||||||
|
free(entry); |
||||||
|
return 0; |
||||||
|
} |
||||||
@ -0,0 +1,81 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
""" |
||||||
|
Script to update test_ll_queue.c for xxx=0 architecture |
||||||
|
Changes all queue_data_* calls to use struct ll_entry* intermediate |
||||||
|
""" |
||||||
|
|
||||||
|
import re |
||||||
|
|
||||||
|
# Read the file |
||||||
|
with open('test_ll_queue.c', 'r') as f: |
||||||
|
content = f.read() |
||||||
|
|
||||||
|
# Pattern 1: queue_data_new with variable declaration |
||||||
|
# FROM: test_data_t* data = (test_data_t*)queue_data_new(sizeof(test_data_t)); |
||||||
|
# TO: struct ll_entry* entry = (struct ll_entry*)queue_data_new(sizeof(test_data_t)); |
||||||
|
# test_data_t* data = (test_data_t*)entry->data; |
||||||
|
|
||||||
|
# Find all occurrences and replace |
||||||
|
lines = content.split('\n') |
||||||
|
new_lines = [] |
||||||
|
i = 0 |
||||||
|
while i < len(lines): |
||||||
|
line = lines[i] |
||||||
|
|
||||||
|
# Pattern 1: test_data_t* data = (test_data_t*)queue_data_new |
||||||
|
match = re.match(r'(\s*)test_data_t\* (\w+) = \(test_data_t\*\)queue_data_new\(sizeof\(test_data_t\)\);', line) |
||||||
|
if match: |
||||||
|
indent = match.group(1) |
||||||
|
var_name = match.group(2) |
||||||
|
# Replace with two lines |
||||||
|
new_lines.append(f'{indent}struct ll_entry* entry_{var_name} = (struct ll_entry*)queue_data_new(sizeof(test_data_t));') |
||||||
|
new_lines.append(f'{indent}test_data_t* {var_name} = (test_data_t*)entry_{var_name}->data;') |
||||||
|
i += 1 |
||||||
|
continue |
||||||
|
|
||||||
|
# Pattern 2: test_data_t* var = (test_data_t*)queue_data_get |
||||||
|
match = re.match(r'(\s*)test_data_t\* (\w+) = \(test_data_t\*\)queue_data_get\(([^)]+)\);', line) |
||||||
|
if match: |
||||||
|
indent = match.group(1) |
||||||
|
var_name = match.group(2) |
||||||
|
queue_var = match.group(3) |
||||||
|
# Replace with two lines |
||||||
|
new_lines.append(f'{indent}struct ll_entry* entry_{var_name} = (struct ll_entry*)queue_data_get({queue_var});') |
||||||
|
new_lines.append(f'{indent}test_data_t* {var_name} = entry_{var_name} ? (test_data_t*)entry_{var_name}->data : NULL;') |
||||||
|
i += 1 |
||||||
|
continue |
||||||
|
|
||||||
|
# Pattern 3: queue_data_put with data variable |
||||||
|
# Need to find the corresponding entry variable |
||||||
|
match = re.match(r'(\s*)(\w+)\(q, (\w+), (\w+)->id\)', line) |
||||||
|
if match and 'queue_data_put' in line: |
||||||
|
func = match.group(2) |
||||||
|
var = match.group(3) |
||||||
|
# Replace data with entry variable |
||||||
|
new_line = line.replace(f'{var}, {var}->id)', f'entry_{var}, {var}->id)') |
||||||
|
new_lines.append(new_line) |
||||||
|
i += 1 |
||||||
|
continue |
||||||
|
|
||||||
|
# Pattern 4: queue_data_free with data variable |
||||||
|
match = re.match(r'(\s*)queue_data_free\((\w+)\);', line) |
||||||
|
if match: |
||||||
|
indent = match.group(1) |
||||||
|
var = match.group(2) |
||||||
|
# Check if this is a data variable (not entry) |
||||||
|
if not var.startswith('entry_') and var != 'data' and var != 'item': |
||||||
|
# Replace with entry variable |
||||||
|
new_lines.append(f'{indent}queue_data_free(entry_{var});') |
||||||
|
else: |
||||||
|
new_lines.append(line) |
||||||
|
i += 1 |
||||||
|
continue |
||||||
|
|
||||||
|
new_lines.append(line) |
||||||
|
i += 1 |
||||||
|
|
||||||
|
# Write the updated file |
||||||
|
with open('test_ll_queue.c', 'w') as f: |
||||||
|
f.write('\n'.join(new_lines)) |
||||||
|
|
||||||
|
print("File updated successfully!") |
||||||
Loading…
Reference in new issue