Commit 9b42f526dffd5e1518ff3d83564eb09111ac5f0d

Authored by Jay Berkenbilt
1 parent 77458416

Update AES classes to work with 256-bit keys

libqpdf/Pl_AES_PDF.cc
@@ -15,19 +15,24 @@ @@ -15,19 +15,24 @@
15 bool Pl_AES_PDF::use_static_iv = false; 15 bool Pl_AES_PDF::use_static_iv = false;
16 16
17 Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, 17 Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next,
18 - bool encrypt, unsigned char const key[key_size]) : 18 + bool encrypt, unsigned char const* key,
  19 + unsigned int key_bytes) :
19 Pipeline(identifier, next), 20 Pipeline(identifier, next),
20 encrypt(encrypt), 21 encrypt(encrypt),
21 cbc_mode(true), 22 cbc_mode(true),
22 first(true), 23 first(true),
23 offset(0), 24 offset(0),
24 - nrounds(0) 25 + nrounds(0),
  26 + use_zero_iv(false),
  27 + disable_padding(false)
25 { 28 {
26 - static int const keybits = 128;  
27 - assert(key_size == KEYLENGTH(keybits));  
28 - assert(sizeof(this->rk) / sizeof(uint32_t) == RKLENGTH(keybits));  
29 - std::memcpy(this->key, key, key_size);  
30 - std::memset(this->rk, 0, sizeof(this->rk)); 29 + unsigned int keybits = 8 * key_bytes;
  30 + assert(key_bytes == KEYLENGTH(keybits));
  31 + this->key = new unsigned char[key_bytes];
  32 + this->rk = new uint32_t[RKLENGTH(keybits)];
  33 + unsigned int rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t);
  34 + std::memcpy(this->key, key, key_bytes);
  35 + std::memset(this->rk, 0, rk_bytes);
31 std::memset(this->inbuf, 0, this->buf_size); 36 std::memset(this->inbuf, 0, this->buf_size);
32 std::memset(this->outbuf, 0, this->buf_size); 37 std::memset(this->outbuf, 0, this->buf_size);
33 std::memset(this->cbc_block, 0, this->buf_size); 38 std::memset(this->cbc_block, 0, this->buf_size);
@@ -44,7 +49,20 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, @@ -44,7 +49,20 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next,
44 49
45 Pl_AES_PDF::~Pl_AES_PDF() 50 Pl_AES_PDF::~Pl_AES_PDF()
46 { 51 {
47 - // nothing needed 52 + delete [] this->key;
  53 + delete [] this->rk;
  54 +}
  55 +
  56 +void
  57 +Pl_AES_PDF::useZeroIV()
  58 +{
  59 + this->use_zero_iv = true;
  60 +}
  61 +
  62 +void
  63 +Pl_AES_PDF::disablePadding()
  64 +{
  65 + this->disable_padding = true;
48 } 66 }
49 67
50 void 68 void
@@ -90,13 +108,16 @@ Pl_AES_PDF::finish() @@ -90,13 +108,16 @@ Pl_AES_PDF::finish()
90 { 108 {
91 flush(false); 109 flush(false);
92 } 110 }
93 - // Pad as described in section 3.5.1 of version 1.7 of the PDF  
94 - // specification, including providing an entire block of padding  
95 - // if the input was a multiple of 16 bytes.  
96 - unsigned char pad = (unsigned char) (this->buf_size - this->offset);  
97 - memset(this->inbuf + this->offset, pad, pad);  
98 - this->offset = this->buf_size;  
99 - flush(false); 111 + if (! this->disable_padding)
  112 + {
  113 + // Pad as described in section 3.5.1 of version 1.7 of the PDF
  114 + // specification, including providing an entire block of padding
  115 + // if the input was a multiple of 16 bytes.
  116 + unsigned char pad = (unsigned char) (this->buf_size - this->offset);
  117 + memset(this->inbuf + this->offset, pad, pad);
  118 + this->offset = this->buf_size;
  119 + flush(false);
  120 + }
100 } 121 }
101 else 122 else
102 { 123 {
@@ -112,7 +133,7 @@ Pl_AES_PDF::finish() @@ -112,7 +133,7 @@ Pl_AES_PDF::finish()
112 this->buf_size - this->offset); 133 this->buf_size - this->offset);
113 this->offset = this->buf_size; 134 this->offset = this->buf_size;
114 } 135 }
115 - flush(true); 136 + flush(! this->disable_padding);
116 } 137 }
117 getNext()->finish(); 138 getNext()->finish();
118 } 139 }
@@ -136,6 +157,13 @@ Pl_AES_PDF::initializeVector() @@ -136,6 +157,13 @@ Pl_AES_PDF::initializeVector()
136 this->cbc_block[i] = 14 * (1 + i); 157 this->cbc_block[i] = 14 * (1 + i);
137 } 158 }
138 } 159 }
  160 + else if (use_zero_iv)
  161 + {
  162 + for (unsigned int i = 0; i < this->buf_size; ++i)
  163 + {
  164 + this->cbc_block[i] = 0;
  165 + }
  166 + }
139 else 167 else
140 { 168 {
141 for (unsigned int i = 0; i < this->buf_size; ++i) 169 for (unsigned int i = 0; i < this->buf_size; ++i)
@@ -157,12 +185,21 @@ Pl_AES_PDF::flush(bool strip_padding) @@ -157,12 +185,21 @@ Pl_AES_PDF::flush(bool strip_padding)
157 { 185 {
158 if (encrypt) 186 if (encrypt)
159 { 187 {
160 - // Set cbc_block to a random initialization vector and  
161 - // write it to the output stream 188 + // Set cbc_block to the initialization vector, and if
  189 + // not zero, write it to the output stream.
162 initializeVector(); 190 initializeVector();
163 - getNext()->write(this->cbc_block, this->buf_size); 191 + if (! this->use_zero_iv)
  192 + {
  193 + getNext()->write(this->cbc_block, this->buf_size);
  194 + }
164 } 195 }
165 - else 196 + else if (this->use_zero_iv)
  197 + {
  198 + // Initialize vector with zeroes; zero vector was not
  199 + // written to the beginning of the input file.
  200 + initializeVector();
  201 + }
  202 + else
166 { 203 {
167 // Take the first block of input as the initialization 204 // Take the first block of input as the initialization
168 // vector. There's nothing to write at this time. 205 // vector. There's nothing to write at this time.
libqpdf/QPDFWriter.cc
@@ -815,13 +815,14 @@ QPDFWriter::pushEncryptionFilter() @@ -815,13 +815,14 @@ QPDFWriter::pushEncryptionFilter()
815 { 815 {
816 p = new Pl_AES_PDF( 816 p = new Pl_AES_PDF(
817 "aes stream encryption", this->pipeline, true, 817 "aes stream encryption", this->pipeline, true,
818 - (unsigned char*) this->cur_data_key.c_str()); 818 + (unsigned char*) this->cur_data_key.c_str(),
  819 + (unsigned int)this->cur_data_key.length());
819 } 820 }
820 else 821 else
821 { 822 {
822 p = new Pl_RC4("rc4 stream encryption", this->pipeline, 823 p = new Pl_RC4("rc4 stream encryption", this->pipeline,
823 (unsigned char*) this->cur_data_key.c_str(), 824 (unsigned char*) this->cur_data_key.c_str(),
824 - (int)this->cur_data_key.length()); 825 + (unsigned int)this->cur_data_key.length());
825 } 826 }
826 pushPipeline(p); 827 pushPipeline(p);
827 } 828 }
@@ -1415,7 +1416,8 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level, @@ -1415,7 +1416,8 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
1415 { 1416 {
1416 Pl_Buffer bufpl("encrypted string"); 1417 Pl_Buffer bufpl("encrypted string");
1417 Pl_AES_PDF pl("aes encrypt string", &bufpl, true, 1418 Pl_AES_PDF pl("aes encrypt string", &bufpl, true,
1418 - (unsigned char const*)this->cur_data_key.c_str()); 1419 + (unsigned char const*)this->cur_data_key.c_str(),
  1420 + (unsigned int)this->cur_data_key.length());
1419 pl.write((unsigned char*) val.c_str(), val.length()); 1421 pl.write((unsigned char*) val.c_str(), val.length());
1420 pl.finish(); 1422 pl.finish();
1421 Buffer* buf = bufpl.getBuffer(); 1423 Buffer* buf = bufpl.getBuffer();
libqpdf/QPDF_encryption.cc
@@ -674,10 +674,10 @@ QPDF::decryptString(std::string&amp; str, int objid, int generation) @@ -674,10 +674,10 @@ QPDF::decryptString(std::string&amp; str, int objid, int generation)
674 if (use_aes) 674 if (use_aes)
675 { 675 {
676 QTC::TC("qpdf", "QPDF_encryption aes decode string"); 676 QTC::TC("qpdf", "QPDF_encryption aes decode string");
677 - assert(key.length() == Pl_AES_PDF::key_size);  
678 Pl_Buffer bufpl("decrypted string"); 677 Pl_Buffer bufpl("decrypted string");
679 Pl_AES_PDF pl("aes decrypt string", &bufpl, false, 678 Pl_AES_PDF pl("aes decrypt string", &bufpl, false,
680 - (unsigned char const*)key.c_str()); 679 + (unsigned char const*)key.c_str(),
  680 + (unsigned int)key.length());
681 pl.write((unsigned char*)str.c_str(), str.length()); 681 pl.write((unsigned char*)str.c_str(), str.length());
682 pl.finish(); 682 pl.finish();
683 PointerHolder<Buffer> buf = bufpl.getBuffer(); 683 PointerHolder<Buffer> buf = bufpl.getBuffer();
@@ -794,15 +794,16 @@ QPDF::decryptStream(Pipeline*&amp; pipeline, int objid, int generation, @@ -794,15 +794,16 @@ QPDF::decryptStream(Pipeline*&amp; pipeline, int objid, int generation,
794 if (use_aes) 794 if (use_aes)
795 { 795 {
796 QTC::TC("qpdf", "QPDF_encryption aes decode stream"); 796 QTC::TC("qpdf", "QPDF_encryption aes decode stream");
797 - assert(key.length() == Pl_AES_PDF::key_size);  
798 pipeline = new Pl_AES_PDF("AES stream decryption", pipeline, 797 pipeline = new Pl_AES_PDF("AES stream decryption", pipeline,
799 - false, (unsigned char*) key.c_str()); 798 + false, (unsigned char*) key.c_str(),
  799 + (unsigned int) key.length());
800 } 800 }
801 else 801 else
802 { 802 {
803 QTC::TC("qpdf", "QPDF_encryption rc4 decode stream"); 803 QTC::TC("qpdf", "QPDF_encryption rc4 decode stream");
804 pipeline = new Pl_RC4("RC4 stream decryption", pipeline, 804 pipeline = new Pl_RC4("RC4 stream decryption", pipeline,
805 - (unsigned char*) key.c_str(), (int)key.length()); 805 + (unsigned char*) key.c_str(),
  806 + (unsigned int) key.length());
806 } 807 }
807 heap.push_back(pipeline); 808 heap.push_back(pipeline);
808 } 809 }
libqpdf/qpdf/Pl_AES_PDF.hh
@@ -7,17 +7,16 @@ @@ -7,17 +7,16 @@
7 # include <stdint.h> 7 # include <stdint.h>
8 #endif 8 #endif
9 9
10 -// This pipeline implements AES-128 with CBC and block padding as  
11 -// specified in the PDF specification. 10 +// This pipeline implements AES-128 and AES-256 with CBC and block
  11 +// padding as specified in the PDF specification.
12 12
13 class Pl_AES_PDF: public Pipeline 13 class Pl_AES_PDF: public Pipeline
14 { 14 {
15 public: 15 public:
16 - // key_data should be a pointer to key_size bytes of data  
17 - static unsigned int const key_size = 16;  
18 QPDF_DLL 16 QPDF_DLL
  17 + // key should be a pointer to key_bytes bytes of data
19 Pl_AES_PDF(char const* identifier, Pipeline* next, 18 Pl_AES_PDF(char const* identifier, Pipeline* next,
20 - bool encrypt, unsigned char const key[key_size]); 19 + bool encrypt, unsigned char const* key, unsigned int key_bytes);
21 QPDF_DLL 20 QPDF_DLL
22 virtual ~Pl_AES_PDF(); 21 virtual ~Pl_AES_PDF();
23 22
@@ -26,6 +25,13 @@ class Pl_AES_PDF: public Pipeline @@ -26,6 +25,13 @@ class Pl_AES_PDF: public Pipeline
26 QPDF_DLL 25 QPDF_DLL
27 virtual void finish(); 26 virtual void finish();
28 27
  28 + // Use zero initialization vector; needed for AESV3
  29 + QPDF_DLL
  30 + void useZeroIV();
  31 + // Disable padding; needed for AESV3
  32 + QPDF_DLL
  33 + void disablePadding();
  34 +
29 // For testing only; PDF always uses CBC 35 // For testing only; PDF always uses CBC
30 QPDF_DLL 36 QPDF_DLL
31 void disableCBC(); 37 void disableCBC();
@@ -44,12 +50,14 @@ class Pl_AES_PDF: public Pipeline @@ -44,12 +50,14 @@ class Pl_AES_PDF: public Pipeline
44 bool cbc_mode; 50 bool cbc_mode;
45 bool first; 51 bool first;
46 size_t offset; // offset into memory buffer 52 size_t offset; // offset into memory buffer
47 - unsigned char key[key_size];  
48 - uint32_t rk[key_size + 28]; 53 + unsigned char* key;
  54 + uint32_t* rk;
49 unsigned char inbuf[buf_size]; 55 unsigned char inbuf[buf_size];
50 unsigned char outbuf[buf_size]; 56 unsigned char outbuf[buf_size];
51 unsigned char cbc_block[buf_size]; 57 unsigned char cbc_block[buf_size];
52 unsigned int nrounds; 58 unsigned int nrounds;
  59 + bool use_zero_iv;
  60 + bool disable_padding;
53 }; 61 };
54 62
55 #endif // __PL_AES_PDF_HH__ 63 #endif // __PL_AES_PDF_HH__
libtests/aes.cc
@@ -8,52 +8,86 @@ @@ -8,52 +8,86 @@
8 8
9 static void usage() 9 static void usage()
10 { 10 {
11 - std::cerr << "Usage: aes [+-]cbc { -encrypt | -decrypt }"  
12 - << " hex-key infile outfile" << std::endl; 11 + std::cerr << "Usage: aes options hex-key infile outfile" << std::endl
  12 + << " -cbc -- disable CBC mode" << std::endl
  13 + << " +cbc -- enable CBC mode" << std::endl
  14 + << " -encrypt -- encrypt" << std::endl
  15 + << " -decrypt -- decrypt CBC mode" << std::endl
  16 + << " -zero-iv -- use zero initialization vector" << std::endl
  17 + << " -static-iv -- use static initialization vector" << std::endl
  18 + << " -no-padding -- disable padding" << std::endl
  19 + << "Options must precede key and file names." << std::endl;
13 exit(2); 20 exit(2);
14 } 21 }
15 22
16 int main(int argc, char* argv[]) 23 int main(int argc, char* argv[])
17 { 24 {
18 - if (argc != 6)  
19 - {  
20 - usage();  
21 - }  
22 -  
23 - char* cbc = argv[1];  
24 - char* action = argv[2];  
25 - char* hexkey = argv[3];  
26 - char* infilename = argv[4];  
27 - char* outfilename = argv[5];  
28 - 25 + bool encrypt = true;
29 bool cbc_mode = true; 26 bool cbc_mode = true;
30 - if (strcmp(cbc, "-cbc") == 0)  
31 - {  
32 - cbc_mode = false;  
33 - }  
34 - else if (strcmp(cbc, "+cbc") != 0)  
35 - {  
36 - usage();  
37 - } 27 + char* hexkey = 0;
  28 + char* infilename = 0;
  29 + char* outfilename = 0;
  30 + bool zero_iv = false;
  31 + bool static_iv = false;
  32 + bool disable_padding = false;
38 33
39 - bool encrypt = true;  
40 - if (strcmp(action, "-decrypt") == 0) 34 + for (int i = 1; i < argc; ++i)
41 { 35 {
42 - encrypt = false; 36 + char* arg = argv[i];
  37 + if ((arg[0] == '-') || (arg[0] == '+'))
  38 + {
  39 + if (strcmp(arg, "-cbc") == 0)
  40 + {
  41 + cbc_mode = false;
  42 + }
  43 + else if (strcmp(arg, "+cbc") == 0)
  44 + {
  45 + cbc_mode = true;
  46 + }
  47 + else if (strcmp(arg, "-decrypt") == 0)
  48 + {
  49 + encrypt = false;
  50 + }
  51 + else if (strcmp(arg, "-encrypt") == 0)
  52 + {
  53 + encrypt = true;
  54 + }
  55 + else if (strcmp(arg, "-zero-iv") == 0)
  56 + {
  57 + zero_iv = true;
  58 + }
  59 + else if (strcmp(arg, "-static-iv") == 0)
  60 + {
  61 + static_iv = true;
  62 + }
  63 + else if (strcmp(arg, "-no-padding") == 0)
  64 + {
  65 + disable_padding = true;
  66 + }
  67 + else
  68 + {
  69 + usage();
  70 + }
  71 + }
  72 + else if (argc == i + 3)
  73 + {
  74 + hexkey = argv[i];
  75 + infilename = argv[i+1];
  76 + outfilename = argv[i+2];
  77 + break;
  78 + }
  79 + else
  80 + {
  81 + usage();
  82 + }
43 } 83 }
44 - else if (strcmp(action, "-encrypt") != 0) 84 + if (outfilename == 0)
45 { 85 {
46 - usage(); 86 + usage();
47 } 87 }
48 88
49 unsigned int hexkeylen = (unsigned int)strlen(hexkey); 89 unsigned int hexkeylen = (unsigned int)strlen(hexkey);
50 unsigned int keylen = hexkeylen / 2; 90 unsigned int keylen = hexkeylen / 2;
51 - if (keylen != Pl_AES_PDF::key_size)  
52 - {  
53 - std::cerr << "key length must be " << Pl_AES_PDF::key_size  
54 - << " bytes" << std::endl;  
55 - exit(2);  
56 - }  
57 91
58 FILE* infile = fopen(infilename, "rb"); 92 FILE* infile = fopen(infilename, "rb");
59 if (infile == 0) 93 if (infile == 0)
@@ -69,7 +103,7 @@ int main(int argc, char* argv[]) @@ -69,7 +103,7 @@ int main(int argc, char* argv[])
69 exit(2); 103 exit(2);
70 } 104 }
71 105
72 - unsigned char key[Pl_AES_PDF::key_size]; 106 + unsigned char* key = new unsigned char[keylen];
73 for (unsigned int i = 0; i < strlen(hexkey); i += 2) 107 for (unsigned int i = 0; i < strlen(hexkey); i += 2)
74 { 108 {
75 char t[3]; 109 char t[3];
@@ -82,11 +116,25 @@ int main(int argc, char* argv[]) @@ -82,11 +116,25 @@ int main(int argc, char* argv[])
82 } 116 }
83 117
84 Pl_StdioFile* out = new Pl_StdioFile("stdout", outfile); 118 Pl_StdioFile* out = new Pl_StdioFile("stdout", outfile);
85 - Pl_AES_PDF* aes = new Pl_AES_PDF("aes_128_cbc", out, encrypt, key); 119 + Pl_AES_PDF* aes = new Pl_AES_PDF("aes_128_cbc", out, encrypt, key, keylen);
  120 + delete [] key;
  121 + key = 0;
86 if (! cbc_mode) 122 if (! cbc_mode)
87 { 123 {
88 aes->disableCBC(); 124 aes->disableCBC();
89 } 125 }
  126 + if (zero_iv)
  127 + {
  128 + aes->useZeroIV();
  129 + }
  130 + else if (static_iv)
  131 + {
  132 + aes->useStaticIV();
  133 + }
  134 + if (disable_padding)
  135 + {
  136 + aes->disablePadding();
  137 + }
90 138
91 // 16 < buffer size, buffer_size is not a multiple of 8 for testing 139 // 16 < buffer size, buffer_size is not a multiple of 8 for testing
92 unsigned char buf[83]; 140 unsigned char buf[83];