Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

Decrypt.cc

Go to the documentation of this file.
00001 //========================================================================
00002 //
00003 // Decrypt.cc
00004 //
00005 // Copyright 1996-2002 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #ifdef __GNUC__
00010 #pragma implementation
00011 #endif
00012 
00013 #include <aconf.h>
00014 #include "gmem.h"
00015 #include "Decrypt.h"
00016 
00017 static void rc4InitKey(Guchar *key, int keyLen, Guchar *state);
00018 static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c);
00019 static void md5(Guchar *msg, int msgLen, Guchar *digest);
00020 
00021 static Guchar passwordPad[32] = {
00022   0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
00023   0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, 
00024   0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 
00025   0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
00026 };
00027 
00028 //------------------------------------------------------------------------
00029 // Decrypt
00030 //------------------------------------------------------------------------
00031 
00032 Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) {
00033   int i;
00034 
00035   // construct object key
00036   for (i = 0; i < keyLength; ++i) {
00037     objKey[i] = fileKey[i];
00038   }
00039   objKey[keyLength] = objNum & 0xff;
00040   objKey[keyLength + 1] = (objNum >> 8) & 0xff;
00041   objKey[keyLength + 2] = (objNum >> 16) & 0xff;
00042   objKey[keyLength + 3] = objGen & 0xff;
00043   objKey[keyLength + 4] = (objGen >> 8) & 0xff;
00044   md5(objKey, keyLength + 5, objKey);
00045 
00046   // set up for decryption
00047   x = y = 0;
00048   if ((objKeyLength = keyLength + 5) > 16) {
00049     objKeyLength = 16;
00050   }
00051   rc4InitKey(objKey, objKeyLength, state);
00052 }
00053 
00054 void Decrypt::reset() {
00055   x = y = 0;
00056   rc4InitKey(objKey, objKeyLength, state);
00057 }
00058 
00059 Guchar Decrypt::decryptByte(Guchar c) {
00060   return rc4DecryptByte(state, &x, &y, c);
00061 }
00062 
00063 GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
00064                            GString *ownerKey, GString *userKey,
00065                            int permissions, GString *fileID,
00066                            GString *ownerPassword, GString *userPassword,
00067                            Guchar *fileKey, GBool *ownerPasswordOk) {
00068   Guchar test[32];
00069   GString *userPassword2;
00070   Guchar fState[256];
00071   Guchar fx, fy;
00072   int len, i;
00073 
00074   // try using the supplied owner password to generate the user password
00075   if (ownerPassword) {
00076     len = ownerPassword->getLength();
00077     if (len < 32) {
00078       memcpy(test, ownerPassword->getCString(), len);
00079       memcpy(test + len, passwordPad, 32 - len);
00080     } else {
00081       memcpy(test, ownerPassword->getCString(), 32);
00082     }
00083   } else {
00084     memcpy(test, passwordPad, 32);
00085   }
00086   md5(test, 32, test);
00087   if (encRevision == 3) {
00088     for (i = 0; i < 50; ++i) {
00089       md5(test, 16, test);
00090     }
00091   }
00092   rc4InitKey(test, keyLength, fState);
00093   fx = fy = 0;
00094   for (i = 0; i < 32; ++i) {
00095     test[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
00096   }
00097   userPassword2 = new GString((char *)test, 32);
00098   if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
00099                    permissions, fileID, userPassword2, fileKey)) {
00100     *ownerPasswordOk = gTrue;
00101     delete userPassword2;
00102     return gTrue;
00103   }
00104   *ownerPasswordOk = gFalse;
00105   delete userPassword2;
00106 
00107   // try using the supplied user password
00108   return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
00109                       permissions, fileID, userPassword, fileKey);
00110 }
00111 
00112 GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
00113                             GString *ownerKey, GString *userKey,
00114                             int permissions, GString *fileID,
00115                             GString *userPassword, Guchar *fileKey) {
00116   Guchar *buf;
00117   Guchar test[32];
00118   Guchar fState[256];
00119   Guchar tmpKey[16];
00120   Guchar fx, fy;
00121   int len, i, j;
00122   GBool ok;
00123 
00124   // generate file key
00125   buf = (Guchar *)gmalloc(68 + fileID->getLength());
00126   if (userPassword) {
00127     len = userPassword->getLength();
00128     if (len < 32) {
00129       memcpy(buf, userPassword->getCString(), len);
00130       memcpy(buf + len, passwordPad, 32 - len);
00131     } else {
00132       memcpy(buf, userPassword->getCString(), 32);
00133     }
00134   } else {
00135     memcpy(buf, passwordPad, 32);
00136   }
00137   memcpy(buf + 32, ownerKey->getCString(), 32);
00138   buf[64] = permissions & 0xff;
00139   buf[65] = (permissions >> 8) & 0xff;
00140   buf[66] = (permissions >> 16) & 0xff;
00141   buf[67] = (permissions >> 24) & 0xff;
00142   memcpy(buf + 68, fileID->getCString(), fileID->getLength());
00143   md5(buf, 68 + fileID->getLength(), fileKey);
00144   if (encRevision == 3) {
00145     for (i = 0; i < 50; ++i) {
00146       md5(fileKey, 16, fileKey);
00147     }
00148   }
00149 
00150   // test user password
00151   if (encRevision == 2) {
00152     rc4InitKey(fileKey, keyLength, fState);
00153     fx = fy = 0;
00154     for (i = 0; i < 32; ++i) {
00155       test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
00156     }
00157     ok = memcmp(test, passwordPad, 32) == 0;
00158   } else if (encRevision == 3) {
00159     memcpy(test, userKey->getCString(), 32);
00160     for (i = 19; i >= 0; --i) {
00161       for (j = 0; j < keyLength; ++j) {
00162         tmpKey[j] = fileKey[j] ^ i;
00163       }
00164       rc4InitKey(tmpKey, keyLength, fState);
00165       fx = fy = 0;
00166       for (j = 0; j < 32; ++j) {
00167         test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]);
00168       }
00169     }
00170     memcpy(buf, passwordPad, 32);
00171     memcpy(buf + 32, fileID->getCString(), fileID->getLength());
00172     md5(buf, 32 + fileID->getLength(), buf);
00173     ok = memcmp(test, buf, 16) == 0;
00174   } else {
00175     ok = gFalse;
00176   }
00177 
00178   gfree(buf);
00179   return ok;
00180 }
00181 
00182 //------------------------------------------------------------------------
00183 // RC4-compatible decryption
00184 //------------------------------------------------------------------------
00185 
00186 static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) {
00187   Guchar index1, index2;
00188   Guchar t;
00189   int i;
00190 
00191   for (i = 0; i < 256; ++i)
00192     state[i] = i;
00193   index1 = index2 = 0;
00194   for (i = 0; i < 256; ++i) {
00195     index2 = (key[index1] + state[i] + index2) % 256;
00196     t = state[i];
00197     state[i] = state[index2];
00198     state[index2] = t;
00199     index1 = (index1 + 1) % keyLen;
00200   }
00201 }
00202 
00203 static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) {
00204   Guchar x1, y1, tx, ty;
00205 
00206   x1 = *x = (*x + 1) % 256;
00207   y1 = *y = (state[*x] + *y) % 256;
00208   tx = state[x1];
00209   ty = state[y1];
00210   state[x1] = ty;
00211   state[y1] = tx;
00212   return c ^ state[(tx + ty) % 256];
00213 }
00214 
00215 //------------------------------------------------------------------------
00216 // MD5 message digest
00217 //------------------------------------------------------------------------
00218 
00219 // this works around a bug in older Sun compilers
00220 static inline Gulong rotateLeft(Gulong x, int r) {
00221   x &= 0xffffffff;
00222   return ((x << r) | (x >> (32 - r))) & 0xffffffff;
00223 }
00224 
00225 static inline Gulong md5Round1(Gulong a, Gulong b, Gulong c, Gulong d,
00226                                Gulong Xk,  Gulong s, Gulong Ti) {
00227   return b + rotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s);
00228 }
00229 
00230 static inline Gulong md5Round2(Gulong a, Gulong b, Gulong c, Gulong d,
00231                                Gulong Xk,  Gulong s, Gulong Ti) {
00232   return b + rotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s);
00233 }
00234 
00235 static inline Gulong md5Round3(Gulong a, Gulong b, Gulong c, Gulong d,
00236                                Gulong Xk,  Gulong s, Gulong Ti) {
00237   return b + rotateLeft((a + (b ^ c ^ d) + Xk + Ti), s);
00238 }
00239 
00240 static inline Gulong md5Round4(Gulong a, Gulong b, Gulong c, Gulong d,
00241                                Gulong Xk,  Gulong s, Gulong Ti) {
00242   return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s);
00243 }
00244 
00245 static void md5(Guchar *msg, int msgLen, Guchar *digest) {
00246   Gulong x[16];
00247   Gulong a, b, c, d, aa, bb, cc, dd;
00248   int n64;
00249   int i, j, k;
00250 
00251   // compute number of 64-byte blocks
00252   // (length + pad byte (0x80) + 8 bytes for length)
00253   n64 = (msgLen + 1 + 8 + 63) / 64;
00254 
00255   // initialize a, b, c, d
00256   a = 0x67452301;
00257   b = 0xefcdab89;
00258   c = 0x98badcfe;
00259   d = 0x10325476;
00260 
00261   // loop through blocks
00262   k = 0;
00263   for (i = 0; i < n64; ++i) {
00264 
00265     // grab a 64-byte block
00266     for (j = 0; j < 16 && k < msgLen - 3; ++j, k += 4)
00267       x[j] = (((((msg[k+3] << 8) + msg[k+2]) << 8) + msg[k+1]) << 8) + msg[k];
00268     if (i == n64 - 1) {
00269       if (k == msgLen - 3)
00270         x[j] = 0x80000000 + (((msg[k+2] << 8) + msg[k+1]) << 8) + msg[k];
00271       else if (k == msgLen - 2)
00272         x[j] = 0x800000 + (msg[k+1] << 8) + msg[k];
00273       else if (k == msgLen - 1)
00274         x[j] = 0x8000 + msg[k];
00275       else
00276         x[j] = 0x80;
00277       ++j;
00278       while (j < 16)
00279         x[j++] = 0;
00280       x[14] = msgLen << 3;
00281     }
00282 
00283     // save a, b, c, d
00284     aa = a;
00285     bb = b;
00286     cc = c;
00287     dd = d;
00288 
00289     // round 1
00290     a = md5Round1(a, b, c, d, x[0],   7, 0xd76aa478);
00291     d = md5Round1(d, a, b, c, x[1],  12, 0xe8c7b756);
00292     c = md5Round1(c, d, a, b, x[2],  17, 0x242070db);
00293     b = md5Round1(b, c, d, a, x[3],  22, 0xc1bdceee);
00294     a = md5Round1(a, b, c, d, x[4],   7, 0xf57c0faf);
00295     d = md5Round1(d, a, b, c, x[5],  12, 0x4787c62a);
00296     c = md5Round1(c, d, a, b, x[6],  17, 0xa8304613);
00297     b = md5Round1(b, c, d, a, x[7],  22, 0xfd469501);
00298     a = md5Round1(a, b, c, d, x[8],   7, 0x698098d8);
00299     d = md5Round1(d, a, b, c, x[9],  12, 0x8b44f7af);
00300     c = md5Round1(c, d, a, b, x[10], 17, 0xffff5bb1);
00301     b = md5Round1(b, c, d, a, x[11], 22, 0x895cd7be);
00302     a = md5Round1(a, b, c, d, x[12],  7, 0x6b901122);
00303     d = md5Round1(d, a, b, c, x[13], 12, 0xfd987193);
00304     c = md5Round1(c, d, a, b, x[14], 17, 0xa679438e);
00305     b = md5Round1(b, c, d, a, x[15], 22, 0x49b40821);
00306 
00307     // round 2
00308     a = md5Round2(a, b, c, d, x[1],   5, 0xf61e2562);
00309     d = md5Round2(d, a, b, c, x[6],   9, 0xc040b340);
00310     c = md5Round2(c, d, a, b, x[11], 14, 0x265e5a51);
00311     b = md5Round2(b, c, d, a, x[0],  20, 0xe9b6c7aa);
00312     a = md5Round2(a, b, c, d, x[5],   5, 0xd62f105d);
00313     d = md5Round2(d, a, b, c, x[10],  9, 0x02441453);
00314     c = md5Round2(c, d, a, b, x[15], 14, 0xd8a1e681);
00315     b = md5Round2(b, c, d, a, x[4],  20, 0xe7d3fbc8);
00316     a = md5Round2(a, b, c, d, x[9],   5, 0x21e1cde6);
00317     d = md5Round2(d, a, b, c, x[14],  9, 0xc33707d6);
00318     c = md5Round2(c, d, a, b, x[3],  14, 0xf4d50d87);
00319     b = md5Round2(b, c, d, a, x[8],  20, 0x455a14ed);
00320     a = md5Round2(a, b, c, d, x[13],  5, 0xa9e3e905);
00321     d = md5Round2(d, a, b, c, x[2],   9, 0xfcefa3f8);
00322     c = md5Round2(c, d, a, b, x[7],  14, 0x676f02d9);
00323     b = md5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a);
00324 
00325     // round 3
00326     a = md5Round3(a, b, c, d, x[5],   4, 0xfffa3942);
00327     d = md5Round3(d, a, b, c, x[8],  11, 0x8771f681);
00328     c = md5Round3(c, d, a, b, x[11], 16, 0x6d9d6122);
00329     b = md5Round3(b, c, d, a, x[14], 23, 0xfde5380c);
00330     a = md5Round3(a, b, c, d, x[1],   4, 0xa4beea44);
00331     d = md5Round3(d, a, b, c, x[4],  11, 0x4bdecfa9);
00332     c = md5Round3(c, d, a, b, x[7],  16, 0xf6bb4b60);
00333     b = md5Round3(b, c, d, a, x[10], 23, 0xbebfbc70);
00334     a = md5Round3(a, b, c, d, x[13],  4, 0x289b7ec6);
00335     d = md5Round3(d, a, b, c, x[0],  11, 0xeaa127fa);
00336     c = md5Round3(c, d, a, b, x[3],  16, 0xd4ef3085);
00337     b = md5Round3(b, c, d, a, x[6],  23, 0x04881d05);
00338     a = md5Round3(a, b, c, d, x[9],   4, 0xd9d4d039);
00339     d = md5Round3(d, a, b, c, x[12], 11, 0xe6db99e5);
00340     c = md5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8);
00341     b = md5Round3(b, c, d, a, x[2],  23, 0xc4ac5665);
00342 
00343     // round 4
00344     a = md5Round4(a, b, c, d, x[0],   6, 0xf4292244);
00345     d = md5Round4(d, a, b, c, x[7],  10, 0x432aff97);
00346     c = md5Round4(c, d, a, b, x[14], 15, 0xab9423a7);
00347     b = md5Round4(b, c, d, a, x[5],  21, 0xfc93a039);
00348     a = md5Round4(a, b, c, d, x[12],  6, 0x655b59c3);
00349     d = md5Round4(d, a, b, c, x[3],  10, 0x8f0ccc92);
00350     c = md5Round4(c, d, a, b, x[10], 15, 0xffeff47d);
00351     b = md5Round4(b, c, d, a, x[1],  21, 0x85845dd1);
00352     a = md5Round4(a, b, c, d, x[8],   6, 0x6fa87e4f);
00353     d = md5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0);
00354     c = md5Round4(c, d, a, b, x[6],  15, 0xa3014314);
00355     b = md5Round4(b, c, d, a, x[13], 21, 0x4e0811a1);
00356     a = md5Round4(a, b, c, d, x[4],   6, 0xf7537e82);
00357     d = md5Round4(d, a, b, c, x[11], 10, 0xbd3af235);
00358     c = md5Round4(c, d, a, b, x[2],  15, 0x2ad7d2bb);
00359     b = md5Round4(b, c, d, a, x[9],  21, 0xeb86d391);
00360 
00361     // increment a, b, c, d
00362     a += aa;
00363     b += bb;
00364     c += cc;
00365     d += dd;
00366   }
00367 
00368   // break digest into bytes
00369   digest[0] = a & 0xff;
00370   digest[1] = (a >>= 8) & 0xff;
00371   digest[2] = (a >>= 8) & 0xff;
00372   digest[3] = (a >>= 8) & 0xff;
00373   digest[4] = b & 0xff;
00374   digest[5] = (b >>= 8) & 0xff;
00375   digest[6] = (b >>= 8) & 0xff;
00376   digest[7] = (b >>= 8) & 0xff;
00377   digest[8] = c & 0xff;
00378   digest[9] = (c >>= 8) & 0xff;
00379   digest[10] = (c >>= 8) & 0xff;
00380   digest[11] = (c >>= 8) & 0xff;
00381   digest[12] = d & 0xff;
00382   digest[13] = (d >>= 8) & 0xff;
00383   digest[14] = (d >>= 8) & 0xff;
00384   digest[15] = (d >>= 8) & 0xff;
00385 }

Generated on Sat Nov 5 16:18:13 2005 for OPIE by  doxygen 1.4.2