From 1896a19eba6302bc24f5c0e86677deac5eef5b4d Mon Sep 17 00:00:00 2001 From: evgeny Date: Sun, 18 Oct 2026 10:41:27 +0200 Subject: [PATCH] Explain exact encrypted container rejection reasons --- src/media_async/encrypted_file.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/media_async/encrypted_file.c b/src/media_async/encrypted_file.c index 268b58b0..8e50445f 100644 --- a/src/media_async/encrypted_file.c +++ b/src/media_async/encrypted_file.c @@ -114,22 +114,37 @@ int encrypted_file_read(const char* source, const char* destination, const uint8 uint8_t actual[32], header[EF_HEADER], meta[EF_META], cipher[EF_META + 16], nonce[13]; size_t length = 0; uint64_t size = 0; - if (!source || !destination || !strcmp(source, destination) || !key || !author || !id || !hash || !info || !type || - ma_sha256_file(source, actual) || CRYPTO_memcmp(actual, hash, 32)) goto done; + const char* reason = "invalid arguments"; + if (!source || !destination || !strcmp(source, destination) || !key || !author || !id || !hash || !info || !type) goto done; + reason = "cannot hash ciphertext"; + if (ma_sha256_file(source, actual)) goto done; + reason = "ciphertext does not match signed manifest hash"; + if (CRYPTO_memcmp(actual, hash, 32)) goto done; + reason = "cannot open ciphertext or truncated header"; in = fopen(source, "rb"); - if (!in || fread(header, 1, sizeof(header), in) != sizeof(header) || memcmp(header, "UTENC001", 8) || - memcmp(header + 8, id, 16)) goto done; + if (!in || fread(header, 1, sizeof(header), in) != sizeof(header)) goto done; + reason = "unsupported container format or mismatched UUID"; + if (memcmp(header, "UTENC001", 8) || memcmp(header + 8, id, 16)) goto done; size_t encrypted_size = ((size_t)header[32] << 8) | header[33]; + reason = "invalid metadata length or truncated metadata"; if (encrypted_size < 32 + 11 + 16 || encrypted_size > sizeof(cipher) || fread(cipher, 1, encrypted_size, in) != encrypted_size) goto done; media_cipher_nonce(author, id, UINT64_MAX, nonce); - if (media_ccm_decrypt(key, nonce, cipher, encrypted_size, meta, &length) || length < 32 || + reason = "metadata authentication failed"; + if (media_ccm_decrypt(key, nonce, cipher, encrypted_size, meta, &length)) goto done; + reason = "invalid attachment metadata"; + if (length < 32 || !memchr(meta, 0, 32) || !meta[0] || attachment_decode(meta + 32, length - 32, info)) goto done; + reason = "invalid content type"; for (unsigned i = 0; i < 32 && meta[i]; i++) if (meta[i] < 33 || meta[i] > 126 || meta[i] == '"' || meta[i] == '\\') goto done; memcpy(type, meta, 32); for (unsigned i = 0; i < 8; i++) size = (size << 8) | header[24 + i]; out = fopen(destination, "wb"); - if (!out || media_decrypt_stream(key, author, id, size, header + 34, in, out)) goto done; + reason = "cannot open temporary plaintext"; + if (!out) goto done; + reason = "file authentication, size or body hash failed"; + if (media_decrypt_stream(key, author, id, size, header + 34, in, out)) goto done; + reason = "close or durable file sync failed"; rc = 0; done: OPENSSL_cleanse(meta, sizeof(meta)); @@ -137,7 +152,7 @@ done: if (out && fclose(out)) rc = -1; if (!rc) rc = encrypted_file_sync(destination); if (rc) { - DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted file: verification/decryption failed source=%s", source ? source : "?"); + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted file: rejected source=%s reason=%s", source ? source : "?", reason); if (out && remove(destination) && errno != ENOENT) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "encrypted file: rejected output cleanup failed"); } else DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "encrypted file: verified author=%llu bytes=%llu", (unsigned long long)author, (unsigned long long)size);