Commit bb427bd11774f47f553257cdc0693f77b559654d

Authored by Jay Berkenbilt
1 parent eadc222f

SHA2: switch to pluggable crypto

include/qpdf/QPDFCryptoImpl.hh
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 #define QPDFCRYPTOIMPL_HH 23 #define QPDFCRYPTOIMPL_HH
24 24
25 #include <qpdf/DLL.h> 25 #include <qpdf/DLL.h>
26 -#include <cstring> 26 +#include <string>
27 27
28 // This class is part of qpdf's pluggable crypto provider support. 28 // This class is part of qpdf's pluggable crypto provider support.
29 // Most users won't need to know or care about this class, but you can 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,6 +41,8 @@ class QPDF_DLL_CLASS QPDFCryptoImpl
41 QPDF_DLL 41 QPDF_DLL
42 virtual ~QPDFCryptoImpl() = default; 42 virtual ~QPDFCryptoImpl() = default;
43 43
  44 + // Hashing
  45 +
44 typedef unsigned char MD5_Digest[16]; 46 typedef unsigned char MD5_Digest[16];
45 QPDF_DLL 47 QPDF_DLL
46 virtual void MD5_init() = 0; 48 virtual void MD5_init() = 0;
@@ -51,6 +53,17 @@ class QPDF_DLL_CLASS QPDFCryptoImpl @@ -51,6 +53,17 @@ class QPDF_DLL_CLASS QPDFCryptoImpl
51 QPDF_DLL 53 QPDF_DLL
52 virtual void MD5_digest(MD5_Digest) = 0; 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 // key_len of -1 means treat key_data as a null-terminated string 67 // key_len of -1 means treat key_data as a null-terminated string
55 QPDF_DLL 68 QPDF_DLL
56 virtual void RC4_init(unsigned char const* key_data, int key_len = -1) = 0; 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,3 +42,27 @@ void
42 QPDFCrypto_native::RC4_finalize() 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 #include <stdexcept> 2 #include <stdexcept>
3 #include <cstdio> 3 #include <cstdio>
4 #include <qpdf/PointerHolder.hh> 4 #include <qpdf/PointerHolder.hh>
5 #include <qpdf/QUtil.hh> 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 void 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 void 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 void 54 void
85 -Pl_SHA2::finish() 55 +SHA2_native::finalize()
86 { 56 {
87 - if (this->getNext(true))  
88 - {  
89 - this->getNext()->finish();  
90 - }  
91 switch (bits) 57 switch (bits)
92 { 58 {
93 case 256: 59 case 256:
@@ -103,26 +69,10 @@ Pl_SHA2::finish() @@ -103,26 +69,10 @@ Pl_SHA2::finish()
103 badBits(); 69 badBits();
104 break; 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 std::string 74 std::string
125 -Pl_SHA2::getRawDigest() 75 +SHA2_native::getRawDigest()
126 { 76 {
127 std::string result; 77 std::string result;
128 switch (bits) 78 switch (bits)
@@ -145,14 +95,3 @@ Pl_SHA2::getRawDigest() @@ -145,14 +95,3 @@ Pl_SHA2::getRawDigest()
145 } 95 }
146 return result; 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
@@ -79,6 +79,7 @@ SRCS_libqpdf = \ @@ -79,6 +79,7 @@ SRCS_libqpdf = \
79 libqpdf/QUtil.cc \ 79 libqpdf/QUtil.cc \
80 libqpdf/RC4.cc \ 80 libqpdf/RC4.cc \
81 libqpdf/RC4_native.cc \ 81 libqpdf/RC4_native.cc \
  82 + libqpdf/SHA2_native.cc \
82 libqpdf/SecureRandomDataProvider.cc \ 83 libqpdf/SecureRandomDataProvider.cc \
83 libqpdf/SparseOHArray.cc \ 84 libqpdf/SparseOHArray.cc \
84 libqpdf/qpdf-c.cc \ 85 libqpdf/qpdf-c.cc \
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,6 +5,7 @@
5 #include <qpdf/QPDFCryptoImpl.hh> 5 #include <qpdf/QPDFCryptoImpl.hh>
6 #include <qpdf/MD5_native.hh> 6 #include <qpdf/MD5_native.hh>
7 #include <qpdf/RC4_native.hh> 7 #include <qpdf/RC4_native.hh>
  8 +#include <qpdf/SHA2_native.hh>
8 #include <memory> 9 #include <memory>
9 10
10 class QPDFCrypto_native: public QPDFCryptoImpl 11 class QPDFCrypto_native: public QPDFCryptoImpl
@@ -25,9 +26,15 @@ class QPDFCrypto_native: public QPDFCryptoImpl @@ -25,9 +26,15 @@ class QPDFCrypto_native: public QPDFCryptoImpl
25 unsigned char* out_data = 0); 26 unsigned char* out_data = 0);
26 virtual void RC4_finalize(); 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 private: 34 private:
29 std::shared_ptr<MD5_native> md5; 35 std::shared_ptr<MD5_native> md5;
30 std::shared_ptr<RC4_native> rc4; 36 std::shared_ptr<RC4_native> rc4;
  37 + std::shared_ptr<SHA2_native> sha2;
31 }; 38 };
32 39
33 #endif // QPDFCRYPTO_NATIVE_HH 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 #include <sph/sph_sha2.h> 4 #include <sph/sph_sha2.h>
  5 +#include <string>
18 6
19 -class Pl_SHA2: public Pipeline 7 +class SHA2_native
20 { 8 {
21 public: 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 std::string getRawDigest(); 14 std::string getRawDigest();
36 15
37 private: 16 private:
38 void badBits(); 17 void badBits();
39 18
40 - bool in_progress;  
41 int bits; 19 int bits;
42 sph_sha256_context ctx256; 20 sph_sha256_context ctx256;
43 sph_sha384_context ctx384; 21 sph_sha384_context ctx384;
@@ -47,4 +25,4 @@ class Pl_SHA2: public Pipeline @@ -47,4 +25,4 @@ class Pl_SHA2: public Pipeline
47 unsigned char sha512sum[64]; 25 unsigned char sha512sum[64];
48 }; 26 };
49 27
50 -#endif // PL_SHA2_HH 28 +#endif // SHA2_NATIVE_HH