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