Prepare DM media as authenticated records using target key
This commit is contained in:
1 parent
10de4f1c71
commit
467d2e7605
2 files changed
+104
No files matched your search
@@ -147,3 +147,90 @@ int dm_decrypt(const uint8_t key[DM_CONTENT_KEY_SIZE], const uint8_t nonce[DM_NO
|
||||
const uint8_t* ct, size_t ct_len, uint8_t* out, size_t* out_len) {
|
||||
return dm_ccm_crypt(key, nonce, ct, ct_len, out, out_len, 0, NULL);
|
||||
}
|
||||
|
||||
/* Каждая порция имеет собственный nonce, ciphertext неизменен для всех сетевых повторов. */
|
||||
int dm_media_encrypt_stream(const uint8_t key[DM_CONTENT_KEY_SIZE], uint64_t author, const uint8_t media_id[16],
|
||||
FILE* src, FILE* dst, uint64_t* plain_size, uint8_t ciphertext_hash[32]) {
|
||||
if (!key || !author || !media_id || !src || !dst || src == dst || !plain_size || !ciphertext_hash) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: invalid media encryption arguments", DM_ID);
|
||||
return -1;
|
||||
}
|
||||
*plain_size = 0;
|
||||
memset(ciphertext_hash, 0, 32);
|
||||
uint8_t plain[DM_MEDIA_PLAIN_SIZE], cipher[DM_MEDIA_PLAIN_SIZE + DM_TAG_SIZE], nonce[DM_NONCE_SIZE];
|
||||
uint64_t part = 0, total = 0;
|
||||
SHA256_CTX hash;
|
||||
SHA256_Init(&hash);
|
||||
for (;;) {
|
||||
size_t n = fread(plain, 1, sizeof(plain), src);
|
||||
if (ferror(src)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: media source read failed part=%llu", DM_ID, (unsigned long long)part);
|
||||
return -1;
|
||||
}
|
||||
if (!n && part) break;
|
||||
size_t clen = 0;
|
||||
dm_build_media_nonce(author, media_id, part, nonce);
|
||||
if (dm_encrypt(key, nonce, plain, n, cipher, &clen) != 0) return -1;
|
||||
if (fwrite(cipher, 1, clen, dst) != clen) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: media ciphertext write failed part=%llu", DM_ID, (unsigned long long)part);
|
||||
return -1;
|
||||
}
|
||||
SHA256_Update(&hash, cipher, clen);
|
||||
total += n;
|
||||
part++;
|
||||
if (n < sizeof(plain)) break;
|
||||
}
|
||||
if (fflush(dst) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: media ciphertext flush failed", DM_ID);
|
||||
return -1;
|
||||
}
|
||||
SHA256_Final(ciphertext_hash, &hash);
|
||||
*plain_size = total;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DM, "%s: media encrypted author=%llu plain=%llu records=%llu", DM_ID,
|
||||
(unsigned long long)author, (unsigned long long)total, (unsigned long long)part);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Размер и хеш берутся из подписанного manifest; никакого size-only принятия файла. */
|
||||
int dm_media_decrypt_stream(const uint8_t key[DM_CONTENT_KEY_SIZE], uint64_t author, const uint8_t media_id[16],
|
||||
uint64_t plain_size, const uint8_t ciphertext_hash[32], FILE* src, FILE* dst) {
|
||||
if (!key || !author || !media_id || !ciphertext_hash || !src || !dst || src == dst) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: invalid media decryption arguments", DM_ID);
|
||||
return -1;
|
||||
}
|
||||
uint8_t plain[DM_MEDIA_PLAIN_SIZE], cipher[DM_MEDIA_PLAIN_SIZE + DM_TAG_SIZE], nonce[DM_NONCE_SIZE];
|
||||
uint64_t remaining = plain_size, part = 0;
|
||||
SHA256_CTX hash;
|
||||
SHA256_Init(&hash);
|
||||
do {
|
||||
size_t n = remaining > DM_MEDIA_PLAIN_SIZE ? DM_MEDIA_PLAIN_SIZE : (size_t)remaining;
|
||||
size_t clen = n + DM_TAG_SIZE, plen = 0;
|
||||
if (fread(cipher, 1, clen, src) != clen) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: media ciphertext short/read failure part=%llu expected=%zu", DM_ID,
|
||||
(unsigned long long)part, clen);
|
||||
return -1;
|
||||
}
|
||||
SHA256_Update(&hash, cipher, clen);
|
||||
dm_build_media_nonce(author, media_id, part, nonce);
|
||||
if (dm_decrypt(key, nonce, cipher, clen, plain, &plen) != 0) return -1;
|
||||
if (plen != n || fwrite(plain, 1, plen, dst) != plen) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: media plaintext write/length failure part=%llu", DM_ID, (unsigned long long)part);
|
||||
return -1;
|
||||
}
|
||||
remaining -= n;
|
||||
part++;
|
||||
} while (remaining);
|
||||
uint8_t actual_hash[32];
|
||||
SHA256_Final(actual_hash, &hash);
|
||||
if (fgetc(src) != EOF || ferror(src) || memcmp(actual_hash, ciphertext_hash, 32)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: media ciphertext size/hash mismatch plain=%llu", DM_ID, (unsigned long long)plain_size);
|
||||
return -1;
|
||||
}
|
||||
if (fflush(dst) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: media plaintext flush failed", DM_ID);
|
||||
return -1;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DM, "%s: media verified author=%llu plain=%llu records=%llu", DM_ID,
|
||||
(unsigned long long)author, (unsigned long long)plain_size, (unsigned long long)part);
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user