AES_PDF: switch to pluggable crypto

This commit is contained in:
Jay Berkenbilt 2019-11-04 13:59:19 -05:00
parent bb427bd117
commit c8cda4f965
8 changed files with 132 additions and 32 deletions

View File

@ -73,6 +73,15 @@ class QPDF_DLL_CLASS QPDFCryptoImpl
unsigned char* out_data = 0) = 0;
QPDF_DLL
virtual void RC4_finalize() = 0;
QPDF_DLL
virtual void rijndael_init(
bool encrypt, unsigned char const* key_data, size_t key_len) = 0;
QPDF_DLL
virtual void rijndael_process(
unsigned char* in_data, unsigned char* out_data) = 0;
QPDF_DLL
virtual void rijndael_finalize() = 0;
};
#endif // QPDFCRYPTOIMPL_HH

55
libqpdf/AES_PDF_native.cc Normal file
View File

@ -0,0 +1,55 @@
#include <qpdf/AES_PDF_native.hh>
#include <qpdf/QUtil.hh>
#include <cstring>
#include <assert.h>
#include <stdexcept>
#include <qpdf/rijndael.h>
#include <qpdf/QIntC.hh>
#include <string>
#include <stdlib.h>
AES_PDF_native::AES_PDF_native(bool encrypt, unsigned char const* key,
size_t key_bytes) :
encrypt(encrypt),
nrounds(0)
{
size_t keybits = 8 * key_bytes;
this->key = std::unique_ptr<unsigned char[]>(
new unsigned char[key_bytes],
std::default_delete<unsigned char[]>());
this->rk = std::unique_ptr<uint32_t[]>(
new uint32_t[RKLENGTH(keybits)],
std::default_delete<uint32_t[]>());
size_t rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t);
std::memcpy(this->key.get(), key, key_bytes);
std::memset(this->rk.get(), 0, rk_bytes);
if (encrypt)
{
this->nrounds = rijndaelSetupEncrypt(
this->rk.get(), this->key.get(), keybits);
}
else
{
this->nrounds = rijndaelSetupDecrypt(
this->rk.get(), this->key.get(), keybits);
}
}
AES_PDF_native::~AES_PDF_native()
{
}
void
AES_PDF_native::update(unsigned char* in_data, unsigned char* out_data)
{
if (this->encrypt)
{
rijndaelEncrypt(this->rk.get(),
this->nrounds, in_data, out_data);
}
else
{
rijndaelDecrypt(this->rk.get(),
this->nrounds, in_data, out_data);
}
}

View File

@ -3,8 +3,8 @@
#include <cstring>
#include <assert.h>
#include <stdexcept>
#include <qpdf/rijndael.h>
#include <qpdf/QIntC.hh>
#include <qpdf/QPDFCryptoProvider.hh>
#include <string>
#include <stdlib.h>
@ -14,38 +14,23 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next,
bool encrypt, unsigned char const* key,
size_t key_bytes) :
Pipeline(identifier, next),
crypto(QPDFCryptoProvider::getImpl()),
encrypt(encrypt),
cbc_mode(true),
first(true),
offset(0),
nrounds(0),
use_zero_iv(false),
use_specified_iv(false),
disable_padding(false)
{
size_t keybits = 8 * key_bytes;
assert(key_bytes == KEYLENGTH(keybits));
this->key = PointerHolder<unsigned char>(
true, new unsigned char[key_bytes]);
this->rk = PointerHolder<uint32_t>(
true, new uint32_t[RKLENGTH(keybits)]);
size_t rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t);
std::memcpy(this->key.getPointer(), key, key_bytes);
std::memset(this->rk.getPointer(), 0, rk_bytes);
this->key = std::unique_ptr<unsigned char[]>(
new unsigned char[key_bytes],
std::default_delete<unsigned char[]>());
std::memcpy(this->key.get(), key, key_bytes);
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);
if (encrypt)
{
this->nrounds = rijndaelSetupEncrypt(
this->rk.getPointer(), this->key.getPointer(), keybits);
}
else
{
this->nrounds = rijndaelSetupDecrypt(
this->rk.getPointer(), this->key.getPointer(), keybits);
}
assert(this->nrounds == NROUNDS(keybits));
this->crypto->rijndael_init(encrypt, this->key.get(), key_bytes);
}
Pl_AES_PDF::~Pl_AES_PDF()
@ -148,6 +133,7 @@ Pl_AES_PDF::finish()
}
flush(! this->disable_padding);
}
this->crypto->rijndael_finalize();
getNext()->finish();
}
@ -224,8 +210,7 @@ Pl_AES_PDF::flush(bool strip_padding)
this->inbuf[i] ^= this->cbc_block[i];
}
}
rijndaelEncrypt(this->rk.getPointer(),
this->nrounds, this->inbuf, this->outbuf);
this->crypto->rijndael_process(this->inbuf, this->outbuf);
if (this->cbc_mode)
{
memcpy(this->cbc_block, this->outbuf, this->buf_size);
@ -233,8 +218,7 @@ Pl_AES_PDF::flush(bool strip_padding)
}
else
{
rijndaelDecrypt(this->rk.getPointer(),
this->nrounds, this->inbuf, this->outbuf);
this->crypto->rijndael_process(this->inbuf, this->outbuf);
if (this->cbc_mode)
{
for (unsigned int i = 0; i < this->buf_size; ++i)

View File

@ -66,3 +66,23 @@ QPDFCrypto_native::SHA2_digest()
{
return this->sha2->getRawDigest();
}
void
QPDFCrypto_native::rijndael_init(
bool encrypt, unsigned char const* key_data, size_t key_len)
{
this->aes_pdf = std::make_shared<AES_PDF_native>(
encrypt, key_data, key_len);
}
void
QPDFCrypto_native::rijndael_process(unsigned char* in_data,
unsigned char* out_data)
{
this->aes_pdf->update(in_data, out_data);
}
void
QPDFCrypto_native::rijndael_finalize()
{
}

View File

@ -5,6 +5,7 @@ LDFLAGS_libqpdf = -Llibqpdf/$(OUTPUT_DIR)
LIBS_libqpdf = -lqpdf
SRCS_libqpdf = \
libqpdf/AES_PDF_native.cc \
libqpdf/BitStream.cc \
libqpdf/BitWriter.cc \
libqpdf/Buffer.cc \

View File

@ -0,0 +1,25 @@
#ifndef AES_PDF_NATIVE_HH
#define AES_PDF_NATIVE_HH
#include <cstdint>
#include <cstring>
#include <memory>
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);
~AES_PDF_native();
void update(unsigned char* in_data, unsigned char* out_data);
private:
bool encrypt;
std::unique_ptr<unsigned char[]> key;
std::unique_ptr<uint32_t[]> rk;
unsigned int nrounds;
};
#endif // AES_PDF_NATIVE_HH

View File

@ -3,9 +3,8 @@
#include <qpdf/Pipeline.hh>
#include <qpdf/qpdf-config.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <qpdf/QPDFCryptoImpl.hh>
#include <memory>
// This pipeline implements AES-128 and AES-256 with CBC and block
// padding as specified in the PDF specification.
@ -51,17 +50,16 @@ class Pl_AES_PDF: public Pipeline
static unsigned int const buf_size = 16;
static bool use_static_iv;
std::shared_ptr<QPDFCryptoImpl> crypto;
bool encrypt;
bool cbc_mode;
bool first;
size_t offset; // offset into memory buffer
PointerHolder<unsigned char> key;
PointerHolder<uint32_t> rk;
std::unique_ptr<unsigned char[]> key;
unsigned char inbuf[buf_size];
unsigned char outbuf[buf_size];
unsigned char cbc_block[buf_size];
unsigned char specified_iv[buf_size];
unsigned int nrounds;
bool use_zero_iv;
bool use_specified_iv;
bool disable_padding;

View File

@ -6,6 +6,7 @@
#include <qpdf/MD5_native.hh>
#include <qpdf/RC4_native.hh>
#include <qpdf/SHA2_native.hh>
#include <qpdf/AES_PDF_native.hh>
#include <memory>
class QPDFCrypto_native: public QPDFCryptoImpl
@ -31,10 +32,17 @@ class QPDFCrypto_native: public QPDFCryptoImpl
virtual void SHA2_finalize();
virtual std::string SHA2_digest();
virtual void rijndael_init(
bool encrypt, unsigned char const* key_data, size_t key_len);
virtual void rijndael_process(
unsigned char* in_data, unsigned char* out_data);
virtual void rijndael_finalize();
private:
std::shared_ptr<MD5_native> md5;
std::shared_ptr<RC4_native> rc4;
std::shared_ptr<SHA2_native> sha2;
std::shared_ptr<AES_PDF_native> aes_pdf;
};
#endif // QPDFCRYPTO_NATIVE_HH