Archives For extensions

In working on the Web Crypto API specification, the valuable feedback and criticism keeps going back to the main pitfall: DOM malleability. The many attack surfaces in each web page makes handing over crypto keys and crypto primitives quite dangerous. As the W3 working group approaches this API we have this issue in mind, but, the API(s) we want to deliver are not going to solve the DOM-is-dangerous problem. Luckily, browser vendors are working on this – and have been – for years, and the work continues.

Firefox OS will introduce signed “privileged” and “certified” web apps that by default have very strict CSP applied to them. No eval(), no remote scripts or styles – the app is pretty well sandboxed against the most common attacks. These apps are signed and verified before installation and update. Let’s hope these kinds of approaches will help make web apps more “trustworthy”:)

So, how can we use crypto in web pages and not expose anything like keys or actual crypto functions or properties to the DOM? What does that look like? After thinking about the use case for this: web-based messaging, digital signatures for code and document verification – among others, I came up with what I am calling a ‘bridge’ API, I have named it “nulltxt”.

It has one method: window.navigator.bridge.getCipherObject()

This function creates a DOMRequest object, which you can attach event handlers to: “success” and “error”.

To generate a keypair, you pass a config object:

{type: "keygen", format: "DER_BASE64"}

into “getCipherObject”:

var request = window.navigator.bridge.getCipherObject({type: "keygen",format: "DER_BASE64"});
request.onsuccess = function (){ */ this.result.publicKey is our key /* };
request.onerror = function (error){};

Once your keypair is generated, the success callback is executed, handing you a public key and an ID you’ll need to decrypt or sign with that particular key. Multiple keys can be generated per origin.

To encrypt data, you call the same function with a different config object:

{ type: "write",
  format: "DER_BASE64",
  recipientName: "drzhivago",
  publicKey: A_PUBLIC_KEY,
  keyID: 7635263572 
}

This operation opens a special writing widget in the browser chrome where you can safely write plain text outside of the DOM:

Write some plain text, then click the encrypt button. The browser encrypts the data and returns it to your success event handler. The encrypted JSON blob is now available to send to the server where it can be received by Alice.

The result object looks like:

{
  "content": "yeGwdhLSs8qKDywerhs7pchNzxIpmtRGuBf59zMHegR/+urU20RbGxmHEvrx5yxmcEk8j9yPYHJLRKH6SJlEcDR4TKFzWNYLsMdoAxFi7AecN74MP2s0udvmg4vU944hYFo/F3fh2E9hnBF6xsdoRtCdkiNBLTRINCdDv3dgxLEe1UgdeXpbsIljgHc8svaD/lYik2rV+UojHk0yk9NFzv2tCu8wb58kzZluuo10qyqrX1X/rLpu2ZVlk/Ik+MbM7HxK1cSBL5kqUdNU/tx9qqVZVLzcAZz2ZDr2l0wRGKwoJ3f41QrwN8SGCRvMtpPEl1PdcYtdpTg4atAbNZ7T3cJhybtrYW64Yu7d9coguFQg2TQFU8hyIiWdFhY7XqOwR71KNgkHQr+ET/dRpV6TmBlN5IiUMgKq7achpOjkyJEBCfEURRpV71ViEo+37dT1SqIzxhlNY8yDn2gPhcC/DHk4eXi5axFkg4OyhxD9Q7hW7oW+1K/pzjYm2M+yCTtguQ9xikYouiiYbC3oFKMO9F6unfmDHJKc/XwWI9nsuYwSVSqPPZ8tj91pI/SB/ng8UyCojPrUO/jJ3cHjsWccY2XDg5ryVYVAmNWQQ9UEsTT8WrwyJ04i9/FEEYvVznyHlYB3z9diKDW35j7EZKPJQi7uYQVcdB3e2NMve2JPrxxwmebBLrHv4hpfaKmS8NcWpvJYp5r5U1iVLnwIpH98wEsHSrhyBKwBq1bf7s+Lvz9Hx8XuME4zbC6SN4j00QIx4eU3yuKnsa2LGj7b8UQ0GrtNwiRWKwF+qaH15f5rUEUN/9bwdljUVkXNbRg0s1Jde8z/OWevnS/B/AX760fPRxVz6QtEcKCSKZd5AqiVnqSTSzJmvY2izmweHb0uUde7PMsY3aYhNU9eNpA7p2Wmvd+YbSQjMNgnaqB9I+XwNwVZymjhQzar91FZtFSvw4YERA/zUIPFVgrEwdnOnp0t0ORyVOo1QZnvyPMwVddfWpN68aJCVK5dYGyI1uL8CzcBjZqgRjuKSQgt9JfhZJakvdXXPyCq3y5N8cbZZeQvpK8VcRCFHk6fRGrt4vAVSU6dgNewEoj51j+RsH0OOgcuCyJJ7BZgP4mHrrQWfLelnMU=",
  "pubKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8p4gH/RlmICUyCJop4AfvHvIkQjMWhUI4keK22MDVyNrDWSektxxX+VN5hLQzmNU/4jTCBBx2gICYcw0DGiw5HGBHp3e0KCmhcc48s3tLwf1TUuhdCEj1v+Oq+Z0FhVEEUF+GYpMBLQvy2HGlPUHbOZsYamKUspMnuiLgqNdsEmjQtO3L8tfrfGcksb7K3siPDomcya1NPkIsmInHy3KB4yv8ATcVQS1rIQ/6I8/vb5OBoVKa9dLm42C5lVcBd9SFqCIxy49Z52DU7y48LmDayUvtrHZx5gI61mV2/CWDhwWSnAD9l/f/s8IjHxuuWzYfaRaO+6ROY380TNIigjTswIDAQAB",
  "wrappedKey": "DWscCbnT63FJuU7dQueXverB31cU0A49omSHw98aqlkW/8qiKuyQgWss9QNp/8qB97xjheJxQcozKrkbulF1ExCfSFuGXR++psel8LFiXoreDRwxJPO/Fqbqf9bIBLpOHx6GLjbUze4fWEGHs1Dt22GHHLvkaHgFPc+sBZcHvHnKF1+iKFonFXSDfUODozNV/poyi1UJ6RrXX/HIgbUlkUos02FcTn9qQqATRUj4lAY0tgFJlqJdpiQJDOWcWV3DJtaPIU2qPo9i95xFDzXBZbb6j/zp6518urFh8hSQKJUG4JPI0yeeW3iTEgN6EUTl0gYXgGvYDQIbeCM+oRZj+A==",
  "iv": "dITA6JK5SUBeP/Hgn6xf1w==",
  "type": "encryptedData",
  "format": "DER_BASE64",
  "signature": "wkkhQVZW3MdQtZha/AKf6hdIntKQI74vvYwKG+VtxUN+XXup2GkeNXWzJJY51YQC2/3EPwn6n+lUXm2xCRjV4ICY3+A0nbZrZnNrG0t6QpDWIQz1g9YYLe8pysjym95CsKy7AlXgo43BX811fv+aShQQTRkLwur5/geHF8idIeYORqt0B/9pwOnjfZnshT4Cj5ILwoe2VKZ3eWnIxND1a3Z8rE0s6WTFojFbshGQU6pf8dOj8w0cD6EDuOnEQ7Y40GbdwR9G3PhDY/JhMUjODhP+5X9nXesW2VlMPXE0byNhtzbnzg5Yi0pP9eBr7t5fTjwBTg5XjR4qDZKeyF0pqQ=="
}

Reading plain text is the reverse process, your app will need to change some of the properties of the received object:

var readCipherObject = receivedCipherObj; // an object received via the app 
readCipherObject.type = "read"; 
readCipherObject.authorName = "Alice"; 
readCipherObject.keyID = myKeyID; 

var request = window.navigator.bridge.getCipherObject(readCipherObject); 
request.onsuccess = function (){ */ this.result.verification contains the 'verification' boolean /* }; 
request.onerror = function (error){};

The reading UI looks like:

Upon clicking “Decrypt”, the content changes to plaintext:

The plain text is read inside the reading widget and is keep out of the content DOM. A validation boolean property is returned in the success event handler, none of the text.

This UI in this addon is only a part of the point of it. I have long wondered how crypto can be used more safely in web apps – where we don’t have to worry about keys being stolen and primitives being ‘monkeypatched’. I am fairly certain the UX can be made much better. The main idea I want to get across is the internal API. It is quite simple. Once you have a keypair, you can do “hide()” and “show()” – similar to the simplicity of Dan Bernstein’s NaCL (box/unbox).

Sign() and Verify() are also in the works. I would also like for this API to support IETF’s JOSE formats.

If you would like to give “nulltxt” a try, (remember, nulltxt is EXPERIMENTAL ONLY), the addon is hosted here: https://addons.mozilla.org/en-US/firefox/addon/nulltxt/

A demo page is hosted here: https://nulltxt.se/nulltxt/demo-code/demo.html

And, of course, the source code is here: https://github.com/daviddahl/nulltxt-extension/

Let me know what you think of this approach. I can imagine a web application where the web site only ever handles ciphered data and provides no crypto in the DOM – offloading all of it to the browser chrome. Of course, there are still attack surfaces here, mainly around spoofing the browser chrome UI. With a severe CSP in place, I think this approach might work well.

I have uploaded the latest DOMCrypt addon, which is version 0.4. It is not reviewed by the Addons team yet.
https://addons.mozilla.org/en-US/firefox/addon/domcrypt/versions/?page=1#version-0.4
I have updated it here as well:
http://mozilla.ddahl.com/domcrypt/extension/built/domcrypt.xpi

(note: The DOMCrypt extension, which is the bleeding edge code still uses ‘window.mozCipher’ as the window property name. The Firefox patch uses ‘window.mozCrypto’, the plan is to eventually merge this API into window.crypto )

I tried to make this API as simple as possible:

Encryption:

window.mozCipher.sym.encrypt(plainText, function callback(aCryptoObject){})

The resulting ‘CryptoObject’ has the following properties:

{
  cipherText: "...ENCRYPTED TEXT...",
  wrappedKey: "...A WRAPPED SYMMETRIC KEY...",
  iv:         "...KEY INITIALIZATION VECTOR...",
  pubKey:     "...A PUBLIC KEY..." // By default this pubKey
                                   // is the current user's public key,
                                   // which is used to wrap the symmetric key
                                   // so the actual key is never exposed to content.
}

Decryption:

window.mozCipher.sym.decrypt(aCryptoObject);

You can also pass in a public key to each method to wrap the key with another user’s key

Internally, a symmetric key is generated each time you run encrypt, it is wrapped with a public key to keep it safe and that cryptoObject is returned.

This is a first pass on an implementation – I tried to make it as simple as possible, with key safety the top priority.

A common use case for this API is localStorage encryption:

// web-based password manager app:)

var myWebPasswords = {gmail: "password", facebook: "password", twitter: "password"};

var jsonPasswords = JSON.stringify(myWebPasswords);

window.mozCipher.sym.encrypt(jsonPasswords, function callback(aCryptoObject){
  var jsonCryptPasswords = JSON.stringify(aCryptoObject);
  localStorage.setItem("jsonCryptPasswords", );
  delete myWebPasswords
});

// decrypt

var myWebPasswords;

var cryptoObj = JSON.parse(localStorage.getItem("jsonCryptPasswords"));

window.mozCipher.sym.decrypt(cryptoObj, function callback (aPlainText){
  myWebPasswords = JSON.parse(aPlainText);
});

This API is simple to use, and gives you a more secure way of using localStorage – or IndexDB, etc.

>For some time now I have been playing with the WeaveCrypto service – now a JavaScript module implemented on top of NSS via jsctypes. It is a pretty easy to use module – thanks in large part to the Weave (now Sync) team, Justin Dolske and many others.

I recently dove back into the code to try and distill down an easy to use API that can be attached as a property to any DOM Window.

The WeaveCrypto API was truncated because Sync started using a better encryption system (J-PAKE) for its purposes, so I had to dig through hg log to find the bits I needed:

http://hg.mozilla.org/mozilla-central/raw-file/d0c40fc38702/services/crypto/modules/WeaveCrypto.js

I took the old WeaveCrypto module and created an easy to use front-end component that sticks a ‘crypt’ property on each DOM Window.

My github repo is here: https://github.com/daviddahl/domcrypt 

A demo (with xpi link) page is here: http://mozilla.ddahl.com/domcrypt/demo.html

The 3 methods exposed (so far)  are generateKeyPair(), encrypt() and decrypt()

While I am not sure this is ‘production system’ ready, I am sure that these are the kinds of tools the users of the web need to build secure communications applications, toolkits and libraries.

Perhaps ‘Do Not Track’ can extend to ‘Do Not Datamine’?