[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