diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties
index af749a2df..629bfb27c 100644
--- a/l10n/en-US/viewer.properties
+++ b/l10n/en-US/viewer.properties
@@ -125,8 +125,10 @@ missing_file_error=Missing PDF file.
 # the PDF spec (32000-1:2008 Table 169 – Annotation types).
 # Some common types are e.g.: "Check", "Text", "Comment", "Note"
 text_annotation_type.alt=[{{type}} Annotation]
-request_password=PDF is protected by a password:
-invalid_password=Invalid Password.
+password_label=Enter the password to open this PDF file.
+password_invalid=Invalid password. Please try again.
+password_ok=OK
+password_cancel=Cancel
 
 printing_not_supported=Warning: Printing is not fully supported by this browser.
 printing_not_ready=Warning: The PDF is not fully loaded for printing.
diff --git a/l10n/nl/viewer.properties b/l10n/nl/viewer.properties
index e3dae8f99..9288af81e 100644
--- a/l10n/nl/viewer.properties
+++ b/l10n/nl/viewer.properties
@@ -125,8 +125,10 @@ missing_file_error=Ontbrekend PDF-bestand.
 # the PDF spec (32000-1:2008 Table 169 – Annotation types).
 # Some common types are e.g.: "Check", "Text", "Comment", "Note"
 text_annotation_type.alt=[{{type}}-aantekening]
-request_password=Dit PDF-bestand is beveiligd met een wachtwoord:
-invalid_password=Onjuist wachtwoord.
+password_label=Voer het wachtwoord in om dit PDF-bestand te openen.
+password_invalid=Onjuist wachtwoord. Probeer het opnieuw.
+password_ok=OK
+password_cancel=Annuleren
 
 printing_not_supported=Waarschuwing: afdrukken wordt niet volledig ondersteund door deze browser.
 printing_not_ready=Waarschuwing: het PDF-bestand is niet volledig geladen en kan daarom nog niet afgedrukt worden.
diff --git a/web/password_prompt.js b/web/password_prompt.js
new file mode 100644
index 000000000..38053fb60
--- /dev/null
+++ b/web/password_prompt.js
@@ -0,0 +1,94 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* globals PDFJS, mozL10n */
+
+'use strict';
+
+var PasswordPrompt = {
+  visible: false,
+  updatePassword: null,
+  reason: null,
+  overlayContainer: null,
+  passwordField: null,
+  passwordText: null,
+  passwordSubmit: null,
+  passwordCancel: null,
+
+  initialize: function secondaryToolbarInitialize(options) {
+    this.overlayContainer = options.overlayContainer;
+    this.passwordField = options.passwordField;
+    this.passwordText = options.passwordText;
+    this.passwordSubmit = options.passwordSubmit;
+    this.passwordCancel = options.passwordCancel;
+
+    // Attach the event listeners.
+    this.passwordSubmit.addEventListener('click',
+      this.verifyPassword.bind(this));
+
+    this.passwordCancel.addEventListener('click', this.hide.bind(this));
+
+    this.passwordField.addEventListener('keydown',
+      function (e) {
+        if (e.keyCode === 13) { // Enter key
+          this.verifyPassword();
+        }
+      }.bind(this));
+
+    this.overlayContainer.addEventListener('keydown',
+      function (e) {
+        if (e.keyCode === 27) { // Esc key
+          this.hide();
+        }
+      }.bind(this));
+  },
+
+  show: function passwordPromptShow() {
+    if (this.visible) {
+      return;
+    }
+    this.visible = true;
+    this.overlayContainer.classList.remove('hidden');
+    this.passwordField.focus();
+
+    var promptString = mozL10n.get('password_label', null,
+      'Enter the password to open this PDF file.');
+
+    if (this.reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) {
+      promptString = mozL10n.get('password_invalid', null,
+        'Invalid password. Please try again.');
+    }
+
+    this.passwordText.textContent = promptString;
+  },
+
+  hide: function passwordPromptClose() {
+    if (!this.visible) {
+      return;
+    }
+    this.visible = false;
+    this.passwordField.value = '';
+    this.overlayContainer.classList.add('hidden');
+  },
+
+  verifyPassword: function passwordPromptVerifyPassword() {
+    var password = this.passwordField.value;
+    if (password && password.length > 0) {
+      this.hide();
+      return this.updatePassword(password);
+    }
+  }
+};
diff --git a/web/viewer.css b/web/viewer.css
index 5669248b6..b44ba7bff 100644
--- a/web/viewer.css
+++ b/web/viewer.css
@@ -547,6 +547,7 @@ html[dir='rtl'] .splitToolbarButton > .toolbarButton {
 .splitToolbarButton > .toolbarButton:hover,
 .splitToolbarButton > .toolbarButton:focus,
 .dropdownToolbarButton:hover,
+.promptButton:hover,
 .toolbarButton.textButton:hover,
 .toolbarButton.textButton:focus {
   background-color: hsla(0,0%,0%,.2);
@@ -603,6 +604,7 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
 
 .toolbarButton,
 .dropdownToolbarButton,
+.promptButton,
 .secondaryToolbarButton {
   min-width: 16px;
   padding: 2px 6px 0;
@@ -625,10 +627,12 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
 }
 
 html[dir='ltr'] .toolbarButton,
+html[dir='ltr'] .promptButton,
 html[dir='ltr'] .dropdownToolbarButton {
   margin: 3px 2px 4px 0;
 }
 html[dir='rtl'] .toolbarButton,
+html[dir='rtl'] .promptButton,
 html[dir='rtl'] .dropdownToolbarButton {
   margin: 3px 0 4px 2px;
 }
@@ -636,6 +640,7 @@ html[dir='rtl'] .dropdownToolbarButton {
 .toolbarButton:hover,
 .toolbarButton:focus,
 .dropdownToolbarButton,
+.promptButton,
 .secondaryToolbarButton:hover,
 .secondaryToolbarButton:focus {
   background-color: hsla(0,0%,0%,.12);
@@ -649,6 +654,7 @@ html[dir='rtl'] .dropdownToolbarButton {
 }
 
 .toolbarButton:hover:active,
+.promptButton:hover:active,
 .dropdownToolbarButton:hover:active,
 .secondaryToolbarButton:hover:active {
   background-color: hsla(0,0%,0%,.2);
@@ -722,6 +728,12 @@ html[dir='rtl'] .dropdownToolbarButton {
   background: hsl(0,0%,24%);
 }
 
+.promptButton {
+  margin: 3px 2px 4px 5px !important;
+  line-height: 16px;
+  padding: 2px 6px 3px 6px;
+}
+
 #customScaleOption {
   display: none;
 }
@@ -1326,6 +1338,60 @@ canvas {
   width: 98%;
 }
 
+#overlayContainer {
+  display: table;
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  background-color: hsla(0,0%,0%,.2);
+  z-index: 10000;
+}
+
+#promptContainer {
+  display: table-cell;
+  vertical-align: middle;
+  text-align: center;
+}
+
+#promptContainer > * {
+  display: inline-block;
+}
+
+.prompt {
+  display: table;
+  padding: 15px;
+  border-spacing: 4px;
+  color: hsl(0,0%,85%);
+  line-height: 14px;
+  text-align: center;
+  background-color: #474747; /* fallback */
+  background-image: url(images/texture.png),
+                    linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+  box-shadow: inset 1px 0 0 hsla(0,0%,100%,.08),
+              inset 0 1px 1px hsla(0,0%,0%,.15),
+              inset 0 -1px 0 hsla(0,0%,100%,.05),
+              0 1px 0 hsla(0,0%,0%,.15),
+              0 1px 1px hsla(0,0%,0%,.1);
+}
+
+.prompt > .row {
+  display: table-row;
+}
+
+.prompt > .row > * {
+  display: table-cell;
+}
+
+.prompt .toolbarField {
+  margin: 5px 0;
+  width: 200px;
+}
+
+.prompt .toolbarField:hover,
+.prompt .toolbarField:focus {
+  border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
+}
+
 .clearBoth {
   clear: both;
 }
diff --git a/web/viewer.html b/web/viewer.html
index 588269424..2b578091a 100644
--- a/web/viewer.html
+++ b/web/viewer.html
@@ -67,6 +67,7 @@ limitations under the License.
     <script type="text/javascript" src="pdf_find_controller.js"></script>
     <script type="text/javascript" src="pdf_history.js"></script>
     <script type="text/javascript" src="secondary_toolbar.js"></script>
+    <script type="text/javascript" src="password_prompt.js"></script>
 <!--#endif-->
 
     <script type="text/javascript" src="debugger.js"></script>
@@ -281,6 +282,23 @@ limitations under the License.
         </div>
       </div> <!-- mainContainer -->
 
+      <div id="overlayContainer" class="hidden">
+        <div id="promptContainer">
+          <div id="passwordContainer" class="prompt doorHanger">
+            <div class="row">
+              <p id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:</p>
+            </div>
+            <div class="row">
+              <input type="password" id="password" class="toolbarField" />
+            </div>
+            <div class="row">
+              <button id="passwordCancel" class="promptButton"><span data-l10n-id="password_cancel">Cancel</span></button>
+              <button id="passwordSubmit" class="promptButton"><span data-l10n-id="password_ok">OK</span></button>
+            </div>
+          </div>
+        </div>
+      </div> 
+
     </div> <!-- outerContainer -->
     <div id="printContainer"></div>
   </body>
diff --git a/web/viewer.js b/web/viewer.js
index c20b97a34..5d71b069a 100644
--- a/web/viewer.js
+++ b/web/viewer.js
@@ -18,7 +18,7 @@
            PDFFindController, ProgressBar, TextLayerBuilder, DownloadManager,
            getFileName, getOutputScale, scrollIntoView, getPDFFileNameFromURL,
            PDFHistory, PageView, ThumbnailView, noContextMenuHandler,
-           SecondaryToolbar */
+           SecondaryToolbar, PasswordPrompt */
 
 'use strict';
 
@@ -167,6 +167,7 @@ var currentPageNumber = 1;
 //#include pdf_find_controller.js
 //#include pdf_history.js
 //#include secondary_toolbar.js
+//#include password_prompt.js
 
 var PDFView = {
   pages: [],
@@ -217,6 +218,14 @@ var PDFView = {
       pageRotateCcw: document.getElementById('pageRotateCcw')
     });
 
+    PasswordPrompt.initialize({
+      overlayContainer: document.getElementById('overlayContainer'),
+      passwordField: document.getElementById('password'),
+      passwordText: document.getElementById('passwordText'),
+      passwordSubmit: document.getElementById('passwordSubmit'),
+      passwordCancel: document.getElementById('passwordCancel')
+    });
+
     PDFFindBar.initialize({
       bar: document.getElementById('findbar'),
       toggleButton: document.getElementById('viewFind'),
@@ -572,18 +581,9 @@ var PDFView = {
     var self = this;
     self.loading = true;
     var passwordNeeded = function passwordNeeded(updatePassword, reason) {
-      var promptString = mozL10n.get('request_password', null,
-                                'PDF is protected by a password:');
-
-      if (reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) {
-        promptString += '\n' + mozL10n.get('invalid_password', null,
-                                'Invalid Password.');
-      }
-
-      password = prompt(promptString);
-      if (password && password.length > 0) {
-        return updatePassword(password);
-      }
+      PasswordPrompt.updatePassword = updatePassword;
+      PasswordPrompt.reason = reason;
+      PasswordPrompt.show();
     };
 
     function getDocumentProgress(progressData) {
@@ -2092,6 +2092,10 @@ window.addEventListener('click', function click(evt) {
 }, false);
 
 window.addEventListener('keydown', function keydown(evt) {
+  if (PasswordPrompt.visible) {
+    return;
+  }
+
   var handled = false;
   var cmd = (evt.ctrlKey ? 1 : 0) |
             (evt.altKey ? 2 : 0) |