mirror of https://github.com/qpdf/qpdf.git
SHA2: switch to pluggable crypto
This commit is contained in:
parent
eadc222ff9
commit
bb427bd117
|
@ -23,7 +23,7 @@
|
|||
#define QPDFCRYPTOIMPL_HH
|
||||
|
||||
#include <qpdf/DLL.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
// This class is part of qpdf's pluggable crypto provider support.
|
||||
// Most users won't need to know or care about this class, but you can
|
||||
|
@ -41,6 +41,8 @@ class QPDF_DLL_CLASS QPDFCryptoImpl
|
|||
QPDF_DLL
|
||||
virtual ~QPDFCryptoImpl() = default;
|
||||
|
||||
// Hashing
|
||||
|
||||
typedef unsigned char MD5_Digest[16];
|
||||
QPDF_DLL
|
||||
virtual void MD5_init() = 0;
|
||||
|
@ -51,6 +53,17 @@ class QPDF_DLL_CLASS QPDFCryptoImpl
|
|||
QPDF_DLL
|
||||
virtual void MD5_digest(MD5_Digest) = 0;
|
||||
|
||||
QPDF_DLL
|
||||
virtual void SHA2_init(int bits) = 0;
|
||||
QPDF_DLL
|
||||
virtual void SHA2_update(unsigned char const* data, size_t len) = 0;
|
||||
QPDF_DLL
|
||||
virtual void SHA2_finalize() = 0;
|
||||
QPDF_DLL
|
||||
virtual std::string SHA2_digest() = 0;
|
||||
|
||||
// Encryption/Decryption
|
||||
|
||||
// key_len of -1 means treat key_data as a null-terminated string
|
||||
QPDF_DLL
|
||||
virtual void RC4_init(unsigned char const* key_data, int key_len = -1) = 0;
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
#include <qpdf/Pl_SHA2.hh>
|
||||
#include <stdexcept>
|
||||
#include <cstdio>
|
||||
#include <qpdf/PointerHolder.hh>
|
||||
#include <qpdf/QUtil.hh>
|
||||
#include <qpdf/QPDFCryptoProvider.hh>
|
||||
|
||||
Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) :
|
||||
Pipeline("sha2", next),
|
||||
in_progress(false)
|
||||
{
|
||||
if (bits)
|
||||
{
|
||||
resetBits(bits);
|
||||
}
|
||||
}
|
||||
|
||||
Pl_SHA2::~Pl_SHA2()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Pl_SHA2::write(unsigned char* buf, size_t len)
|
||||
{
|
||||
if (! this->in_progress)
|
||||
{
|
||||
this->in_progress = true;
|
||||
}
|
||||
|
||||
// Write in chunks in case len is too big to fit in an int.
|
||||
// Assume int is at least 32 bits.
|
||||
static size_t const max_bytes = 1 << 30;
|
||||
size_t bytes_left = len;
|
||||
unsigned char* data = buf;
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
|
||||
this->crypto->SHA2_update(data, bytes);
|
||||
bytes_left -= bytes;
|
||||
data += bytes;
|
||||
}
|
||||
|
||||
if (this->getNext(true))
|
||||
{
|
||||
this->getNext()->write(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pl_SHA2::finish()
|
||||
{
|
||||
if (this->getNext(true))
|
||||
{
|
||||
this->getNext()->finish();
|
||||
}
|
||||
this->crypto->SHA2_finalize();
|
||||
this->in_progress = false;
|
||||
}
|
||||
|
||||
void
|
||||
Pl_SHA2::resetBits(int bits)
|
||||
{
|
||||
if (this->in_progress)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"bit reset requested for in-progress SHA2 Pipeline");
|
||||
}
|
||||
this->crypto = QPDFCryptoProvider::getImpl();
|
||||
this->crypto->SHA2_init(bits);
|
||||
}
|
||||
|
||||
std::string
|
||||
Pl_SHA2::getRawDigest()
|
||||
{
|
||||
if (this->in_progress)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"digest requested for in-progress SHA2 Pipeline");
|
||||
}
|
||||
return this->crypto->SHA2_digest();
|
||||
}
|
||||
|
||||
std::string
|
||||
Pl_SHA2::getHexDigest()
|
||||
{
|
||||
if (this->in_progress)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"digest requested for in-progress SHA2 Pipeline");
|
||||
}
|
||||
return QUtil::hex_encode(getRawDigest());
|
||||
}
|
|
@ -42,3 +42,27 @@ void
|
|||
QPDFCrypto_native::RC4_finalize()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
QPDFCrypto_native::SHA2_init(int bits)
|
||||
{
|
||||
this->sha2 = std::make_shared<SHA2_native>(bits);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFCrypto_native::SHA2_update(unsigned char const* data, size_t len)
|
||||
{
|
||||
this->sha2->update(data, len);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFCrypto_native::SHA2_finalize()
|
||||
{
|
||||
this->sha2->finalize();
|
||||
}
|
||||
|
||||
std::string
|
||||
QPDFCrypto_native::SHA2_digest()
|
||||
{
|
||||
return this->sha2->getRawDigest();
|
||||
}
|
||||
|
|
|
@ -1,93 +1,59 @@
|
|||
#include <qpdf/Pl_SHA2.hh>
|
||||
#include <qpdf/SHA2_native.hh>
|
||||
#include <stdexcept>
|
||||
#include <cstdio>
|
||||
#include <qpdf/PointerHolder.hh>
|
||||
#include <qpdf/QUtil.hh>
|
||||
|
||||
Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) :
|
||||
Pipeline("sha2", next),
|
||||
in_progress(false),
|
||||
bits(0)
|
||||
|
||||
SHA2_native::SHA2_native(int bits) :
|
||||
bits(bits)
|
||||
{
|
||||
if (bits)
|
||||
switch (bits)
|
||||
{
|
||||
resetBits(bits);
|
||||
}
|
||||
}
|
||||
|
||||
Pl_SHA2::~Pl_SHA2()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Pl_SHA2::badBits()
|
||||
{
|
||||
throw std::logic_error("Pl_SHA2 has unexpected value for bits");
|
||||
}
|
||||
|
||||
void
|
||||
Pl_SHA2::write(unsigned char* buf, size_t len)
|
||||
{
|
||||
if (! this->in_progress)
|
||||
{
|
||||
switch (bits)
|
||||
{
|
||||
case 256:
|
||||
sph_sha256_init(&this->ctx256);
|
||||
break;
|
||||
case 384:
|
||||
sph_sha384_init(&this->ctx384);
|
||||
break;
|
||||
case 512:
|
||||
sph_sha512_init(&this->ctx512);
|
||||
break;
|
||||
default:
|
||||
badBits();
|
||||
break;
|
||||
}
|
||||
this->in_progress = true;
|
||||
}
|
||||
|
||||
// Write in chunks in case len is too big to fit in an int.
|
||||
// Assume int is at least 32 bits.
|
||||
static size_t const max_bytes = 1 << 30;
|
||||
size_t bytes_left = len;
|
||||
unsigned char* data = buf;
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
|
||||
switch (bits)
|
||||
{
|
||||
case 256:
|
||||
sph_sha256(&this->ctx256, data, bytes);
|
||||
break;
|
||||
case 384:
|
||||
sph_sha384(&this->ctx384, data, bytes);
|
||||
break;
|
||||
case 512:
|
||||
sph_sha512(&this->ctx512, data, bytes);
|
||||
break;
|
||||
default:
|
||||
badBits();
|
||||
break;
|
||||
}
|
||||
bytes_left -= bytes;
|
||||
data += bytes;
|
||||
}
|
||||
|
||||
if (this->getNext(true))
|
||||
{
|
||||
this->getNext()->write(buf, len);
|
||||
case 256:
|
||||
sph_sha256_init(&this->ctx256);
|
||||
break;
|
||||
case 384:
|
||||
sph_sha384_init(&this->ctx384);
|
||||
break;
|
||||
case 512:
|
||||
sph_sha512_init(&this->ctx512);
|
||||
break;
|
||||
default:
|
||||
badBits();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pl_SHA2::finish()
|
||||
SHA2_native::badBits()
|
||||
{
|
||||
if (this->getNext(true))
|
||||
throw std::logic_error("SHA2_native has bits != 256, 384, or 512");
|
||||
}
|
||||
|
||||
void
|
||||
SHA2_native::update(unsigned char const* buf, size_t len)
|
||||
{
|
||||
switch (bits)
|
||||
{
|
||||
this->getNext()->finish();
|
||||
case 256:
|
||||
sph_sha256(&this->ctx256, buf, len);
|
||||
break;
|
||||
case 384:
|
||||
sph_sha384(&this->ctx384, buf, len);
|
||||
break;
|
||||
case 512:
|
||||
sph_sha512(&this->ctx512, buf, len);
|
||||
break;
|
||||
default:
|
||||
badBits();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SHA2_native::finalize()
|
||||
{
|
||||
switch (bits)
|
||||
{
|
||||
case 256:
|
||||
|
@ -103,26 +69,10 @@ Pl_SHA2::finish()
|
|||
badBits();
|
||||
break;
|
||||
}
|
||||
this->in_progress = false;
|
||||
}
|
||||
|
||||
void
|
||||
Pl_SHA2::resetBits(int bits)
|
||||
{
|
||||
if (this->in_progress)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"bit reset requested for in-progress SHA2 Pipeline");
|
||||
}
|
||||
if (! ((bits == 256) || (bits == 384) || (bits == 512)))
|
||||
{
|
||||
throw std::logic_error("Pl_SHA2 called with bits != 256, 384, or 512");
|
||||
}
|
||||
this->bits = bits;
|
||||
}
|
||||
|
||||
std::string
|
||||
Pl_SHA2::getRawDigest()
|
||||
SHA2_native::getRawDigest()
|
||||
{
|
||||
std::string result;
|
||||
switch (bits)
|
||||
|
@ -145,14 +95,3 @@ Pl_SHA2::getRawDigest()
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string
|
||||
Pl_SHA2::getHexDigest()
|
||||
{
|
||||
if (this->in_progress)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"digest requested for in-progress SHA2 Pipeline");
|
||||
}
|
||||
return QUtil::hex_encode(getRawDigest());
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ SRCS_libqpdf = \
|
|||
libqpdf/QUtil.cc \
|
||||
libqpdf/RC4.cc \
|
||||
libqpdf/RC4_native.cc \
|
||||
libqpdf/SHA2_native.cc \
|
||||
libqpdf/SecureRandomDataProvider.cc \
|
||||
libqpdf/SparseOHArray.cc \
|
||||
libqpdf/qpdf-c.cc \
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef PL_SHA2_HH
|
||||
#define PL_SHA2_HH
|
||||
|
||||
// Bits must be a supported number of bits, currently only 256, 384,
|
||||
// or 512. Passing 0 as bits leaves the pipeline uncommitted, in
|
||||
// which case resetBits must be called before the pipeline is used.
|
||||
// If a next is provided, this pipeline sends its output to its
|
||||
// successor unmodified. After calling finish, the SHA2 checksum of
|
||||
// the data that passed through the pipeline is available.
|
||||
|
||||
// This pipeline is reusable; i.e., it is safe to call write() after
|
||||
// calling finish(). The first call to write() after a call to
|
||||
// finish() initializes a new SHA2 object. resetBits may also be
|
||||
// called between finish and the next call to write.
|
||||
|
||||
#include <qpdf/Pipeline.hh>
|
||||
#include <qpdf/QPDFCryptoImpl.hh>
|
||||
#include <memory>
|
||||
|
||||
class Pl_SHA2: public Pipeline
|
||||
{
|
||||
public:
|
||||
QPDF_DLL
|
||||
Pl_SHA2(int bits = 0, Pipeline* next = 0);
|
||||
QPDF_DLL
|
||||
virtual ~Pl_SHA2();
|
||||
QPDF_DLL
|
||||
virtual void write(unsigned char*, size_t);
|
||||
QPDF_DLL
|
||||
virtual void finish();
|
||||
QPDF_DLL
|
||||
void resetBits(int bits);
|
||||
QPDF_DLL
|
||||
std::string getHexDigest();
|
||||
QPDF_DLL
|
||||
std::string getRawDigest();
|
||||
|
||||
private:
|
||||
bool in_progress;
|
||||
std::shared_ptr<QPDFCryptoImpl> crypto;
|
||||
};
|
||||
|
||||
#endif // PL_SHA2_HH
|
|
@ -5,6 +5,7 @@
|
|||
#include <qpdf/QPDFCryptoImpl.hh>
|
||||
#include <qpdf/MD5_native.hh>
|
||||
#include <qpdf/RC4_native.hh>
|
||||
#include <qpdf/SHA2_native.hh>
|
||||
#include <memory>
|
||||
|
||||
class QPDFCrypto_native: public QPDFCryptoImpl
|
||||
|
@ -25,9 +26,15 @@ class QPDFCrypto_native: public QPDFCryptoImpl
|
|||
unsigned char* out_data = 0);
|
||||
virtual void RC4_finalize();
|
||||
|
||||
virtual void SHA2_init(int bits);
|
||||
virtual void SHA2_update(unsigned char const* data, size_t len);
|
||||
virtual void SHA2_finalize();
|
||||
virtual std::string SHA2_digest();
|
||||
|
||||
private:
|
||||
std::shared_ptr<MD5_native> md5;
|
||||
std::shared_ptr<RC4_native> rc4;
|
||||
std::shared_ptr<SHA2_native> sha2;
|
||||
};
|
||||
|
||||
#endif // QPDFCRYPTO_NATIVE_HH
|
||||
|
|
|
@ -1,43 +1,21 @@
|
|||
#ifndef PL_SHA2_HH
|
||||
#define PL_SHA2_HH
|
||||
#ifndef SHA2_NATIVE_HH
|
||||
#define SHA2_NATIVE_HH
|
||||
|
||||
// Bits must be a supported number of bits, currently only 256, 384,
|
||||
// or 512. Passing 0 as bits leaves the pipeline uncommitted, in
|
||||
// which case resetBits must be called before the pipeline is used.
|
||||
// If a next is provided, this pipeline sends its output to its
|
||||
// successor unmodified. After calling finish, the SHA2 checksum of
|
||||
// the data that passed through the pipeline is available.
|
||||
|
||||
// This pipeline is reusable; i.e., it is safe to call write() after
|
||||
// calling finish(). The first call to write() after a call to
|
||||
// finish() initializes a new SHA2 object. resetBits may also be
|
||||
// called between finish and the next call to write.
|
||||
|
||||
#include <qpdf/Pipeline.hh>
|
||||
#include <sph/sph_sha2.h>
|
||||
#include <string>
|
||||
|
||||
class Pl_SHA2: public Pipeline
|
||||
class SHA2_native
|
||||
{
|
||||
public:
|
||||
QPDF_DLL
|
||||
Pl_SHA2(int bits = 0, Pipeline* next = 0);
|
||||
QPDF_DLL
|
||||
virtual ~Pl_SHA2();
|
||||
QPDF_DLL
|
||||
virtual void write(unsigned char*, size_t);
|
||||
QPDF_DLL
|
||||
virtual void finish();
|
||||
QPDF_DLL
|
||||
void resetBits(int bits);
|
||||
QPDF_DLL
|
||||
std::string getHexDigest();
|
||||
QPDF_DLL
|
||||
SHA2_native(int bits);
|
||||
~SHA2_native() = default;
|
||||
void update(unsigned char const* const, size_t);
|
||||
void finalize();
|
||||
std::string getRawDigest();
|
||||
|
||||
private:
|
||||
void badBits();
|
||||
|
||||
bool in_progress;
|
||||
int bits;
|
||||
sph_sha256_context ctx256;
|
||||
sph_sha384_context ctx384;
|
||||
|
@ -47,4 +25,4 @@ class Pl_SHA2: public Pipeline
|
|||
unsigned char sha512sum[64];
|
||||
};
|
||||
|
||||
#endif // PL_SHA2_HH
|
||||
#endif // SHA2_NATIVE_HH
|
||||
|
|
Loading…
Reference in New Issue