toolkit/components/passwordmgr/crypto-SDR.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:b678c3cbdb5b
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
6 const Cc = Components.classes;
7 const Ci = Components.interfaces;
8 const Cr = Components.results;
9
10 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
11 Components.utils.import("resource://gre/modules/Services.jsm");
12
13 function LoginManagerCrypto_SDR() {
14 this.init();
15 };
16
17 LoginManagerCrypto_SDR.prototype = {
18
19 classID : Components.ID("{dc6c2976-0f73-4f1f-b9ff-3d72b4e28309}"),
20 QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManagerCrypto]),
21
22 __sdrSlot : null, // PKCS#11 slot being used by the SDR.
23 get _sdrSlot() {
24 if (!this.__sdrSlot) {
25 let modules = Cc["@mozilla.org/security/pkcs11moduledb;1"].
26 getService(Ci.nsIPKCS11ModuleDB);
27 this.__sdrSlot = modules.findSlotByName("");
28 }
29 return this.__sdrSlot;
30 },
31
32 __decoderRing : null, // nsSecretDecoderRing service
33 get _decoderRing() {
34 if (!this.__decoderRing)
35 this.__decoderRing = Cc["@mozilla.org/security/sdr;1"].
36 getService(Ci.nsISecretDecoderRing);
37 return this.__decoderRing;
38 },
39
40 __utfConverter : null, // UCS2 <--> UTF8 string conversion
41 get _utfConverter() {
42 if (!this.__utfConverter) {
43 this.__utfConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
44 createInstance(Ci.nsIScriptableUnicodeConverter);
45 this.__utfConverter.charset = "UTF-8";
46 }
47 return this.__utfConverter;
48 },
49
50 _utfConverterReset : function() {
51 this.__utfConverter = null;
52 },
53
54 _debug : false, // mirrors signon.debug
55 _uiBusy : false,
56
57
58 /*
59 * log
60 *
61 * Internal function for logging debug messages to the Error Console.
62 */
63 log : function (message) {
64 if (!this._debug)
65 return;
66 dump("PwMgr cryptoSDR: " + message + "\n");
67 Services.console.logStringMessage("PwMgr cryptoSDR: " + message);
68 },
69
70
71 init : function () {
72 // Connect to the correct preferences branch.
73 this._prefBranch = Services.prefs.getBranch("signon.");
74
75 this._debug = this._prefBranch.getBoolPref("debug");
76
77 // Check to see if the internal PKCS#11 token has been initialized.
78 // If not, set a blank password.
79 let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].
80 getService(Ci.nsIPK11TokenDB);
81
82 let token = tokenDB.getInternalKeyToken();
83 if (token.needsUserInit) {
84 this.log("Initializing key3.db with default blank password.");
85 token.initPassword("");
86 }
87 },
88
89
90 /*
91 * encrypt
92 *
93 * Encrypts the specified string, using the SecretDecoderRing.
94 *
95 * Returns the encrypted string, or throws an exception if there was a
96 * problem.
97 */
98 encrypt : function (plainText) {
99 let cipherText = null;
100
101 let wasLoggedIn = this.isLoggedIn;
102 let canceledMP = false;
103
104 this._uiBusy = true;
105 try {
106 let plainOctet = this._utfConverter.ConvertFromUnicode(plainText);
107 plainOctet += this._utfConverter.Finish();
108 cipherText = this._decoderRing.encryptString(plainOctet);
109 } catch (e) {
110 this.log("Failed to encrypt string. (" + e.name + ")");
111 // If the user clicks Cancel, we get NS_ERROR_FAILURE.
112 // (unlike decrypting, which gets NS_ERROR_NOT_AVAILABLE).
113 if (e.result == Cr.NS_ERROR_FAILURE) {
114 canceledMP = true;
115 throw Components.Exception("User canceled master password entry", Cr.NS_ERROR_ABORT);
116 } else {
117 throw Components.Exception("Couldn't encrypt string", Cr.NS_ERROR_FAILURE);
118 }
119 } finally {
120 this._uiBusy = false;
121 // If we triggered a master password prompt, notify observers.
122 if (!wasLoggedIn && this.isLoggedIn)
123 this._notifyObservers("passwordmgr-crypto-login");
124 else if (canceledMP)
125 this._notifyObservers("passwordmgr-crypto-loginCanceled");
126 }
127 return cipherText;
128 },
129
130
131 /*
132 * decrypt
133 *
134 * Decrypts the specified string, using the SecretDecoderRing.
135 *
136 * Returns the decrypted string, or throws an exception if there was a
137 * problem.
138 */
139 decrypt : function (cipherText) {
140 let plainText = null;
141
142 let wasLoggedIn = this.isLoggedIn;
143 let canceledMP = false;
144
145 this._uiBusy = true;
146 try {
147 let plainOctet;
148 plainOctet = this._decoderRing.decryptString(cipherText);
149 plainText = this._utfConverter.ConvertToUnicode(plainOctet);
150 } catch (e) {
151 this.log("Failed to decrypt string: " + cipherText +
152 " (" + e.name + ")");
153
154 // In the unlikely event the converter threw, reset it.
155 this._utfConverterReset();
156
157 // If the user clicks Cancel, we get NS_ERROR_NOT_AVAILABLE.
158 // If the cipherText is bad / wrong key, we get NS_ERROR_FAILURE
159 // Wrong passwords are handled by the decoderRing reprompting;
160 // we get no notification.
161 if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
162 canceledMP = true;
163 throw Components.Exception("User canceled master password entry", Cr.NS_ERROR_ABORT);
164 } else {
165 throw Components.Exception("Couldn't decrypt string", Cr.NS_ERROR_FAILURE);
166 }
167 } finally {
168 this._uiBusy = false;
169 // If we triggered a master password prompt, notify observers.
170 if (!wasLoggedIn && this.isLoggedIn)
171 this._notifyObservers("passwordmgr-crypto-login");
172 else if (canceledMP)
173 this._notifyObservers("passwordmgr-crypto-loginCanceled");
174 }
175
176 return plainText;
177 },
178
179
180 /*
181 * uiBusy
182 */
183 get uiBusy() {
184 return this._uiBusy;
185 },
186
187
188 /*
189 * isLoggedIn
190 */
191 get isLoggedIn() {
192 let status = this._sdrSlot.status;
193 this.log("SDR slot status is " + status);
194 if (status == Ci.nsIPKCS11Slot.SLOT_READY ||
195 status == Ci.nsIPKCS11Slot.SLOT_LOGGED_IN)
196 return true;
197 if (status == Ci.nsIPKCS11Slot.SLOT_NOT_LOGGED_IN)
198 return false;
199 throw Components.Exception("unexpected slot status: " + status, Cr.NS_ERROR_FAILURE);
200 },
201
202
203 /*
204 * defaultEncType
205 */
206 get defaultEncType() {
207 return Ci.nsILoginManagerCrypto.ENCTYPE_SDR;
208 },
209
210
211 /*
212 * _notifyObservers
213 */
214 _notifyObservers : function(topic) {
215 this.log("Prompted for a master password, notifying for " + topic);
216 Services.obs.notifyObservers(null, topic, null);
217 },
218 }; // end of nsLoginManagerCrypto_SDR implementation
219
220 let component = [LoginManagerCrypto_SDR];
221 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);

mercurial