I've updated three patches: - Tidied up BaseCryptStream::getChar() implementation I had moved the code that moved the buffer position forward in the base class. However, it's better to keep it duplicated in EncryptStream and DecryptStream (it's only simple incremement), as this keeps code simpler. This change affects 0001 and 0002.
- Fill CBC initialization vector (IV) in EncryptStream ctor, not when reset() is called. Otherwise, the IV is reinitialized with different values, resulting in the same stream having different contents each time. This change affects 0002 and 0005. I'm attaching the updated pathes. Fabio
From fba7818e4de13951594c76ca991cc6caf7625000 Mon Sep 17 00:00:00 2001 From: Fabio D'Urso <[email protected]> Date: Thu, 2 Aug 2012 18:56:29 +0200 Subject: [PATCH 01/19] Refactoring of Decrypt.cc/.h in preparation for encryption support --- poppler/Decrypt.cc | 219 ++++++++++++++++++++++++++-------------------------- poppler/Decrypt.h | 35 ++++++--- 2 files changed, 133 insertions(+), 121 deletions(-) diff --git a/poppler/Decrypt.cc b/poppler/Decrypt.cc index 24af996..272edc2 100644 --- a/poppler/Decrypt.cc +++ b/poppler/Decrypt.cc @@ -17,6 +17,7 @@ // Copyright (C) 2008, 2010 Albert Astals Cid <[email protected]> // Copyright (C) 2009 Matthias Franz <[email protected]> // Copyright (C) 2009 David Benjamin <[email protected]> +// Copyright (C) 2012 Fabio D'Urso <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -34,12 +35,17 @@ #include "Decrypt.h" #include "Error.h" -static void aesKeyExpansion(DecryptAESState *s, - Guchar *objKey, int objKeyLen); +static void rc4InitKey(Guchar *key, int keyLen, Guchar *state); +static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); + +static GBool aesReadBlock(Stream *str, Guchar *in, GBool addPadding); + +static void aesKeyExpansion(DecryptAESState *s, Guchar *objKey, int objKeyLen, GBool decrypt); static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last); -static void aes256KeyExpansion(DecryptAES256State *s, - Guchar *objKey, int objKeyLen); + +static void aes256KeyExpansion(DecryptAES256State *s, Guchar *objKey, int objKeyLen, GBool decrypt); static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last); + static void sha256(Guchar *msg, int msgLen, Guchar *hash); static const Guchar passwordPad[32] = { @@ -90,7 +96,7 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, memcpy(test + len, ownerKey->getCString() + 40, 8); memcpy(test + len + 8, userKey->getCString(), 48); sha256(test, len + 56, test); - aes256KeyExpansion(&state, test, 32); + aes256KeyExpansion(&state, test, 32, gTrue); for (i = 0; i < 16; ++i) { state.cbc[i] = 0; } @@ -121,7 +127,7 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, memcpy(test, userPassword->getCString(), len); memcpy(test + len, userKey->getCString() + 40, 8); sha256(test, len + 8, test); - aes256KeyExpansion(&state, test, 32); + aes256KeyExpansion(&state, test, 32, gTrue); for (i = 0; i < 16; ++i) { state.cbc[i] = 0; } @@ -269,12 +275,11 @@ GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, } //------------------------------------------------------------------------ -// DecryptStream +// BaseCryptStream //------------------------------------------------------------------------ -DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey, - CryptAlgorithm algoA, int keyLength, - int objNum, int objGen): +BaseCryptStream::BaseCryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA, + int keyLength, int objNum, int objGen): FilterStream(strA) { int i; @@ -320,30 +325,65 @@ DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey, charactersRead = 0; } -DecryptStream::~DecryptStream() { +BaseCryptStream::~BaseCryptStream() { delete str; } +void BaseCryptStream::reset() { + charactersRead = 0; + nextCharBuff = EOF; + str->reset(); +} + +int BaseCryptStream::getPos() { + return charactersRead; +} + +int BaseCryptStream::getChar() { + // Read next character and empty the buffer, so that a new character will be read next time + int c = lookChar(); + nextCharBuff = EOF; + + if (c != EOF) + charactersRead++; + return c; +} + +GBool BaseCryptStream::isBinary(GBool last) { + return str->isBinary(last); +} + +//------------------------------------------------------------------------ +// DecryptStream +//------------------------------------------------------------------------ + +DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA, + int keyLength, int objNum, int objGen): + BaseCryptStream(strA, fileKey, algoA, keyLength, objNum, objGen) +{ +} + +DecryptStream::~DecryptStream() { +} + void DecryptStream::reset() { int i; + BaseCryptStream::reset(); - charactersRead = 0; - str->reset(); switch (algo) { case cryptRC4: state.rc4.x = state.rc4.y = 0; rc4InitKey(objKey, objKeyLength, state.rc4.state); - state.rc4.buf = EOF; break; case cryptAES: - aesKeyExpansion(&state.aes, objKey, objKeyLength); + aesKeyExpansion(&state.aes, objKey, objKeyLength, gTrue); for (i = 0; i < 16; ++i) { state.aes.cbc[i] = str->getChar(); } state.aes.bufIdx = 16; break; case cryptAES256: - aes256KeyExpansion(&state.aes256, objKey, objKeyLength); + aes256KeyExpansion(&state.aes256, objKey, objKeyLength, gTrue); for (i = 0; i < 16; ++i) { state.aes256.cbc[i] = str->getChar(); } @@ -352,36 +392,25 @@ void DecryptStream::reset() { } } -int DecryptStream::getPos() { - return charactersRead; -} - -int DecryptStream::getChar() { +int DecryptStream::lookChar() { Guchar in[16]; - int c, i; + int c; + + if (nextCharBuff != EOF) + return nextCharBuff; c = EOF; // make gcc happy switch (algo) { case cryptRC4: - if (state.rc4.buf == EOF) { - c = str->getChar(); - if (c != EOF) { - state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x, - &state.rc4.y, (Guchar)c); - } + if ((c = str->getChar()) != EOF) { + c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c); } - c = state.rc4.buf; - state.rc4.buf = EOF; break; case cryptAES: if (state.aes.bufIdx == 16) { - for (i = 0; i < 16; ++i) { - if ((c = str->getChar()) == EOF) { - return EOF; - } - in[i] = (Guchar)c; + if (aesReadBlock(str, in, gFalse)) { + aesDecryptBlock(&state.aes, in, str->lookChar() == EOF); } - aesDecryptBlock(&state.aes, in, str->lookChar() == EOF); } if (state.aes.bufIdx == 16) { c = EOF; @@ -391,13 +420,9 @@ int DecryptStream::getChar() { break; case cryptAES256: if (state.aes256.bufIdx == 16) { - for (i = 0; i < 16; ++i) { - if ((c = str->getChar()) == EOF) { - return EOF; - } - in[i] = (Guchar)c; + if (aesReadBlock(str, in, gFalse)) { + aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF); } - aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF); } if (state.aes256.bufIdx == 16) { c = EOF; @@ -406,72 +431,14 @@ int DecryptStream::getChar() { } break; } - if (c != EOF) - charactersRead++; - return c; -} - -int DecryptStream::lookChar() { - Guchar in[16]; - int c, i; - - c = EOF; // make gcc happy - switch (algo) { - case cryptRC4: - if (state.rc4.buf == EOF) { - c = str->getChar(); - if (c != EOF) { - state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x, - &state.rc4.y, (Guchar)c); - } - } - c = state.rc4.buf; - break; - case cryptAES: - if (state.aes.bufIdx == 16) { - for (i = 0; i < 16; ++i) { - if ((c = str->getChar()) == EOF) { - return EOF; - } - in[i] = c; - } - aesDecryptBlock(&state.aes, in, str->lookChar() == EOF); - } - if (state.aes.bufIdx == 16) { - c = EOF; - } else { - c = state.aes.buf[state.aes.bufIdx]; - } - break; - case cryptAES256: - if (state.aes256.bufIdx == 16) { - for (i = 0; i < 16; ++i) { - if ((c = str->getChar()) == EOF) { - return EOF; - } - in[i] = c; - } - aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF); - } - if (state.aes256.bufIdx == 16) { - c = EOF; - } else { - c = state.aes256.buf[state.aes256.bufIdx]; - } - break; - } - return c; -} - -GBool DecryptStream::isBinary(GBool last) { - return str->isBinary(last); + return (nextCharBuff = c); } //------------------------------------------------------------------------ // RC4-compatible decryption //------------------------------------------------------------------------ -void rc4InitKey(Guchar *key, int keyLen, Guchar *state) { +static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) { Guchar index1, index2; Guchar t; int i; @@ -492,7 +459,7 @@ void rc4InitKey(Guchar *key, int keyLen, Guchar *state) { } } -Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { +static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { Guchar x1, y1, tx, ty; x1 = *x = (*x + 1) % 256; @@ -508,6 +475,32 @@ Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { // AES decryption //------------------------------------------------------------------------ +// Returns gFalse if EOF was reached, gTrue otherwise +static GBool aesReadBlock(Stream *str, Guchar *in, GBool addPadding) +{ + int c, i; + + for (i = 0; i < 16; ++i) { + if ((c = str->getChar()) != EOF) { + in[i] = (Guchar)c; + } else { + break; + } + } + + if (i == 16) { + return gTrue; + } else { + if (addPadding) { + c = 16 - i; + while (i < 16) { + in[i++] = (Guchar)c; + } + } + return gFalse; + } +} + static const Guchar sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, @@ -686,7 +679,7 @@ static inline void addRoundKey(Guchar *state, Guint *w) { } static void aesKeyExpansion(DecryptAESState *s, - Guchar *objKey, int /*objKeyLen*/) { + Guchar *objKey, int /*objKeyLen*/, GBool decrypt) { Guint temp; int i, round; @@ -703,8 +696,12 @@ static void aesKeyExpansion(DecryptAESState *s, } s->w[i] = s->w[i-4] ^ temp; } - for (round = 1; round <= 9; ++round) { - invMixColumnsW(&s->w[round * 4]); + + /* In case of decryption, adjust the key schedule for the equivalent inverse cipher */ + if (decrypt) { + for (round = 1; round <= 9; ++round) { + invMixColumnsW(&s->w[round * 4]); + } } } @@ -767,7 +764,7 @@ static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) { //------------------------------------------------------------------------ static void aes256KeyExpansion(DecryptAES256State *s, - Guchar *objKey, int objKeyLen) { + Guchar *objKey, int objKeyLen, GBool decrypt) { Guint temp; int i, round; @@ -786,8 +783,12 @@ static void aes256KeyExpansion(DecryptAES256State *s, } s->w[i] = s->w[i-8] ^ temp; } - for (round = 1; round <= 13; ++round) { - invMixColumnsW(&s->w[round * 4]); + + /* In case of decryption, adjust the key schedule for the equivalent inverse cipher */ + if (decrypt) { + for (round = 1; round <= 13; ++round) { + invMixColumnsW(&s->w[round * 4]); + } } } diff --git a/poppler/Decrypt.h b/poppler/Decrypt.h index d947f41..237d551 100644 --- a/poppler/Decrypt.h +++ b/poppler/Decrypt.h @@ -15,6 +15,7 @@ // // Copyright (C) 2008 Julien Rebetez <[email protected]> // Copyright (C) 2009 David Benjamin <[email protected]> +// Copyright (C) 2012 Fabio D'Urso <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -63,13 +64,12 @@ private: }; //------------------------------------------------------------------------ -// DecryptStream +// Helper classes //------------------------------------------------------------------------ struct DecryptRC4State { Guchar state[256]; Guchar x, y; - int buf; }; struct DecryptAESState { @@ -88,27 +88,26 @@ struct DecryptAES256State { int bufIdx; }; -class DecryptStream: public FilterStream { +class BaseCryptStream : public FilterStream { public: - DecryptStream(Stream *strA, Guchar *fileKey, - CryptAlgorithm algoA, int keyLength, - int objNum, int objGen); - virtual ~DecryptStream(); + BaseCryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA, + int keyLength, int objNum, int objGen); + virtual ~BaseCryptStream(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual int getChar(); - virtual int lookChar(); + virtual int lookChar() = 0; virtual int getPos(); virtual GBool isBinary(GBool last); virtual Stream *getUndecodedStream() { return this; } -private: - +protected: CryptAlgorithm algo; int objKeyLength; Guchar objKey[32]; int charactersRead; // so that getPos() can be correct + int nextCharBuff; // EOF means not read yet union { DecryptRC4State rc4; @@ -116,11 +115,23 @@ private: DecryptAES256State aes256; } state; }; + +//------------------------------------------------------------------------ +// DecryptStream +//------------------------------------------------------------------------ + +class DecryptStream : public BaseCryptStream { +public: + + DecryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA, + int keyLength, int objNum, int objGen); + ~DecryptStream(); + virtual void reset(); + virtual int lookChar(); +}; //------------------------------------------------------------------------ -extern void rc4InitKey(Guchar *key, int keyLen, Guchar *state); -extern Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); extern void md5(Guchar *msg, int msgLen, Guchar *digest); #endif -- 1.7.6.5
From 750ec6283cf1290e090670af57555782ad15a60d Mon Sep 17 00:00:00 2001 From: Fabio D'Urso <[email protected]> Date: Fri, 3 Aug 2012 12:46:06 +0200 Subject: [PATCH 02/19] Added encryption support in Decrypt.cc/.h --- poppler/Decrypt.cc | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++ poppler/Decrypt.h | 21 +++++- 2 files changed, 242 insertions(+), 1 deletions(-) diff --git a/poppler/Decrypt.cc b/poppler/Decrypt.cc index 272edc2..865bea6 100644 --- a/poppler/Decrypt.cc +++ b/poppler/Decrypt.cc @@ -41,9 +41,11 @@ static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); static GBool aesReadBlock(Stream *str, Guchar *in, GBool addPadding); static void aesKeyExpansion(DecryptAESState *s, Guchar *objKey, int objKeyLen, GBool decrypt); +static void aesEncryptBlock(DecryptAESState *s, Guchar *in); static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last); static void aes256KeyExpansion(DecryptAES256State *s, Guchar *objKey, int objKeyLen, GBool decrypt); +static void aes256EncryptBlock(DecryptAES256State *s, Guchar *in); static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last); static void sha256(Guchar *msg, int msgLen, Guchar *hash); @@ -354,6 +356,94 @@ GBool BaseCryptStream::isBinary(GBool last) { } //------------------------------------------------------------------------ +// EncryptStream +//------------------------------------------------------------------------ + +EncryptStream::EncryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA, + int keyLength, int objNum, int objGen): + BaseCryptStream(strA, fileKey, algoA, keyLength, objNum, objGen) +{ + // Fill the CBC initialization vector for AES and AES-256 + switch (algo) { + case cryptAES: + memset(state.aes.cbc, 0, 16); // TODO: Nonce + break; + case cryptAES256: + memset(state.aes256.cbc, 0, 16); // TODO: Nonce + break; + default: + break; + } +} + +EncryptStream::~EncryptStream() { +} + +void EncryptStream::reset() { + BaseCryptStream::reset(); + + switch (algo) { + case cryptRC4: + state.rc4.x = state.rc4.y = 0; + rc4InitKey(objKey, objKeyLength, state.rc4.state); + break; + case cryptAES: + aesKeyExpansion(&state.aes, objKey, objKeyLength, gFalse); + memcpy(state.aes.buf, state.aes.cbc, 16); // Copy CBC IV to buf + state.aes.bufIdx = 0; + state.aes.paddingReached = gFalse; + break; + case cryptAES256: + aes256KeyExpansion(&state.aes256, objKey, objKeyLength, gFalse); + memcpy(state.aes256.buf, state.aes256.cbc, 16); // Copy CBC IV to buf + state.aes256.bufIdx = 0; + state.aes256.paddingReached = gFalse; + break; + } +} + +int EncryptStream::lookChar() { + Guchar in[16]; + int c; + + if (nextCharBuff != EOF) + return nextCharBuff; + + c = EOF; // make gcc happy + switch (algo) { + case cryptRC4: + if ((c = str->getChar()) != EOF) { + // RC4 is XOR-based: the decryption algorithm works for encryption too + c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c); + } + break; + case cryptAES: + if (state.aes.bufIdx == 16 && !state.aes.paddingReached) { + state.aes.paddingReached = !aesReadBlock(str, in, gTrue); + aesEncryptBlock(&state.aes, in); + } + if (state.aes.bufIdx == 16) { + c = EOF; + } else { + c = state.aes.buf[state.aes.bufIdx++]; + } + break; + case cryptAES256: + if (state.aes256.bufIdx == 16 && !state.aes256.paddingReached) { + state.aes256.paddingReached = !aesReadBlock(str, in, gTrue); + aes256EncryptBlock(&state.aes256, in); + } + if (state.aes256.bufIdx == 16) { + c = EOF; + } else { + c = state.aes256.buf[state.aes256.bufIdx++]; + } + break; + } + return (nextCharBuff = c); +} + +//------------------------------------------------------------------------ // DecryptStream //------------------------------------------------------------------------ @@ -564,6 +654,14 @@ static inline Guint rotWord(Guint x) { return ((x << 8) & 0xffffffff) | (x >> 24); } +static inline void subBytes(Guchar *state) { + int i; + + for (i = 0; i < 16; ++i) { + state[i] = sbox[state[i]]; + } +} + static inline void invSubBytes(Guchar *state) { int i; @@ -572,6 +670,29 @@ static inline void invSubBytes(Guchar *state) { } } +static inline void shiftRows(Guchar *state) { + Guchar t; + + t = state[4]; + state[4] = state[5]; + state[5] = state[6]; + state[6] = state[7]; + state[7] = t; + + t = state[8]; + state[8] = state[10]; + state[10] = t; + t = state[9]; + state[9] = state[11]; + state[11] = t; + + t = state[15]; + state[15] = state[14]; + state[14] = state[13]; + state[13] = state[12]; + state[12] = t; +} + static inline void invShiftRows(Guchar *state) { Guchar t; @@ -595,6 +716,17 @@ static inline void invShiftRows(Guchar *state) { state[15] = t; } +// {02} \cdot s +static inline Guchar mul02(Guchar s) { + return (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); +} + +// {03} \cdot s +static inline Guchar mul03(Guchar s) { + Guchar s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); + return s ^ s2; +} + // {09} \cdot s static inline Guchar mul09(Guchar s) { Guchar s2, s4, s8; @@ -635,6 +767,22 @@ static inline Guchar mul0e(Guchar s) { return s2 ^ s4 ^ s8; } +static inline void mixColumns(Guchar *state) { + int c; + Guchar s0, s1, s2, s3; + + for (c = 0; c < 4; ++c) { + s0 = state[c]; + s1 = state[4+c]; + s2 = state[8+c]; + s3 = state[12+c]; + state[c] = mul02(s0) ^ mul03(s1) ^ s2 ^ s3; + state[4+c] = s0 ^ mul02(s1) ^ mul03(s2) ^ s3; + state[8+c] = s0 ^ s1 ^ mul02(s2) ^ mul03(s3); + state[12+c] = mul03(s0) ^ s1 ^ s2 ^ mul02(s3); + } +} + static inline void invMixColumns(Guchar *state) { int c; Guchar s0, s1, s2, s3; @@ -705,6 +853,43 @@ static void aesKeyExpansion(DecryptAESState *s, } } +static void aesEncryptBlock(DecryptAESState *s, Guchar *in) { + int c, round; + + // initial state (input is xor'd with previous output because of CBC) + for (c = 0; c < 4; ++c) { + s->state[c] = in[4*c] ^ s->buf[4*c]; + s->state[4+c] = in[4*c+1] ^ s->buf[4*c+1]; + s->state[8+c] = in[4*c+2] ^ s->buf[4*c+2]; + s->state[12+c] = in[4*c+3] ^ s->buf[4*c+3]; + } + + // round 0 + addRoundKey(s->state, &s->w[0]); + + // rounds 1-9 + for (round = 1; round <= 9; ++round) { + subBytes(s->state); + shiftRows(s->state); + mixColumns(s->state); + addRoundKey(s->state, &s->w[round * 4]); + } + + // round 10 + subBytes(s->state); + shiftRows(s->state); + addRoundKey(s->state, &s->w[10 * 4]); + + for (c = 0; c < 4; ++c) { + s->buf[4*c] = s->state[c]; + s->buf[4*c+1] = s->state[4+c]; + s->buf[4*c+2] = s->state[8+c]; + s->buf[4*c+3] = s->state[12+c]; + } + + s->bufIdx = 0; +} + static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) { int c, round, n, i; @@ -792,6 +977,43 @@ static void aes256KeyExpansion(DecryptAES256State *s, } } +static void aes256EncryptBlock(DecryptAES256State *s, Guchar *in) { + int c, round; + + // initial state (input is xor'd with previous output because of CBC) + for (c = 0; c < 4; ++c) { + s->state[c] = in[4*c] ^ s->buf[4*c]; + s->state[4+c] = in[4*c+1] ^ s->buf[4*c+1]; + s->state[8+c] = in[4*c+2] ^ s->buf[4*c+2]; + s->state[12+c] = in[4*c+3] ^ s->buf[4*c+3]; + } + + // round 0 + addRoundKey(s->state, &s->w[0]); + + // rounds 1-13 + for (round = 1; round <= 13; ++round) { + subBytes(s->state); + shiftRows(s->state); + mixColumns(s->state); + addRoundKey(s->state, &s->w[round * 4]); + } + + // round 14 + subBytes(s->state); + shiftRows(s->state); + addRoundKey(s->state, &s->w[14 * 4]); + + for (c = 0; c < 4; ++c) { + s->buf[4*c] = s->state[c]; + s->buf[4*c+1] = s->state[4+c]; + s->buf[4*c+2] = s->state[8+c]; + s->buf[4*c+3] = s->state[12+c]; + } + + s->bufIdx = 0; +} + static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last) { int c, round, n, i; diff --git a/poppler/Decrypt.h b/poppler/Decrypt.h index 237d551..c64c8c1 100644 --- a/poppler/Decrypt.h +++ b/poppler/Decrypt.h @@ -67,6 +67,13 @@ private: // Helper classes //------------------------------------------------------------------------ +/* DecryptRC4State, DecryptAESState, DecryptAES256State are named like this for + * historical reasons, but they're used for encryption too. + * In case of decryption, the cbc field in AES and AES-256 contains the previous + * input block or the CBC initialization vector (IV) if the stream has just been + * reset). In case of encryption, it always contains the IV, whereas the + * previous output is kept in buf. The paddingReached field is only used in + * case of encryption. */ struct DecryptRC4State { Guchar state[256]; Guchar x, y; @@ -77,6 +84,7 @@ struct DecryptAESState { Guchar state[16]; Guchar cbc[16]; Guchar buf[16]; + GBool paddingReached; // encryption only int bufIdx; }; @@ -85,6 +93,7 @@ struct DecryptAES256State { Guchar state[16]; Guchar cbc[16]; Guchar buf[16]; + GBool paddingReached; // encryption only int bufIdx; }; @@ -117,9 +126,19 @@ protected: }; //------------------------------------------------------------------------ -// DecryptStream +// EncryptStream / DecryptStream //------------------------------------------------------------------------ +class EncryptStream : public BaseCryptStream { +public: + + EncryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA, + int keyLength, int objNum, int objGen); + ~EncryptStream(); + virtual void reset(); + virtual int lookChar(); +}; + class DecryptStream : public BaseCryptStream { public: -- 1.7.6.5
From c7a8492a5e19af51ea8c0b67b87653aa075e18b6 Mon Sep 17 00:00:00 2001 From: Fabio D'Urso <[email protected]> Date: Mon, 6 Aug 2012 02:08:27 +0200 Subject: [PATCH 05/19] Initialize AES encryption with random CBC IV data --- poppler/Decrypt.cc | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/poppler/Decrypt.cc b/poppler/Decrypt.cc index 865bea6..e329a2e 100644 --- a/poppler/Decrypt.cc +++ b/poppler/Decrypt.cc @@ -32,6 +32,7 @@ #include <string.h> #include "goo/gmem.h" +#include "goo/grandom.h" #include "Decrypt.h" #include "Error.h" @@ -366,10 +367,10 @@ EncryptStream::EncryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA // Fill the CBC initialization vector for AES and AES-256 switch (algo) { case cryptAES: - memset(state.aes.cbc, 0, 16); // TODO: Nonce + grandom_fill(state.aes.cbc, 16); break; case cryptAES256: - memset(state.aes256.cbc, 0, 16); // TODO: Nonce + grandom_fill(state.aes256.cbc, 16); break; default: break; -- 1.7.6.5
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
