Friday, July 25, 2014

Week 11

Group key decryption was added to the extension this week. The group key is encrypted with some symmetric ciphers, for example, aes-256-cbc, and the key of the symmetric cipher is then encrypted under a user's public key using RSA. Therefore, only the user knowing the corresponding private key can retrieve the key for the symmetric cipher, and then decrypt the group key, which, in our case, is indeed the information of the current group state, and can be used to derived the actual group key.

At present, the encrypted group key obtained from a key server is in the following format:

  1. The initialization vector of the aes-cbc cipher in hexadecimal.
  2. The aec-cbc key encrypted with the user's public key in base64
  3. The encrypted group key in base64
A sample encrypted group key looks as follows:

For the RSA decryption compatible with openssl, I have imported another library called jsencrypt. To be honest, I'm feeling uncomfortable with importing so many different libraries in javascript, so I have started implementing my own crypto library in javascript. For now, the library only provide some basic interface for big number arithmetic including addition, subtraction, multiplication, and division. I am going to work on the library further so that encryption and decryption with various ciphers will be possible. The library is currently held on github. Here is the link: https://github.com/qiyuh/CLJS.

During the following weeks, I will have the extension check the signature of the message to ensure the authenticity. It seems that I have to find some other libraries to do so because openssl signs a message with a pretty complicated process. The message is first hashed, and then ASN1 encoded. So what's signed in the end is the ASN1 encoded hash of the message.

Friday, July 18, 2014

Week 10

I am struggling with different formats for encoding the keys this week. Basically, Nick is using the PEM keys on the publisher side, while Google's e2e library can only import the PGP encoded keys. Although the body of both formats is in Base64, they have different key structure, and I cannot find a converter between the two formats at this moment.

Here is an example of a PEM encoded private key.

The PEM encoded keys adopt the ASN.1 (Abstract Syntax Notation One) notation, and the structure of the key is as follows:

It is simply an array of different parameters of the RSA algorithm.

And here comes a sample PGP encoded private key.

The key material is encoded in packets, which in turn consist of packet header, indicating the type and length of the data, and packet body, the actual data, encrypted or unencrypted. For more information, please refer to Section 5.5 in RFC 4880.

If we decide to transform a key in PEM format into one in PGP format, so that we can make use of the e2e library to import a user key, we may need to parse the PEM key and then generate the PGP formatted key according to the parameters obtained from the PEM key. I found a ASN1 decoder in javascript and modified it a little bit to print out the parameters in the PEM key shown above.

All of the parameters are in hexadecimal. For instance, the version number is "0x00", which is 0, and the public exponent is "0x010001", which is 65537 in decimal, a common number for the public exponent in RSA.

I will discuss with other teammates about the issue of the key format. If we decide to adopt the PEM encoded keys on the publisher side, probably I need to write a converter between the two key formats, PEM and PGP.

Monday, July 14, 2014

Week 9

Sorry for the late update. First is some clarification on some of the statements I made in my previous blog last week. I misunderstood the usage of the passphrase in the openpgp keyring of the google's e2e library. It served just as a key for the encryption or decryption of the keyring, rather than an identifier of different keyrings. Therefore, for the support of multiple users, only the passphrase sounds not enough, and the google's library stores only one keyring encrypted with the passphrase, given that it is not empty. When an user enters an incorrect passphrase, the library gives the following warning:

As a matter of fact, the localStorage is not modified. Instead, because the HMAC key is also generated from the passphrase, as long as an incorrect passphrase is given, the computed HMAC is not the same as the one stored in localStorage.

In one word, the e2e library stores only one keyring encrypted under the passphrase, and if an incorrect passphrase is entered to access an encrypted keyring, the attempt fails since the HMACs do not match.

A basic file parser was added to the extension. For now, the extension is able to handle AES decryption automatically. For an encrypted file like this,

The cipher for encrypting the message, "aes-256-cbc", is specified after the header. The group number, 22, the group state, 0, and the initialization vector for decrypting the encrypted file key and initialization vector, are shown after the cipher. And the encrypted file key and initialization vector come next, which is followed by the header and the body of the encrypted message. Once the extension knows the current group state, which is obtained from the key server, it unwinds it to previous state if necessary and takes the hash value of the correct state as the key. Using this key, the extension gets the file key and initialization vector, which is encrypted under "aes-256-cbc" by default (note that this cipher may be different from the one specified in the header, and the one in the header is only the cipher for encrypting the message). With file key and initialization vector, the decrypted message is retrieved from the body of the encrypted message.

Finally, there seems to be a bug in injecting codes to subframes. Google does not provide API for injecting code for a specific subframe, so I import a library implemented by a third-party developer to allow me to do so. However, this library, although works, is not stable and fails to inject codes to a subframe sometimes. I just came up with a new idea to inject codes using random number as an identifier for different subframes. I am going to implement this and talk about it if it works in my next blog.

Thursday, July 3, 2014

Week 8

I implemented a user interface for entering passphrase which may allow the support of multiple users in the future. Besides, I took a look at the google's e2e library, especially the keyring implementation of the openpgp, and played around with it.

The extension is off by default, unless a user enter a non-empty passphrase to turn it on, and an empty passphrase is used to turn off or disable the extension. The user interface looks like this:

After entering the passphrase, the extension is on and gets the keyring specified by the passphrase, so multiple users are allowed to use the extension by providing different passphrase.
When the extension is on, the user can change the passphrase by entering a new and non-empty one, or turn it off by entering an empty passphrase.

As for the google's e2e library, I took a closer look at the "keyring.js" file under the openpgp library this week so as to learn how they handle the key management.

The keyring and all the associated keys are stored using the HTML5LocalStorage. To be more specific, the whole keyring is first serialized, and then encrypted using the passphrase. What is stored is an encrypted string recording the information about the keyring. The following is the function for encrypting the serialized keyring.

As shown in the figure, the serialized keyring is encrypted using AES128 under CFB mode with a key generated from the passphrase and a random initialization vector. Also, an HMAC (Hash-based message authentication code) is included for further verification of data integrity and authenticity. Therefore, even though the attackers may modify the HTML5LocalStorage, the library can detect this and avoid using the modified keyring.

However, it seems that the library is only able to import keys with the openpgp format in ASCII Armor. If we want to import keys in other format, probably we need to implement our own keyring.