#pragma once #include #include #include #include #include #include #include #include #include class CBufferPool; constexpr std::size_t M2PACK_MAGIC_SIZE = 8; constexpr std::size_t M2PACK_HASH_SIZE = 32; constexpr std::size_t M2PACK_SIGNATURE_SIZE = 64; constexpr std::size_t M2PACK_KEY_SIZE = crypto_aead_xchacha20poly1305_ietf_KEYBYTES; constexpr std::size_t M2PACK_NONCE_SIZE = crypto_aead_xchacha20poly1305_ietf_NPUBBYTES; constexpr std::size_t M2PACK_PUBLIC_KEY_SIZE = crypto_sign_PUBLICKEYBYTES; #pragma pack(push, 1) struct TM2PackHeader { char magic[M2PACK_MAGIC_SIZE]; uint32_t version; uint32_t flags; uint32_t key_id; uint64_t manifest_offset; uint64_t manifest_size; uint8_t manifest_hash[M2PACK_HASH_SIZE]; uint8_t manifest_signature[M2PACK_SIGNATURE_SIZE]; uint8_t reserved[60]; }; struct TM2PackManifestHeader { uint32_t entry_count; uint32_t flags; }; struct TM2PackManifestEntryFixed { uint16_t path_size; uint8_t compression; uint8_t flags; uint64_t data_offset; uint64_t original_size; uint64_t stored_size; uint8_t nonce[M2PACK_NONCE_SIZE]; uint8_t plaintext_hash[M2PACK_HASH_SIZE]; }; #pragma pack(pop) struct TM2PackEntry { std::string path; uint8_t compression = 0; uint64_t data_offset = 0; uint64_t original_size = 0; uint64_t stored_size = 0; std::array nonce {}; std::array plaintext_hash {}; }; class CM2Pack : public std::enable_shared_from_this { public: CM2Pack() = default; ~CM2Pack() = default; bool Load(const std::string& path); const std::vector& GetIndex() const { return m_index; } bool GetFile(const TM2PackEntry& entry, std::vector& result); bool GetFileWithPool(const TM2PackEntry& entry, std::vector& result, CBufferPool* pPool); private: bool ValidateManifest(); bool DecryptEntryPayload(const TM2PackEntry& entry, std::vector& decrypted, CBufferPool* pPool); private: TM2PackHeader m_header {}; std::vector m_manifest_bytes; std::vector m_index; mio::mmap_source m_file; }; using TM2PackFileMapEntry = std::pair, TM2PackEntry>; using TM2PackFileMap = std::unordered_map; #include "M2PackKeys.h"