mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 433949 - Use WeaveCrypto component (NSS) instead of OpenSSL
This commit is contained in:
parent
bb55bba909
commit
6ed3755104
@ -19,6 +19,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dan Mills <thunder@mozilla.com>
|
||||
* Justin Dolske <dolske@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -65,6 +66,15 @@ CryptoSvc.prototype = {
|
||||
return this.__os;
|
||||
},
|
||||
|
||||
__crypto: null,
|
||||
get _crypto() {
|
||||
if (!this.__crypto)
|
||||
this.__crypto = Cc["@labs.mozilla.com/Weave/Crypto;1"].
|
||||
createInstance(Ci.IWeaveCrypto);
|
||||
return this.__crypto;
|
||||
},
|
||||
|
||||
|
||||
get defaultAlgorithm() {
|
||||
return Utils.prefs.getCharPref("encryption");
|
||||
},
|
||||
@ -82,271 +92,6 @@ CryptoSvc.prototype = {
|
||||
branch.addObserver("extensions.weave.encryption", this, false);
|
||||
},
|
||||
|
||||
_openssl: function Crypto__openssl() {
|
||||
let extMgr = Cc["@mozilla.org/extensions/manager;1"]
|
||||
.getService(Ci.nsIExtensionManager);
|
||||
let loc = extMgr.getInstallLocation("{340c2bbc-ce74-4362-90b5-7c26312808ef}");
|
||||
|
||||
let wrap = loc.getItemLocation("{340c2bbc-ce74-4362-90b5-7c26312808ef}");
|
||||
wrap.append("openssl");
|
||||
let bin;
|
||||
|
||||
let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||
switch(os) {
|
||||
case "WINNT":
|
||||
wrap.append("win32");
|
||||
wrap.append("exec.bat");
|
||||
bin = wrap.parent.path + "\\openssl.exe";
|
||||
break;
|
||||
case "Linux":
|
||||
case "Darwin":
|
||||
wrap.append("unix");
|
||||
wrap.append("exec.sh");
|
||||
bin = "openssl";
|
||||
break;
|
||||
default:
|
||||
throw "encryption not supported on this platform: " + os;
|
||||
}
|
||||
|
||||
let args = Array.prototype.slice.call(arguments);
|
||||
args.unshift(wrap, Utils.getTmp().path, bin);
|
||||
|
||||
let rv = Utils.runCmd.apply(null, args);
|
||||
if (rv != 0)
|
||||
throw "openssl did not run successfully, error code " + rv;
|
||||
},
|
||||
|
||||
_opensslPBE: function Crypto__openssl(op, algorithm, input, password) {
|
||||
let inputFile = Utils.getTmp("input");
|
||||
let [inputFOS] = Utils.open(inputFile, ">");
|
||||
inputFOS.writeString(input);
|
||||
inputFOS.close();
|
||||
|
||||
// nsIProcess doesn't support stdin, so we write a file instead
|
||||
let passFile = Utils.getTmp("pass");
|
||||
let [passFOS] = Utils.open(passFile, ">", PERMS_PASSFILE);
|
||||
passFOS.writeString(password);
|
||||
passFOS.close();
|
||||
|
||||
try {
|
||||
this._openssl(algorithm, op, "-a", "-salt", "-in", "input",
|
||||
"-out", "output", "-pass", "file:pass");
|
||||
|
||||
} catch (e) {
|
||||
throw e;
|
||||
|
||||
} finally {
|
||||
passFile.remove(false);
|
||||
inputFile.remove(false);
|
||||
}
|
||||
|
||||
let outputFile = Utils.getTmp("output");
|
||||
let [outputFIS] = Utils.open(outputFile, "<");
|
||||
let ret = Utils.readStream(outputFIS);
|
||||
outputFIS.close();
|
||||
outputFile.remove(false);
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
// generates a random string that can be used as a passphrase
|
||||
_opensslRand: function Crypto__opensslRand(length) {
|
||||
if (!length)
|
||||
length = 128;
|
||||
|
||||
let outputFile = Utils.getTmp("output");
|
||||
if (outputFile.exists())
|
||||
outputFile.remove(false);
|
||||
|
||||
this._openssl("rand", "-base64", "-out", "output", length);
|
||||
|
||||
let [outputFIS] = Utils.open(outputFile, "<");
|
||||
let ret = Utils.readStream(outputFIS);
|
||||
outputFIS.close();
|
||||
outputFile.remove(false);
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
// generates an rsa public/private key pair, with the private key encrypted
|
||||
_opensslRSAKeyGen: function Crypto__opensslRSAKeyGen(identity, algorithm, bits) {
|
||||
if (!algorithm)
|
||||
algorithm = "aes-256-cbc";
|
||||
if (!bits)
|
||||
bits = "2048";
|
||||
|
||||
let privKeyF = Utils.getTmp("privkey.pem");
|
||||
if (privKeyF.exists())
|
||||
privKeyF.remove(false);
|
||||
|
||||
this._openssl("genrsa", "-out", "privkey.pem", bits);
|
||||
|
||||
let pubKeyF = Utils.getTmp("pubkey.pem");
|
||||
if (pubKeyF.exists())
|
||||
pubKeyF.remove(false);
|
||||
|
||||
this._openssl("rsa", "-in", "privkey.pem", "-out", "pubkey.pem",
|
||||
"-outform", "PEM", "-pubout");
|
||||
|
||||
let cryptedKeyF = Utils.getTmp("enckey.pem");
|
||||
if (cryptedKeyF.exists())
|
||||
cryptedKeyF.remove(false);
|
||||
|
||||
// nsIProcess doesn't support stdin, so we write a file instead
|
||||
let passFile = Utils.getTmp("pass");
|
||||
let [passFOS] = Utils.open(passFile, ">", PERMS_PASSFILE);
|
||||
passFOS.writeString(identity.password);
|
||||
passFOS.close();
|
||||
|
||||
try {
|
||||
this._openssl("pkcs8", "-in", "privkey.pem", "-out", "enckey.pem",
|
||||
"-topk8", "-v2", algorithm, "-passout", "file:pass");
|
||||
|
||||
} catch (e) {
|
||||
throw e;
|
||||
|
||||
} finally {
|
||||
passFile.remove(false);
|
||||
privKeyF.remove(false);
|
||||
}
|
||||
|
||||
let [cryptedKeyFIS] = Utils.open(cryptedKeyF, "<");
|
||||
let cryptedKey = Utils.readStream(cryptedKeyFIS);
|
||||
cryptedKeyFIS.close();
|
||||
cryptedKeyF.remove(false);
|
||||
|
||||
let [pubKeyFIS] = Utils.open(pubKeyF, "<");
|
||||
let pubKey = Utils.readStream(pubKeyFIS);
|
||||
pubKeyFIS.close();
|
||||
pubKeyF.remove(false);
|
||||
|
||||
return [cryptedKey, pubKey];
|
||||
},
|
||||
|
||||
// returns 'input' encrypted with the 'pubkey' public RSA key
|
||||
_opensslRSAencrypt: function Crypto__opensslRSAencrypt(input, identity) {
|
||||
let inputFile = Utils.getTmp("input");
|
||||
let [inputFOS] = Utils.open(inputFile, ">");
|
||||
inputFOS.writeString(input);
|
||||
inputFOS.close();
|
||||
|
||||
let keyFile = Utils.getTmp("key");
|
||||
let [keyFOS] = Utils.open(keyFile, ">");
|
||||
keyFOS.writeString(identity.pubkey);
|
||||
keyFOS.close();
|
||||
|
||||
let tmpFile = Utils.getTmp("tmp-output");
|
||||
if (tmpFile.exists())
|
||||
tmpFile.remove(false);
|
||||
|
||||
let outputFile = Utils.getTmp("output");
|
||||
if (outputFile.exists())
|
||||
outputFile.remove(false);
|
||||
|
||||
this._openssl("rsautl", "-encrypt", "-pubin", "-inkey", "key",
|
||||
"-in", "input", "-out", "tmp-output");
|
||||
this._openssl("base64", "-in", "tmp-output", "-out", "output");
|
||||
|
||||
let [outputFIS] = Utils.open(outputFile, "<");
|
||||
let output = Utils.readStream(outputFIS);
|
||||
outputFIS.close();
|
||||
outputFile.remove(false);
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
// returns 'input' decrypted with the 'privkey' private RSA key and password
|
||||
_opensslRSAdecrypt: function Crypto__opensslRSAdecrypt(input, identity) {
|
||||
let inputFile = Utils.getTmp("input");
|
||||
let [inputFOS] = Utils.open(inputFile, ">");
|
||||
inputFOS.writeString(input);
|
||||
inputFOS.close();
|
||||
|
||||
let keyFile = Utils.getTmp("key");
|
||||
let [keyFOS] = Utils.open(keyFile, ">");
|
||||
keyFOS.writeString(identity.privkey);
|
||||
keyFOS.close();
|
||||
|
||||
let tmpKeyFile = Utils.getTmp("tmp-key");
|
||||
if (tmpKeyFile.exists())
|
||||
tmpKeyFile.remove(false);
|
||||
|
||||
let tmpFile = Utils.getTmp("tmp-output");
|
||||
if (tmpFile.exists())
|
||||
tmpFile.remove(false);
|
||||
|
||||
let outputFile = Utils.getTmp("output");
|
||||
if (outputFile.exists())
|
||||
outputFile.remove(false);
|
||||
|
||||
// nsIProcess doesn't support stdin, so we write a file instead
|
||||
let passFile = Utils.getTmp("pass");
|
||||
let [passFOS] = Utils.open(passFile, ">", PERMS_PASSFILE);
|
||||
passFOS.writeString(identity.password);
|
||||
passFOS.close();
|
||||
|
||||
try {
|
||||
this._openssl("base64", "-d", "-in", "input", "-out", "tmp-output");
|
||||
// FIXME: this is because openssl.exe (in windows only) doesn't
|
||||
// seem to support -passin for rsautl, but it works for rsa.
|
||||
this._openssl("rsa", "-in", "key", "-out", "tmp-key", "-passin", "file:pass");
|
||||
this._openssl("rsautl", "-decrypt", "-inkey", "tmp-key",
|
||||
"-in", "tmp-output", "-out", "output");
|
||||
|
||||
} catch(e) {
|
||||
throw e;
|
||||
|
||||
} finally {
|
||||
passFile.remove(false);
|
||||
tmpKeyFile.remove(false);
|
||||
tmpFile.remove(false);
|
||||
keyFile.remove(false);
|
||||
}
|
||||
|
||||
let [outputFIS] = Utils.open(outputFile, "<");
|
||||
let output = Utils.readStream(outputFIS);
|
||||
outputFIS.close();
|
||||
outputFile.remove(false);
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
// returns the public key from the private key
|
||||
_opensslRSAkeydecrypt: function Crypto__opensslRSAkeydecrypt(identity) {
|
||||
let keyFile = Utils.getTmp("key");
|
||||
let [keyFOS] = Utils.open(keyFile, ">");
|
||||
keyFOS.writeString(identity.privkey);
|
||||
keyFOS.close();
|
||||
|
||||
let outputFile = Utils.getTmp("output");
|
||||
if (outputFile.exists())
|
||||
outputFile.remove(false);
|
||||
|
||||
// nsIProcess doesn't support stdin, so we write a file instead
|
||||
let passFile = Utils.getTmp("pass");
|
||||
let [passFOS] = Utils.open(passFile, ">", PERMS_PASSFILE);
|
||||
passFOS.writeString(identity.password);
|
||||
passFOS.close();
|
||||
|
||||
try {
|
||||
this._openssl("rsa", "-in", "key", "-pubout", "-out", "output",
|
||||
"-passin", "file:pass");
|
||||
|
||||
} catch(e) {
|
||||
throw e;
|
||||
|
||||
} finally {
|
||||
passFile.remove(false);
|
||||
}
|
||||
|
||||
let [outputFIS] = Utils.open(outputFile, "<");
|
||||
let output = Utils.readStream(outputFIS);
|
||||
outputFIS.close();
|
||||
outputFile.remove(false);
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupports]),
|
||||
|
||||
// nsIObserver
|
||||
@ -381,99 +126,107 @@ CryptoSvc.prototype = {
|
||||
|
||||
// Crypto
|
||||
|
||||
PBEencrypt: function Crypto_PBEencrypt(data, identity, algorithm) {
|
||||
encryptData: function Crypto_encryptData(data, identity) {
|
||||
let self = yield;
|
||||
let ret;
|
||||
|
||||
if (!algorithm)
|
||||
algorithm = this.defaultAlgorithm;
|
||||
this._log.trace("encrypt called. [id=" + identity.realm + "]");
|
||||
|
||||
if (algorithm != "none")
|
||||
this._log.debug("Encrypting data");
|
||||
|
||||
switch (algorithm) {
|
||||
case "none":
|
||||
if ("none" == this.defaultAlgorithm) {
|
||||
this._log.debug("NOT encrypting data");
|
||||
ret = data;
|
||||
break;
|
||||
|
||||
case "aes-128-cbc":
|
||||
case "aes-192-cbc":
|
||||
case "aes-256-cbc":
|
||||
case "bf-cbc":
|
||||
case "des-ede3-cbc":
|
||||
ret = this._opensslPBE("-e", algorithm, data, identity.password);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw "Unknown encryption algorithm: " + algorithm;
|
||||
} else {
|
||||
let symkey = identity.bulkKey;
|
||||
let iv = identity.bulkIV;
|
||||
ret = this._crypto.encrypt(data, symkey, iv);
|
||||
}
|
||||
|
||||
if (algorithm != "none")
|
||||
this._log.debug("Done encrypting data");
|
||||
|
||||
self.done(ret);
|
||||
},
|
||||
|
||||
PBEdecrypt: function Crypto_PBEdecrypt(data, identity, algorithm) {
|
||||
decryptData: function Crypto_decryptData(data, identity) {
|
||||
let self = yield;
|
||||
let ret;
|
||||
|
||||
if (!algorithm)
|
||||
algorithm = this.defaultAlgorithm;
|
||||
this._log.trace("decrypt called. [id=" + identity.realm + "]");
|
||||
|
||||
if (algorithm != "none")
|
||||
this._log.debug("Decrypting data");
|
||||
|
||||
switch (algorithm) {
|
||||
case "none":
|
||||
if ("none" == this.defaultAlgorithm) {
|
||||
this._log.debug("NOT decrypting data");
|
||||
ret = data;
|
||||
break;
|
||||
|
||||
case "aes-128-cbc":
|
||||
case "aes-192-cbc":
|
||||
case "aes-256-cbc":
|
||||
case "bf-cbc":
|
||||
case "des-ede3-cbc":
|
||||
ret = this._opensslPBE("-d", algorithm, data, identity.password);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw "Unknown encryption algorithm: " + algorithm;
|
||||
} else {
|
||||
let symkey = identity.bulkKey;
|
||||
let iv = identity.bulkIV;
|
||||
ret = this._crypto.decrypt(data, symkey, iv);
|
||||
}
|
||||
|
||||
if (algorithm != "none")
|
||||
this._log.debug("Done decrypting data");
|
||||
|
||||
self.done(ret);
|
||||
},
|
||||
|
||||
PBEkeygen: function Crypto_PBEkeygen() {
|
||||
/*
|
||||
* randomKeyGen
|
||||
*
|
||||
* Generates a random symmetric key and IV, and puts them in the specified
|
||||
* identity.
|
||||
*/
|
||||
randomKeyGen: function Crypto_randomKeyGen(identity) {
|
||||
let self = yield;
|
||||
let ret = this._opensslRand();
|
||||
self.done(ret);
|
||||
|
||||
this._log.trace("randomKeyGen called. [id=" + identity.realm + "]");
|
||||
|
||||
let symkey = this._crypto.generateRandomKey();
|
||||
let iv = this._crypto.generateRandomIV();
|
||||
|
||||
identity.bulkKey = symkey;
|
||||
identity.bulkIV = iv;
|
||||
},
|
||||
|
||||
/*
|
||||
* RSAkeygen
|
||||
*
|
||||
* Generates a new RSA keypair, as well as the salt/IV used for protecting
|
||||
* the private key, and puts them in the specified identity.
|
||||
*/
|
||||
RSAkeygen: function Crypto_RSAkeygen(identity) {
|
||||
let self = yield;
|
||||
let ret = this._opensslRSAKeyGen(identity);
|
||||
|
||||
this._log.trace("RSAkeygen called. [id=" + identity.realm + "]");
|
||||
let privOut = {};
|
||||
let pubOut = {};
|
||||
|
||||
// Generate a blob of random data for salting the passphrase used to
|
||||
// encrypt the private key.
|
||||
let salt = this._crypto.generateRandomBytes(32);
|
||||
let iv = this._crypto.generateRandomIV();
|
||||
|
||||
this._crypto.generateKeypair(identity.password,
|
||||
salt, iv,
|
||||
pubOut, privOut);
|
||||
|
||||
identity.keypairAlg = "RSA";
|
||||
identity.pubkey = pubOut.value;
|
||||
identity.privkey = privOut.value;
|
||||
identity.passphraseSalt = salt;
|
||||
identity.privkeyWrapIV = iv;
|
||||
},
|
||||
|
||||
wrapKey : function Crypto_wrapKey(data, identity) {
|
||||
let self = yield;
|
||||
|
||||
this._log.trace("wrapKey called. [id=" + identity.realm + "]");
|
||||
let ret = this._crypto.wrapSymmetricKey(data, identity.pubkey);
|
||||
|
||||
self.done(ret);
|
||||
},
|
||||
|
||||
RSAencrypt: function Crypto_RSAencrypt(data, identity) {
|
||||
unwrapKey: function Crypto_unwrapKey(data, identity) {
|
||||
let self = yield;
|
||||
let ret = this._opensslRSAencrypt(data, identity);
|
||||
|
||||
this._log.trace("upwrapKey called. [id=" + identity.realm + "]");
|
||||
let ret = this._crypto.unwrapSymmetricKey(data,
|
||||
identity.privkey,
|
||||
identity.password,
|
||||
identity.passphraseSalt,
|
||||
identity.privkeyWrapIV);
|
||||
self.done(ret);
|
||||
},
|
||||
|
||||
RSAdecrypt: function Crypto_RSAdecrypt(data, identity) {
|
||||
let self = yield;
|
||||
let ret = this._opensslRSAdecrypt(data, identity);
|
||||
self.done(ret);
|
||||
},
|
||||
|
||||
RSAkeydecrypt: function Crypto_RSAkeydecrypt(identity) {
|
||||
let self = yield;
|
||||
let ret = this._opensslRSAkeydecrypt(identity);
|
||||
self.done(ret);
|
||||
}
|
||||
};
|
||||
|
@ -161,24 +161,13 @@ Engine.prototype = {
|
||||
this.__snapshot = value;
|
||||
},
|
||||
|
||||
get pbeId() {
|
||||
let id = ID.get('Engine:PBE:' + this.name);
|
||||
if (!id)
|
||||
id = ID.get('Engine:PBE:default');
|
||||
if (!id)
|
||||
throw "No identity found for engine PBE!";
|
||||
return id;
|
||||
},
|
||||
|
||||
get engineId() {
|
||||
let id = ID.get('Engine:' + this.name);
|
||||
if (!id ||
|
||||
id.username != this.pbeId.username || id.realm != this.pbeId.realm) {
|
||||
let password = null;
|
||||
if (id)
|
||||
password = id.password;
|
||||
id = new Identity(this.pbeId.realm + ' - ' + this.logName,
|
||||
this.pbeId.username, password);
|
||||
if (!id) {
|
||||
// Copy the service login from WeaveID
|
||||
let masterID = ID.get('WeaveID');
|
||||
|
||||
id = new Identity(this.logName, masterID.username, masterID.password);
|
||||
ID.set('Engine:' + this.name, id);
|
||||
}
|
||||
return id;
|
||||
@ -271,10 +260,8 @@ Engine.prototype = {
|
||||
this._log.info("Local snapshot version: " + this._snapshot.version);
|
||||
this._log.info("Server maxVersion: " + this._remote.status.data.maxVersion);
|
||||
|
||||
if ("none" != Utils.prefs.getCharPref("encryption")) {
|
||||
let symkey = yield this._remote.keys.getKey(self.cb, this.pbeId);
|
||||
this.engineId.setTempPassword(symkey);
|
||||
}
|
||||
if ("none" != Utils.prefs.getCharPref("encryption"))
|
||||
yield this._remote.keys.getKeyAndIV(self.cb, this.engineId);
|
||||
|
||||
// 1) Fetch server deltas
|
||||
let server = {};
|
||||
|
@ -341,28 +341,40 @@ BookmarksEngine.prototype = {
|
||||
this._annoSvc.EXPIRE_NEVER);
|
||||
|
||||
// Create a new symmetric key, to be used only for encrypting this share.
|
||||
Crypto.PBEkeygen.async(Crypto, self.cb);
|
||||
let newSymKey = yield;
|
||||
// XXX HACK. Seems like the engine shouldn't have to be doing any of this, or
|
||||
// should use its own identity here.
|
||||
let tmpIdentity = {
|
||||
realm : "temp ID",
|
||||
bulkKey : null,
|
||||
bulkIV : null
|
||||
};
|
||||
Crypto.randomKeyGen.async(Crypto, self.cb, tmpIdentity);
|
||||
yield;
|
||||
let bulkKey = tmpIdentity.bulkKey;
|
||||
let bulkIV = tmpIdentity.bulkIV;
|
||||
|
||||
/* Get public keys for me and the user I'm sharing with.
|
||||
Each user's public key is stored in /user/username/public/pubkey. */
|
||||
let myPubKeyFile = new Resource("/user/" + myUserName + "/public/pubkey");
|
||||
myPubKeyFile.get(self.cb);
|
||||
let myPubKey = yield;
|
||||
let idRSA = ID.get('WeaveCryptoID');
|
||||
let userPubKeyFile = new Resource("/user/" + username + "/public/pubkey");
|
||||
userPubKeyFile.get(self.cb);
|
||||
let userPubKey = yield;
|
||||
|
||||
/* Create the keyring, containing the sym key encrypted with each
|
||||
of our public keys: */
|
||||
Crypto.RSAencrypt.async(Crypto, self.cb, symKey, {pubkey: myPubKey} );
|
||||
Crypto.wrapKey.async(Crypto, self.cb, bulkKey, {realm : "tmpWrapID", pubkey: idRSA.pubkey} );
|
||||
let encryptedForMe = yield;
|
||||
Crypto.RSAencrypt.async(Crypto, self.cb, symKey, {pubkey: userPubKey} );
|
||||
Crypto.wrapKey.async(Crypto, self.cb, bulkKey, {realm : "tmpWrapID", pubkey: userPubKey} );
|
||||
let encryptedForYou = yield;
|
||||
let keyring = { myUserName: encryptedForMe,
|
||||
username: encryptedForYou };
|
||||
let keys = {
|
||||
ring : { },
|
||||
bulkIV : bulkIV
|
||||
};
|
||||
keys.ring[myUserName] = encryptedForMe;
|
||||
keys.ring[username] = encryptedForYou;
|
||||
|
||||
let keyringFile = new Resource( serverPath + "/" + KEYRING_FILE_NAME );
|
||||
keyringFile.put( self.cb, this._json.encode( keyring ) );
|
||||
keyringFile.put( self.cb, this._json.encode( keys ) );
|
||||
yield;
|
||||
|
||||
// Call Atul's js api for setting htaccess:
|
||||
@ -390,8 +402,14 @@ BookmarksEngine.prototype = {
|
||||
// key that we'll use to encrypt.
|
||||
let keyringFile = new Resource(serverPath + "/" + KEYRING_FILE_NAME);
|
||||
keyringFile.get(self.cb);
|
||||
let keyring = yield;
|
||||
let symKey = keyring[ myUserName ];
|
||||
let keys = yield;
|
||||
|
||||
// Unwrap (decrypt) the key with the user's private key.
|
||||
let idRSA = ID.get('WeaveCryptoID');
|
||||
let bulkKey = yield Crypto.unwrapKey.async(Crypto, self.cb,
|
||||
keys.ring[myUserName], idRSA);
|
||||
let bulkIV = keys.bulkIV;
|
||||
|
||||
// Get the json-wrapped contents of everything in the folder:
|
||||
let json = this._store._wrapMount( folderNode, myUserName );
|
||||
/* TODO what does wrapMount do with this username? Should I be passing
|
||||
@ -399,7 +417,12 @@ BookmarksEngine.prototype = {
|
||||
|
||||
// Encrypt it with the symkey and put it into the shared-bookmark file.
|
||||
let bmkFile = new Resource(serverPath + "/" + SHARED_BOOKMARK_FILE_NAME);
|
||||
Crypto.PBEencrypt.async( Crypto, self.cb, json, {password:symKey} );
|
||||
let tmpIdentity = {
|
||||
realm : "temp ID",
|
||||
bulkKey : bulkKey,
|
||||
bulkIV : bulkIV
|
||||
};
|
||||
Crypto.encryptData.async( Crypto, self.cb, json, tmpIdentity );
|
||||
let cyphertext = yield;
|
||||
bmkFile.put( self.cb, cyphertext );
|
||||
yield;
|
||||
@ -545,14 +568,18 @@ BookmarksEngine.prototype = {
|
||||
// key that we'll use to encrypt.
|
||||
let keyringFile = new Resource(serverPath + "/" + KEYRING_FILE_NAME);
|
||||
keyringFile.get(self.cb);
|
||||
let keyring = yield;
|
||||
let symKey = keyring[ myUserName ];
|
||||
let keys = yield;
|
||||
|
||||
// Decrypt the contents of the bookmark file with the symmetric key:
|
||||
let bmkFile = new Resource(serverPath + "/" + SHARED_BOOKMARK_FILE_NAME);
|
||||
bmkFile.get(self.cb);
|
||||
let cyphertext = yield;
|
||||
Crypto.PBEdecrypt.async( Crypto, self.cb, cyphertext, {password:symKey} );
|
||||
let tmpIdentity = {
|
||||
realm : "temp ID",
|
||||
bulkKey : keys.ring[myUserName],
|
||||
bulkIV : keys.bulkIV
|
||||
};
|
||||
Crypto.decryptData.async( Crypto, self.cb, cyphertext, tmpIdentity );
|
||||
let json = yield;
|
||||
// TODO error handling (see what Resource can throw or return...)
|
||||
|
||||
|
@ -87,28 +87,26 @@ IDManager.prototype = {
|
||||
*/
|
||||
|
||||
function Identity(realm, username, password) {
|
||||
this._realm = realm;
|
||||
this._username = username;
|
||||
this.realm = realm;
|
||||
this.username = username;
|
||||
this._password = password;
|
||||
}
|
||||
Identity.prototype = {
|
||||
get realm() { return this._realm; },
|
||||
set realm(value) { this._realm = value; },
|
||||
realm : null,
|
||||
|
||||
get username() { return this._username; },
|
||||
set username(value) { this._username = value; },
|
||||
// Only the "WeaveCryptoID" realm uses these:
|
||||
privkey : null,
|
||||
pubkey : null,
|
||||
passphraseSalt : null,
|
||||
privkeyWrapIV : null,
|
||||
|
||||
// Only the per-engine identity uses these:
|
||||
bulkKey : null,
|
||||
bulkIV : null,
|
||||
|
||||
username : null,
|
||||
get userHash() { return Utils.sha1(this.username); },
|
||||
|
||||
_privkey: null,
|
||||
get privkey() { return this._privkey; },
|
||||
set privkey(value) { this._privkey = value; },
|
||||
|
||||
// FIXME: get this from the privkey using crypto.js?
|
||||
_pubkey: null,
|
||||
get pubkey() { return this._pubkey; },
|
||||
set pubkey(value) { this._pubkey = value; },
|
||||
|
||||
_password: null,
|
||||
get password() {
|
||||
if (!this._password)
|
||||
|
@ -282,7 +282,7 @@ CryptoFilter.prototype = {
|
||||
beforePUT: function CryptoFilter_beforePUT(data) {
|
||||
let self = yield;
|
||||
this._log.debug("Encrypting data");
|
||||
Crypto.PBEencrypt.async(Crypto, self.cb, data, this._remote.engineId);
|
||||
Crypto.encryptData.async(Crypto, self.cb, data, this._remote.engineId);
|
||||
let ret = yield;
|
||||
self.done(ret);
|
||||
},
|
||||
@ -292,7 +292,7 @@ CryptoFilter.prototype = {
|
||||
this._log.debug("Decrypting data");
|
||||
if (!this._remote.status.data)
|
||||
throw "Remote status must be initialized before crypto filter can be used"
|
||||
Crypto.PBEdecrypt.async(Crypto, self.cb, data, this._remote.engineId);
|
||||
Crypto.decryptData.async(Crypto, self.cb, data, this._remote.engineId);
|
||||
let ret = yield;
|
||||
self.done(ret);
|
||||
}
|
||||
@ -320,21 +320,25 @@ Keychain.prototype = {
|
||||
this.__proto__.__proto__._init.call(this, this._remote.serverPrefix + "keys.json");
|
||||
this.pushFilter(new JsonFilter());
|
||||
},
|
||||
_getKey: function Keychain__getKey(identity) {
|
||||
_getKeyAndIV: function Keychain__getKeyAndIV(identity) {
|
||||
let self = yield;
|
||||
|
||||
this.get(self.cb);
|
||||
yield;
|
||||
if (!this.data || !this.data.ring || !this.data.ring[identity.username])
|
||||
throw "Keyring does not contain a key for this user";
|
||||
Crypto.RSAdecrypt.async(Crypto, self.cb,
|
||||
this.data.ring[identity.username], identity);
|
||||
let symkey = yield;
|
||||
|
||||
self.done(symkey);
|
||||
// Unwrap (decrypt) the key with the user's private key.
|
||||
let idRSA = ID.get('WeaveCryptoID');
|
||||
let symkey = yield Crypto.unwrapKey.async(Crypto, self.cb,
|
||||
this.data.ring[identity.username], idRSA);
|
||||
let iv = this.data.bulkIV;
|
||||
|
||||
identity.bulkKey = symkey;
|
||||
identity.bulkIV = iv;
|
||||
},
|
||||
getKey: function Keychain_getKey(onComplete, identity) {
|
||||
this._getKey.async(this, onComplete, identity);
|
||||
getKeyAndIV: function Keychain_getKeyAndIV(onComplete, identity) {
|
||||
this._getKeyAndIV.async(this, onComplete, identity);
|
||||
}
|
||||
// FIXME: implement setKey()
|
||||
};
|
||||
@ -346,7 +350,6 @@ function RemoteStore(engine) {
|
||||
RemoteStore.prototype = {
|
||||
get serverPrefix() this._engine.serverPrefix,
|
||||
get engineId() this._engine.engineId,
|
||||
get pbeId() this._engine.pbeId,
|
||||
|
||||
get status() {
|
||||
let status = new Status(this);
|
||||
@ -420,23 +423,20 @@ RemoteStore.prototype = {
|
||||
// Does a fresh upload of the given snapshot to a new store
|
||||
_initialize: function RStore__initialize(snapshot) {
|
||||
let self = yield;
|
||||
let symkey;
|
||||
let wrappedSymkey;
|
||||
|
||||
if ("none" != Utils.prefs.getCharPref("encryption")) {
|
||||
symkey = yield Crypto.PBEkeygen.async(Crypto, self.cb);
|
||||
if (!symkey)
|
||||
throw "Could not generate a symmetric encryption key";
|
||||
this.engineId.setTempPassword(symkey);
|
||||
Crypto.randomKeyGen.async(Crypto, self.cb, this.engineId);
|
||||
yield;
|
||||
|
||||
symkey = yield Crypto.RSAencrypt.async(Crypto, self.cb,
|
||||
this.engineId.password,
|
||||
this.pbeId);
|
||||
if (!symkey)
|
||||
throw "Could not encrypt symmetric encryption key";
|
||||
// Wrap (encrypt) this key with the user's public key.
|
||||
let idRSA = ID.get('WeaveCryptoID');
|
||||
wrappedSymkey = yield Crypto.wrapKey.async(Crypto, self.cb,
|
||||
this.engineId.bulkKey, idRSA);
|
||||
}
|
||||
|
||||
let keys = {ring: {}};
|
||||
keys.ring[this.engineId.username] = symkey;
|
||||
let keys = {ring: {}, bulkIV: this.engineId.bulkIV};
|
||||
keys.ring[this.engineId.username] = wrappedSymkey;
|
||||
yield this.keys.put(self.cb, keys);
|
||||
|
||||
yield this._snapshot.put(self.cb, snapshot.data);
|
||||
@ -505,6 +505,7 @@ RemoteStore.prototype = {
|
||||
snap.version = this.status.data.maxVersion;
|
||||
|
||||
if (lastSyncSnap.version < this.status.data.snapVersion) {
|
||||
this._log.trace("Getting latest from snap --> scratch");
|
||||
self.done(yield this._getLatestFromScratch.async(this, self.cb));
|
||||
return;
|
||||
|
||||
|
@ -163,6 +163,14 @@ WeaveSvc.prototype = {
|
||||
return this.__dirSvc;
|
||||
},
|
||||
|
||||
__json: null,
|
||||
get _json() {
|
||||
if (!this.__json)
|
||||
this.__json = Cc["@mozilla.org/dom/json;1"].
|
||||
createInstance(Ci.nsIJSON);
|
||||
return this.__json;
|
||||
},
|
||||
|
||||
// Timer object for automagically syncing
|
||||
_scheduleTimer: null,
|
||||
|
||||
@ -357,25 +365,53 @@ WeaveSvc.prototype = {
|
||||
finally { DAV.defaultPrefix = prefix; }
|
||||
},
|
||||
|
||||
_keyCheck: function WeaveSvc__keyCheck() {
|
||||
_getKeypair : function WeaveSync__getKeypair() {
|
||||
let self = yield;
|
||||
|
||||
if ("none" != Utils.prefs.getCharPref("encryption")) {
|
||||
DAV.GET("private/privkey", self.cb);
|
||||
let keyResp = yield;
|
||||
Utils.ensureStatus(keyResp.status,
|
||||
"Could not get private key from server", [[200,300],404]);
|
||||
if ("none" == Utils.prefs.getCharPref("encryption"))
|
||||
return;
|
||||
|
||||
if (keyResp.status != 404) {
|
||||
let id = ID.get('WeaveCryptoID');
|
||||
id.privkey = keyResp.responseText;
|
||||
Crypto.RSAkeydecrypt.async(Crypto, self.cb, id);
|
||||
id.pubkey = yield;
|
||||
} else {
|
||||
this._log.trace("Retrieving keypair from server");
|
||||
|
||||
// XXX this kind of replaces _keyCheck
|
||||
// seems like key generation should only happen during setup?
|
||||
DAV.GET("private/privkey", self.cb);
|
||||
let privkeyResp = yield;
|
||||
Utils.ensureStatus(privkeyResp.status,
|
||||
"Could not get private key from server", [[200,300],404]);
|
||||
|
||||
DAV.GET("public/pubkey", self.cb);
|
||||
let pubkeyResp = yield;
|
||||
Utils.ensureStatus(pubkeyResp.status,
|
||||
"Could not get public key from server", [[200,300],404]);
|
||||
|
||||
if (privkeyResp.status == 404 || pubkeyResp.status == 404) {
|
||||
this._generateKeys.async(this, self.cb);
|
||||
yield;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let privkeyData = this._json.decode(privkeyResp.responseText);
|
||||
let pubkeyData = this._json.decode(pubkeyResp.responseText);
|
||||
|
||||
if (!privkeyData || !pubkeyData)
|
||||
throw "Bad keypair JSON";
|
||||
if (privkeyData.version != 1 || pubkeyData.version != 1)
|
||||
throw "Unexpected keypair data version";
|
||||
if (privkeyData.algorithm != "RSA" || pubkeyData.algorithm != "RSA")
|
||||
throw "Only RSA keys currently supported";
|
||||
|
||||
|
||||
let id = ID.get('WeaveCryptoID');
|
||||
id.keypairAlg = privkeyData.algorithm;
|
||||
id.privkey = privkeyData.privkey;
|
||||
id.privkeyWrapIV = privkeyData.privkeyIV;
|
||||
id.passphraseSalt = privkeyData.privkeySalt;
|
||||
|
||||
id.pubkey = pubkeyData.pubkey;
|
||||
|
||||
// XXX note that we have not used the private key, so we don't yet
|
||||
// know if the user's passphrase works or not.
|
||||
},
|
||||
|
||||
_generateKeys: function WeaveSync__generateKeys() {
|
||||
@ -383,12 +419,10 @@ WeaveSvc.prototype = {
|
||||
|
||||
this._log.debug("Generating new RSA key");
|
||||
|
||||
// RSAkeygen will set the needed |id| properties.
|
||||
let id = ID.get('WeaveCryptoID');
|
||||
Crypto.RSAkeygen.async(Crypto, self.cb, id);
|
||||
let [privkey, pubkey] = yield;
|
||||
|
||||
id.privkey = privkey;
|
||||
id.pubkey = pubkey;
|
||||
yield;
|
||||
|
||||
DAV.MKCOL("private/", self.cb);
|
||||
let ret = yield;
|
||||
@ -400,11 +434,26 @@ WeaveSvc.prototype = {
|
||||
if (!ret)
|
||||
throw "Could not create public key directory";
|
||||
|
||||
DAV.PUT("private/privkey", privkey, self.cb);
|
||||
let privkeyData = { version : 1,
|
||||
algorithm : id.keypairAlg,
|
||||
privkey : id.privkey,
|
||||
privkeyIV : id.privkeyWrapIV,
|
||||
privkeySalt : id.passphraseSalt
|
||||
};
|
||||
let data = this._json.encode(privkeyData);
|
||||
|
||||
DAV.PUT("private/privkey", data, self.cb);
|
||||
ret = yield;
|
||||
Utils.ensureStatus(ret.status, "Could not upload private key");
|
||||
|
||||
DAV.PUT("public/pubkey", pubkey, self.cb);
|
||||
|
||||
let pubkeyData = { version : 1,
|
||||
algorithm : id.keypairAlg,
|
||||
pubkey : id.pubkey,
|
||||
};
|
||||
data = this._json.encode(pubkeyData);
|
||||
|
||||
DAV.PUT("public/pubkey", data, self.cb);
|
||||
ret = yield;
|
||||
Utils.ensureStatus(ret.status, "Could not upload public key");
|
||||
},
|
||||
@ -491,7 +540,7 @@ WeaveSvc.prototype = {
|
||||
|
||||
this._versionCheck.async(this, self.cb);
|
||||
yield;
|
||||
this._keyCheck.async(this, self.cb);
|
||||
this._getKeypair.async(this, self.cb);
|
||||
yield;
|
||||
|
||||
this._loggedIn = true;
|
||||
@ -559,7 +608,7 @@ WeaveSvc.prototype = {
|
||||
this._versionCheck.async(this, self.cb);
|
||||
yield;
|
||||
|
||||
this._keyCheck.async(this, self.cb);
|
||||
this._getKeypair.async(this, self.cb);
|
||||
yield;
|
||||
|
||||
let engines = Engines.getAll();
|
||||
@ -586,7 +635,7 @@ WeaveSvc.prototype = {
|
||||
this._versionCheck.async(this, self.cb);
|
||||
yield;
|
||||
|
||||
this._keyCheck.async(this, self.cb);
|
||||
this._getKeypair.async(this, self.cb);
|
||||
yield;
|
||||
|
||||
let engines = Engines.getAll();
|
||||
|
@ -5,15 +5,20 @@ const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
// initialize nss
|
||||
let ch = Cc["@mozilla.org/security/hash;1"].
|
||||
createInstance(Ci.nsICryptoHash);
|
||||
|
||||
let ds = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
|
||||
let provider = {
|
||||
getFile: function(prop, persistent) {
|
||||
persistent.value = true;
|
||||
if (prop == "ExtPrefDL") {
|
||||
if (prop == "ExtPrefDL")
|
||||
return [ds.get("CurProcD", Ci.nsIFile)];
|
||||
}
|
||||
else if (prop == "ProfD")
|
||||
return ds.get("CurProcD", Ci.nsIFile);
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
},
|
||||
QueryInterface: function(iid) {
|
||||
|
149
services/sync/tests/unit/test_crypto_crypt.js
Normal file
149
services/sync/tests/unit/test_crypto_crypt.js
Normal file
@ -0,0 +1,149 @@
|
||||
function run_test() {
|
||||
var cryptoSvc = Cc["@labs.mozilla.com/Weave/Crypto;1"].
|
||||
getService(Ci.IWeaveCrypto);
|
||||
|
||||
// First, do a normal run with expected usage... Generate a random key and
|
||||
// iv, encrypt and decrypt a string.
|
||||
var iv = cryptoSvc.generateRandomIV();
|
||||
do_check_eq(iv.length, 24);
|
||||
|
||||
var key = cryptoSvc.generateRandomKey();
|
||||
do_check_eq(key.length, 44);
|
||||
|
||||
var mySecret = "bacon is a vegetable";
|
||||
var cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
do_check_eq(cipherText.length, 44);
|
||||
|
||||
var clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(clearText.length, 20);
|
||||
|
||||
// Did the text survive the encryption round-trip?
|
||||
do_check_eq(clearText, mySecret);
|
||||
do_check_neq(cipherText, mySecret); // just to be explicit
|
||||
|
||||
|
||||
// Do some more tests with a fixed key/iv, to check for reproducable results.
|
||||
cryptoSvc.algorithm = Ci.IWeaveCrypto.AES_128_CBC;
|
||||
key = "St1tFCor7vQEJNug/465dQ==";
|
||||
iv = "oLjkfrLIOnK2bDRvW4kXYA==";
|
||||
|
||||
// Test small input sizes
|
||||
mySecret = "";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "OGQjp6mK1a3fs9k9Ml4L3w==");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
mySecret = "x";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "96iMl4vhOxFUW/lVHHzVqg==");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
mySecret = "xx";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "olpPbETRYROCSqFWcH2SWg==");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
mySecret = "xxx";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "rRbpHGyVSZizLX/x43Wm+Q==");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
mySecret = "xxxx";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "HeC7miVGDcpxae9RmiIKAw==");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
// Tests input spanning a block boundary (AES block size is 16 bytes)
|
||||
mySecret = "123456789012345";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "e6c5hwphe45/3VN/M0bMUA==");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
mySecret = "1234567890123456";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP1JOIQF87E2vTUvBUQnyV04=");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
mySecret = "12345678901234567";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP5GvxWJ9+GIAS6lXw+5fHTI=");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
|
||||
// Test with 192 bit key.
|
||||
cryptoSvc.algorithm = Ci.IWeaveCrypto.AES_192_CBC;
|
||||
key = "iz35tuIMq4/H+IYw2KTgow==";
|
||||
iv = "TJYrvva2KxvkM8hvOIvWp3xgjTXgq5Ss";
|
||||
mySecret = "i like pie";
|
||||
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "DLGx8BWqSCLGG7i/xwvvxg==");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
// Test with 256 bit key.
|
||||
cryptoSvc.algorithm = Ci.IWeaveCrypto.AES_256_CBC;
|
||||
key = "c5hG3YG+NC61FFy8NOHQak1ZhMEWO79bwiAfar2euzI=";
|
||||
iv = "gsgLRDaxWvIfKt75RjuvFWERt83FFsY2A0TW+0b2iVk=";
|
||||
mySecret = "i like pie";
|
||||
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, iv);
|
||||
do_check_eq(cipherText, "o+ADtdMd8ubzNWurS6jt0Q==");
|
||||
do_check_eq(clearText, mySecret);
|
||||
|
||||
|
||||
// Test with bogus inputs
|
||||
cryptoSvc.algorithm = Ci.IWeaveCrypto.AES_128_CBC;
|
||||
key = "St1tFCor7vQEJNug/465dQ==";
|
||||
iv = "oLjkfrLIOnK2bDRvW4kXYA==";
|
||||
mySecret = "does thunder read testcases?";
|
||||
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
|
||||
do_check_eq(cipherText, "T6fik9Ros+DB2ablH9zZ8FWZ0xm/szSwJjIHZu7sjPs=");
|
||||
|
||||
var badkey = "badkeybadkeybadkeybadk==";
|
||||
var badiv = "badivbadivbadivbadivbad==";
|
||||
var badcipher = "crapinputcrapinputcrapinputcrapinputcrapinp=";
|
||||
var failure;
|
||||
|
||||
try {
|
||||
failure = false;
|
||||
clearText = cryptoSvc.decrypt(cipherText, badkey, iv);
|
||||
} catch (e) {
|
||||
failure = true;
|
||||
}
|
||||
do_check_true(failure);
|
||||
|
||||
try {
|
||||
failure = false;
|
||||
clearText = cryptoSvc.decrypt(cipherText, key, badiv);
|
||||
} catch (e) {
|
||||
failure = true;
|
||||
}
|
||||
do_check_true(failure);
|
||||
|
||||
try {
|
||||
failure = false;
|
||||
clearText = cryptoSvc.decrypt(cipherText, badkey, badiv);
|
||||
} catch (e) {
|
||||
failure = true;
|
||||
}
|
||||
do_check_true(failure);
|
||||
|
||||
try {
|
||||
failure = false;
|
||||
clearText = cryptoSvc.decrypt(badcipher, key, iv);
|
||||
} catch (e) {
|
||||
failure = true;
|
||||
}
|
||||
do_check_true(failure);
|
||||
|
||||
}
|
63
services/sync/tests/unit/test_crypto_keypair.js
Normal file
63
services/sync/tests/unit/test_crypto_keypair.js
Normal file
@ -0,0 +1,63 @@
|
||||
function run_test() {
|
||||
var cryptoSvc = Cc["@labs.mozilla.com/Weave/Crypto;1"].
|
||||
getService(Ci.IWeaveCrypto);
|
||||
|
||||
var salt = cryptoSvc.generateRandomBytes(16);
|
||||
do_check_eq(salt.length, 24);
|
||||
|
||||
var iv = cryptoSvc.generateRandomIV();
|
||||
do_check_eq(iv.length, 24);
|
||||
|
||||
var symKey = cryptoSvc.generateRandomKey();
|
||||
do_check_eq(symKey.length, 44);
|
||||
|
||||
|
||||
// Tests with a 2048 bit key (the default)
|
||||
do_check_eq(cryptoSvc.keypairBits, 2048)
|
||||
|
||||
var pubOut = {};
|
||||
var privOut = {};
|
||||
cryptoSvc.generateKeypair("my passphrase", salt, iv, pubOut, privOut);
|
||||
var pubKey = pubOut.value;
|
||||
var privKey = privOut.value;
|
||||
do_check_true(!!pubKey);
|
||||
do_check_true(!!privKey);
|
||||
do_check_eq(pubKey.length, 392);
|
||||
do_check_eq(privKey.length, 1644);
|
||||
|
||||
// do some key wrapping
|
||||
var wrappedKey = cryptoSvc.wrapSymmetricKey(symKey, pubKey);
|
||||
do_check_eq(wrappedKey.length, 344);
|
||||
|
||||
var unwrappedKey = cryptoSvc.unwrapSymmetricKey(wrappedKey, privKey,
|
||||
"my passphrase", salt, iv);
|
||||
do_check_eq(unwrappedKey.length, 44);
|
||||
|
||||
// The acid test... Is our unwrapped key the same thing we started with?
|
||||
do_check_eq(unwrappedKey, symKey);
|
||||
|
||||
|
||||
// Tests with a 1024 bit key
|
||||
cryptoSvc.keypairBits = 1024;
|
||||
do_check_eq(cryptoSvc.keypairBits, 1024)
|
||||
|
||||
cryptoSvc.generateKeypair("my passphrase", salt, iv, pubOut, privOut);
|
||||
var pubKey = pubOut.value;
|
||||
var privKey = privOut.value;
|
||||
do_check_true(!!pubKey);
|
||||
do_check_true(!!privKey);
|
||||
do_check_eq(pubKey.length, 216);
|
||||
do_check_eq(privKey.length, 856);
|
||||
|
||||
// do some key wrapping
|
||||
wrappedKey = cryptoSvc.wrapSymmetricKey(symKey, pubKey);
|
||||
do_check_eq(wrappedKey.length, 172);
|
||||
unwrappedKey = cryptoSvc.unwrapSymmetricKey(wrappedKey, privKey,
|
||||
"my passphrase", salt, iv);
|
||||
do_check_eq(unwrappedKey.length, 44);
|
||||
|
||||
// The acid test... Is our unwrapped key the same thing we started with?
|
||||
do_check_eq(unwrappedKey, symKey);
|
||||
|
||||
|
||||
}
|
65
services/sync/tests/unit/test_crypto_random.js
Normal file
65
services/sync/tests/unit/test_crypto_random.js
Normal file
@ -0,0 +1,65 @@
|
||||
function run_test() {
|
||||
var cryptoSvc = Cc["@labs.mozilla.com/Weave/Crypto;1"].
|
||||
getService(Ci.IWeaveCrypto);
|
||||
|
||||
// Test salt generation.
|
||||
var salt;
|
||||
|
||||
salt = cryptoSvc.generateRandomBytes(0);
|
||||
do_check_eq(salt.length, 0);
|
||||
salt = cryptoSvc.generateRandomBytes(1);
|
||||
do_check_eq(salt.length, 4);
|
||||
salt = cryptoSvc.generateRandomBytes(2);
|
||||
do_check_eq(salt.length, 4);
|
||||
salt = cryptoSvc.generateRandomBytes(3);
|
||||
do_check_eq(salt.length, 4);
|
||||
salt = cryptoSvc.generateRandomBytes(4);
|
||||
do_check_eq(salt.length, 8);
|
||||
salt = cryptoSvc.generateRandomBytes(8);
|
||||
do_check_eq(salt.length, 12);
|
||||
|
||||
// sanity check to make sure salts seem random
|
||||
var salt2 = cryptoSvc.generateRandomBytes(8);
|
||||
do_check_eq(salt2.length, 12);
|
||||
do_check_neq(salt, salt2);
|
||||
|
||||
salt = cryptoSvc.generateRandomBytes(16);
|
||||
do_check_eq(salt.length, 24);
|
||||
salt = cryptoSvc.generateRandomBytes(1024);
|
||||
do_check_eq(salt.length, 1368);
|
||||
|
||||
|
||||
// Test random key generation
|
||||
var keydata, keydata2, iv;
|
||||
|
||||
keydata = cryptoSvc.generateRandomKey();
|
||||
do_check_eq(keydata.length, 44);
|
||||
keydata2 = cryptoSvc.generateRandomKey();
|
||||
do_check_neq(keydata, keydata2); // sanity check for randomness
|
||||
iv = cryptoSvc.generateRandomIV();
|
||||
do_check_eq(iv.length, 24);
|
||||
|
||||
cryptoSvc.algorithm = Ci.IWeaveCrypto.AES_256_CBC;
|
||||
keydata = cryptoSvc.generateRandomKey();
|
||||
do_check_eq(keydata.length, 44);
|
||||
keydata2 = cryptoSvc.generateRandomKey();
|
||||
do_check_neq(keydata, keydata2); // sanity check for randomness
|
||||
iv = cryptoSvc.generateRandomIV();
|
||||
do_check_eq(iv.length, 24);
|
||||
|
||||
cryptoSvc.algorithm = Ci.IWeaveCrypto.AES_192_CBC;
|
||||
keydata = cryptoSvc.generateRandomKey();
|
||||
do_check_eq(keydata.length, 32);
|
||||
keydata2 = cryptoSvc.generateRandomKey();
|
||||
do_check_neq(keydata, keydata2); // sanity check for randomness
|
||||
iv = cryptoSvc.generateRandomIV();
|
||||
do_check_eq(iv.length, 24);
|
||||
|
||||
cryptoSvc.algorithm = Ci.IWeaveCrypto.AES_128_CBC;
|
||||
keydata = cryptoSvc.generateRandomKey();
|
||||
do_check_eq(keydata.length, 24);
|
||||
keydata2 = cryptoSvc.generateRandomKey();
|
||||
do_check_neq(keydata, keydata2); // sanity check for randomness
|
||||
iv = cryptoSvc.generateRandomIV();
|
||||
do_check_eq(iv.length, 24);
|
||||
}
|
@ -35,7 +35,7 @@ let __fakeLogins = [
|
||||
// ----------------------------------------
|
||||
|
||||
function run_test() {
|
||||
ID.set('Engine:PBE:default',
|
||||
ID.set('WeaveID',
|
||||
new Identity('Mozilla Services Encryption Passphrase', 'foo'));
|
||||
|
||||
// The JS module we're testing, with all members exposed.
|
||||
|
@ -1,24 +0,0 @@
|
||||
function run_test() {
|
||||
// initialize nss
|
||||
let ch = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
|
||||
let pbe = Cc["@labs.mozilla.com/Weave/Crypto;1"].getService(Ci.IWeaveCrypto);
|
||||
|
||||
pbe.algorithm = pbe.DES_EDE3_CBC;
|
||||
let cipherTxt = pbe.encrypt("passphrase", "my very secret message!");
|
||||
|
||||
do_check_true(cipherTxt != "my very secret message!");
|
||||
|
||||
let clearTxt = pbe.decrypt("passphrase", cipherTxt);
|
||||
do_check_true(clearTxt == "my very secret message!");
|
||||
|
||||
// The following check with wrong password must cause decryption to fail
|
||||
// because of used padding-schema cipher, RFC 3852 Section 6.3
|
||||
let failure = false;
|
||||
try {
|
||||
pbe.decrypt("wrongpassphrase", cipherTxt);
|
||||
} catch (e) {
|
||||
failure = true;
|
||||
}
|
||||
do_check_true(failure);
|
||||
}
|
@ -21,18 +21,6 @@ let __fakePasswords = {
|
||||
'Mozilla Services Encryption Passphrase': {foo: "passphrase"}
|
||||
};
|
||||
|
||||
Crypto.__proto__ = {
|
||||
RSAkeydecrypt: function fake_RSAkeydecrypt(identity) {
|
||||
let self = yield;
|
||||
|
||||
if (identity.password == "passphrase" &&
|
||||
identity.privkey == "fake private key")
|
||||
self.done("fake public key");
|
||||
else
|
||||
throw new Error("Unexpected identity information.");
|
||||
}
|
||||
};
|
||||
|
||||
let Service = loadInSandbox("resource://weave/service.js");
|
||||
|
||||
function TestService() {
|
||||
|
Loading…
Reference in New Issue
Block a user