[poppler] [PATCHv2 4/4] Added revision6Hash function and cases for Revision 6 in makeFileKey function.
Alok Anand
alok4nand at gmail.com
Thu Mar 10 18:34:20 UTC 2016
Implemention of Algorithm 2.B of subsection 7.6.3.3 of ISO/DIS 32000-2.This will be
used in checking passwords and creating file encryption keys to decrypt revision 6
documents.
---
poppler/Decrypt.cc | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 101 insertions(+), 1 deletion(-)
diff --git a/poppler/Decrypt.cc b/poppler/Decrypt.cc
index affd1d6..7cb0a56 100644
--- a/poppler/Decrypt.cc
+++ b/poppler/Decrypt.cc
@@ -54,6 +54,8 @@ static void sha256(Guchar *msg, int msgLen, Guchar *hash);
static void sha384(Guchar *msg, int msgLen, Guchar *hash);
static void sha512(Guchar *msg, int msgLen, Guchar *hash);
+static void revision6Hash(GooString *inputPassword,Guchar *K,Guchar *userKey);
+
static const Guchar passwordPad[32] = {
0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
@@ -82,7 +84,7 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
*ownerPasswordOk = gFalse;
- if (encRevision == 5) {
+ if (encRevision == 5 || encRevision == 6) {
// check the owner password
if (ownerPassword) {
@@ -95,6 +97,10 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
memcpy(test + len, ownerKey->getCString() + 32, 8);
memcpy(test + len + 8, userKey->getCString(), 48);
sha256(test, len + 56, test);
+ if (encRevision == 6){
+ //test contains the initial SHA-256 hash as input K.
+ revision6Hash(ownerPassword,test,(Guchar *)userKey->getCString());
+ }
if (!memcmp(test, ownerKey->getCString(), 32)) {
// compute the file key from the owner password
@@ -102,6 +108,10 @@ 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);
+ if (encRevision == 6){
+ //test contains the initial SHA-256 hash input K.
+ revision6Hash(ownerPassword,test,(Guchar *)userKey->getCString());
+ }
aes256KeyExpansion(&state, test, 32, gTrue);
for (i = 0; i < 16; ++i) {
state.cbc[i] = 0;
@@ -127,12 +137,22 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
memcpy(test, userPassword->getCString(), len);
memcpy(test + len, userKey->getCString() + 32, 8);
sha256(test, len + 8, test);
+ if(encRevision == 6){
+ //test contains the initial SHA-256 hash input K.
+ //user key is not used in checking user password.
+ revision6Hash(userPassword,test,NULL);
+ }
if (!memcmp(test, userKey->getCString(), 32)) {
// compute the file key from the user password
memcpy(test, userPassword->getCString(), len);
memcpy(test + len, userKey->getCString() + 40, 8);
sha256(test, len + 8, test);
+ if(encRevision == 6){
+ //test contains the initial SHA-256 hash input K.
+ //user key is not used in computing intermediate user key.
+ revision6Hash(userPassword,test,NULL);
+ }
aes256KeyExpansion(&state, test, 32, gTrue);
for (i = 0; i < 16; ++i) {
state.cbc[i] = 0;
@@ -1659,3 +1679,83 @@ static void sha384(Guchar *msg, int msgLen, Guchar *hash) {
hash[i*8 + 7] = (Guchar)H[i];
}
}
+//------------------------------------------------------------------------
+// Section 7.6.3.3 (Encryption Key algorithm) of ISO/DIS 32000-2
+// Algorithm 2.B:Computing a hash (for revision 6).
+//------------------------------------------------------------------------
+static void revision6Hash(GooString *inputPassword,Guchar *K,Guchar *userKey){
+Guchar K1[64*(127+64+48)];
+Guchar E[64*(127+64+48)];
+DecryptAESState state;
+Guchar aesKey[16];
+Guchar BE16byteNumber[16];
+
+int inputPasswordLength = inputPassword->getLength();
+int KLength = 32;
+int userKeyLength = 0;
+if(userKey){
+ userKeyLength = 48;}
+int sequenceLength;
+int totalLength;
+int i,rounds = 0;
+
+ while(rounds < 64 || rounds < E[totalLength-1] + 32 ){
+ sequenceLength = inputPasswordLength + KLength + userKeyLength;
+ totalLength = 64 * sequenceLength;
+ //a.make the string K1
+ memcpy(K1, inputPassword, inputPasswordLength);
+ memcpy(K1 + inputPasswordLength, K , KLength);
+ memcpy(K1 + inputPasswordLength + KLength,userKey,userKeyLength);
+ for(i = 1; i < 64 ; ++i){
+ memcpy(K1 + (i * sequenceLength),K1,sequenceLength);
+ }
+ //b.Encrypt K1
+ memcpy(aesKey,K,16);
+ memcpy(state.cbc,K + 16,16);
+ memcpy(state.buf, state.cbc, 16); // Copy CBC IV to buf
+ state.bufIdx = 0;
+ state.paddingReached = gFalse;
+ aesKeyExpansion(&state,aesKey,16,gFalse);
+
+ for(int i = 0; i < (4 * sequenceLength); i++){
+ aesEncryptBlock(&state,K1 + (16 * i));
+ memcpy(E +(16 * i),state.buf,16);
+ }
+ memcpy(BE16byteNumber,E,16);
+ //c.Taking the first 16 Bytes of E as unsigned big-endian integer,
+ //compute the remainder,modulo 3.
+ uint64_t N1 = 0,N2 = 0,N3 = 0;
+ // N1 contains first 8 bytes of BE16byteNumber
+ N1 = ((uint64_t)BE16byteNumber[0] << 56 | (uint64_t)BE16byteNumber[1] << 48
+ |(uint64_t)BE16byteNumber[2] << 40 | (uint64_t)BE16byteNumber[3] << 32
+ |(uint64_t)BE16byteNumber[4] << 24 | (uint64_t)BE16byteNumber[5] << 16
+ |(uint64_t)BE16byteNumber[6] << 8 | (uint64_t)BE16byteNumber[7] );
+ uint64_t rem = N1 % 3 ;
+ // N2 conatains 0s in higer 4 bytes and 9th to 12 th bytes of BE16byteNumber in lower 4 bytes.
+ N2 = ((uint64_t)BE16byteNumber[8] << 24 | (uint64_t)BE16byteNumber[9] << 16
+ |(uint64_t)BE16byteNumber[10] << 8 | (uint64_t)BE16byteNumber[11] );
+ rem = ((rem << 32 ) | N2) % 3 ;
+ // N3 conatains 0s in higer 4 bytes and 13th to 16th bytes of BE16byteNumber in lower 4 bytes.
+ N3 = ((uint64_t)BE16byteNumber[12] << 24 | (uint64_t)BE16byteNumber[13] << 16
+ |(uint64_t)BE16byteNumber[14] << 8 | (uint64_t)BE16byteNumber[15] );
+ rem = ((rem << 32 ) | N3) % 3 ;
+
+ //d.If remainder is 0 perform SHA-256
+ if(rem == 0){
+ KLength = 32;
+ sha256(E,totalLength,K);
+ }
+ // remainder is 1 perform SHA-384
+ else if(rem == 1){
+ KLength = 48;
+ sha384(E,totalLength,K);
+ }
+ // remainder is 2 perform SHA-512
+ else if(rem == 2){
+ KLength = 64;
+ sha512(E,totalLength,K);
+ }
+ rounds++;
+ }
+ //the first 32 bytes of the final K are the output of the function.
+}
--
2.7.2
More information about the poppler
mailing list