diff --git a/frontend/src/crypt.c b/frontend/src/crypt.c index a376c46..1845b55 100644 --- a/frontend/src/crypt.c +++ b/frontend/src/crypt.c @@ -226,10 +226,7 @@ int encrypt(const char *const passphrase, const CHR *const input_path, const CHR clean_up: - if (ctx) - { - slunkcrypt_free(ctx); - } + SLUNKCRYPT_SAFE_FREE(ctx); if (file_out) { @@ -424,10 +421,7 @@ int decrypt(const char *const passphrase, const CHR *const input_path, const CHR clean_up: - if (ctx) - { - slunkcrypt_free(ctx); - } + SLUNKCRYPT_SAFE_FREE(ctx); if (file_out) { diff --git a/frontend/src/selftest.c b/frontend/src/selftest.c index c21e9fe..cefe7bb 100644 --- a/frontend/src/selftest.c +++ b/frontend/src/selftest.c @@ -106,10 +106,7 @@ static int run_testcase(const char* const message, const uint64_t nonce, const u clean_up: - if (ctx) - { - slunkcrypt_free(ctx); - } + SLUNKCRYPT_SAFE_FREE(ctx); if (text_temp) { @@ -120,9 +117,93 @@ clean_up: return result; } +static int run_stresstest(const uint64_t nonce) +{ + static const char* const TEST_PASSPHRASE = "OrpheanBeh0lderScry!Doubt"; + static const size_t LENGTH = 134217689U, CHUNKZ_ENC = 8191U, CHUNKZ_DEC = 8179U; + + int status, result = EXIT_FAILURE; + size_t offset, chunk_size; + slunkcrypt_t ctx = SLUNKCRYPT_NULL; + + uint8_t* const buffer = (uint8_t*)malloc(LENGTH * sizeof(uint8_t)); + if (!buffer) + { + FPUTS(T("\n\nWhoops: Failed to allocate message buffer!\n\n"), stderr); + goto clean_up; + } + + if (slunkcrypt_random_bytes(buffer, LENGTH) != LENGTH) + { + FPUTS(T("\n\nWhoops: Failed to generate random message!\n\n"), stderr); + goto clean_up; + } + + const uint64_t checksum_original = blake2s_compute(buffer, LENGTH); + + ctx = slunkcrypt_alloc(nonce, (const uint8_t*)TEST_PASSPHRASE, strlen(TEST_PASSPHRASE), SLUNKCRYPT_ENCRYPT); + if (!ctx) + { + FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to initialize encoder!\n\n"), stderr); + goto clean_up; + } + + for (offset = 0U; offset < LENGTH; offset += chunk_size) + { + chunk_size = ((LENGTH - offset) > CHUNKZ_ENC) ? CHUNKZ_ENC : (LENGTH - offset); + status = slunkcrypt_inplace(ctx, buffer + offset, chunk_size); + if (status != SLUNKCRYPT_SUCCESS) + { + FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to encrypt the message!\n\n"), stderr); + goto clean_up; + } + } + + status = slunkcrypt_reset(ctx, nonce, (const uint8_t*)TEST_PASSPHRASE, strlen(TEST_PASSPHRASE), SLUNKCRYPT_DECRYPT); + if (status != SLUNKCRYPT_SUCCESS) + { + FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to initialize decoder!\n\n"), stderr); + goto clean_up; + } + + for (offset = 0U; offset < LENGTH; offset += chunk_size) + { + chunk_size = ((LENGTH - offset) > CHUNKZ_DEC) ? CHUNKZ_DEC : (LENGTH - offset); + status = slunkcrypt_inplace(ctx, buffer + offset, chunk_size); + if (status != SLUNKCRYPT_SUCCESS) + { + FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to decrypt the message!\n\n"), stderr); + goto clean_up; + } + } + + const uint64_t checksum_decrypted = blake2s_compute(buffer, LENGTH); + if (checksum_decrypted != checksum_original) + { + FPRINTF(stderr, T("\n\nWhoops: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_original, checksum_decrypted); + goto clean_up; + } + + result = EXIT_SUCCESS; + +clean_up: + + SLUNKCRYPT_SAFE_FREE(ctx); + + if (buffer) + { + slunkcrypt_bzero(buffer, LENGTH); + free(buffer); + } + + return result; +} + int run_selftest_routine(void) { + static const size_t ITERATIONS = 2U; static const uint64_t TEST_NONCE[] = { 0x243F6A8885A308D3, 0x13198A2E03707344 }; + const struct { const char* text; @@ -136,15 +217,17 @@ int run_selftest_routine(void) { TEST_DATA_3, TEST_CHCK_ORIG_3, { TEST_CHCK_ENCR_3[0U], TEST_CHCK_ENCR_3[1U] } }, }; - const size_t total = ARRAY_SIZE(TEST_NONCE) * ARRAY_SIZE(TEST_STAGE); - FPRINTF(stderr, T("Self-test is in progress, please be patient... stage %u/%u "), 0U, (unsigned)total); + const size_t total = ARRAY_SIZE(TEST_NONCE) * (ITERATIONS + ARRAY_SIZE(TEST_STAGE)); + size_t count = 0U; + + FPRINTF(stderr, T("Self-test is in progress, please be patient... stage %2u/%2u "), 0U, (unsigned)total); fflush(stderr); - for (size_t i = 0U, count = 0U; i < ARRAY_SIZE(TEST_STAGE); ++i) + for (size_t i = 0U; i < ARRAY_SIZE(TEST_STAGE); ++i) { for (size_t j = 0U; j < ARRAY_SIZE(TEST_NONCE); ++j) { - FPRINTF(stderr, T("\b\b\b\b%u/%u "), (unsigned)++count, (unsigned)total); + FPRINTF(stderr, T("\b\b\b\b\b\b%2u/%2u "), (unsigned)++count, (unsigned)total); fflush(stderr); if (run_testcase(TEST_STAGE[i].text, TEST_NONCE[j], TEST_STAGE[i].check_orig, TEST_STAGE[i].check_encr[j]) != EXIT_SUCCESS) { @@ -153,7 +236,20 @@ int run_selftest_routine(void) } } - FPRINTF(stderr, T("\b\b\b\b%u/%u\n\nCompleted successfully.\n\n"), (unsigned)total, (unsigned)total); + for (size_t i = 0U; i < ITERATIONS; ++i) + { + for (size_t j = 0U; j < ARRAY_SIZE(TEST_NONCE); ++j) + { + FPRINTF(stderr, T("\b\b\b\b\b\b%2u/%2u "), (unsigned)++count, (unsigned)total); + fflush(stderr); + if (run_stresstest(TEST_NONCE[j]) != EXIT_SUCCESS) + { + return EXIT_FAILURE; + } + } + } + + FPRINTF(stderr, T("\b\b\b\b\b\b%2u/%2u\n\nCompleted successfully.\n\n"), (unsigned)total, (unsigned)total); fflush(stderr); return EXIT_SUCCESS; diff --git a/libslunkcrypt/include/slunkcrypt.h b/libslunkcrypt/include/slunkcrypt.h index ce9c7f8..fc57c87 100644 --- a/libslunkcrypt/include/slunkcrypt.h +++ b/libslunkcrypt/include/slunkcrypt.h @@ -128,6 +128,11 @@ SLUNKCRYPT_API int slunkcrypt_inplace(const slunkcrypt_t context, uint8_t *const SLUNKCRYPT_API size_t slunkcrypt_random_bytes(uint8_t *const buffer, const size_t length); SLUNKCRYPT_API void slunkcrypt_bzero(void *const buffer, const size_t length); +/* + * Helper macros + */ +#define SLUNKCRYPT_SAFE_FREE(X) do { if((X) != SLUNKCRYPT_NULL) { slunkcrypt_free((X)); X = SLUNKCRYPT_NULL; } } while(0) + #ifdef __cplusplus } #endif