summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/crypto-SDR.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/crypto-SDR.js')
-rw-r--r--toolkit/components/passwordmgr/crypto-SDR.js207
1 files changed, 207 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/crypto-SDR.js b/toolkit/components/passwordmgr/crypto-SDR.js
new file mode 100644
index 000000000..b0916eb29
--- /dev/null
+++ b/toolkit/components/passwordmgr/crypto-SDR.js
@@ -0,0 +1,207 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
+ "resource://gre/modules/LoginHelper.jsm");
+
+function LoginManagerCrypto_SDR() {
+ this.init();
+}
+
+LoginManagerCrypto_SDR.prototype = {
+
+ classID : Components.ID("{dc6c2976-0f73-4f1f-b9ff-3d72b4e28309}"),
+ QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManagerCrypto]),
+
+ __sdrSlot : null, // PKCS#11 slot being used by the SDR.
+ get _sdrSlot() {
+ if (!this.__sdrSlot) {
+ let modules = Cc["@mozilla.org/security/pkcs11moduledb;1"].
+ getService(Ci.nsIPKCS11ModuleDB);
+ this.__sdrSlot = modules.findSlotByName("");
+ }
+ return this.__sdrSlot;
+ },
+
+ __decoderRing : null, // nsSecretDecoderRing service
+ get _decoderRing() {
+ if (!this.__decoderRing)
+ this.__decoderRing = Cc["@mozilla.org/security/sdr;1"].
+ getService(Ci.nsISecretDecoderRing);
+ return this.__decoderRing;
+ },
+
+ __utfConverter : null, // UCS2 <--> UTF8 string conversion
+ get _utfConverter() {
+ if (!this.__utfConverter) {
+ this.__utfConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
+ createInstance(Ci.nsIScriptableUnicodeConverter);
+ this.__utfConverter.charset = "UTF-8";
+ }
+ return this.__utfConverter;
+ },
+
+ _utfConverterReset : function() {
+ this.__utfConverter = null;
+ },
+
+ _uiBusy : false,
+
+
+ init : function () {
+ // Check to see if the internal PKCS#11 token has been initialized.
+ // If not, set a blank password.
+ let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].
+ getService(Ci.nsIPK11TokenDB);
+
+ let token = tokenDB.getInternalKeyToken();
+ if (token.needsUserInit) {
+ this.log("Initializing key3.db with default blank password.");
+ token.initPassword("");
+ }
+ },
+
+
+ /*
+ * encrypt
+ *
+ * Encrypts the specified string, using the SecretDecoderRing.
+ *
+ * Returns the encrypted string, or throws an exception if there was a
+ * problem.
+ */
+ encrypt : function (plainText) {
+ let cipherText = null;
+
+ let wasLoggedIn = this.isLoggedIn;
+ let canceledMP = false;
+
+ this._uiBusy = true;
+ try {
+ let plainOctet = this._utfConverter.ConvertFromUnicode(plainText);
+ plainOctet += this._utfConverter.Finish();
+ cipherText = this._decoderRing.encryptString(plainOctet);
+ } catch (e) {
+ this.log("Failed to encrypt string. (" + e.name + ")");
+ // If the user clicks Cancel, we get NS_ERROR_FAILURE.
+ // (unlike decrypting, which gets NS_ERROR_NOT_AVAILABLE).
+ if (e.result == Cr.NS_ERROR_FAILURE) {
+ canceledMP = true;
+ throw Components.Exception("User canceled master password entry", Cr.NS_ERROR_ABORT);
+ } else {
+ throw Components.Exception("Couldn't encrypt string", Cr.NS_ERROR_FAILURE);
+ }
+ } finally {
+ this._uiBusy = false;
+ // If we triggered a master password prompt, notify observers.
+ if (!wasLoggedIn && this.isLoggedIn)
+ this._notifyObservers("passwordmgr-crypto-login");
+ else if (canceledMP)
+ this._notifyObservers("passwordmgr-crypto-loginCanceled");
+ }
+ return cipherText;
+ },
+
+
+ /*
+ * decrypt
+ *
+ * Decrypts the specified string, using the SecretDecoderRing.
+ *
+ * Returns the decrypted string, or throws an exception if there was a
+ * problem.
+ */
+ decrypt : function (cipherText) {
+ let plainText = null;
+
+ let wasLoggedIn = this.isLoggedIn;
+ let canceledMP = false;
+
+ this._uiBusy = true;
+ try {
+ let plainOctet;
+ plainOctet = this._decoderRing.decryptString(cipherText);
+ plainText = this._utfConverter.ConvertToUnicode(plainOctet);
+ } catch (e) {
+ this.log("Failed to decrypt string: " + cipherText +
+ " (" + e.name + ")");
+
+ // In the unlikely event the converter threw, reset it.
+ this._utfConverterReset();
+
+ // If the user clicks Cancel, we get NS_ERROR_NOT_AVAILABLE.
+ // If the cipherText is bad / wrong key, we get NS_ERROR_FAILURE
+ // Wrong passwords are handled by the decoderRing reprompting;
+ // we get no notification.
+ if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
+ canceledMP = true;
+ throw Components.Exception("User canceled master password entry", Cr.NS_ERROR_ABORT);
+ } else {
+ throw Components.Exception("Couldn't decrypt string", Cr.NS_ERROR_FAILURE);
+ }
+ } finally {
+ this._uiBusy = false;
+ // If we triggered a master password prompt, notify observers.
+ if (!wasLoggedIn && this.isLoggedIn)
+ this._notifyObservers("passwordmgr-crypto-login");
+ else if (canceledMP)
+ this._notifyObservers("passwordmgr-crypto-loginCanceled");
+ }
+
+ return plainText;
+ },
+
+
+ /*
+ * uiBusy
+ */
+ get uiBusy() {
+ return this._uiBusy;
+ },
+
+
+ /*
+ * isLoggedIn
+ */
+ get isLoggedIn() {
+ let status = this._sdrSlot.status;
+ this.log("SDR slot status is " + status);
+ if (status == Ci.nsIPKCS11Slot.SLOT_READY ||
+ status == Ci.nsIPKCS11Slot.SLOT_LOGGED_IN)
+ return true;
+ if (status == Ci.nsIPKCS11Slot.SLOT_NOT_LOGGED_IN)
+ return false;
+ throw Components.Exception("unexpected slot status: " + status, Cr.NS_ERROR_FAILURE);
+ },
+
+
+ /*
+ * defaultEncType
+ */
+ get defaultEncType() {
+ return Ci.nsILoginManagerCrypto.ENCTYPE_SDR;
+ },
+
+
+ /*
+ * _notifyObservers
+ */
+ _notifyObservers : function(topic) {
+ this.log("Prompted for a master password, notifying for " + topic);
+ Services.obs.notifyObservers(null, topic, null);
+ },
+}; // end of nsLoginManagerCrypto_SDR implementation
+
+XPCOMUtils.defineLazyGetter(this.LoginManagerCrypto_SDR.prototype, "log", () => {
+ let logger = LoginHelper.createLogger("Login crypto");
+ return logger.log.bind(logger);
+});
+
+var component = [LoginManagerCrypto_SDR];
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);