BrowserID Key Wrapping
When a user logs in to a web site directly, that web site has the user's password available to it, and it can use this password as a source of entropy for a cryptographic key. Once a web site uses BrowserID, that goes away. With BrowserID key wrapping, we're bringing this feature back. We're providing a way for web sites to get access to a cryptographic key based on the user's login.
API and Overall Behavior
A web site wants to have access to a securely stored cryptographic key bound to each of its users. That key should survive across multiple BrowserID logins, and be as stable as possible: if it is lost, the user's data that the site chooses to secure with this key will also be lost.
BrowserID does not store any data on behalf of the web site. Instead, it provides a wrapping/unwrapping API. The web site is expected to generate the user's key, wrap it via BrowserID, and store the wrapped key on its own servers.
It goes like this:
// web site logs the user in via BrowserID
navigator.id.get(gotAssertion);
function gotAssertion(assertion) {
var key = generateKey();
// wrap the key
navigator.id.secret.wrap(assertion, key,
function(wrappedKey) {
// store the wrappedKey on the server
},
function(error) {});
}
The key must be base64-encoded. The wrappedKey that is passed back is also base64-encoded. The plaintext is expected to be fairly short: mostly this is for wrapping other keys.
Internal API
Before this is exposed as a content API, BrowserID exposes secret wrapping as an internal API:
navigator.id.internal.secret.wrap(origin, assertion, plainKey, successCB, failureCB) navigator.id.internal.secret.unwrap(origin, assertion, wrappedKey, successCB, failureCB);
In this internal API, the origin has to be explicitly specified.
Architecture
Crypto Preliminaries
We don't ever do raw encryption. We perform encryption-and-MAC. We do this by encrypting the plaintext, then HMACing the ciphertext. The decryption process first checks the HMAC, and decrypts only if it is valid. In the following description, every time we talk about a single key, we really mean two keys: one for encryption, and one for HMACing. We use AES in CBC mode for encryption, and HMAC-SHA256 for MACs.
Wrapping a key means encrypting (and HMACing) a data structure that contains the key and some optional tags. We denote this
WRAP(wrapper_key, wrapped_key, {key1: val1, key2: val2})
User Key
BrowserID generates a new key for each email address it verifies. We call this the user key UK. BrowserID encrypts UK with a password-key (PWK) derived from the user's password. When the user changes their password, UK is unwrapped and rewrapped appropriately with a new PWK'. If the user loses their password completely, in the current specification, UK is unrecoverable and may as well be deleted.
Wrapping
Once a user key is established within BrowserID for a given email address, a site can generate a key SK, then ask BrowserID to wrap it. BrowserID will do so using UK, including an authenticated tag
[diagram of wrapped keys]
