[poppler] [PATCH 4/4] Added revision 6 hash (Algorithm 2.B) and its calls to makeFileKey function.

Alok Anand alok4nand at gmail.com
Wed Mar 9 18:12:30 UTC 2016


---
 poppler/Decrypt.cc | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 102 insertions(+), 5 deletions(-)
 mode change 100644 => 100755 poppler/Decrypt.cc

diff --git a/poppler/Decrypt.cc b/poppler/Decrypt.cc
old mode 100644
new mode 100755
index dcbb230..66275e3
--- 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,14 +97,22 @@ 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 (!memcmp(test, ownerKey->getCString(), 32)) {
+      if (encRevision == 6){
+      //test contains the initial SHA-256 hash as input for revision 6 hash.
+      revision6Hash(ownerPassword,test,(Guchar *)userKey->getCString());
+          }
+      if (!memcmp(test,ownerKey->getCString(), 32)) {
 
 	// compute the file key from the owner password
 	memcpy(test, ownerPassword->getCString(), len);
 	memcpy(test + len, ownerKey->getCString() + 40, 8);
 	memcpy(test + len + 8, userKey->getCString(), 48);
 	sha256(test, len + 56, test);
-	aes256KeyExpansion(&state, test, 32, gTrue);
+  if(encRevision == 6){
+    //test contains the initial SHA-256 hash as input for revision 6 hash.
+    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 as input for revision 6 hash.
+        //for checking user password ,userKey is not used.
+        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 as input for revision 6 hash.
+    //for computing intermediate user key,userKey is not used.
+    revision6Hash(userPassword,test,NULL);
+  }
 	aes256KeyExpansion(&state, test, 32, gTrue);
 	for (i = 0; i < 16; ++i) {
 	  state.cbc[i] = 0;
@@ -148,7 +168,7 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
     }
 
     return gFalse;
-  } else {
+    } else {
 
     // try using the supplied owner password to generate the user password
     if (ownerPassword) {
@@ -1260,7 +1280,6 @@ void md5(Guchar *msg, int msgLen, Guchar *digest) {
   digest[14] = (Guchar)((d >>= 8) & 0xff);
   digest[15] = (Guchar)((d >>= 8) & 0xff);
 }
-
 //------------------------------------------------------------------------
 // SHA-256 hash
 //------------------------------------------------------------------------
@@ -1659,3 +1678,81 @@ static void sha384(Guchar *msg, int msgLen, Guchar *hash) {
     hash[i*8 + 7] = (Guchar)H[i];
   }
 }
+//------------------------------------------------------------------------
+// Hash Algorithm 2.B
+//------------------------------------------------------------------------
+
+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;
+  //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);
+  }
+  //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);
+//Taking the first 16 Bytes of E as unsigned big-endian integer,
+//compute the remainder,modulo 3.
+  Guoffset N1 = 0,N2 = 0,N3 = 0;
+  // N1 contains first 8 bytes of BE16byteNumber
+  N1 = ((Guoffset)BE16byteNumber[0] << 56 | (Guoffset)BE16byteNumber[1] << 48
+       |(Guoffset)BE16byteNumber[2] << 40 | (Guoffset)BE16byteNumber[3] << 32
+       |(Guoffset)BE16byteNumber[4] << 24 | (Guoffset)BE16byteNumber[5] << 16
+       |(Guoffset)BE16byteNumber[6] << 8  | (Guoffset)BE16byteNumber[7] );
+  Guoffset rem = N1 % 3 ;
+ // N2 conatains 0s in higer 4 bytes and 9th to 12 th bytes of BE16byteNumber in lower 4 bytes.
+  N2 = ((Guoffset)BE16byteNumber[8] << 24 | (Guoffset)BE16byteNumber[9] << 16
+       |(Guoffset)BE16byteNumber[10] << 8 | (Guoffset)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 = ((Guoffset)BE16byteNumber[12] << 24 | (Guoffset)BE16byteNumber[13] << 16
+       |(Guoffset)BE16byteNumber[14] << 8  | (Guoffset)BE16byteNumber[15] );
+        rem = ((rem << 32 ) | N3) % 3 ;
+ //If remainder is 0 perform SHA-256
+  if(rem == 0){
+    KLength = 32;
+    sha256(E,totalLength,K);
+  }
+  // If remainder is 1 perform SHA-384
+  else if(rem == 1){
+    KLength = 48;
+    sha384(E,totalLength,K);
+  }
+  // If remainder is 2 perform SHA-512
+  else if(rem == 2){
+    KLength = 64;
+    sha512(E,totalLength,K);
+  }
+ rounds++;
+ }
+}
-- 
2.7.2



More information about the poppler mailing list