f8a0a1
diff --git a/config.h.cmake b/config.h.cmake
f8a0a1
index 7989cbfb..6f5e147e 100644
f8a0a1
--- a/config.h.cmake
f8a0a1
+++ b/config.h.cmake
f8a0a1
@@ -24,9 +24,6 @@
f8a0a1
 /* Use zlib instead of builtin zlib decoder to uncompress flate streams. */
f8a0a1
 #cmakedefine ENABLE_ZLIB_UNCOMPRESS 1
f8a0a1
 
f8a0a1
-/* Build against libnss3 for digital signature validation */
f8a0a1
-#cmakedefine ENABLE_NSS3 1
f8a0a1
-
f8a0a1
 /* Use cairo for rendering. */
f8a0a1
 #cmakedefine HAVE_CAIRO 1
f8a0a1
 
f8a0a1
diff --git a/poppler/Decrypt.cc b/poppler/Decrypt.cc
f8a0a1
index 16476f4f..9f4adda3 100644
f8a0a1
--- a/poppler/Decrypt.cc
f8a0a1
+++ b/poppler/Decrypt.cc
f8a0a1
@@ -39,17 +39,33 @@
f8a0a1
 #include "goo/grandom.h"
f8a0a1
 #include "Decrypt.h"
f8a0a1
 #include "Error.h"
f8a0a1
-
f8a0a1
+#ifdef ENABLE_NSS3
f8a0a1
+#include <nss.h>
f8a0a1
+#include <prerror.h>
f8a0a1
+#include <sechash.h>
f8a0a1
+#endif
f8a0a1
+
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+static PK11Context *rc4InitContext(const unsigned char *key, int keyLen);
3e2f0e
+static unsigned char rc4DecryptByte(PK11Context *context, unsigned char c);
f8a0a1
+#else
3e2f0e
 static void rc4InitKey(const unsigned char *key, int keyLen, unsigned char *state);
3e2f0e
 static unsigned char rc4DecryptByte(unsigned char *state, unsigned char *x, unsigned char *y, unsigned char c);
f8a0a1
+#endif
f8a0a1
 
3e2f0e
 static bool aesReadBlock(Stream *str, unsigned char *in, bool addPadding);
f8a0a1
 
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+static PK11Context *aesInitContext(unsigned char *in, unsigned char *objKey, int objKeyLength, bool decrypt);
f8a0a1
+#else
3e2f0e
 static void aesKeyExpansion(DecryptAESState *s, const unsigned char *objKey, int objKeyLen, bool decrypt);
f8a0a1
+#endif
3e2f0e
 static void aesEncryptBlock(DecryptAESState *s, const unsigned char *in);
3e2f0e
 static void aesDecryptBlock(DecryptAESState *s, const unsigned char *in, bool last);
f8a0a1
 
f8a0a1
+#ifndef ENABLE_NSS3
3e2f0e
 static void aes256KeyExpansion(DecryptAES256State *s, const unsigned char *objKey, int objKeyLen, bool decrypt);
f8a0a1
+#endif
3e2f0e
 static void aes256EncryptBlock(DecryptAES256State *s, const unsigned char *in);
3e2f0e
 static void aes256DecryptBlock(DecryptAES256State *s, const unsigned char *in, bool last);
f8a0a1
 
3e2f0e
@@ -70,6 +86,31 @@ static const unsigned char passwordPad[32] = {
f8a0a1
 // Decrypt
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 
f8a0a1
+#ifdef ENABLE_NSS3
f8a0a1
+static void shutdownNSS()
f8a0a1
+{
3e2f0e
+    if (NSS_Shutdown() != SECSuccess) {
3e2f0e
+        error(errInternal, -1, "NSS shutdown failed: {0:s}",
3e2f0e
+              PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
3e2f0e
+    }
f8a0a1
+}
f8a0a1
+
3e2f0e
+static bool initNSS() {
3e2f0e
+    if (NSS_IsInitialized()) {
3e2f0e
+        return true;
f8a0a1
+    } else {
3e2f0e
+        if (NSS_NoDB_Init(".") != SECSuccess) {
3e2f0e
+            error(errInternal, -1, "NSS initialization failed: {0:s}",
3e2f0e
+                  PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
3e2f0e
+            return false;
3e2f0e
+        } else {
3e2f0e
+            atexit(shutdownNSS);
3e2f0e
+            return true;
3e2f0e
+        }
f8a0a1
+    }
f8a0a1
+}
f8a0a1
+#endif
f8a0a1
+
3e2f0e
 bool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, const GooString *ownerKey, const GooString *userKey, const GooString *ownerEnc, const GooString *userEnc, int permissions, const GooString *fileID,
3e2f0e
                           const GooString *ownerPassword, const GooString *userPassword, unsigned char *fileKey, bool encryptMetadata, bool *ownerPasswordOk)
3e2f0e
 {
3e2f0e
@@ -80,13 +121,21 @@ bool Decrypt::makeFileKey(int encVersio
3e2f0e
     DecryptAES256State state;
3e2f0e
     unsigned char test[127 + 56], test2[32];
3e2f0e
     GooString *userPassword2;
3e2f0e
-    unsigned char fState[256];
3e2f0e
     unsigned char tmpKey[16];
3e2f0e
-    unsigned char fx, fy;
3e2f0e
     int len, i, j;
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    PK11Context *rc4Context;
f8a0a1
+#else
3e2f0e
+    unsigned char fState[256];
3e2f0e
+    unsigned char fx, fy;
f8a0a1
+#endif
f8a0a1
 
3e2f0e
     *ownerPasswordOk = false;
f8a0a1
 
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    initNSS();
f8a0a1
+#endif
f8a0a1
+
3e2f0e
     if (encRevision == 5 || encRevision == 6) {
f8a0a1
 
3e2f0e
         // check the owner password
3e2f0e
@@ -115,14 +164,26 @@ bool Decrypt::makeFileKey(int encVersio
3e2f0e
                     // test contains the initial SHA-256 hash input K.
3e2f0e
                     revision6Hash(ownerPassword, test, userKey->c_str());
3e2f0e
                 }
f8a0a1
+#ifndef ENABLE_NSS3
3e2f0e
                 aes256KeyExpansion(&state, test, 32, true);
f8a0a1
+#endif
3e2f0e
                 for (i = 0; i < 16; ++i) {
3e2f0e
                     state.cbc[i] = 0;
3e2f0e
                 }
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+                state.context = aesInitContext(state.cbc, test, 32, true);
3e2f0e
+                if (state.context) {
f8a0a1
+#endif
3e2f0e
                 aes256DecryptBlock(&state, (unsigned char *)ownerEnc->c_str(), false);
3e2f0e
                 memcpy(fileKey, state.buf, 16);
3e2f0e
                 aes256DecryptBlock(&state, (unsigned char *)ownerEnc->c_str() + 16, false);
3e2f0e
                 memcpy(fileKey + 16, state.buf, 16);
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+                PK11_DestroyContext(state.context, PR_TRUE);
3e2f0e
+                } else {
3e2f0e
+                    return false;
3e2f0e
+                }
f8a0a1
+#endif
f8a0a1
 
3e2f0e
                 *ownerPasswordOk = true;
3e2f0e
                 return true;
3e2f0e
@@ -156,14 +217,26 @@ bool Decrypt::makeFileKey(int encVersio
3e2f0e
                     // user key is not used in computing intermediate user key.
3e2f0e
                     revision6Hash(userPassword, test, nullptr);
3e2f0e
                 }
f8a0a1
+#ifndef ENABLE_NSS3
3e2f0e
                 aes256KeyExpansion(&state, test, 32, true);
f8a0a1
+#endif
3e2f0e
                 for (i = 0; i < 16; ++i) {
3e2f0e
                     state.cbc[i] = 0;
3e2f0e
                 }
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+                state.context = aesInitContext(state.cbc, test, 32, true);
3e2f0e
+                if (state.context) {
f8a0a1
+#endif
3e2f0e
                 aes256DecryptBlock(&state, (unsigned char *)userEnc->c_str(), false);
3e2f0e
                 memcpy(fileKey, state.buf, 16);
3e2f0e
                 aes256DecryptBlock(&state, (unsigned char *)userEnc->c_str() + 16, false);
3e2f0e
                 memcpy(fileKey + 16, state.buf, 16);
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+                PK11_DestroyContext(state.context, PR_TRUE);
3e2f0e
+                } else {
3e2f0e
+                    return false;
3e2f0e
+                }
f8a0a1
+#endif
f8a0a1
 
3e2f0e
                 return true;
3e2f0e
             }
3e2f0e
@@ -189,22 +262,41 @@ bool Decrypt::makeFileKey(int encVersio
3e2f0e
                 }
3e2f0e
             }
3e2f0e
             if (encRevision == 2) {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+                rc4Context = rc4InitContext(test, keyLength);
3e2f0e
+                if (rc4Context) {
3e2f0e
+                    for (i = 0; i < 32; ++i)
3e2f0e
+                        test2[i] = rc4DecryptByte(rc4Context, ownerKey->getChar(i));
3e2f0e
+                    PK11_DestroyContext(rc4Context, PR_TRUE);
3e2f0e
+                }
f8a0a1
+#else
3e2f0e
                 rc4InitKey(test, keyLength, fState);
3e2f0e
                 fx = fy = 0;
3e2f0e
                 for (i = 0; i < 32; ++i) {
3e2f0e
                     test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
3e2f0e
                 }
f8a0a1
+#endif
3e2f0e
             } else {
3e2f0e
                 memcpy(test2, ownerKey->c_str(), 32);
3e2f0e
                 for (i = 19; i >= 0; --i) {
3e2f0e
                     for (j = 0; j < keyLength; ++j) {
3e2f0e
                         tmpKey[j] = test[j] ^ i;
3e2f0e
                     }
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+                    rc4Context = rc4InitContext(tmpKey, keyLength);
3e2f0e
+                    if (rc4Context) {
3e2f0e
+                        for (j = 0; j < 32; ++j) {
3e2f0e
+                            test2[j] = rc4DecryptByte(rc4Context, test2[j]);
3e2f0e
+                        }
3e2f0e
+                        PK11_DestroyContext(rc4Context, PR_TRUE);
3e2f0e
+                    }
f8a0a1
+#else
3e2f0e
                     rc4InitKey(tmpKey, keyLength, fState);
3e2f0e
                     fx = fy = 0;
3e2f0e
                     for (j = 0; j < 32; ++j) {
3e2f0e
                         test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]);
3e2f0e
                     }
f8a0a1
+#endif
3e2f0e
                 }
3e2f0e
             }
3e2f0e
             userPassword2 = new GooString((char *)test2, 32);
3e2f0e
@@ -232,11 +324,15 @@ bool Decrypt::makeFileKey2(int encVersi
3e2f0e
 {
3e2f0e
     unsigned char *buf;
3e2f0e
     unsigned char test[32];
3e2f0e
-    unsigned char fState[256];
3e2f0e
     unsigned char tmpKey[16];
3e2f0e
-    unsigned char fx, fy;
3e2f0e
     int len, i, j;
3e2f0e
-    bool ok;
3e2f0e
+    bool ok = true;
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    PK11Context *rc4Context;
f8a0a1
+#else
3e2f0e
+    unsigned char fState[256];
3e2f0e
+    unsigned char fx, fy;
f8a0a1
+#endif
f8a0a1
 
3e2f0e
     // generate file key
3e2f0e
     buf = (unsigned char *)gmalloc(72 + fileID->getLength());
3e2f0e
@@ -273,28 +369,52 @@ bool Decrypt::makeFileKey2(int encVersi
f8a0a1
 
3e2f0e
     // test user password
3e2f0e
     if (encRevision == 2) {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        rc4Context = rc4InitContext(fileKey, keyLength);
3e2f0e
+        if (rc4Context) {
3e2f0e
+            for (i = 0; i < 32; ++i)
3e2f0e
+                test[i] = rc4DecryptByte(rc4Context, userKey->getChar(i));
3e2f0e
+            PK11_DestroyContext(rc4Context, PR_TRUE);
3e2f0e
+        } else {
3e2f0e
+            ok = false;
3e2f0e
+        }
f8a0a1
+#else
3e2f0e
         rc4InitKey(fileKey, keyLength, fState);
3e2f0e
         fx = fy = 0;
3e2f0e
         for (i = 0; i < 32; ++i) {
3e2f0e
             test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
3e2f0e
         }
3e2f0e
-        ok = memcmp(test, passwordPad, 32) == 0;
f8a0a1
+#endif
3e2f0e
+        if (ok)
3e2f0e
+            ok = memcmp(test, passwordPad, 32) == 0;
3e2f0e
     } else if (encRevision == 3) {
3e2f0e
         memcpy(test, userKey->c_str(), 32);
3e2f0e
         for (i = 19; i >= 0; --i) {
3e2f0e
             for (j = 0; j < keyLength; ++j) {
3e2f0e
                 tmpKey[j] = fileKey[j] ^ i;
3e2f0e
             }
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+            rc4Context = rc4InitContext(tmpKey, keyLength);
3e2f0e
+            if (rc4Context) {
3e2f0e
+                for (j = 0; j < 32; ++j)
3e2f0e
+                    test[j] = rc4DecryptByte(rc4Context, test[j]);
3e2f0e
+                PK11_DestroyContext(rc4Context, PR_TRUE);
3e2f0e
+            } else {
3e2f0e
+                ok = false;
3e2f0e
+            }
f8a0a1
+#else
3e2f0e
             rc4InitKey(tmpKey, keyLength, fState);
3e2f0e
             fx = fy = 0;
3e2f0e
             for (j = 0; j < 32; ++j) {
3e2f0e
                 test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]);
3e2f0e
             }
f8a0a1
+#endif
3e2f0e
         }
3e2f0e
         memcpy(buf, passwordPad, 32);
3e2f0e
         memcpy(buf + 32, fileID->c_str(), fileID->getLength());
3e2f0e
         md5(buf, 32 + fileID->getLength(), buf);
3e2f0e
-        ok = memcmp(test, buf, 16) == 0;
3e2f0e
+        if (ok)
3e2f0e
+            ok = memcmp(test, buf, 16) == 0;
3e2f0e
     } else {
3e2f0e
         ok = false;
f8a0a1
     }
f8a0a1
@@ -334,6 +454,9 @@ BaseCryptStream::BaseCryptStream(Stream
3e2f0e
         if ((objKeyLength = keyLength + 5) > 16) {
3e2f0e
             objKeyLength = 16;
3e2f0e
         }
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        state.rc4.context = nullptr;
f8a0a1
+#endif
3e2f0e
         break;
3e2f0e
     case cryptAES:
3e2f0e
         objKey[keyLength] = refA.num & 0xff;
f8a0a1
@@ -349,9 +472,15 @@ BaseCryptStream::BaseCryptStream(Stream
3e2f0e
         if ((objKeyLength = keyLength + 5) > 16) {
3e2f0e
             objKeyLength = 16;
3e2f0e
         }
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        state.aes.context = nullptr;
f8a0a1
+#endif
3e2f0e
         break;
3e2f0e
     case cryptAES256:
3e2f0e
         objKeyLength = keyLength;
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        state.aes256.context = nullptr;
f8a0a1
+#endif
3e2f0e
         break;
3e2f0e
     case cryptNone:
3e2f0e
         break;
3e2f0e
@@ -359,10 +488,33 @@ BaseCryptStream::BaseCryptStream(Stream
3e2f0e
     charactersRead = 0;
3e2f0e
     nextCharBuff = EOF;
3e2f0e
     autoDelete = true;
f8a0a1
+
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    initNSS();
f8a0a1
+#endif
f8a0a1
 }
f8a0a1
 
3e2f0e
 BaseCryptStream::~BaseCryptStream()
3e2f0e
 {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    switch (algo) {
3e2f0e
+    case cryptRC4:
3e2f0e
+        if (state.rc4.context)
3e2f0e
+            PK11_DestroyContext(state.rc4.context, PR_TRUE);
3e2f0e
+        break;
3e2f0e
+    case cryptAES:
3e2f0e
+        if (state.aes.context)
3e2f0e
+            PK11_DestroyContext(state.aes.context, PR_TRUE);
3e2f0e
+        break;
3e2f0e
+    case cryptAES256:
3e2f0e
+        if (state.aes256.context)
3e2f0e
+            PK11_DestroyContext(state.aes256.context, PR_TRUE);
3e2f0e
+        break;
3e2f0e
+    default:
3e2f0e
+        break;
3e2f0e
+    }
f8a0a1
+#endif
f8a0a1
+
3e2f0e
     if (autoDelete) {
3e2f0e
         delete str;
3e2f0e
     }
f8a0a1
@@ -424,18 +576,40 @@ void EncryptStream::reset() {
f8a0a1
 
3e2f0e
     switch (algo) {
3e2f0e
     case cryptRC4:
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        if (state.rc4.context)
3e2f0e
+            PK11_DestroyContext(state.rc4.context, PR_TRUE);
3e2f0e
+        state.rc4.context = rc4InitContext(objKey, objKeyLength);
f8a0a1
+#else
3e2f0e
         state.rc4.x = state.rc4.y = 0;
3e2f0e
         rc4InitKey(objKey, objKeyLength, state.rc4.state);
f8a0a1
+#endif
3e2f0e
         break;
3e2f0e
     case cryptAES:
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        memcpy(state.aes.buf, state.aes.cbc, 16); // Copy CBC IV to buf
3e2f0e
+        if (state.aes.context)
3e2f0e
+            PK11_DestroyContext(state.aes.context, PR_TRUE);
3e2f0e
+        state.aes.context = aesInitContext(state.aes.cbc, objKey, objKeyLength,
3e2f0e
+                                           false);
f8a0a1
+#else
3e2f0e
         aesKeyExpansion(&state.aes, objKey, objKeyLength, false);
3e2f0e
         memcpy(state.aes.buf, state.aes.cbc, 16); // Copy CBC IV to buf
f8a0a1
+#endif
3e2f0e
         state.aes.bufIdx = 0;
3e2f0e
         state.aes.paddingReached = false;
3e2f0e
         break;
3e2f0e
     case cryptAES256:
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        memcpy(state.aes256.buf, state.aes256.cbc, 16); // Copy CBC IV to buf
3e2f0e
+        if (state.aes256.context)
3e2f0e
+            PK11_DestroyContext(state.aes256.context, PR_TRUE);
3e2f0e
+        state.aes256.context = aesInitContext(state.aes256.cbc, objKey, objKeyLength,
3e2f0e
+                                              false);
f8a0a1
+#else
3e2f0e
         aes256KeyExpansion(&state.aes256, objKey, objKeyLength, false);
3e2f0e
         memcpy(state.aes256.buf, state.aes256.cbc, 16); // Copy CBC IV to buf
f8a0a1
+#endif
3e2f0e
         state.aes256.bufIdx = 0;
3e2f0e
         state.aes256.paddingReached = false;
3e2f0e
         break;
f8a0a1
@@ -456,7 +630,11 @@ int EncryptStream::lookChar() {
3e2f0e
     case cryptRC4:
3e2f0e
         if ((c = str->getChar()) != EOF) {
3e2f0e
             // RC4 is XOR-based: the decryption algorithm works for encryption too
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+            c = rc4DecryptByte(state.rc4.context, (unsigned char)c);
f8a0a1
+#else
3e2f0e
             c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (unsigned char)c);
f8a0a1
+#endif
3e2f0e
         }
3e2f0e
         break;
3e2f0e
     case cryptAES:
f8a0a1
@@ -506,21 +684,47 @@ void DecryptStream::reset() {
f8a0a1
 
3e2f0e
     switch (algo) {
3e2f0e
     case cryptRC4:
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        if (state.rc4.context)
3e2f0e
+            PK11_DestroyContext(state.rc4.context, PR_TRUE);
3e2f0e
+        state.rc4.context = rc4InitContext(objKey, objKeyLength);
f8a0a1
+#else
3e2f0e
         state.rc4.x = state.rc4.y = 0;
3e2f0e
         rc4InitKey(objKey, objKeyLength, state.rc4.state);
f8a0a1
+#endif
3e2f0e
         break;
3e2f0e
     case cryptAES:
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        if (state.aes.context)
3e2f0e
+            PK11_DestroyContext(state.aes.context, PR_TRUE);
3e2f0e
+        for (i = 0; i < 16; ++i) {
3e2f0e
+            state.aes.cbc[i] = str->getChar();
3e2f0e
+        }
3e2f0e
+        state.aes.context = aesInitContext(state.aes.cbc, objKey, objKeyLength,
3e2f0e
+                                           true);
f8a0a1
+#else
3e2f0e
         aesKeyExpansion(&state.aes, objKey, objKeyLength, true);
3e2f0e
         for (i = 0; i < 16; ++i) {
3e2f0e
             state.aes.cbc[i] = str->getChar();
3e2f0e
         }
f8a0a1
+#endif
3e2f0e
         state.aes.bufIdx = 16;
3e2f0e
         break;
3e2f0e
     case cryptAES256:
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        if (state.aes256.context)
3e2f0e
+            PK11_DestroyContext(state.aes256.context, PR_TRUE);
3e2f0e
+        for (i = 0; i < 16; ++i) {
3e2f0e
+            state.aes256.cbc[i] = str->getChar();
3e2f0e
+        }
3e2f0e
+        state.aes256.context = aesInitContext(state.aes256.cbc, objKey, objKeyLength,
3e2f0e
+                                              true);
f8a0a1
+#else
3e2f0e
         aes256KeyExpansion(&state.aes256, objKey, objKeyLength, true);
3e2f0e
         for (i = 0; i < 16; ++i) {
3e2f0e
             state.aes256.cbc[i] = str->getChar();
3e2f0e
         }
f8a0a1
+#endif
3e2f0e
         state.aes256.bufIdx = 16;
3e2f0e
         break;
3e2f0e
     case cryptNone:
f8a0a1
@@ -539,10 +743,21 @@ int DecryptStream::lookChar() {
3e2f0e
     switch (algo) {
3e2f0e
     case cryptRC4:
3e2f0e
         if ((c = str->getChar()) != EOF) {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+            if (unlikely(state.rc4.context == nullptr))
3e2f0e
+                c = EOF;
3e2f0e
+            else
3e2f0e
+                c = rc4DecryptByte(state.rc4.context, (unsigned char)c);
f8a0a1
+#else
3e2f0e
             c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (unsigned char)c);
f8a0a1
+#endif
3e2f0e
         }
3e2f0e
         break;
3e2f0e
     case cryptAES:
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        if (unlikely(state.aes.context == nullptr))
3e2f0e
+            break;
f8a0a1
+#endif
3e2f0e
         if (state.aes.bufIdx == 16) {
3e2f0e
             if (aesReadBlock(str, in, false)) {
3e2f0e
                 aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
f8a0a1
@@ -555,6 +770,10 @@ int DecryptStream::lookChar() {
3e2f0e
         }
3e2f0e
         break;
3e2f0e
     case cryptAES256:
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        if (unlikely(state.aes256.context == nullptr))
3e2f0e
+            break;
f8a0a1
+#endif
3e2f0e
         if (state.aes256.bufIdx == 16) {
3e2f0e
             if (aesReadBlock(str, in, false)) {
3e2f0e
                 aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF);
3e2f0e
@@ -576,7 +795,176 @@ int DecryptStream::lookChar() {
f8a0a1
 // RC4-compatible decryption
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 
f8a0a1
+#ifdef ENABLE_NSS3
f8a0a1
+/*
f8a0a1
+ * This function turns given key into token key (compared to a session key
f8a0a1
+ * which is prohibited in FIPS mode).
f8a0a1
+ */
3e2f0e
+static PK11SymKey *tokenizeKey(const unsigned char *key, int keyLen,
f8a0a1
+                               CK_ATTRIBUTE_TYPE operation) {
3e2f0e
+    CK_MECHANISM_TYPE  cipherMech = CKM_AES_CBC_PAD;
3e2f0e
+    PK11SlotInfo      *slot;
3e2f0e
+    PK11SymKey        *wrappingKey = nullptr;
3e2f0e
+    PK11SymKey        *symKey = nullptr;
3e2f0e
+    PK11SymKey        *token = nullptr;
3e2f0e
+    SECStatus          retval;
3e2f0e
+    SECItem           *secParam = nullptr;
3e2f0e
+    SECItem            ivItem, wrappedKey;
3e2f0e
+    unsigned char      output[48];   // Buffer to hold 256 bit key + padding
3e2f0e
+    unsigned char      iv[16];       // Initialization vector for AES
3e2f0e
+    unsigned int       outputLength;
3e2f0e
+    int                i;
3e2f0e
+
3e2f0e
+    slot = PK11_GetBestSlot(CKM_AES_KEY_GEN, nullptr);
3e2f0e
+    if (slot == nullptr) {
3e2f0e
+        error(errInternal, -1, "Unable to find security device (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    // Generate random key for wrapping of given key by AES-256
3e2f0e
+    wrappingKey = PK11_KeyGen(slot, CKM_AES_KEY_GEN, nullptr, 32, nullptr);
3e2f0e
+    if (wrappingKey == nullptr) {
3e2f0e
+        error(errInternal, -1, "Failed to generate wrapping key (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    for (i = 0; i < 16; i++)
3e2f0e
+        iv[i] = i;
f8a0a1
+
3e2f0e
+    ivItem.type = siBuffer;
3e2f0e
+    ivItem.data = iv;
3e2f0e
+    ivItem.len = 16;
f8a0a1
+
3e2f0e
+    secParam = PK11_ParamFromIV(cipherMech, &ivItem);
3e2f0e
+    if (secParam == nullptr) {
3e2f0e
+        error(errInternal, -1, "Failed to set up PKCS11 param (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    // Encrypt given key
3e2f0e
+    retval = PK11_Encrypt(wrappingKey,
3e2f0e
+                          cipherMech,
3e2f0e
+                          secParam,
3e2f0e
+                          output,
3e2f0e
+                          &outputLength,
3e2f0e
+                          sizeof(output),
3e2f0e
+                          key,
3e2f0e
+                          keyLen);
3e2f0e
+    if (retval != SECSuccess) {
3e2f0e
+        error(errInternal, -1, "Failed to encrypt key (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    wrappedKey.type = siBuffer;
3e2f0e
+    wrappedKey.data = output;
3e2f0e
+    wrappedKey.len = outputLength;
3e2f0e
+
3e2f0e
+    // Unwrap the wrapped key to token so it can be used in FIPS mode
3e2f0e
+    token = PK11_UnwrapSymKey(wrappingKey,
3e2f0e
+                              cipherMech,
3e2f0e
+                              &ivItem,
3e2f0e
+                              &wrappedKey,
3e2f0e
+                              operation,
3e2f0e
+                              CKA_UNWRAP,
3e2f0e
+                              keyLen);
3e2f0e
+
3e2f0e
+    if (token == nullptr) {
3e2f0e
+        error(errInternal, -1, "Failed to unwrap symmetric key (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+    }
f8a0a1
+
f8a0a1
+err:
3e2f0e
+    if (secParam != nullptr)
3e2f0e
+        SECITEM_FreeItem(secParam, PR_TRUE);
f8a0a1
+
3e2f0e
+    if (wrappingKey != nullptr)
3e2f0e
+        PK11_FreeSymKey(wrappingKey);
f8a0a1
+
3e2f0e
+    if (symKey != nullptr)
3e2f0e
+        PK11_FreeSymKey(symKey);
f8a0a1
+
3e2f0e
+    if (slot != nullptr)
3e2f0e
+        PK11_FreeSlot(slot);
3e2f0e
+
3e2f0e
+    return token;
f8a0a1
+}
f8a0a1
+
3e2f0e
+static PK11Context *rc4InitContext(const unsigned char *key, int keyLen) {
3e2f0e
+    CK_MECHANISM_TYPE  cipherMech = CKM_RC4;
3e2f0e
+    PK11SlotInfo      *slot = nullptr;
3e2f0e
+    PK11SymKey        *symKey = nullptr;
3e2f0e
+    SECItem           *secParam = nullptr;
3e2f0e
+    PK11Context       *context = nullptr;
3e2f0e
+
3e2f0e
+    slot = PK11_GetBestSlot(cipherMech, nullptr);
3e2f0e
+    if (slot == nullptr) {
3e2f0e
+        error(errInternal, -1, "Unable to find security device (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
3e2f0e
+
3e2f0e
+    symKey = tokenizeKey(key, keyLen, cipherMech);
3e2f0e
+    if (symKey == nullptr) {
3e2f0e
+        error(errInternal, -1, "Failed to create token from key (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
3e2f0e
+
3e2f0e
+    secParam = PK11_ParamFromIV(cipherMech, nullptr);
3e2f0e
+    if (secParam == nullptr) {
3e2f0e
+        error(errInternal, -1, "Failed to set up PKCS11 param (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    context = PK11_CreateContextBySymKey(cipherMech,
3e2f0e
+                                         CKA_DECRYPT,
3e2f0e
+                                         symKey,
3e2f0e
+                                         secParam);
3e2f0e
+    if (context == nullptr) {
3e2f0e
+        error(errInternal, -1, "Failed to create context (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+    }
3e2f0e
+
3e2f0e
+err:
3e2f0e
+    if (secParam != nullptr)
3e2f0e
+        SECITEM_FreeItem(secParam, PR_TRUE);
f8a0a1
+
3e2f0e
+    if (symKey != nullptr)
3e2f0e
+        PK11_FreeSymKey(symKey);
f8a0a1
+
3e2f0e
+    if (slot != nullptr)
3e2f0e
+        PK11_FreeSlot(slot);
3e2f0e
+
3e2f0e
+    return context;
3e2f0e
+}
3e2f0e
+
3e2f0e
+static unsigned char rc4DecryptByte(PK11Context *context, unsigned char c) {
3e2f0e
+    unsigned char outputChar = 0;
3e2f0e
+    SECStatus     retval;
3e2f0e
+    int           outputLength;
3e2f0e
+
3e2f0e
+    retval = PK11_CipherOp(context,
3e2f0e
+                           &outputChar,
3e2f0e
+                           &outputLength,
3e2f0e
+                           1,
3e2f0e
+                           &c,
3e2f0e
+                           1);
3e2f0e
+
3e2f0e
+    if (retval != SECSuccess) {
3e2f0e
+        error(errInternal, -1, "Failed to decrypt byte (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+    }
3e2f0e
+
3e2f0e
+    return outputChar;
f8a0a1
+}
f8a0a1
+
f8a0a1
+#else
f8a0a1
+
3e2f0e
 static void rc4InitKey(const unsigned char *key, int keyLen, unsigned char *state)
3e2f0e
 {
3e2f0e
     unsigned char index1, index2;
3e2f0e
     unsigned char t;
3e2f0e
@@ -609,6 +997,8 @@ static unsigned char rc4DecryptByte(unsigned char *sta
3e2f0e
     return c ^ state[(tx + ty) % 256];
f8a0a1
 }
f8a0a1
 
f8a0a1
+#endif
f8a0a1
+
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 // AES decryption
f8a0a1
 //------------------------------------------------------------------------
3e2f0e
@@ -639,6 +1029,178 @@ static bool aesReadBlock(Stream *str, G
3e2f0e
     }
f8a0a1
 }
f8a0a1
 
f8a0a1
+#ifdef ENABLE_NSS3
f8a0a1
+
3e2f0e
+static PK11Context *aesInitContext(unsigned char *in, unsigned char *objKey,
3e2f0e
+                                   int objKeyLength, bool decrypt) {
3e2f0e
+    CK_MECHANISM_TYPE  cipherMech = CKM_AES_CBC;
3e2f0e
+    CK_ATTRIBUTE_TYPE  operationType = decrypt ? CKA_DECRYPT : CKA_ENCRYPT;
3e2f0e
+    PK11SlotInfo      *slot;
3e2f0e
+    PK11SymKey        *symKey = nullptr;
3e2f0e
+    SECItem           *secParam = nullptr;
3e2f0e
+    PK11Context       *context = nullptr;
3e2f0e
+    SECItem            ivItem;
3e2f0e
+
3e2f0e
+    slot = PK11_GetBestSlot(cipherMech, nullptr);
3e2f0e
+    if (slot == nullptr) {
3e2f0e
+        error(errInternal, -1, "Unable to find security device (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    symKey = tokenizeKey(objKey, objKeyLength, cipherMech);
3e2f0e
+    if (symKey == nullptr) {
3e2f0e
+        error(errInternal, -1, "Failed to create token from key (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    ivItem.type = siBuffer;
3e2f0e
+    ivItem.data = in;
3e2f0e
+    ivItem.len = 16;
f8a0a1
+
3e2f0e
+    secParam = PK11_ParamFromIV(cipherMech, &ivItem);
3e2f0e
+    if (secParam == nullptr) {
3e2f0e
+        error(errInternal, -1, "Failed to set up PKCS11 param (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    context = PK11_CreateContextBySymKey(cipherMech,
3e2f0e
+                                         operationType,
3e2f0e
+                                         symKey,
3e2f0e
+                                         secParam);
3e2f0e
+
3e2f0e
+err:
3e2f0e
+    if (secParam != nullptr)
3e2f0e
+        SECITEM_FreeItem(secParam, PR_TRUE);
f8a0a1
+
3e2f0e
+    if (symKey != nullptr)
3e2f0e
+        PK11_FreeSymKey(symKey);
f8a0a1
+
3e2f0e
+    if (slot != nullptr)
3e2f0e
+        PK11_FreeSlot(slot);
f8a0a1
+
3e2f0e
+    return context;
3e2f0e
+}
3e2f0e
+
3e2f0e
+static void aesEncryptBlock(DecryptAESState *s, const unsigned char *in) {
3e2f0e
+    SECStatus rv;
3e2f0e
+    int       outputLength;
3e2f0e
+
3e2f0e
+    rv = PK11_CipherOp(s->context,
3e2f0e
+                       s->buf,
3e2f0e
+                       &outputLength,
3e2f0e
+                       16,
3e2f0e
+                       in,
3e2f0e
+                       16);
3e2f0e
+
3e2f0e
+    if (rv != SECSuccess) {
3e2f0e
+        error(errInternal, -1, "Failed to encrypt input block (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    s->bufIdx = 0;
f8a0a1
+
f8a0a1
+err:
3e2f0e
+    return;
f8a0a1
+}
f8a0a1
+
3e2f0e
+static void aesDecryptBlock(DecryptAESState *s, const unsigned char *in, bool last) {
3e2f0e
+    SECStatus rv1;
3e2f0e
+    int       outputLen;
3e2f0e
+    int       n, i;
3e2f0e
+
3e2f0e
+    rv1 = PK11_CipherOp(s->context,
3e2f0e
+                        s->buf,
3e2f0e
+                        &outputLen,
3e2f0e
+                        16,
3e2f0e
+                        in,
3e2f0e
+                        16);
3e2f0e
+
3e2f0e
+    if (rv1 != SECSuccess) {
3e2f0e
+        error(errInternal, -1, "Failed to decrypt input block (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
f8a0a1
+    }
3e2f0e
+
3e2f0e
+    s->bufIdx = 0;
3e2f0e
+    if (last) {
3e2f0e
+        n = s->buf[15];
3e2f0e
+        if (n < 1 || n > 16) { // this should never happen
3e2f0e
+            n = 16;
3e2f0e
+        }
3e2f0e
+        for (i = 15; i >= n; --i) {
3e2f0e
+            s->buf[i] = s->buf[i-n];
3e2f0e
+        }
3e2f0e
+        s->bufIdx = n;
f8a0a1
+    }
f8a0a1
+
f8a0a1
+err:
3e2f0e
+    return;
f8a0a1
+}
f8a0a1
+
3e2f0e
+static void aes256EncryptBlock(DecryptAES256State *s, const unsigned char *in) {
3e2f0e
+    SECStatus rv;
3e2f0e
+    int       outputLength;
3e2f0e
+
3e2f0e
+    rv = PK11_CipherOp(s->context,
3e2f0e
+                       s->buf,
3e2f0e
+                       &outputLength,
3e2f0e
+                       16,
3e2f0e
+                       in,
3e2f0e
+                       16);
3e2f0e
+
3e2f0e
+    if (rv != SECSuccess) {
3e2f0e
+        error(errInternal, -1, "Failed to encrypt input block (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
3e2f0e
+    }
f8a0a1
+
3e2f0e
+    s->bufIdx = 0;
f8a0a1
+
f8a0a1
+err:
3e2f0e
+    return;
f8a0a1
+}
f8a0a1
+
3e2f0e
+static void aes256DecryptBlock(DecryptAES256State *s, const unsigned char *in,
3e2f0e
+                               bool last) {
3e2f0e
+    SECStatus rv1;
3e2f0e
+    int       outputLen;
3e2f0e
+    int       n, i;
3e2f0e
+
3e2f0e
+    rv1 = PK11_CipherOp(s->context,
3e2f0e
+                        s->buf,
3e2f0e
+                        &outputLen,
3e2f0e
+                        16,
3e2f0e
+                        in,
3e2f0e
+                        16);
3e2f0e
+
3e2f0e
+    if (rv1 != SECSuccess) {
3e2f0e
+        error(errInternal, -1, "Failed to decrypt input block (err {0:d})",
3e2f0e
+              PR_GetError());
3e2f0e
+        goto err;
f8a0a1
+    }
3e2f0e
+
3e2f0e
+    s->bufIdx = 0;
3e2f0e
+    if (last) {
3e2f0e
+        n = s->buf[15];
3e2f0e
+        if (n < 1 || n > 16) { // this should never happen
3e2f0e
+            n = 16;
3e2f0e
+        }
3e2f0e
+        for (i = 15; i >= n; --i) {
3e2f0e
+            s->buf[i] = s->buf[i-n];
3e2f0e
+        }
3e2f0e
+        s->bufIdx = n;
f8a0a1
+    }
f8a0a1
+
f8a0a1
+err:
3e2f0e
+    return;
f8a0a1
+}
f8a0a1
+
f8a0a1
+#else
f8a0a1
+
3e2f0e
 static const unsigned char 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,
3e2f0e
                                          0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
3e2f0e
                                          0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
f8a0a1
@@ -1121,10 +1683,33 @@ static void aes256DecryptBlock(DecryptAE
3e2f0e
     }
f8a0a1
 }
f8a0a1
 
f8a0a1
+#endif
f8a0a1
+
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 // MD5 message digest
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+static void hashFunc(const unsigned char *msg, int msgLen, unsigned char *hash,
f8a0a1
+                     HASH_HashType type) {
3e2f0e
+    HASHContext *context;
3e2f0e
+    unsigned int hashLen = 0;
f8a0a1
+
3e2f0e
+    if (!initNSS())
3e2f0e
+        return;
f8a0a1
+
3e2f0e
+    context = HASH_Create(type);
3e2f0e
+    if (context == nullptr)
3e2f0e
+        return;
f8a0a1
+
3e2f0e
+    HASH_Begin(context);
3e2f0e
+    HASH_Update(context, msg, msgLen);
3e2f0e
+    HASH_End(context, hash, &hashLen, HASH_ResultLen(type));
3e2f0e
+    HASH_Destroy(context);
f8a0a1
+}
f8a0a1
+
f8a0a1
+#else
f8a0a1
+
f8a0a1
 // this works around a bug in older Sun compilers
3e2f0e
 static inline unsigned long rotateLeft(unsigned long x, int r)
3e2f0e
 {
3e2f0e
@@ -1151,8 +1736,13 @@ static inline unsigned long md5Round4(unsigned long a,
3e2f0e
     state->digest[15] = (unsigned char)(state->d >> 24);
f8a0a1
 }
f8a0a1
 
f8a0a1
+#endif
f8a0a1
+
3e2f0e
 void md5(const unsigned char *msg, int msgLen, unsigned char *digest)
3e2f0e
 {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    hashFunc(msg, msgLen, digest, HASH_AlgMD5);
f8a0a1
+#else
3e2f0e
     if (msgLen < 0) {
3e2f0e
         return;
3e2f0e
     }
3e2f0e
@@ -1296,12 +1886,14 @@ void md5(unsigned char *msg, int msgLen, unsigned char
3e2f0e
     for (int i = 0; i < 16; ++i) {
3e2f0e
         digest[i] = state.digest[i];
3e2f0e
     }
f8a0a1
+#endif
f8a0a1
 }
f8a0a1
 
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 // SHA-256 hash
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 
f8a0a1
+#ifndef ENABLE_NSS3
3e2f0e
 static const unsigned int sha256K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
3e2f0e
                                           0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
3e2f0e
                                           0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
3e2f0e
@@ -1400,9 +1992,13 @@ static void sha256HashBlock(unsigned char *blk,
3e2f0e
     H[6] += g;
3e2f0e
     H[7] += h;
f8a0a1
 }
f8a0a1
+#endif
f8a0a1
 
3e2f0e
 static void sha256(unsigned char *msg, int msgLen, unsigned char *hash)
3e2f0e
 {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    hashFunc(msg, msgLen, hash, HASH_AlgSHA256);
f8a0a1
+#else
3e2f0e
     unsigned char blk[64];
3e2f0e
     unsigned int H[8];
3e2f0e
     int blkLen, i;
3e2f0e
@@ -1453,7 +2049,10 @@ static void sha256(unsigned char *msg, int msgL
3e2f0e
         hash[i * 4 + 2] = (unsigned char)(H[i] >> 8);
3e2f0e
         hash[i * 4 + 3] = (unsigned char)H[i];
3e2f0e
     }
f8a0a1
+#endif
f8a0a1
 }
f8a0a1
+
f8a0a1
+#ifndef ENABLE_NSS3
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 // SHA-512 hash (see FIPS 180-4)
f8a0a1
 //------------------------------------------------------------------------
3e2f0e
@@ -1557,9 +2156,13 @@ static void sha512HashBlock(unsigned char *blk,
3e2f0e
     H[6] += g;
3e2f0e
     H[7] += h;
f8a0a1
 }
f8a0a1
+#endif
f8a0a1
 
3e2f0e
 static void sha512(unsigned char *msg, int msgLen, unsigned char *hash)
3e2f0e
 {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    hashFunc(msg, msgLen, hash, HASH_AlgSHA512);
f8a0a1
+#else
3e2f0e
     unsigned char blk[128];
3e2f0e
     uint64_t H[8];
3e2f0e
     int blkLen = 0, i;
3e2f0e
@@ -1622,6 +2225,7 @@ static void sha512(unsigned char *msg, int msgL
3e2f0e
         hash[i * 8 + 6] = (unsigned char)(H[i] >> 8);
3e2f0e
         hash[i * 8 + 7] = (unsigned char)H[i];
3e2f0e
     }
f8a0a1
+#endif
f8a0a1
 }
f8a0a1
 
f8a0a1
 //------------------------------------------------------------------------
3e2f0e
@@ -1631,6 +2235,9 @@ static void sha512(unsigned char *msg, int msgL
3e2f0e
 // 2.A 384 bit message digest is obtained by truncating the final hash value.
3e2f0e
 static void sha384(unsigned char *msg, int msgLen, unsigned char *hash)
3e2f0e
 {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    hashFunc(msg, msgLen, hash, HASH_AlgSHA384);
f8a0a1
+#else
3e2f0e
     unsigned char blk[128];
3e2f0e
     uint64_t H[8];
3e2f0e
     int blkLen, i;
3e2f0e
@@ -1696,6 +2303,7 @@ static void sha384(unsigned char *msg, int msgL
3e2f0e
         hash[i * 8 + 6] = (unsigned char)(H[i] >> 8);
3e2f0e
         hash[i * 8 + 7] = (unsigned char)H[i];
3e2f0e
     }
f8a0a1
+#endif
f8a0a1
 }
f8a0a1
 
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
@@ -1735,7 +2344,11 @@ static void revision6Hash(GooString *inp
3e2f0e
         memcpy(state.buf, state.cbc, 16); // Copy CBC IV to buf
3e2f0e
         state.bufIdx = 0;
3e2f0e
         state.paddingReached = false;
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        state.context = aesInitContext(state.cbc, aesKey, 16, false);
f8a0a1
+#else
3e2f0e
         aesKeyExpansion(&state, aesKey, 16, false);
f8a0a1
+#endif
f8a0a1
 
3e2f0e
         for (int i = 0; i < (4 * sequenceLength); i++) {
3e2f0e
             aesEncryptBlock(&state, K1 + (16 * i));
f8a0a1
@@ -1776,6 +2389,9 @@ static void revision6Hash(GooString *inp
3e2f0e
             sha512(E, totalLength, K);
3e2f0e
         }
3e2f0e
         rounds++;
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+        PK11_DestroyContext(state.context, PR_TRUE);
f8a0a1
+#endif
3e2f0e
     }
3e2f0e
     // the first 32 bytes of the final K are the output of the function.
f8a0a1
 }
f8a0a1
diff --git a/poppler/Decrypt.h b/poppler/Decrypt.h
f8a0a1
index d4667c8c..16fa9830 100644
f8a0a1
--- a/poppler/Decrypt.h
f8a0a1
+++ b/poppler/Decrypt.h
f8a0a1
@@ -31,6 +32,9 @@
f8a0a1
 #include "goo/GooString.h"
f8a0a1
 #include "Object.h"
f8a0a1
 #include "Stream.h"
f8a0a1
+#ifdef ENABLE_NSS3
f8a0a1
+#include <pk11pub.h>
f8a0a1
+#endif
f8a0a1
 
f8a0a1
 //------------------------------------------------------------------------
f8a0a1
 // Decrypt
3e2f0e
@@ -73,14 +77,22 @@ private:
f8a0a1
  * case of encryption. */
3e2f0e
 struct DecryptRC4State
3e2f0e
 {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    PK11Context *context;
f8a0a1
+#else
3e2f0e
     unsigned char state[256];
3e2f0e
     unsigned char x, y;
f8a0a1
+#endif
f8a0a1
 };
f8a0a1
 
3e2f0e
 struct DecryptAESState
3e2f0e
 {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    PK11Context *context;
f8a0a1
+#else
3e2f0e
     unsigned int w[44];
3e2f0e
     unsigned char state[16];
f8a0a1
+#endif
3e2f0e
     unsigned char cbc[16];
3e2f0e
     unsigned char buf[16];
3e2f0e
     bool paddingReached; // encryption only
f8a0a1
@@ -87,8 +99,12 @@ struct DecryptAESState {
f8a0a1
 
3e2f0e
 struct DecryptAES256State
3e2f0e
 {
f8a0a1
+#ifdef ENABLE_NSS3
3e2f0e
+    PK11Context *context;
f8a0a1
+#else
3e2f0e
     unsigned int w[60];
3e2f0e
     unsigned char state[16];
f8a0a1
+#endif
3e2f0e
     unsigned char cbc[16];
3e2f0e
     unsigned char buf[16];
3e2f0e
     bool paddingReached; // encryption only
f8a0a1
diff --git a/poppler/poppler-config.h.cmake b/poppler/poppler-config.h.cmake
f8a0a1
index f0a5a1a0..dcaade6f 100644
f8a0a1
--- a/poppler/poppler-config.h.cmake
f8a0a1
+++ b/poppler/poppler-config.h.cmake
f8a0a1
@@ -115,6 +115,12 @@
3e2f0e
 #cmakedefine USE_BOOST_HEADERS 1
f8a0a1
 #endif
f8a0a1
 
f8a0a1
+/* Build against libnss3 for digital signature validation and
f8a0a1
+   implementation of encryption/decryption. */
f8a0a1
+#ifndef ENABLE_NSS3
f8a0a1
+#cmakedefine ENABLE_NSS3 1
f8a0a1
+#endif
f8a0a1
+
3e2f0e
 //------------------------------------------------------------------------
3e2f0e
 // version
3e2f0e
 //------------------------------------------------------------------------