Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions cdoc/CDoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,16 @@ enum {
NOT_SUPPORTED = -101,
/**
* @brief Conflicting or invalid arguments for a method
*
* This does not set CDocReader/CDocWriter into error state - so invoking subsequent methods
* with correct arguments will succeed
*/
WRONG_ARGUMENTS = -102,
/**
* @brief Components of multi-method workflow are called in wrong order
*
* This does not set CDocReader/CDocWriter into error state - so invoking subsequent methods
* in correct order will succeed
*/
WORKFLOW_ERROR = -103,
/**
Expand All @@ -85,6 +91,9 @@ enum {
INPUT_STREAM_ERROR = -108,
/**
* @brief The supplied decryption key is wrong
*
* This does not set CDocReader/CDocWriter into error state - so invoking subsequent methods
* with correct key will succeed
*/
WRONG_KEY = -109,
/**
Expand Down
80 changes: 56 additions & 24 deletions cdoc/CDoc2Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ struct CDoc2Reader::Private {
std::unique_ptr<libcdoc::DecryptionSource> dec;
std::unique_ptr<libcdoc::ZSource> zsrc;
std::unique_ptr<libcdoc::TarSource> tar;

result_t decryptAllAndClose() {
std::array<uint8_t, 1024> buf;
result_t rv = dec->read(buf.data(), buf.size());
while (rv == buf.size()) {
rv = dec->read(buf.data(), buf.size());
}
if (rv < 0) return rv;
zsrc.reset();
tar.reset();
rv = dec->close();
dec.reset();
return rv;
}
};

CDoc2Reader::~CDoc2Reader()
Expand Down Expand Up @@ -118,35 +132,44 @@ CDoc2Reader::getLockForCert(const std::vector<uint8_t>& cert){
libcdoc::result_t
CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
{
if (lock_idx >= priv->locks.size()) {
setLastError(t_("Invalid lock index"));
LOG_ERROR("{}", last_error);
return libcdoc::WRONG_ARGUMENTS;
}
LOG_DBG("CDoc2Reader::getFMK: {}", lock_idx);
LOG_DBG("CDoc2Reader::num locks: {}", priv->locks.size());
const Lock& lock = priv->locks.at(lock_idx);
LOG_DBG("Label: {}", lock.label);
std::vector<uint8_t> kek;
if (lock.type == Lock::Type::PASSWORD) {
// Password
LOG_DBG("password");
std::string info_str = libcdoc::CDoc2::getSaltForExpand(lock.label);
LOG_DBG("info: {}", toHex(info_str));
std::vector<uint8_t> kek_pm;
crypto->extractHKDF(kek_pm, lock.getBytes(Lock::SALT), lock.getBytes(Lock::PW_SALT), lock.getInt(Lock::KDF_ITER), lock_idx);
LOG_DBG("password2");
if (auto rv = crypto->extractHKDF(kek_pm, lock.getBytes(Lock::SALT), lock.getBytes(Lock::PW_SALT), lock.getInt(Lock::KDF_ITER), lock_idx); rv != libcdoc::OK) {
setLastError(crypto->getLastErrorStr(rv));
LOG_ERROR("{}", last_error);
return rv;
}
LOG_TRACE_KEY("salt: {}", lock.getBytes(Lock::SALT));
LOG_TRACE_KEY("kek_pm: {}", kek_pm);
kek = libcdoc::Crypto::expand(kek_pm, info_str, 32);
if (kek.empty()) return libcdoc::CRYPTO_ERROR;
LOG_DBG("password3");
} else if (lock.type == Lock::Type::SYMMETRIC_KEY) {
// Symmetric key
LOG_DBG("symmetric");
std::string info_str = libcdoc::CDoc2::getSaltForExpand(lock.label);
std::vector<uint8_t> kek_pm;
crypto->extractHKDF(kek_pm, lock.getBytes(Lock::SALT), {}, 0, lock_idx);
kek = libcdoc::Crypto::expand(kek_pm, info_str, 32);

LOG_DBG("Label: {}", lock.label);
LOG_DBG("info: {}", toHex(info_str));
std::vector<uint8_t> kek_pm;
if (auto rv = crypto->extractHKDF(kek_pm, lock.getBytes(Lock::SALT), {}, 0, lock_idx); rv != libcdoc::OK) {
setLastError(crypto->getLastErrorStr(rv));
LOG_ERROR("{}", last_error);
return rv;
}
LOG_TRACE_KEY("salt: {}", lock.getBytes(Lock::SALT));
LOG_TRACE_KEY("kek_pm: {}", kek_pm);
LOG_TRACE_KEY("kek: {}", kek);

if (kek.empty()) return libcdoc::CRYPTO_ERROR;
kek = libcdoc::Crypto::expand(kek_pm, info_str, 32);
} else if ((lock.type == Lock::Type::PUBLIC_KEY) || (lock.type == Lock::Type::SERVER)) {
// Public/private key
std::vector<uint8_t> key_material;
Expand Down Expand Up @@ -196,13 +219,9 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
LOG_ERROR("{}", last_error);
return result;
}

LOG_TRACE_KEY("Key kekPm: {}", kek_pm);

std::string info_str = libcdoc::CDoc2::getSaltForExpand(key_material, lock.getBytes(Lock::Params::RCPT_KEY));

LOG_DBG("info: {}", toHex(info_str));

kek = libcdoc::Crypto::expand(kek_pm, info_str, libcdoc::CDoc2::KEY_LEN);
}
} else if (lock.type == Lock::Type::SHARE_SERVER) {
Expand Down Expand Up @@ -312,7 +331,6 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)

LOG_TRACE_KEY("KEK: {}", kek);


if(kek.empty()) {
setLastError(t_("Failed to derive KEK"));
LOG_ERROR("{}", last_error);
Expand Down Expand Up @@ -394,10 +412,10 @@ CDoc2Reader::beginDecryption(const std::vector<uint8_t>& fmk)
std::vector<uint8_t> aad(libcdoc::CDoc2::PAYLOAD.cbegin(), libcdoc::CDoc2::PAYLOAD.cend());
aad.insert(aad.end(), priv->header_data.cbegin(), priv->header_data.cend());
aad.insert(aad.end(), priv->headerHMAC.cbegin(), priv->headerHMAC.cend());
if(priv->dec->updateAAD(aad) != OK) {
setLastError("Wrong decryption key (FMK)");
if(auto rv = priv->dec->updateAAD(aad); rv != OK) {
setLastError(priv->dec->getLastErrorStr(rv));
LOG_ERROR("{}", last_error);
return libcdoc::WRONG_KEY;
return rv;
}

priv->zsrc = std::make_unique<libcdoc::ZSource>(priv->dec.get(), false);
Expand All @@ -414,8 +432,13 @@ CDoc2Reader::nextFile(std::string& name, int64_t& size)
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
result_t result = priv->tar->next(name, size);
if (result != OK) {
result_t result = priv->tar->next(name, size);
if (result < 0) {
result_t sr = priv->decryptAllAndClose();
if (sr != OK) {
setLastError("Crypto payload integrity check failed");
return sr;
}
setLastError(priv->tar->getLastErrorStr(result));
}
return result;
Expand All @@ -430,7 +453,12 @@ CDoc2Reader::readData(uint8_t *dst, size_t size)
return libcdoc::WORKFLOW_ERROR;
}
result_t result = priv->tar->read(dst, size);
if (result != OK) {
if (result < 0) {
result_t sr = priv->decryptAllAndClose();
if (sr != OK) {
setLastError("Crypto payload integrity check failed");
return sr;
}
setLastError(priv->tar->getLastErrorStr(result));
}
return result;
Expand All @@ -439,11 +467,15 @@ CDoc2Reader::readData(uint8_t *dst, size_t size)
libcdoc::result_t
CDoc2Reader::finishDecryption()
{
if (!priv->tar) {
setLastError("finishDecryption() called before beginDecryption()");
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
if (!priv->zsrc->isEof()) {
setLastError(t_("CDoc contains additional payload data that is not part of content"));
LOG_WARN("{}", last_error);
}

setLastError({});
priv->zsrc.reset();
priv->tar.reset();
Expand Down
42 changes: 41 additions & 1 deletion cdoc/CDoc2Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,11 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
libcdoc::result_t
CDoc2Writer::addRecipient(const libcdoc::Recipient& rcpt)
{
if (finished) {
setLastError("Encryption finished");
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
if(tar) {
setLastError("Cannot add Recipient when files are added");
LOG_ERROR("{}", last_error);
Expand All @@ -469,6 +474,11 @@ CDoc2Writer::addRecipient(const libcdoc::Recipient& rcpt)
libcdoc::result_t
CDoc2Writer::beginEncryption()
{
if (finished) {
setLastError("Encryption finished");
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
last_error.clear();
if(recipients.empty()) {
setLastError("No recipients added");
Expand All @@ -488,12 +498,26 @@ CDoc2Writer::beginEncryption()
libcdoc::result_t
CDoc2Writer::addFile(const std::string& name, size_t size)
{
if (finished) {
setLastError("Encryption finished");
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
if(!tar) {
setLastError("Encryption not started");
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
if (name.empty() || !libcdoc::isValidUtf8(name)) return libcdoc::DATA_FORMAT_ERROR;
if (name.empty() || !libcdoc::isValidUtf8(name)) {
setLastError("Invalid file name");
LOG_ERROR("{}", last_error);
return libcdoc::DATA_FORMAT_ERROR;
}
if (size > 8ULL * 1024 * 1024 * 1024) {
setLastError("Invalid file size");
LOG_ERROR("{}", last_error);
return libcdoc::WRONG_ARGUMENTS;
}
if(auto rv = tar->open(name, size); rv < 0) {
setLastError(tar->getLastErrorStr(rv));
LOG_ERROR("{}", last_error);
Expand All @@ -505,6 +529,11 @@ CDoc2Writer::addFile(const std::string& name, size_t size)
libcdoc::result_t
CDoc2Writer::writeData(const uint8_t *src, size_t size)
{
if (finished) {
setLastError("Encryption finished");
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
if(!tar) {
setLastError("No file added");
LOG_ERROR("{}", last_error);
Expand All @@ -520,6 +549,11 @@ CDoc2Writer::writeData(const uint8_t *src, size_t size)
libcdoc::result_t
CDoc2Writer::finishEncryption()
{
if (finished) {
setLastError("Encryption finished");
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
if(!tar) {
setLastError("No file added");
LOG_ERROR("{}", last_error);
Expand All @@ -531,12 +565,18 @@ CDoc2Writer::finishEncryption()
tar.reset();
recipients.clear();
if (owned) dst->close();
finished = true;
return rv;
}

libcdoc::result_t
CDoc2Writer::encrypt(libcdoc::MultiDataSource& src, const std::vector<libcdoc::Recipient>& keys)
{
if (finished) {
setLastError("Encryption finished");
LOG_ERROR("{}", last_error);
return libcdoc::WORKFLOW_ERROR;
}
for (auto rcpt : keys) {
if(auto rv = addRecipient(rcpt); rv != libcdoc::OK)
return rv;
Expand Down
1 change: 1 addition & 0 deletions cdoc/CDoc2Writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class CDoc2Writer final: public libcdoc::CDocWriter {

std::unique_ptr<libcdoc::TarConsumer> tar;
std::vector<libcdoc::Recipient> recipients;
bool finished = false;
};

}
4 changes: 2 additions & 2 deletions cdoc/CryptoBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ CryptoBackend::getKeyMaterial(std::vector<uint8_t>& key_material, const std::vec
if (pw_salt.empty()) return INVALID_PARAMS;
std::vector<uint8_t> secret;
int result = getSecret(secret, idx);
if (result < 0) return result;
if (result) return result;

LOG_DBG("Secret: {}", toHex(secret));

Expand All @@ -91,7 +91,7 @@ CryptoBackend::getKeyMaterial(std::vector<uint8_t>& key_material, const std::vec
if (key_material.empty()) return OPENSSL_ERROR;
} else {
int result = getSecret(key_material, idx);
if (result < 0) return result;
if (result) return result;
LOG_DBG("Secret: {}", toHex(key_material));
if (key_material.size() != 32) {
return INVALID_PARAMS;
Expand Down
2 changes: 1 addition & 1 deletion cdoc/Io.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ struct CDOC_EXPORT IStreamSource : public DataSource {
if (_owned) delete _ifs;
}

result_t seek(size_t pos) {
result_t seek(size_t pos) override {
if(_ifs->bad()) return INPUT_STREAM_ERROR;
_ifs->clear();
_ifs->seekg(pos);
Expand Down
40 changes: 27 additions & 13 deletions cdoc/Tar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ libcdoc::TarConsumer::~TarConsumer()
libcdoc::result_t
libcdoc::TarConsumer::write(const uint8_t *src, size_t size) noexcept
{
if ((_current_size >= 0) && ((_current_written + size) > _current_size)) {
return WORKFLOW_ERROR;
}
_current_written += size;
return _dst->write(src, size);
}

Expand Down Expand Up @@ -160,19 +164,25 @@ libcdoc::TarConsumer::writePadding(int64_t size) noexcept {
libcdoc::result_t
libcdoc::TarConsumer::close() noexcept
{
if (_current_size > 0) {
if(auto rv = writePadding(_current_size); rv != OK)
return rv;
}
Header empty = {};
if(auto rv = writeHeader(empty); rv != OK)
return rv;
if(auto rv = writeHeader(empty); rv != OK)
return rv;
result_t result = OK;
if ((_current_size >= 0) && (_current_written < _current_size)) {
result = DATA_FORMAT_ERROR;
} else {
if (_current_written > 0) {
if(auto rv = writePadding(_current_written); rv != OK)
return rv;
}
Header empty = {};
if(auto rv = writeHeader(empty); rv != OK)
return rv;
if(auto rv = writeHeader(empty); rv != OK)
return rv;
}
if (_owned) {
return _dst->close();
if (auto rv = _dst->close(); rv != OK)
return rv;
}
return OK;
return result;
}

bool
Expand All @@ -184,12 +194,16 @@ libcdoc::TarConsumer::isError() noexcept
libcdoc::result_t
libcdoc::TarConsumer::open(const std::string& name, int64_t size)
{
if (_current_size > 0) {
if(auto rv = writePadding(_current_size); rv != OK)
if ((_current_size >= 0) && (_current_written < _current_size)) {
return WORKFLOW_ERROR;
}
if (_current_written > 0) {
if(auto rv = writePadding(_current_written); rv != OK)
return rv;
}

_current_size = size;
_current_written = 0;
Header h {};
size_t len = std::min(name.size(), h.name.size());
std::copy_n(name.cbegin(), len, h.name.begin());
Expand Down
Loading