From bd05ab6d3a07a77dd53e9d40a0eae70bd72cd502 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 1 Oct 2026 14:35:43 +0300 Subject: [PATCH] Verify DM media record boundaries and corrupted artifacts --- tests/test_dm.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/test_dm.c b/tests/test_dm.c index 44d8b973..d09fb606 100644 --- a/tests/test_dm.c +++ b/tests/test_dm.c @@ -15,6 +15,85 @@ #include #include "../lib/mem.h" +/* Потоковые файлы разного размера; результат доступен только после всех проверок. */ +static int test_media_stream(const uint8_t key1[32], const uint8_t key2[32], uint64_t author, size_t size) { + FILE* src = tmpfile(); + FILE* cipher = tmpfile(); + FILE* plain = tmpfile(); + FILE* short_cipher = tmpfile(); + if (!src || !cipher || !plain || !short_cipher) { + DEBUG_ERROR(DEBUG_CATEGORY_DM, "media test temporary file creation failed"); + if (src) fclose(src); + if (cipher) fclose(cipher); + if (plain) fclose(plain); + if (short_cipher) fclose(short_cipher); + return 1; + } + uint8_t pattern[4096], actual[4096], id[16] = {1}, hash[32]; + for (size_t i = 0; i < sizeof(pattern); i++) pattern[i] = (uint8_t)(i * 17 + 3); + int failed = 0; + size_t remaining = size; + while (remaining) { + size_t n = remaining > sizeof(pattern) ? sizeof(pattern) : remaining; + if (fwrite(pattern, 1, n, src) != n) { failed = 1; goto done; } + remaining -= n; + } + rewind(src); + uint64_t reported_size = 0; + if (dm_media_encrypt_stream(key1, author, id, src, cipher, &reported_size, hash) != 0 || reported_size != size) { + failed = 1; + goto done; + } + long cipher_size = ftell(cipher); + size_t records = size ? (size + DM_MEDIA_PLAIN_SIZE - 1) / DM_MEDIA_PLAIN_SIZE : 1; + if (cipher_size != (long)(size + records * DM_TAG_SIZE)) { failed = 1; goto done; } + rewind(cipher); + if (dm_media_decrypt_stream(key2, author, id, size, hash, cipher, plain) != 0 || ftell(plain) != (long)size) { + failed = 1; + goto done; + } + rewind(plain); + remaining = size; + while (remaining) { + size_t n = remaining > sizeof(actual) ? sizeof(actual) : remaining; + if (fread(actual, 1, n, plain) != n || memcmp(actual, pattern, n)) { failed = 1; goto done; } + remaining -= n; + } + /* Неправильный получатель, автор, ID и manifest hash не принимаются. */ + uint8_t wrong_key[32] = {0}; + rewind(cipher); + if (dm_media_decrypt_stream(wrong_key, author, id, size, hash, cipher, plain) == 0) failed = 1; + rewind(cipher); + if (dm_media_decrypt_stream(key2, author + 1, id, size, hash, cipher, plain) == 0) failed = 1; + id[1] = 1; + rewind(cipher); + if (dm_media_decrypt_stream(key2, author, id, size, hash, cipher, plain) == 0) failed = 1; + id[1] = 0; + hash[0] ^= 1; + rewind(cipher); + if (dm_media_decrypt_stream(key2, author, id, size, hash, cipher, plain) == 0) failed = 1; + hash[0] ^= 1; + /* Обрезанный файл и лишние байты обнаруживаются независимо от тегов порций. */ + rewind(cipher); + for (long i = 0; i < cipher_size - 1; i++) { + int ch = fgetc(cipher); + if (ch == EOF || fputc(ch, short_cipher) == EOF) { failed = 1; goto done; } + } + rewind(short_cipher); + if (dm_media_decrypt_stream(key2, author, id, size, hash, short_cipher, plain) == 0) failed = 1; + fseek(cipher, 0, SEEK_END); + if (fputc(1, cipher) == EOF) { failed = 1; goto done; } + rewind(cipher); + if (dm_media_decrypt_stream(key2, author, id, size, hash, cipher, plain) == 0) failed = 1; +done: + fclose(src); + fclose(cipher); + fclose(plain); + fclose(short_cipher); + if (failed) DEBUG_ERROR(DEBUG_CATEGORY_DM, "media stream test failed plain_size=%zu", size); + return failed; +} + int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); @@ -131,6 +210,9 @@ int main(void) { u_free(large); u_free(cipher); u_free(restored); + const size_t file_sizes[] = {0, 1, DM_MEDIA_PLAIN_SIZE, DM_MEDIA_PLAIN_SIZE + 1, DM_MEDIA_PLAIN_SIZE * 3 + 77}; + for (size_t i = 0; i < sizeof(file_sizes) / sizeof(file_sizes[0]); i++) + failures += test_media_stream(key1, key2, a, file_sizes[i]); if (failures == 0) { printf("TEST PASSED\n");