@@ -87,6 +87,20 @@ struct CDoc2Reader::Private {
8787 std::unique_ptr<libcdoc::DecryptionSource> dec;
8888 std::unique_ptr<libcdoc::ZSource> zsrc;
8989 std::unique_ptr<libcdoc::TarSource> tar;
90+
91+ result_t decryptAllAndClose () {
92+ std::array<uint8_t , 1024 > buf;
93+ result_t rv = dec->read (buf.data (), buf.size ());
94+ while (rv == buf.size ()) {
95+ rv = dec->read (buf.data (), buf.size ());
96+ }
97+ if (rv < 0 ) return rv;
98+ zsrc.reset ();
99+ tar.reset ();
100+ rv = dec->close ();
101+ dec.reset ();
102+ return rv;
103+ }
90104};
91105
92106CDoc2Reader::~CDoc2Reader ()
@@ -118,35 +132,44 @@ CDoc2Reader::getLockForCert(const std::vector<uint8_t>& cert){
118132libcdoc::result_t
119133CDoc2Reader::getFMK (std::vector<uint8_t >& fmk, unsigned int lock_idx)
120134{
135+ if (lock_idx >= priv->locks .size ()) {
136+ setLastError (t_ (" Invalid lock index" ));
137+ LOG_ERROR (" {}" , last_error);
138+ return libcdoc::WRONG_ARGUMENTS;
139+ }
121140 LOG_DBG (" CDoc2Reader::getFMK: {}" , lock_idx);
122141 LOG_DBG (" CDoc2Reader::num locks: {}" , priv->locks .size ());
123142 const Lock& lock = priv->locks .at (lock_idx);
143+ LOG_DBG (" Label: {}" , lock.label );
124144 std::vector<uint8_t > kek;
125145 if (lock.type == Lock::Type::PASSWORD) {
126146 // Password
127147 LOG_DBG (" password" );
128148 std::string info_str = libcdoc::CDoc2::getSaltForExpand (lock.label );
149+ LOG_DBG (" info: {}" , toHex (info_str));
129150 std::vector<uint8_t > kek_pm;
130- crypto->extractHKDF (kek_pm, lock.getBytes (Lock::SALT), lock.getBytes (Lock::PW_SALT), lock.getInt (Lock::KDF_ITER), lock_idx);
131- LOG_DBG (" password2" );
151+ 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) {
152+ setLastError (crypto->getLastErrorStr (rv));
153+ LOG_ERROR (" {}" , last_error);
154+ return rv;
155+ }
156+ LOG_TRACE_KEY (" salt: {}" , lock.getBytes (Lock::SALT));
157+ LOG_TRACE_KEY (" kek_pm: {}" , kek_pm);
132158 kek = libcdoc::Crypto::expand (kek_pm, info_str, 32 );
133- if (kek.empty ()) return libcdoc::CRYPTO_ERROR;
134- LOG_DBG (" password3" );
135159 } else if (lock.type == Lock::Type::SYMMETRIC_KEY) {
136160 // Symmetric key
137161 LOG_DBG (" symmetric" );
138162 std::string info_str = libcdoc::CDoc2::getSaltForExpand (lock.label );
139- std::vector<uint8_t > kek_pm;
140- crypto->extractHKDF (kek_pm, lock.getBytes (Lock::SALT), {}, 0 , lock_idx);
141- kek = libcdoc::Crypto::expand (kek_pm, info_str, 32 );
142-
143- LOG_DBG (" Label: {}" , lock.label );
144163 LOG_DBG (" info: {}" , toHex (info_str));
164+ std::vector<uint8_t > kek_pm;
165+ if (auto rv = crypto->extractHKDF (kek_pm, lock.getBytes (Lock::SALT), {}, 0 , lock_idx); rv != libcdoc::OK) {
166+ setLastError (crypto->getLastErrorStr (rv));
167+ LOG_ERROR (" {}" , last_error);
168+ return rv;
169+ }
145170 LOG_TRACE_KEY (" salt: {}" , lock.getBytes (Lock::SALT));
146171 LOG_TRACE_KEY (" kek_pm: {}" , kek_pm);
147- LOG_TRACE_KEY (" kek: {}" , kek);
148-
149- if (kek.empty ()) return libcdoc::CRYPTO_ERROR;
172+ kek = libcdoc::Crypto::expand (kek_pm, info_str, 32 );
150173 } else if ((lock.type == Lock::Type::PUBLIC_KEY) || (lock.type == Lock::Type::SERVER)) {
151174 // Public/private key
152175 std::vector<uint8_t > key_material;
@@ -196,13 +219,9 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
196219 LOG_ERROR (" {}" , last_error);
197220 return result;
198221 }
199-
200222 LOG_TRACE_KEY (" Key kekPm: {}" , kek_pm);
201-
202223 std::string info_str = libcdoc::CDoc2::getSaltForExpand (key_material, lock.getBytes (Lock::Params::RCPT_KEY));
203-
204224 LOG_DBG (" info: {}" , toHex (info_str));
205-
206225 kek = libcdoc::Crypto::expand (kek_pm, info_str, libcdoc::CDoc2::KEY_LEN);
207226 }
208227 } else if (lock.type == Lock::Type::SHARE_SERVER) {
@@ -312,7 +331,6 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
312331
313332 LOG_TRACE_KEY (" KEK: {}" , kek);
314333
315-
316334 if (kek.empty ()) {
317335 setLastError (t_ (" Failed to derive KEK" ));
318336 LOG_ERROR (" {}" , last_error);
@@ -394,10 +412,10 @@ CDoc2Reader::beginDecryption(const std::vector<uint8_t>& fmk)
394412 std::vector<uint8_t > aad (libcdoc::CDoc2::PAYLOAD.cbegin (), libcdoc::CDoc2::PAYLOAD.cend ());
395413 aad.insert (aad.end (), priv->header_data .cbegin (), priv->header_data .cend ());
396414 aad.insert (aad.end (), priv->headerHMAC .cbegin (), priv->headerHMAC .cend ());
397- if (priv->dec ->updateAAD (aad) != OK) {
398- setLastError (" Wrong decryption key (FMK) " );
415+ if (auto rv = priv->dec ->updateAAD (aad); rv != OK) {
416+ setLastError (priv-> dec -> getLastErrorStr (rv) );
399417 LOG_ERROR (" {}" , last_error);
400- return libcdoc::WRONG_KEY ;
418+ return rv ;
401419 }
402420
403421 priv->zsrc = std::make_unique<libcdoc::ZSource>(priv->dec .get (), false );
@@ -414,8 +432,13 @@ CDoc2Reader::nextFile(std::string& name, int64_t& size)
414432 LOG_ERROR (" {}" , last_error);
415433 return libcdoc::WORKFLOW_ERROR;
416434 }
417- result_t result = priv->tar ->next (name, size);
418- if (result != OK) {
435+ result_t result = priv->tar ->next (name, size);
436+ if (result < 0 ) {
437+ result_t sr = priv->decryptAllAndClose ();
438+ if (sr != OK) {
439+ setLastError (" Crypto payload integrity check failed" );
440+ return sr;
441+ }
419442 setLastError (priv->tar ->getLastErrorStr (result));
420443 }
421444 return result;
@@ -430,7 +453,12 @@ CDoc2Reader::readData(uint8_t *dst, size_t size)
430453 return libcdoc::WORKFLOW_ERROR;
431454 }
432455 result_t result = priv->tar ->read (dst, size);
433- if (result != OK) {
456+ if (result < 0 ) {
457+ result_t sr = priv->decryptAllAndClose ();
458+ if (sr != OK) {
459+ setLastError (" Crypto payload integrity check failed" );
460+ return sr;
461+ }
434462 setLastError (priv->tar ->getLastErrorStr (result));
435463 }
436464 return result;
@@ -439,11 +467,15 @@ CDoc2Reader::readData(uint8_t *dst, size_t size)
439467libcdoc::result_t
440468CDoc2Reader::finishDecryption ()
441469{
470+ if (!priv->tar ) {
471+ setLastError (" finishDecryption() called before beginDecryption()" );
472+ LOG_ERROR (" {}" , last_error);
473+ return libcdoc::WORKFLOW_ERROR;
474+ }
442475 if (!priv->zsrc ->isEof ()) {
443476 setLastError (t_ (" CDoc contains additional payload data that is not part of content" ));
444477 LOG_WARN (" {}" , last_error);
445478 }
446-
447479 setLastError ({});
448480 priv->zsrc .reset ();
449481 priv->tar .reset ();
0 commit comments