Commit bb427bd11774f47f553257cdc0693f77b559654d
1 parent
eadc222f
SHA2: switch to pluggable crypto
Showing
8 changed files
with
225 additions
and
128 deletions
include/qpdf/QPDFCryptoImpl.hh
| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | #define QPDFCRYPTOIMPL_HH |
| 24 | 24 | |
| 25 | 25 | #include <qpdf/DLL.h> |
| 26 | -#include <cstring> | |
| 26 | +#include <string> | |
| 27 | 27 | |
| 28 | 28 | // This class is part of qpdf's pluggable crypto provider support. |
| 29 | 29 | // Most users won't need to know or care about this class, but you can |
| ... | ... | @@ -41,6 +41,8 @@ class QPDF_DLL_CLASS QPDFCryptoImpl |
| 41 | 41 | QPDF_DLL |
| 42 | 42 | virtual ~QPDFCryptoImpl() = default; |
| 43 | 43 | |
| 44 | + // Hashing | |
| 45 | + | |
| 44 | 46 | typedef unsigned char MD5_Digest[16]; |
| 45 | 47 | QPDF_DLL |
| 46 | 48 | virtual void MD5_init() = 0; |
| ... | ... | @@ -51,6 +53,17 @@ class QPDF_DLL_CLASS QPDFCryptoImpl |
| 51 | 53 | QPDF_DLL |
| 52 | 54 | virtual void MD5_digest(MD5_Digest) = 0; |
| 53 | 55 | |
| 56 | + QPDF_DLL | |
| 57 | + virtual void SHA2_init(int bits) = 0; | |
| 58 | + QPDF_DLL | |
| 59 | + virtual void SHA2_update(unsigned char const* data, size_t len) = 0; | |
| 60 | + QPDF_DLL | |
| 61 | + virtual void SHA2_finalize() = 0; | |
| 62 | + QPDF_DLL | |
| 63 | + virtual std::string SHA2_digest() = 0; | |
| 64 | + | |
| 65 | + // Encryption/Decryption | |
| 66 | + | |
| 54 | 67 | // key_len of -1 means treat key_data as a null-terminated string |
| 55 | 68 | QPDF_DLL |
| 56 | 69 | virtual void RC4_init(unsigned char const* key_data, int key_len = -1) = 0; | ... | ... |
libqpdf/Pl_SHA2.cc
0 → 100644
| 1 | +#include <qpdf/Pl_SHA2.hh> | |
| 2 | +#include <stdexcept> | |
| 3 | +#include <cstdio> | |
| 4 | +#include <qpdf/PointerHolder.hh> | |
| 5 | +#include <qpdf/QUtil.hh> | |
| 6 | +#include <qpdf/QPDFCryptoProvider.hh> | |
| 7 | + | |
| 8 | +Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) : | |
| 9 | + Pipeline("sha2", next), | |
| 10 | + in_progress(false) | |
| 11 | +{ | |
| 12 | + if (bits) | |
| 13 | + { | |
| 14 | + resetBits(bits); | |
| 15 | + } | |
| 16 | +} | |
| 17 | + | |
| 18 | +Pl_SHA2::~Pl_SHA2() | |
| 19 | +{ | |
| 20 | +} | |
| 21 | + | |
| 22 | +void | |
| 23 | +Pl_SHA2::write(unsigned char* buf, size_t len) | |
| 24 | +{ | |
| 25 | + if (! this->in_progress) | |
| 26 | + { | |
| 27 | + this->in_progress = true; | |
| 28 | + } | |
| 29 | + | |
| 30 | + // Write in chunks in case len is too big to fit in an int. | |
| 31 | + // Assume int is at least 32 bits. | |
| 32 | + static size_t const max_bytes = 1 << 30; | |
| 33 | + size_t bytes_left = len; | |
| 34 | + unsigned char* data = buf; | |
| 35 | + while (bytes_left > 0) | |
| 36 | + { | |
| 37 | + size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left); | |
| 38 | + this->crypto->SHA2_update(data, bytes); | |
| 39 | + bytes_left -= bytes; | |
| 40 | + data += bytes; | |
| 41 | + } | |
| 42 | + | |
| 43 | + if (this->getNext(true)) | |
| 44 | + { | |
| 45 | + this->getNext()->write(buf, len); | |
| 46 | + } | |
| 47 | +} | |
| 48 | + | |
| 49 | +void | |
| 50 | +Pl_SHA2::finish() | |
| 51 | +{ | |
| 52 | + if (this->getNext(true)) | |
| 53 | + { | |
| 54 | + this->getNext()->finish(); | |
| 55 | + } | |
| 56 | + this->crypto->SHA2_finalize(); | |
| 57 | + this->in_progress = false; | |
| 58 | +} | |
| 59 | + | |
| 60 | +void | |
| 61 | +Pl_SHA2::resetBits(int bits) | |
| 62 | +{ | |
| 63 | + if (this->in_progress) | |
| 64 | + { | |
| 65 | + throw std::logic_error( | |
| 66 | + "bit reset requested for in-progress SHA2 Pipeline"); | |
| 67 | + } | |
| 68 | + this->crypto = QPDFCryptoProvider::getImpl(); | |
| 69 | + this->crypto->SHA2_init(bits); | |
| 70 | +} | |
| 71 | + | |
| 72 | +std::string | |
| 73 | +Pl_SHA2::getRawDigest() | |
| 74 | +{ | |
| 75 | + if (this->in_progress) | |
| 76 | + { | |
| 77 | + throw std::logic_error( | |
| 78 | + "digest requested for in-progress SHA2 Pipeline"); | |
| 79 | + } | |
| 80 | + return this->crypto->SHA2_digest(); | |
| 81 | +} | |
| 82 | + | |
| 83 | +std::string | |
| 84 | +Pl_SHA2::getHexDigest() | |
| 85 | +{ | |
| 86 | + if (this->in_progress) | |
| 87 | + { | |
| 88 | + throw std::logic_error( | |
| 89 | + "digest requested for in-progress SHA2 Pipeline"); | |
| 90 | + } | |
| 91 | + return QUtil::hex_encode(getRawDigest()); | |
| 92 | +} | ... | ... |
libqpdf/QPDFCrypto_native.cc
| ... | ... | @@ -42,3 +42,27 @@ void |
| 42 | 42 | QPDFCrypto_native::RC4_finalize() |
| 43 | 43 | { |
| 44 | 44 | } |
| 45 | + | |
| 46 | +void | |
| 47 | +QPDFCrypto_native::SHA2_init(int bits) | |
| 48 | +{ | |
| 49 | + this->sha2 = std::make_shared<SHA2_native>(bits); | |
| 50 | +} | |
| 51 | + | |
| 52 | +void | |
| 53 | +QPDFCrypto_native::SHA2_update(unsigned char const* data, size_t len) | |
| 54 | +{ | |
| 55 | + this->sha2->update(data, len); | |
| 56 | +} | |
| 57 | + | |
| 58 | +void | |
| 59 | +QPDFCrypto_native::SHA2_finalize() | |
| 60 | +{ | |
| 61 | + this->sha2->finalize(); | |
| 62 | +} | |
| 63 | + | |
| 64 | +std::string | |
| 65 | +QPDFCrypto_native::SHA2_digest() | |
| 66 | +{ | |
| 67 | + return this->sha2->getRawDigest(); | |
| 68 | +} | ... | ... |
libqpdf/SHA2_native.cc
| 1 | -#include <qpdf/Pl_SHA2.hh> | |
| 1 | +#include <qpdf/SHA2_native.hh> | |
| 2 | 2 | #include <stdexcept> |
| 3 | 3 | #include <cstdio> |
| 4 | 4 | #include <qpdf/PointerHolder.hh> |
| 5 | 5 | #include <qpdf/QUtil.hh> |
| 6 | 6 | |
| 7 | -Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) : | |
| 8 | - Pipeline("sha2", next), | |
| 9 | - in_progress(false), | |
| 10 | - bits(0) | |
| 7 | + | |
| 8 | +SHA2_native::SHA2_native(int bits) : | |
| 9 | + bits(bits) | |
| 11 | 10 | { |
| 12 | - if (bits) | |
| 11 | + switch (bits) | |
| 13 | 12 | { |
| 14 | - resetBits(bits); | |
| 13 | + case 256: | |
| 14 | + sph_sha256_init(&this->ctx256); | |
| 15 | + break; | |
| 16 | + case 384: | |
| 17 | + sph_sha384_init(&this->ctx384); | |
| 18 | + break; | |
| 19 | + case 512: | |
| 20 | + sph_sha512_init(&this->ctx512); | |
| 21 | + break; | |
| 22 | + default: | |
| 23 | + badBits(); | |
| 24 | + break; | |
| 15 | 25 | } |
| 16 | 26 | } |
| 17 | 27 | |
| 18 | -Pl_SHA2::~Pl_SHA2() | |
| 19 | -{ | |
| 20 | -} | |
| 21 | - | |
| 22 | 28 | void |
| 23 | -Pl_SHA2::badBits() | |
| 29 | +SHA2_native::badBits() | |
| 24 | 30 | { |
| 25 | - throw std::logic_error("Pl_SHA2 has unexpected value for bits"); | |
| 31 | + throw std::logic_error("SHA2_native has bits != 256, 384, or 512"); | |
| 26 | 32 | } |
| 27 | 33 | |
| 28 | 34 | void |
| 29 | -Pl_SHA2::write(unsigned char* buf, size_t len) | |
| 35 | +SHA2_native::update(unsigned char const* buf, size_t len) | |
| 30 | 36 | { |
| 31 | - if (! this->in_progress) | |
| 32 | - { | |
| 33 | - switch (bits) | |
| 34 | - { | |
| 35 | - case 256: | |
| 36 | - sph_sha256_init(&this->ctx256); | |
| 37 | - break; | |
| 38 | - case 384: | |
| 39 | - sph_sha384_init(&this->ctx384); | |
| 40 | - break; | |
| 41 | - case 512: | |
| 42 | - sph_sha512_init(&this->ctx512); | |
| 43 | - break; | |
| 44 | - default: | |
| 45 | - badBits(); | |
| 46 | - break; | |
| 47 | - } | |
| 48 | - this->in_progress = true; | |
| 49 | - } | |
| 50 | - | |
| 51 | - // Write in chunks in case len is too big to fit in an int. | |
| 52 | - // Assume int is at least 32 bits. | |
| 53 | - static size_t const max_bytes = 1 << 30; | |
| 54 | - size_t bytes_left = len; | |
| 55 | - unsigned char* data = buf; | |
| 56 | - while (bytes_left > 0) | |
| 57 | - { | |
| 58 | - size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left); | |
| 59 | - switch (bits) | |
| 60 | - { | |
| 61 | - case 256: | |
| 62 | - sph_sha256(&this->ctx256, data, bytes); | |
| 63 | - break; | |
| 64 | - case 384: | |
| 65 | - sph_sha384(&this->ctx384, data, bytes); | |
| 66 | - break; | |
| 67 | - case 512: | |
| 68 | - sph_sha512(&this->ctx512, data, bytes); | |
| 69 | - break; | |
| 70 | - default: | |
| 71 | - badBits(); | |
| 72 | - break; | |
| 73 | - } | |
| 74 | - bytes_left -= bytes; | |
| 75 | - data += bytes; | |
| 76 | - } | |
| 77 | - | |
| 78 | - if (this->getNext(true)) | |
| 37 | + switch (bits) | |
| 79 | 38 | { |
| 80 | - this->getNext()->write(buf, len); | |
| 39 | + case 256: | |
| 40 | + sph_sha256(&this->ctx256, buf, len); | |
| 41 | + break; | |
| 42 | + case 384: | |
| 43 | + sph_sha384(&this->ctx384, buf, len); | |
| 44 | + break; | |
| 45 | + case 512: | |
| 46 | + sph_sha512(&this->ctx512, buf, len); | |
| 47 | + break; | |
| 48 | + default: | |
| 49 | + badBits(); | |
| 50 | + break; | |
| 81 | 51 | } |
| 82 | 52 | } |
| 83 | 53 | |
| 84 | 54 | void |
| 85 | -Pl_SHA2::finish() | |
| 55 | +SHA2_native::finalize() | |
| 86 | 56 | { |
| 87 | - if (this->getNext(true)) | |
| 88 | - { | |
| 89 | - this->getNext()->finish(); | |
| 90 | - } | |
| 91 | 57 | switch (bits) |
| 92 | 58 | { |
| 93 | 59 | case 256: |
| ... | ... | @@ -103,26 +69,10 @@ Pl_SHA2::finish() |
| 103 | 69 | badBits(); |
| 104 | 70 | break; |
| 105 | 71 | } |
| 106 | - this->in_progress = false; | |
| 107 | -} | |
| 108 | - | |
| 109 | -void | |
| 110 | -Pl_SHA2::resetBits(int bits) | |
| 111 | -{ | |
| 112 | - if (this->in_progress) | |
| 113 | - { | |
| 114 | - throw std::logic_error( | |
| 115 | - "bit reset requested for in-progress SHA2 Pipeline"); | |
| 116 | - } | |
| 117 | - if (! ((bits == 256) || (bits == 384) || (bits == 512))) | |
| 118 | - { | |
| 119 | - throw std::logic_error("Pl_SHA2 called with bits != 256, 384, or 512"); | |
| 120 | - } | |
| 121 | - this->bits = bits; | |
| 122 | 72 | } |
| 123 | 73 | |
| 124 | 74 | std::string |
| 125 | -Pl_SHA2::getRawDigest() | |
| 75 | +SHA2_native::getRawDigest() | |
| 126 | 76 | { |
| 127 | 77 | std::string result; |
| 128 | 78 | switch (bits) |
| ... | ... | @@ -145,14 +95,3 @@ Pl_SHA2::getRawDigest() |
| 145 | 95 | } |
| 146 | 96 | return result; |
| 147 | 97 | } |
| 148 | - | |
| 149 | -std::string | |
| 150 | -Pl_SHA2::getHexDigest() | |
| 151 | -{ | |
| 152 | - if (this->in_progress) | |
| 153 | - { | |
| 154 | - throw std::logic_error( | |
| 155 | - "digest requested for in-progress SHA2 Pipeline"); | |
| 156 | - } | |
| 157 | - return QUtil::hex_encode(getRawDigest()); | |
| 158 | -} | ... | ... |
libqpdf/build.mk
libqpdf/qpdf/Pl_SHA2.hh
0 → 100644
| 1 | +#ifndef PL_SHA2_HH | |
| 2 | +#define PL_SHA2_HH | |
| 3 | + | |
| 4 | +// Bits must be a supported number of bits, currently only 256, 384, | |
| 5 | +// or 512. Passing 0 as bits leaves the pipeline uncommitted, in | |
| 6 | +// which case resetBits must be called before the pipeline is used. | |
| 7 | +// If a next is provided, this pipeline sends its output to its | |
| 8 | +// successor unmodified. After calling finish, the SHA2 checksum of | |
| 9 | +// the data that passed through the pipeline is available. | |
| 10 | + | |
| 11 | +// This pipeline is reusable; i.e., it is safe to call write() after | |
| 12 | +// calling finish(). The first call to write() after a call to | |
| 13 | +// finish() initializes a new SHA2 object. resetBits may also be | |
| 14 | +// called between finish and the next call to write. | |
| 15 | + | |
| 16 | +#include <qpdf/Pipeline.hh> | |
| 17 | +#include <qpdf/QPDFCryptoImpl.hh> | |
| 18 | +#include <memory> | |
| 19 | + | |
| 20 | +class Pl_SHA2: public Pipeline | |
| 21 | +{ | |
| 22 | + public: | |
| 23 | + QPDF_DLL | |
| 24 | + Pl_SHA2(int bits = 0, Pipeline* next = 0); | |
| 25 | + QPDF_DLL | |
| 26 | + virtual ~Pl_SHA2(); | |
| 27 | + QPDF_DLL | |
| 28 | + virtual void write(unsigned char*, size_t); | |
| 29 | + QPDF_DLL | |
| 30 | + virtual void finish(); | |
| 31 | + QPDF_DLL | |
| 32 | + void resetBits(int bits); | |
| 33 | + QPDF_DLL | |
| 34 | + std::string getHexDigest(); | |
| 35 | + QPDF_DLL | |
| 36 | + std::string getRawDigest(); | |
| 37 | + | |
| 38 | + private: | |
| 39 | + bool in_progress; | |
| 40 | + std::shared_ptr<QPDFCryptoImpl> crypto; | |
| 41 | +}; | |
| 42 | + | |
| 43 | +#endif // PL_SHA2_HH | ... | ... |
libqpdf/qpdf/QPDFCrypto_native.hh
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | #include <qpdf/QPDFCryptoImpl.hh> |
| 6 | 6 | #include <qpdf/MD5_native.hh> |
| 7 | 7 | #include <qpdf/RC4_native.hh> |
| 8 | +#include <qpdf/SHA2_native.hh> | |
| 8 | 9 | #include <memory> |
| 9 | 10 | |
| 10 | 11 | class QPDFCrypto_native: public QPDFCryptoImpl |
| ... | ... | @@ -25,9 +26,15 @@ class QPDFCrypto_native: public QPDFCryptoImpl |
| 25 | 26 | unsigned char* out_data = 0); |
| 26 | 27 | virtual void RC4_finalize(); |
| 27 | 28 | |
| 29 | + virtual void SHA2_init(int bits); | |
| 30 | + virtual void SHA2_update(unsigned char const* data, size_t len); | |
| 31 | + virtual void SHA2_finalize(); | |
| 32 | + virtual std::string SHA2_digest(); | |
| 33 | + | |
| 28 | 34 | private: |
| 29 | 35 | std::shared_ptr<MD5_native> md5; |
| 30 | 36 | std::shared_ptr<RC4_native> rc4; |
| 37 | + std::shared_ptr<SHA2_native> sha2; | |
| 31 | 38 | }; |
| 32 | 39 | |
| 33 | 40 | #endif // QPDFCRYPTO_NATIVE_HH | ... | ... |
libqpdf/qpdf/SHA2_native.hh
| 1 | -#ifndef PL_SHA2_HH | |
| 2 | -#define PL_SHA2_HH | |
| 1 | +#ifndef SHA2_NATIVE_HH | |
| 2 | +#define SHA2_NATIVE_HH | |
| 3 | 3 | |
| 4 | -// Bits must be a supported number of bits, currently only 256, 384, | |
| 5 | -// or 512. Passing 0 as bits leaves the pipeline uncommitted, in | |
| 6 | -// which case resetBits must be called before the pipeline is used. | |
| 7 | -// If a next is provided, this pipeline sends its output to its | |
| 8 | -// successor unmodified. After calling finish, the SHA2 checksum of | |
| 9 | -// the data that passed through the pipeline is available. | |
| 10 | - | |
| 11 | -// This pipeline is reusable; i.e., it is safe to call write() after | |
| 12 | -// calling finish(). The first call to write() after a call to | |
| 13 | -// finish() initializes a new SHA2 object. resetBits may also be | |
| 14 | -// called between finish and the next call to write. | |
| 15 | - | |
| 16 | -#include <qpdf/Pipeline.hh> | |
| 17 | 4 | #include <sph/sph_sha2.h> |
| 5 | +#include <string> | |
| 18 | 6 | |
| 19 | -class Pl_SHA2: public Pipeline | |
| 7 | +class SHA2_native | |
| 20 | 8 | { |
| 21 | 9 | public: |
| 22 | - QPDF_DLL | |
| 23 | - Pl_SHA2(int bits = 0, Pipeline* next = 0); | |
| 24 | - QPDF_DLL | |
| 25 | - virtual ~Pl_SHA2(); | |
| 26 | - QPDF_DLL | |
| 27 | - virtual void write(unsigned char*, size_t); | |
| 28 | - QPDF_DLL | |
| 29 | - virtual void finish(); | |
| 30 | - QPDF_DLL | |
| 31 | - void resetBits(int bits); | |
| 32 | - QPDF_DLL | |
| 33 | - std::string getHexDigest(); | |
| 34 | - QPDF_DLL | |
| 10 | + SHA2_native(int bits); | |
| 11 | + ~SHA2_native() = default; | |
| 12 | + void update(unsigned char const* const, size_t); | |
| 13 | + void finalize(); | |
| 35 | 14 | std::string getRawDigest(); |
| 36 | 15 | |
| 37 | 16 | private: |
| 38 | 17 | void badBits(); |
| 39 | 18 | |
| 40 | - bool in_progress; | |
| 41 | 19 | int bits; |
| 42 | 20 | sph_sha256_context ctx256; |
| 43 | 21 | sph_sha384_context ctx384; |
| ... | ... | @@ -47,4 +25,4 @@ class Pl_SHA2: public Pipeline |
| 47 | 25 | unsigned char sha512sum[64]; |
| 48 | 26 | }; |
| 49 | 27 | |
| 50 | -#endif // PL_SHA2_HH | |
| 28 | +#endif // SHA2_NATIVE_HH | ... | ... |