|
|
|
@ -73,6 +73,63 @@ sc_status_t sc_init_ctx(sc_context_t *ctx, struct SC_MYKEYS *mykeys) { |
|
|
|
return SC_OK; |
|
|
|
return SC_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Common helper functions for input validation and CRC handling
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static sc_status_t validate_encrypt_inputs(sc_context_t *ctx, const uint8_t *plaintext,
|
|
|
|
|
|
|
|
const uint8_t *ciphertext, const size_t *ciphertext_len, |
|
|
|
|
|
|
|
size_t plaintext_len) { |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return SC_OK; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static sc_status_t validate_decrypt_inputs(sc_context_t *ctx, const uint8_t *ciphertext, |
|
|
|
|
|
|
|
const uint8_t *plaintext, const size_t *plaintext_len, |
|
|
|
|
|
|
|
size_t ciphertext_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; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return SC_OK; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void append_crc32(const uint8_t *plaintext, size_t plaintext_len, uint8_t *output) { |
|
|
|
|
|
|
|
memcpy(output, plaintext, plaintext_len); |
|
|
|
|
|
|
|
uint32_t crc = crc32_calc(plaintext, plaintext_len); |
|
|
|
|
|
|
|
output[plaintext_len] = (crc >> 0) & 0xFF; |
|
|
|
|
|
|
|
output[plaintext_len + 1] = (crc >> 8) & 0xFF; |
|
|
|
|
|
|
|
output[plaintext_len + 2] = (crc >> 16) & 0xFF; |
|
|
|
|
|
|
|
output[plaintext_len + 3] = (crc >> 24) & 0xFF; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static sc_status_t verify_and_strip_crc32(uint8_t *plaintext_with_crc, size_t total_len, |
|
|
|
|
|
|
|
uint8_t *plaintext, size_t *plaintext_len) { |
|
|
|
|
|
|
|
size_t data_len = total_len - SC_CRC32_SIZE; |
|
|
|
|
|
|
|
uint32_t received_crc = ((uint32_t)plaintext_with_crc[data_len]) | |
|
|
|
|
|
|
|
((uint32_t)plaintext_with_crc[data_len + 1] << 8) | |
|
|
|
|
|
|
|
((uint32_t)plaintext_with_crc[data_len + 2] << 16) | |
|
|
|
|
|
|
|
((uint32_t)plaintext_with_crc[data_len + 3] << 24); |
|
|
|
|
|
|
|
uint32_t calc_crc = crc32_calc(plaintext_with_crc, data_len); |
|
|
|
|
|
|
|
if (received_crc != calc_crc) { |
|
|
|
|
|
|
|
return SC_ERR_CRC_FAILED; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
memcpy(plaintext, plaintext_with_crc, data_len); |
|
|
|
|
|
|
|
*plaintext_len = data_len; |
|
|
|
|
|
|
|
return SC_OK; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef USE_OPENSSL |
|
|
|
#ifdef USE_OPENSSL |
|
|
|
|
|
|
|
|
|
|
|
// OpenSSL-specific implementations
|
|
|
|
// OpenSSL-specific implementations
|
|
|
|
@ -310,22 +367,11 @@ static void sc_build_nonce(uint64_t counter, uint8_t *nonce_out) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len) { |
|
|
|
if (!ctx || !plaintext || !ciphertext || !ciphertext_len) { |
|
|
|
sc_status_t status = validate_encrypt_inputs(ctx, plaintext, ciphertext, ciphertext_len, plaintext_len); |
|
|
|
return SC_ERR_INVALID_ARG; |
|
|
|
if (status != SC_OK) return status; |
|
|
|
} |
|
|
|
|
|
|
|
if (!ctx->session_ready) { |
|
|
|
|
|
|
|
return SC_ERR_NOT_INITIALIZED; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (plaintext_len == 0) { |
|
|
|
|
|
|
|
return SC_ERR_INVALID_ARG; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
uint8_t plaintext_with_crc[plaintext_len + SC_CRC32_SIZE]; |
|
|
|
uint8_t plaintext_with_crc[plaintext_len + SC_CRC32_SIZE]; |
|
|
|
memcpy(plaintext_with_crc, plaintext, plaintext_len); |
|
|
|
append_crc32(plaintext, plaintext_len, plaintext_with_crc); |
|
|
|
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; |
|
|
|
|
|
|
|
size_t total_plaintext_len = plaintext_len + SC_CRC32_SIZE; |
|
|
|
size_t total_plaintext_len = plaintext_len + SC_CRC32_SIZE; |
|
|
|
uint8_t nonce[SC_NONCE_SIZE]; |
|
|
|
uint8_t nonce[SC_NONCE_SIZE]; |
|
|
|
sc_build_nonce(ctx->tx_counter, nonce); |
|
|
|
sc_build_nonce(ctx->tx_counter, nonce); |
|
|
|
@ -374,15 +420,9 @@ sc_status_t sc_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plain |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
sc_status_t sc_decrypt(sc_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t *plaintext_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) { |
|
|
|
if (!ctx || !ciphertext || !plaintext || !plaintext_len) { |
|
|
|
sc_status_t status = validate_decrypt_inputs(ctx, ciphertext, plaintext, plaintext_len, ciphertext_len); |
|
|
|
return SC_ERR_INVALID_ARG; |
|
|
|
if (status != SC_OK) return status; |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
uint8_t nonce[SC_NONCE_SIZE]; |
|
|
|
uint8_t nonce[SC_NONCE_SIZE]; |
|
|
|
memcpy(nonce, ciphertext, SC_NONCE_SIZE); |
|
|
|
memcpy(nonce, ciphertext, SC_NONCE_SIZE); |
|
|
|
const uint8_t *encrypted_data = ciphertext + SC_NONCE_SIZE; |
|
|
|
const uint8_t *encrypted_data = ciphertext + SC_NONCE_SIZE; |
|
|
|
@ -419,19 +459,11 @@ sc_status_t sc_decrypt(sc_context_t *ctx, const uint8_t *ciphertext, size_t ciph |
|
|
|
return SC_ERR_AUTH_FAILED; |
|
|
|
return SC_ERR_AUTH_FAILED; |
|
|
|
} |
|
|
|
} |
|
|
|
EVP_CIPHER_CTX_free(dctx); |
|
|
|
EVP_CIPHER_CTX_free(dctx); |
|
|
|
size_t data_len = total_plaintext_len - SC_CRC32_SIZE; |
|
|
|
sc_status_t result = verify_and_strip_crc32(plaintext_with_crc, total_plaintext_len, plaintext, plaintext_len); |
|
|
|
uint32_t expected_crc = crc32_calc(plaintext_with_crc, data_len); |
|
|
|
if (result == SC_OK) { |
|
|
|
uint32_t received_crc = (plaintext_with_crc[data_len] << 0) | |
|
|
|
ctx->rx_counter++; |
|
|
|
(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; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
memcpy(plaintext, plaintext_with_crc, data_len); |
|
|
|
return result; |
|
|
|
*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) { |
|
|
|
sc_status_t sc_compute_public_key_from_private(const uint8_t *private_key, uint8_t *public_key) { |
|
|
|
@ -671,6 +703,9 @@ static void sc_build_nonce(uint64_t counter, uint8_t *nonce_out) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len) { |
|
|
|
|
|
|
|
sc_status_t status = validate_encrypt_inputs(ctx, plaintext, ciphertext, ciphertext_len, plaintext_len); |
|
|
|
|
|
|
|
if (status != SC_OK) return status; |
|
|
|
|
|
|
|
|
|
|
|
uint8_t nonce[SC_NONCE_SIZE]; |
|
|
|
uint8_t nonce[SC_NONCE_SIZE]; |
|
|
|
uint8_t plaintext_with_crc[plaintext_len + SC_CRC32_SIZE]; |
|
|
|
uint8_t plaintext_with_crc[plaintext_len + SC_CRC32_SIZE]; |
|
|
|
size_t total_plaintext_len = plaintext_len + SC_CRC32_SIZE; |
|
|
|
size_t total_plaintext_len = plaintext_len + SC_CRC32_SIZE; |
|
|
|
@ -678,25 +713,8 @@ sc_status_t sc_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plain |
|
|
|
struct tc_aes_key_sched_struct sched; |
|
|
|
struct tc_aes_key_sched_struct sched; |
|
|
|
struct tc_ccm_mode_struct ccm_state; |
|
|
|
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 к данным */ |
|
|
|
/* Добавляем CRC32 к данным */ |
|
|
|
memcpy(plaintext_with_crc, plaintext, plaintext_len); |
|
|
|
append_crc32(plaintext, plaintext_len, plaintext_with_crc); |
|
|
|
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 с таймером */ |
|
|
|
/* Генерируем nonce с таймером */ |
|
|
|
sc_build_nonce(ctx->tx_counter, nonce); |
|
|
|
sc_build_nonce(ctx->tx_counter, nonce); |
|
|
|
@ -735,24 +753,15 @@ sc_status_t sc_decrypt(sc_context_t *ctx, |
|
|
|
uint8_t *plaintext, |
|
|
|
uint8_t *plaintext, |
|
|
|
size_t *plaintext_len) |
|
|
|
size_t *plaintext_len) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
sc_status_t status = validate_decrypt_inputs(ctx, ciphertext, plaintext, plaintext_len, ciphertext_len); |
|
|
|
|
|
|
|
if (status != SC_OK) return status; |
|
|
|
|
|
|
|
|
|
|
|
uint8_t nonce[SC_NONCE_SIZE]; |
|
|
|
uint8_t nonce[SC_NONCE_SIZE]; |
|
|
|
struct tc_aes_key_sched_struct sched; |
|
|
|
struct tc_aes_key_sched_struct sched; |
|
|
|
struct tc_ccm_mode_struct ccm_state; |
|
|
|
struct tc_ccm_mode_struct ccm_state; |
|
|
|
size_t total_plaintext_len = ciphertext_len - SC_NONCE_SIZE - SC_TAG_SIZE; |
|
|
|
size_t total_plaintext_len = ciphertext_len - SC_NONCE_SIZE - SC_TAG_SIZE; |
|
|
|
uint8_t plaintext_with_crc[total_plaintext_len]; |
|
|
|
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 */ |
|
|
|
/* Извлекаем nonce из начала ciphertext */ |
|
|
|
memcpy(nonce, ciphertext, SC_NONCE_SIZE); |
|
|
|
memcpy(nonce, ciphertext, SC_NONCE_SIZE); |
|
|
|
|
|
|
|
|
|
|
|
@ -778,25 +787,12 @@ sc_status_t sc_decrypt(sc_context_t *ctx, |
|
|
|
return SC_ERR_AUTH_FAILED; |
|
|
|
return SC_ERR_AUTH_FAILED; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Проверяем CRC32 */ |
|
|
|
/* Проверяем CRC32 используя helper-функцию */ |
|
|
|
size_t data_len = total_plaintext_len - SC_CRC32_SIZE; |
|
|
|
sc_status_t result = verify_and_strip_crc32(plaintext_with_crc, total_plaintext_len, plaintext, plaintext_len); |
|
|
|
uint32_t expected_crc = crc32_calc(plaintext_with_crc, data_len); |
|
|
|
if (result == SC_OK) { |
|
|
|
uint32_t received_crc = (plaintext_with_crc[data_len] << 0) | |
|
|
|
ctx->rx_counter++; |
|
|
|
(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; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
/* Копируем данные без 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) { |
|
|
|
sc_status_t sc_compute_public_key_from_private(const uint8_t *private_key, uint8_t *public_key) { |
|
|
|
|