diff --git a/include/qpdf/QPDFCryptoImpl.hh b/include/qpdf/QPDFCryptoImpl.hh index edeea0d3..22e452dd 100644 --- a/include/qpdf/QPDFCryptoImpl.hh +++ b/include/qpdf/QPDFCryptoImpl.hh @@ -74,9 +74,11 @@ class QPDF_DLL_CLASS QPDFCryptoImpl QPDF_DLL virtual void RC4_finalize() = 0; + static size_t constexpr rijndael_buf_size = 16; QPDF_DLL virtual void rijndael_init( - bool encrypt, unsigned char const* key_data, size_t key_len) = 0; + bool encrypt, unsigned char const* key_data, size_t key_len, + bool cbc_mode, unsigned char* cbc_block) = 0; QPDF_DLL virtual void rijndael_process( unsigned char* in_data, unsigned char* out_data) = 0; diff --git a/libqpdf/AES_PDF_native.cc b/libqpdf/AES_PDF_native.cc index d6907ee3..697b3a37 100644 --- a/libqpdf/AES_PDF_native.cc +++ b/libqpdf/AES_PDF_native.cc @@ -7,10 +7,14 @@ #include #include #include +#include AES_PDF_native::AES_PDF_native(bool encrypt, unsigned char const* key, - size_t key_bytes) : + size_t key_bytes, bool cbc_mode, + unsigned char* cbc_block) : encrypt(encrypt), + cbc_mode(cbc_mode), + cbc_block(cbc_block), nrounds(0) { size_t keybits = 8 * key_bytes; @@ -44,12 +48,33 @@ AES_PDF_native::update(unsigned char* in_data, unsigned char* out_data) { if (this->encrypt) { + if (this->cbc_mode) + { + for (size_t i = 0; i < QPDFCryptoImpl::rijndael_buf_size; ++i) + { + in_data[i] ^= this->cbc_block[i]; + } + } rijndaelEncrypt(this->rk.get(), this->nrounds, in_data, out_data); + if (this->cbc_mode) + { + memcpy(this->cbc_block, out_data, + QPDFCryptoImpl::rijndael_buf_size); + } } else { rijndaelDecrypt(this->rk.get(), this->nrounds, in_data, out_data); + if (this->cbc_mode) + { + for (size_t i = 0; i < QPDFCryptoImpl::rijndael_buf_size; ++i) + { + out_data[i] ^= this->cbc_block[i]; + } + memcpy(this->cbc_block, in_data, + QPDFCryptoImpl::rijndael_buf_size); + } } } diff --git a/libqpdf/Pl_AES_PDF.cc b/libqpdf/Pl_AES_PDF.cc index a6756035..18cf3a4d 100644 --- a/libqpdf/Pl_AES_PDF.cc +++ b/libqpdf/Pl_AES_PDF.cc @@ -19,6 +19,7 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, cbc_mode(true), first(true), offset(0), + key_bytes(key_bytes), use_zero_iv(false), use_specified_iv(false), disable_padding(false) @@ -30,7 +31,6 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, std::memset(this->inbuf, 0, this->buf_size); std::memset(this->outbuf, 0, this->buf_size); std::memset(this->cbc_block, 0, this->buf_size); - this->crypto->rijndael_init(encrypt, this->key.get(), key_bytes); } Pl_AES_PDF::~Pl_AES_PDF() @@ -172,6 +172,7 @@ Pl_AES_PDF::flush(bool strip_padding) if (first) { first = false; + bool return_after_init = false; if (this->cbc_mode) { if (encrypt) @@ -196,37 +197,25 @@ Pl_AES_PDF::flush(bool strip_padding) // vector. There's nothing to write at this time. memcpy(this->cbc_block, this->inbuf, this->buf_size); this->offset = 0; - return; + return_after_init = true; } } + this->crypto->rijndael_init( + encrypt, this->key.get(), key_bytes, + this->cbc_mode, this->cbc_block); + if (return_after_init) + { + return; + } } if (this->encrypt) { - if (this->cbc_mode) - { - for (unsigned int i = 0; i < this->buf_size; ++i) - { - this->inbuf[i] ^= this->cbc_block[i]; - } - } this->crypto->rijndael_process(this->inbuf, this->outbuf); - if (this->cbc_mode) - { - memcpy(this->cbc_block, this->outbuf, this->buf_size); - } } else { this->crypto->rijndael_process(this->inbuf, this->outbuf); - if (this->cbc_mode) - { - for (unsigned int i = 0; i < this->buf_size; ++i) - { - this->outbuf[i] ^= this->cbc_block[i]; - } - memcpy(this->cbc_block, this->inbuf, this->buf_size); - } } unsigned int bytes = this->buf_size; if (strip_padding) diff --git a/libqpdf/QPDFCrypto_native.cc b/libqpdf/QPDFCrypto_native.cc index 971897dc..d078ba77 100644 --- a/libqpdf/QPDFCrypto_native.cc +++ b/libqpdf/QPDFCrypto_native.cc @@ -69,10 +69,12 @@ QPDFCrypto_native::SHA2_digest() void QPDFCrypto_native::rijndael_init( - bool encrypt, unsigned char const* key_data, size_t key_len) + bool encrypt, unsigned char const* key_data, size_t key_len, + bool cbc_mode, unsigned char* cbc_block) + { this->aes_pdf = std::make_shared( - encrypt, key_data, key_len); + encrypt, key_data, key_len, cbc_mode, cbc_block); } void diff --git a/libqpdf/qpdf/AES_PDF_native.hh b/libqpdf/qpdf/AES_PDF_native.hh index f663533b..d1f08631 100644 --- a/libqpdf/qpdf/AES_PDF_native.hh +++ b/libqpdf/qpdf/AES_PDF_native.hh @@ -10,13 +10,15 @@ class AES_PDF_native public: // key should be a pointer to key_bytes bytes of data AES_PDF_native(bool encrypt, unsigned char const* key, - size_t key_bytes); + size_t key_bytes, bool cbc_mode, unsigned char* cbc_block); ~AES_PDF_native(); void update(unsigned char* in_data, unsigned char* out_data); private: bool encrypt; + bool cbc_mode; + unsigned char* cbc_block; std::unique_ptr key; std::unique_ptr rk; unsigned int nrounds; diff --git a/libqpdf/qpdf/Pl_AES_PDF.hh b/libqpdf/qpdf/Pl_AES_PDF.hh index f8f44c70..4d0d5fb3 100644 --- a/libqpdf/qpdf/Pl_AES_PDF.hh +++ b/libqpdf/qpdf/Pl_AES_PDF.hh @@ -2,7 +2,6 @@ #define PL_AES_PDF_HH #include -#include #include #include @@ -47,7 +46,7 @@ class Pl_AES_PDF: public Pipeline void flush(bool discard_padding); void initializeVector(); - static unsigned int const buf_size = 16; + static unsigned int const buf_size = QPDFCryptoImpl::rijndael_buf_size; static bool use_static_iv; std::shared_ptr crypto; @@ -56,6 +55,7 @@ class Pl_AES_PDF: public Pipeline bool first; size_t offset; // offset into memory buffer std::unique_ptr key; + size_t key_bytes; unsigned char inbuf[buf_size]; unsigned char outbuf[buf_size]; unsigned char cbc_block[buf_size]; diff --git a/libqpdf/qpdf/QPDFCrypto_native.hh b/libqpdf/qpdf/QPDFCrypto_native.hh index 1f006d3c..dcfb6834 100644 --- a/libqpdf/qpdf/QPDFCrypto_native.hh +++ b/libqpdf/qpdf/QPDFCrypto_native.hh @@ -33,7 +33,8 @@ class QPDFCrypto_native: public QPDFCryptoImpl virtual std::string SHA2_digest(); virtual void rijndael_init( - bool encrypt, unsigned char const* key_data, size_t key_len); + bool encrypt, unsigned char const* key_data, size_t key_len, + bool cbc_mode, unsigned char* cbc_block); virtual void rijndael_process( unsigned char* in_data, unsigned char* out_data); virtual void rijndael_finalize();