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