From 7874b01bc3c9c8732428e67385fe18f814d09a28 Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Tue, 28 Apr 2026 09:16:00 +0300 Subject: [PATCH] Coverity fixes IB-8899 Signed-off-by: Raul Metsma --- cdoc/CDoc2.h | 2 +- cdoc/CDoc2Reader.cpp | 21 ++++---- cdoc/CDoc2Writer.cpp | 65 +++++++++++------------ cdoc/CDocCipher.cpp | 58 +++++--------------- cdoc/DDocWriter.cpp | 6 ++- cdoc/DDocWriter.h | 1 + cdoc/Lock.cpp | 5 -- cdoc/Tar.cpp | 117 ++++++++++++++++++++++------------------- cdoc/Tar.h | 20 +++---- cdoc/Utils.cpp | 1 + cdoc/Utils.h | 28 ++++++++-- test/libcdoc_boost.cpp | 70 +++++++++++++++++++++--- 12 files changed, 224 insertions(+), 170 deletions(-) diff --git a/cdoc/CDoc2.h b/cdoc/CDoc2.h index 009a61d9..2a687e0e 100644 --- a/cdoc/CDoc2.h +++ b/cdoc/CDoc2.h @@ -31,7 +31,7 @@ static constexpr std::string_view CEK = "CDOC20cek"; static constexpr std::string_view HMAC = "CDOC20hmac"; static constexpr std::string_view KEK = "CDOC20kek"; static constexpr std::string_view KEKPREMASTER = "CDOC20kekpremaster"; -static constexpr std::string_view PAYLOAD = "CDOC20payload"; +static const std::vector PAYLOAD = {'C', 'D', 'O', 'C', '2', '0', 'p', 'a', 'y', 'l', 'o', 'a', 'd'}; static constexpr std::string_view SALT = "CDOC20salt"; static constexpr int KEY_LEN = 32; diff --git a/cdoc/CDoc2Reader.cpp b/cdoc/CDoc2Reader.cpp index 591e5f1f..28d0fc74 100644 --- a/cdoc/CDoc2Reader.cpp +++ b/cdoc/CDoc2Reader.cpp @@ -317,10 +317,10 @@ CDoc2Reader::getFMK(std::vector& fmk, unsigned int lock_idx) LOG_ERROR("Cannot fetch share {}", i); return result; } - if (Crypto::xor_data(kek, kek, share.share) != libcdoc::OK) { + if (auto err = libcdoc::Crypto::xor_data(kek, kek, share.share); err != libcdoc::OK) { setLastError("Failed to derive kek"); LOG_ERROR("Failed to derive kek"); - return libcdoc::CRYPTO_ERROR; + return err; } } LOG_INFO("Fetched all shares"); @@ -338,10 +338,10 @@ CDoc2Reader::getFMK(std::vector& fmk, unsigned int lock_idx) LOG_ERROR("{}", last_error); return CRYPTO_ERROR; } - if (libcdoc::Crypto::xor_data(fmk, lock.encrypted_fmk, kek) != libcdoc::OK) { + if (auto err = libcdoc::Crypto::xor_data(fmk, lock.encrypted_fmk, kek); err != libcdoc::OK) { setLastError(t_("Failed to decrypt/derive fmk")); LOG_ERROR("{}", last_error); - return libcdoc::CRYPTO_ERROR; + return err; } std::vector hhk = libcdoc::Crypto::expand(fmk, libcdoc::CDoc2::HMAC); @@ -410,13 +410,12 @@ CDoc2Reader::beginDecryption(const std::vector& fmk) LOG_TRACE_KEY("cek: {}", cek); priv->dec = std::make_unique(*priv->_src, EVP_chacha20_poly1305(), cek, libcdoc::CDoc2::NONCE_LEN); - std::vector aad = toUint8Vector(libcdoc::CDoc2::PAYLOAD); - aad.insert(aad.end(), priv->header_data.cbegin(), priv->header_data.cend()); - aad.insert(aad.end(), priv->headerHMAC.cbegin(), priv->headerHMAC.cend()); - if(auto rv = priv->dec->updateAAD(aad); rv != OK) { - setLastError(priv->dec->getLastErrorStr(rv)); - LOG_ERROR("{}", last_error); - return rv; + for(const auto &aad: {libcdoc::CDoc2::PAYLOAD, priv->header_data, priv->headerHMAC}) { + if(auto rv = priv->dec->updateAAD(aad); rv != OK) { + setLastError(priv->dec->getLastErrorStr(rv)); + LOG_ERROR("{}", last_error); + return rv; + } } priv->zsrc = std::make_unique(priv->dec.get(), false); diff --git a/cdoc/CDoc2Writer.cpp b/cdoc/CDoc2Writer.cpp index eb29fee3..af07d84a 100644 --- a/cdoc/CDoc2Writer.cpp +++ b/cdoc/CDoc2Writer.cpp @@ -82,12 +82,11 @@ CDoc2Writer::writeHeader(const std::vector &recipients) std::vector nonce; crypto->random(nonce, libcdoc::CDoc2::NONCE_LEN); LOG_TRACE_KEY("nonce: {}", nonce); - auto cipher = std::make_unique(*dst, EVP_chacha20_poly1305(), Crypto::Key(std::move(cek), nonce)); - std::vector aad(libcdoc::CDoc2::PAYLOAD.cbegin(), libcdoc::CDoc2::PAYLOAD.cend()); - aad.insert(aad.end(), header.cbegin(), header.cend()); - aad.insert(aad.end(), headerHMAC.cbegin(), headerHMAC.cend()); - if(auto rv = cipher->writeAAD(aad); rv < 0) - return rv; + auto cipher = std::make_unique(*dst, EVP_chacha20_poly1305(), Crypto::Key(std::move(cek), std::move(nonce))); + for(const auto &aad: {libcdoc::CDoc2::PAYLOAD, std::move(header), std::move(headerHMAC)}) { + if(auto rv = cipher->writeAAD(aad); rv < 0) + return rv; + } auto *zcons = new ZConsumer(cipher.release(), true); tar = std::make_unique(zcons, true); @@ -197,7 +196,7 @@ CDoc2Writer::buildHeader(std::vector& header, const std::vector> fb_rcpts; - std::vector xor_key(libcdoc::CDoc2::KEY_LEN); + std::vector xor_key; for (unsigned int rcpt_idx = 0; rcpt_idx < recipients.size(); rcpt_idx++) { const libcdoc::Recipient& rcpt = recipients.at(rcpt_idx); if (rcpt.isPKI()) { @@ -214,8 +213,8 @@ CDoc2Writer::buildHeader(std::vector& header, const std::vectorrandom(kek, libcdoc::CDoc2::KEY_LEN); - if (libcdoc::Crypto::xor_data(xor_key, fmk, kek) != libcdoc::OK) - FAIL("Internal error", libcdoc::CRYPTO_ERROR); + if (auto err = libcdoc::Crypto::xor_data(xor_key, fmk, kek); err != libcdoc::OK) + FAIL("Internal error", err); auto publicKey = libcdoc::Crypto::fromRSAPublicKeyDer(rcpt.rcpt_key); if(!publicKey) FAIL("Invalid RSA key", libcdoc::CRYPTO_ERROR); @@ -249,8 +248,8 @@ CDoc2Writer::buildHeader(std::vector& header, const std::vector& header, const std::vector 0) { fb_rcpts.push_back(createPasswordCapsule(builder, rcpt, salt, pw_salt, xor_key)); } else { @@ -341,8 +340,8 @@ CDoc2Writer::buildHeader(std::vector& header, const std::vector kek = libcdoc::Crypto::expand(kek_pm, info_str); LOG_TRACE_KEY("kek: {}", kek); if (kek.empty()) return libcdoc::CRYPTO_ERROR; - if (libcdoc::Crypto::xor_data(xor_key, fmk, kek) != libcdoc::OK) - FAIL("Internal error", libcdoc::CRYPTO_ERROR); + if (auto err = libcdoc::Crypto::xor_data(xor_key, fmk, kek); err != libcdoc::OK) + FAIL("Internal error", err); // # Splitting KEK_i into shares // for j in (2, 3, ..., n): @@ -354,8 +353,8 @@ CDoc2Writer::buildHeader(std::vector& header, const std::vector 8ULL * 1024 * 1024 * 1024) + if (constexpr size_t MAX_SIZE = 8ULL * 1024 * 1024 * 1024; size > MAX_SIZE) FAIL("Invalid file size", libcdoc::WRONG_ARGUMENTS); if(auto rv = tar->open(name, size); rv < 0) FAIL(tar->getLastErrorStr(rv), rv); @@ -496,7 +495,7 @@ CDoc2Writer::encrypt(libcdoc::MultiDataSource& src, const std::vector #include -#include #include #include #include @@ -39,8 +38,6 @@ using namespace std; using namespace libcdoc; -static string GenerateRandomSequence(); - struct ToolPKCS11 : public libcdoc::PKCS11Backend { const std::map& rcpts; @@ -271,18 +268,18 @@ fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vectorgetLocks()) { map parsed_label(Lock::parseLabel(lock.label)); @@ -707,35 +705,3 @@ void CDocCipher::Locks(const char* file) const lock_id++; } } - -static string GenerateRandomSequence() -{ - constexpr uint32_t upperbound = 'z' - '0' + 1; - constexpr int MaxSequenceLength = 11; - - uint32_t rnd; - uint8_t rndByte; - ostringstream sequence; - for (int cnt = 0; cnt < MaxSequenceLength;) - { - if (RAND_bytes(&rndByte, 1) < 1) - { - rnd = rand() % upperbound + '0'; - } - else - { - rnd = rndByte % upperbound + '0'; - } - - // arc4random_uniform tends to be not available on all platforms. - // rnd = arc4random_uniform(upperbound) + '0'; - - if (isalnum(rnd)) - { - sequence << static_cast(rnd); - cnt++; - } - } - - return sequence.str(); -} diff --git a/cdoc/DDocWriter.cpp b/cdoc/DDocWriter.cpp index eb85d1a6..2133e8e4 100644 --- a/cdoc/DDocWriter.cpp +++ b/cdoc/DDocWriter.cpp @@ -31,8 +31,8 @@ constexpr XMLWriter::NS DDOC{ nullptr, "http://www.sk.ee/DigiDoc/v1.3.0#" }; DDOCWriter::DDOCWriter(DataConsumer &dst) : XMLWriter(dst) + , state(writeStartElement(DDOC, "SignedDoc", {{"format", "DIGIDOC-XML"}, {"version", "1.3"}})) { - writeStartElement(DDOC, "SignedDoc", {{"format", "DIGIDOC-XML"}, {"version", "1.3"}}); } DDOCWriter::~DDOCWriter() noexcept @@ -49,6 +49,8 @@ DDOCWriter::~DDOCWriter() noexcept */ int64_t DDOCWriter::addFile(const std::string &file, const std::string &mime, size_t size, libcdoc::DataSource& src) { + if (state != OK) + return state; return writeBase64Element(DDOC, "DataFile", [&src](DataConsumer &dst){ return src.readAll(dst); }, { {"ContentType", "EMBEDDED_BASE64"}, {"Filename", file}, @@ -66,6 +68,8 @@ int64_t DDOCWriter::addFile(const std::string &file, const std::string &mime, si */ int64_t DDOCWriter::addFile(const std::string &file, const std::string &mime, const std::vector &data) { + if (state != OK) + return state; return writeBase64Element(DDOC, "DataFile", data, { {"ContentType", "EMBEDDED_BASE64"}, {"Filename", file}, diff --git a/cdoc/DDocWriter.h b/cdoc/DDocWriter.h index 2bfe4829..9bfa48cb 100644 --- a/cdoc/DDocWriter.h +++ b/cdoc/DDocWriter.h @@ -35,6 +35,7 @@ class DDOCWriter final: public XMLWriter private: DDOCWriter(const DDOCWriter &) = delete; DDOCWriter &operator=(const DDOCWriter &) = delete; + int64_t state; int fileCount = 0; }; diff --git a/cdoc/Lock.cpp b/cdoc/Lock.cpp index 6b660d2c..37322529 100644 --- a/cdoc/Lock.cpp +++ b/cdoc/Lock.cpp @@ -91,11 +91,6 @@ Lock::parseLabel(const std::string& label) label_to_prcss = label_wo_prefix; } - auto range_to_sv = [](auto range) constexpr { - if (range.empty()) - return std::string_view(); - return std::string_view(&*range.begin(), std::ranges::distance(range)); - }; for (const auto &part : std::ranges::split_view(label_to_prcss, '&')) { auto label_data_parts = std::ranges::split_view(part, '='); diff --git a/cdoc/Tar.cpp b/cdoc/Tar.cpp index 5200964f..b039e910 100644 --- a/cdoc/Tar.cpp +++ b/cdoc/Tar.cpp @@ -20,14 +20,27 @@ #include "Utils.h" #include +#include #include +#include using namespace libcdoc; constexpr unsigned int BLOCKSIZE = 512; +template +[[nodiscard]] static constexpr auto svtoi(std::string_view data) noexcept +{ + T result {}; + if (data.empty()) + return result; + auto p = &*data.begin(); + std::from_chars(p, p + std::ranges::distance(data), result); + return result; +} + template -static int64_t fromOctal(const std::array &data) +static constexpr int64_t fromOctal(const std::array &data) noexcept { int64_t i = 0; for(const char c: data) @@ -41,7 +54,7 @@ static int64_t fromOctal(const std::array &data) } template -static void toOctal(std::array &data, int64_t value) +static constexpr void toOctal(std::array &data, int64_t value) noexcept { data.fill(' '); for(auto it = data.rbegin() + 1; it != data.rend(); ++it) @@ -70,7 +83,7 @@ struct libcdoc::Header { std::array prefix; std::array padding; - std::pair checksum() const + std::pair checksum() const noexcept { int64_t unsignedSum = 0; int64_t signedSum = 0; @@ -81,12 +94,12 @@ struct libcdoc::Header { return {unsignedSum, signedSum}; } - bool isNull() const { - static const Header empty{}; + constexpr bool isNull() const noexcept { + constexpr Header empty{}; return *this == empty; } - bool verify() { + bool verify() noexcept { auto copy = chksum; chksum.fill(' '); auto checkSum = checksum(); @@ -100,22 +113,22 @@ struct libcdoc::Header { return std::string(name.data(), std::min(name.size(), strlen(name.data()))); } - int64_t getSize() const { + constexpr int64_t getSize() const noexcept { return fromOctal(size); } - bool operator==(const Header&) const = default; + constexpr bool operator==(const Header&) const noexcept = default; }; static_assert (sizeof(Header) == BLOCKSIZE, "Header struct size is incorrect"); -static int padding(int64_t size) +static constexpr int padding(int64_t size) noexcept { return BLOCKSIZE * ((size + BLOCKSIZE - 1) / BLOCKSIZE) - size; } -std::string toPaxRecord (const std::string &keyword, const std::string &value) { - std::string record = ' ' + keyword + '=' + value + '\n'; +std::string toPaxRecord (std::string &&keyword, const std::string &value) { + std::string record = ' ' + std::move(keyword) + '=' + value + '\n'; std::string result; for(auto len = record.size() + 1; result.size() != len; ++len) result = std::to_string(len + 1) + record; @@ -125,7 +138,6 @@ std::string toPaxRecord (const std::string &keyword, const std::string &value) { libcdoc::TarConsumer::TarConsumer(DataConsumer *dst, bool take_ownership) : _dst(dst), _owned(take_ownership) { - } libcdoc::TarConsumer::~TarConsumer() @@ -166,7 +178,7 @@ libcdoc::TarConsumer::writeHeader(const std::string& name, int64_t size, char ty libcdoc::result_t libcdoc::TarConsumer::writePadding(int64_t size) noexcept { - static const std::array pad {}; + static constexpr std::array pad {}; auto padSize = padding(size); if(auto rv = _dst->write(pad.data(), padSize); rv != padSize) return rv < OK ? rv : OUTPUT_ERROR; @@ -217,13 +229,15 @@ libcdoc::TarConsumer::open(const std::string& name, int64_t size) _current_size = size; _current_written = 0; - bool need_pax_name = (name.size() >= 100); - for (auto c : name) { - if ((c & 0x80) || (c < ' ')) { - need_pax_name = true; - break; - } - } + bool need_pax_name = (name.size() >= 100); + if (!need_pax_name) { + for (auto c : name) { + if ((c & 0x80) || (c < ' ')) { + need_pax_name = true; + break; + } + } + } if(need_pax_name || size > 07777777) { LOG_DBG("Writing Pax header: name {} size {}", name, size); std::string paxData; @@ -249,9 +263,8 @@ libcdoc::TarConsumer::open(const std::string& name, int64_t size) } libcdoc::TarSource::TarSource(DataSource *src, bool take_ownership) - : _src(src), _owned(take_ownership), _eof(false), _error(OK), _block_size(0), _data_size(0), _pos(0) + : _src(src), _owned(take_ownership) { - } libcdoc::TarSource::~TarSource() @@ -303,33 +316,30 @@ libcdoc::TarSource::readPaxHeader(const Header& hdr, std::string& name, int64_t& return _error; } _src->skip(padding(h_size)); - // Parse Pax data - for(const std::string &data: split(paxData, '\n')) { - if(data.empty()) break; - size_t eq_pos = data.find_first_of('='); - if (eq_pos == std::string::npos) { - _error = DATA_FORMAT_ERROR; - return _error; - } - std::string headerValue = data.substr(eq_pos + 1, data.size() - eq_pos - 1); - size_t sp_pos = data.find_first_of(' '); - if ((sp_pos == std::string::npos) || (sp_pos >= eq_pos)) { - _error = DATA_FORMAT_ERROR; - return _error; - } - std::string lenStr = data.substr(0, sp_pos); - std::string keyWord = data.substr(sp_pos + 1, eq_pos - sp_pos - 1); - if(data.size() + 1 != stoi(lenStr)) { - _error = DATA_FORMAT_ERROR; - return _error; - } - LOG_DBG("PAX {} : {}", keyWord, headerValue); - if(keyWord == "path") - name = std::move(headerValue); - if(keyWord == "size") - size = stoll(headerValue); - } - return OK; + // Parse Pax data: each line is " =\n" + for(const auto &line: paxData | std::views::split('\n')) { + if(line.empty()) break; + + auto sp = std::ranges::find(line, ' '); + if (sp == line.end()) { _error = DATA_FORMAT_ERROR; return _error; } + auto eq = std::ranges::find(std::next(sp), line.end(), '='); + if (eq == line.end()) { _error = DATA_FORMAT_ERROR; return _error; } + + auto lenStr = range_to_sv(line.begin(), sp); + auto keyWord = range_to_sv(std::next(sp), eq); + auto headerValue = range_to_sv(std::next(eq), line.end()); + + if (std::ranges::distance(line) + 1 != svtoi(lenStr)) { + _error = DATA_FORMAT_ERROR; + return _error; + } + LOG_DBG("PAX {} : {}", keyWord, headerValue); + if (keyWord == "path") + name = headerValue; + if (keyWord == "size") + size = svtoi(headerValue); + } + return OK; } libcdoc::result_t @@ -403,11 +413,10 @@ libcdoc::TarSource::next(std::string& name, int64_t& size) _block_size = size + padding(size); _eof = false; return OK; - } else { - // Skip other header types ('g') - h_size = h.getSize(); - _src->skip(h_size + padding(h_size)); - } + } + // Skip other header types ('g') + h_size = h.getSize(); + _src->skip(h_size + padding(h_size)); } return END_OF_STREAM; } diff --git a/cdoc/Tar.h b/cdoc/Tar.h index 729b83b9..696d4b02 100644 --- a/cdoc/Tar.h +++ b/cdoc/Tar.h @@ -29,7 +29,7 @@ struct TarConsumer final : public MultiDataConsumer { public: TarConsumer(DataConsumer *dst, bool take_ownership); - ~TarConsumer(); + ~TarConsumer() final; libcdoc::result_t write(const uint8_t *src, size_t size) noexcept final; libcdoc::result_t close() noexcept final; @@ -46,24 +46,24 @@ struct TarConsumer final : public MultiDataConsumer int64_t _current_written = 0; }; -struct TarSource : public MultiDataSource +struct TarSource final : public MultiDataSource { public: TarSource(DataSource *src, bool take_ownership); - ~TarSource(); + ~TarSource() final; libcdoc::result_t read(uint8_t *dst, size_t size) noexcept final; bool isError() noexcept final; bool isEof() noexcept final; - libcdoc::result_t getNumComponents() override final { return NOT_IMPLEMENTED; }; - libcdoc::result_t next(std::string& name, int64_t& size) override final; + libcdoc::result_t getNumComponents() final { return NOT_IMPLEMENTED; }; + libcdoc::result_t next(std::string& name, int64_t& size) final; private: DataSource *_src; bool _owned; - bool _eof; - int _error; - size_t _block_size; - size_t _data_size; - size_t _pos; + bool _eof = false; + int _error = OK; + size_t _block_size = 0; + size_t _data_size = 0; + size_t _pos = 0; libcdoc::result_t readPaxHeader(const Header& hdr, std::string& name, int64_t& size); }; diff --git a/cdoc/Utils.cpp b/cdoc/Utils.cpp index 28a023f3..07853336 100644 --- a/cdoc/Utils.cpp +++ b/cdoc/Utils.cpp @@ -138,6 +138,7 @@ buildURL(const std::string& host, int port) std::ostream& operator<<(std::ostream& escaped, urlEncode src) { + restoreFlags rf(escaped); escaped.fill('0'); escaped << std::hex; diff --git a/cdoc/Utils.h b/cdoc/Utils.h index 392b81b4..dad25f3a 100644 --- a/cdoc/Utils.h +++ b/cdoc/Utils.h @@ -186,12 +186,34 @@ urlDecode(std::string_view src) return ret; } +struct restoreFlags { + std::ostream& os; + std::ios_base::fmtflags f; + restoreFlags(std::ostream &os) : os(os), f(os.flags()) {} + CDOC_DISABLE_MOVE_COPY(restoreFlags) + ~restoreFlags() { os.flags(f); } +}; + +[[nodiscard]] constexpr auto range_to_sv(auto begin, auto end) noexcept { + if (begin == end) + return std::string_view(); + return std::string_view(&*begin, std::ranges::distance(begin, end)); +}; + +[[nodiscard]] constexpr auto range_to_sv(auto range) noexcept { + return range_to_sv(range.begin(), range.end()); +}; + #ifndef SWIG template -static inline void LogFormat(LogLevel level, std::string_view file, int line, fmt::format_string fmt, Args&&... args) +static inline void LogFormat(LogLevel level, std::string_view file, int line, fmt::format_string fmt, Args&&... args) noexcept { - auto msg = fmt::format(fmt, std::forward(args)...); - libcdoc::log(level, file, line, msg); + try { + libcdoc::log(level, file, line, fmt::format(fmt, std::forward(args)...)); + } catch (const std::exception&) { + auto sv = fmt.get(); + libcdoc::log(level, file, line, std::string_view(sv.data(), sv.size())); + } } static inline void LogFormat(LogLevel level, std::string_view file, int line, std::string_view msg) diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index 160111aa..904e9986 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -60,7 +60,7 @@ constexpr string_view RSACertFile("rsa_2048_cert.der"); const string Label("Proov"); -constexpr string_view Password("Proov123"); +const std::vector Password = {'P', 'r', 'o', 'o', 'v', '1', '2', '3'}; constexpr string_view AESKey = "E165475C6D8B9DD0B696EE2A37D7176DFDF4D7B510406648E70BAE8E80493E5E"sv; @@ -296,7 +296,8 @@ decrypt(const std::vector& files, const std::string& container, con error_code e; fs::remove(path, e); if(e) - BOOST_TEST_MESSAGE("Failed to remove file"); } + BOOST_TEST_MESSAGE("Failed to remove file"); + } } static void @@ -526,7 +527,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordAndLabel, EncryptFixture, * utf::description("Encrypting a file with password and given label")) { std::vector rcpts { - {libcdoc::RcptInfo::PASSWORD, Label, {}, std::vector(Password.cbegin(), Password.cend())} + {libcdoc::RcptInfo::PASSWORD, Label, {}, Password} }; encrypt(2, {checkDataFile(sources[0])}, formTargetFile("PasswordUsageWithoutLabel.cdoc"), rcpts); } @@ -534,7 +535,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithPasswordAndLabel, DecryptFixture, * utf::depends_on("PasswordUsageWithLabel/EncryptWithPasswordAndLabel") * utf::description("Decrypting a file with password and given label")) { - libcdoc::RcptInfo rcpt {.type=libcdoc::RcptInfo::LOCK, .label=Label, .secret=std::vector(Password.cbegin(), Password.cend())}; + libcdoc::RcptInfo rcpt {.type=libcdoc::RcptInfo::LOCK, .label=Label, .secret=Password}; decrypt({checkDataFile(sources[0])}, checkTargetFile("PasswordUsageWithoutLabel.cdoc"), decodeName(tmpDataPath), rcpt); } BOOST_AUTO_TEST_SUITE_END() @@ -546,7 +547,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordWithoutLabel, EncryptFixtu * utf::description("Encrypting a file with password and without label")) { std::vector rcpts { - {libcdoc::RcptInfo::PASSWORD, "auto", {}, std::vector(Password.cbegin(), Password.cend())} + {libcdoc::RcptInfo::PASSWORD, "auto", {}, Password} }; encrypt(2, {checkDataFile(sources[0])}, formTargetFile("PasswordUsageWithoutLabel.cdoc"), rcpts); } @@ -554,7 +555,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithPasswordLabelIndex, DecryptFixture * utf::depends_on("PasswordUsageWithoutLabel/EncryptWithPasswordWithoutLabel") * utf::description("Decrypting a file with password and label index")) { - decrypt({checkDataFile(sources[0])}, checkTargetFile("PasswordUsageWithoutLabel.cdoc"), tmpDataPath.string(), std::vector(Password.cbegin(), Password.cend())); + decrypt({checkDataFile(sources[0])}, checkTargetFile("PasswordUsageWithoutLabel.cdoc"), tmpDataPath.string(), Password); } BOOST_AUTO_TEST_SUITE_END() @@ -819,6 +820,63 @@ BOOST_AUTO_TEST_CASE(LabelParsingEmptyLabel) BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(TarPaxHeader) + +struct PaxFixture : public FixtureBase +{ + static void encryptDecrypt(const fs::path& srcFile, const fs::path& cdocFile, const fs::path& outDir) + { + std::vector rcpts { + {libcdoc::RcptInfo::PASSWORD, "label", {}, Password} + }; + encrypt(2, {srcFile.string()}, cdocFile.string(), rcpts); + + libcdoc::RcptInfo rcpt { + .type=libcdoc::RcptInfo::LOCK, + .label="label", + .secret=Password + }; + libcdoc::ToolConf conf; + conf.input_files.push_back(cdocFile.string()); + conf.out = outDir.string(); + libcdoc::CDocCipher cipher; + BOOST_CHECK_EQUAL(cipher.Decrypt(conf, rcpt), 0); + } +}; + +BOOST_FIXTURE_TEST_CASE(LongFilename, PaxFixture) +{ + const std::string name(110, 'a'); + const fs::path src = tmpDataPath / name; + std::ofstream(src) << "hello"; + BOOST_TEST_REQUIRE(fs::exists(src)); + + const fs::path cdoc = tmpDataPath / "pax_long.cdoc"; + const fs::path outDir = tmpDataPath / "pax_long_out"; + fs::create_directories(outDir); + + encryptDecrypt(src, cdoc, outDir); + BOOST_TEST(fs::exists(outDir / name)); +} + +BOOST_FIXTURE_TEST_CASE(NonAsciiFilename, PaxFixture) +{ + // õäöü in UTF-8 + const fs::path namePath(u8"\u00f5\u00e4\u00f6\u00fc.txt"); + const fs::path src = tmpDataPath / namePath; + std::ofstream(src) << "hello"; + BOOST_TEST_REQUIRE(fs::exists(src)); + + const fs::path cdoc = tmpDataPath / "pax_unicode.cdoc"; + const fs::path outDir = tmpDataPath / "pax_unicode_out"; + fs::create_directories(outDir); + + encryptDecrypt(src, cdoc, outDir); + BOOST_TEST(fs::exists(outDir / namePath)); +} + +BOOST_AUTO_TEST_SUITE_END() + BOOST_AUTO_TEST_SUITE(StreamingDecryption) using BufTypes = std::tuple, std::array, std::array, std::array>; BOOST_AUTO_TEST_CASE_TEMPLATE(constructor, Buf, BufTypes)