Friday, August 8, 2014

Week 13

Basic key import and management is available now. The private keys are encrypted with a passphrase provided by the user and stored locally, while the public keys are stored unencrypted. Every private key stored is encrypted with a key generated from the associated passphrase using AES in CBC mode. The following figures show how to import a private key:

1. Click "Set a private key".

2. Copy and paste your private key, and then enter the passphrase used for encryption.

3. Click "Set". Now your private key is stored locally and encrypted with the key generated from your passphrase.

To import the public keys from the publishers, first login with your passphrase.

Then click "Import a public key".

Copy and paste the public key you want to import, and enter your publisher's group number.

Hit "Import" and you are all set. Now you can use the extension as shown in the previous blogs.

Monday, August 4, 2014

Week 12

Here is a brief summary of the progress last week.

I removed the google closure library from the extension last week and imported a new crypto library called forge, since forge is more compatible with openssl (we are using openssl for the publisher) and more developer-friendly in terms of API. Also, I added the function of signature verification to the client extension.

If the signature is verified with the publisher's public key, the content or what's signed under the signature is displayed.

If the signature is not verified, the extension prompts the user that the signature is not verified.

What's more, group key unwinding was implemented. We adopt the RSA scheme for group key winding and unwinding, which allows easy revocation and group state update. Basically, with the RSA private key (n, e, d), where n is the public modulus, e is the public exponent, and d is the private exponent, the group state mi+1 = mid mod n for winding or updating the group state, where mi+1 is the updated group state, and mi is the previous group state. Reversely, for unwinding the group state and retrieving the group key, mi = mi+1e mod n, and the group key at state i is HASH(mi).

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.

Friday, June 27, 2014

Week 7

The chrome extension supports <iframe> tags with the 'src' attribute pointing to a gnocchi file on the server now. Also, I change the way the browser interprets a gnocchi file to prevent the possible code injection attack. Rather than "text/html", the modified content-type of a gnocchi file is "text/plain", so all the injected codes would be regarded as just plain text by the chrome browser.

To resolve the <iframe> reference, I add two listeners: one is added on the event "chrome.webRequest.onHeadersReceived", which is fired when the request header is received to check for gnocchi files, and the other one is added on the event "chrome.webNavigation.onCompleted", which is fired when the document resources are completely loaded and initialized.

For now, I'm using a global variable to record the urls of the gnocchi files. I know that using global variables is not a good practice in coding, but it seems to me that it is the best solution. Alternatives are message sending and local storage. Message sending is more tedious and turning the code even less readable than global variables. Besides, I have no idea how to embed a listener on the event "chrome.webNavigation.onCompleted" inside another listener on the event of receiving message at this point. Anyway, I will manage message sending to see how well it works if I have time. As for local storage, that is a inferior choice considering the performance of the extension. Also, local storage runs asynchronously, competition between different processes makes the extension less reliable.

Here is the result of the test case with 20 <iframe> tags in a webpage (some of them are not visible due to the limited size):

Key management on the client side is my next step. I will take a look at google's e2e library to learn more about how they manage it. Furthermore, message sending between different listeners of the extension is also in my plan so as to get rid of annoying global variables.

Friday, June 20, 2014

Week 6

I removed redirection from the chrome extension this week, and did some research on the chrome file system.

First thanks go to Olga for inspiring me to find a way to circumvent redirection. Here is how it goes. The chrome extension checks the response headers to detect gnocchi files, as I mentioned before. If a gnocchi encryption or signature file is to be received, the extension will modify the headers so that the browser would process the response body as with content-type "text/html", rather than "multipart/signed" or "multipart/encrypted". In this way, an associated DOM document is created, whose content is the data received from the server. After the content is loaded, the extension injects codes to replace the encrypted message obtained from the server with the corresponding decrypted message.

Here is a possible attack I come up with. Since the DOM document is first loaded with the data from the server as its content. Is it possible for a malicious attacker to inject codes by sending them as the encrypted data?

As for the file system, fortunately, google provides an API named "goog.fs" for temporarily storing some files locally. What's more, "goog.fs" tends to work asynchronously, which is a piece of good news for the extension's performance. With a workable file system, I am going to solve the <iframe> src reference as follows. The extension would detect the web requests. And if a request to a gnocchi file is detected, the extension would make a XMLHttpRequest to retrieve the encrypted message first, decrypt it, store the decrypted message locally using the file system, and finally modify the src attribute in the <iframe> tags to reference to the local decrypted files.

Next week, I mean, in the near future (why should I say "next week", if, as a matter of fact, I am not finishing the tasks next week?), I am going to resolve the <iframe> src reference and take a look at how google's e2e library manage their key storage. Hopefully, google's method is helpful for me to figure a way for key management in the chrome extension.

Friday, June 13, 2014

Week 5

The chrome extension performs basic AES decryption now. The data are in three different encoding formats:

  • Base64, for retrieving from the server
  • Byte arrays, for decryption
  • Text string, for displaying

We adopt the AES algorithm in CBC mode for decryption and encryption. The following is the data retrieved from the server:

Since we do not have mechanism for key distribution now, the decryption key is included in the data, the shorter base64 string. The key length indicates that the encryption algorithm is AES128. Also, the initialization vector (iv) for CBC decryption is included in the ciphertext, the longer base64 string, as the first 16 bytes. Knowing the key and the iv, we can obtain the plaintext by decryption.
The plaintext includes the message, "Hello Secret world!" and the corresponding signature in RSA scheme.

I also managed to come up with a way for key management and storage on the client side. Because it is generally considered not possible to use file systems on the browser-side in JavaScript (see http://stackoverflow.com/questions/585234/how-to-read-and-write-into-file-using-javascript), I have to use the not-so-secure chrome.storage API.

To ensure security, the following is a preliminary idea to encrypt the keys stored on the extension. Every user creates a user name and the associated password. All the keys are stored encrypted using AES with the hash value of the password as the key. To verify the user, another pair of plaintext and ciphertext is stored with the plaintext randomly generated. Thus, only the encrypted keys and a pair of plaintext and cipher text are stored. In order to check whether a user enters the correct password, we only have to take the hash value of the input, use it as the key to decrypt the ciphertext, and check whether the resulted plaintext matches the one stored on the extension.

For next week, I will try to do more research on this problem: how to store keys securely with storage that the attackers may have access to. Also, I will implement the idea above or some other solutions to solve the problem.

Friday, June 6, 2014

Week 4

"Redirection" was implemented and the end-to-end (e2e) google crypto library in javascript was imported this week.

The quotation make in "Redirection" indicates that it is in fact not real redirection. It works as follows. Once the extension detects a gnocchi file to be received from the server, it opens a new tab in the browser, displays the content (encrypted message for now, since I don't have time to work more on the crypto part), and closes the original tab. I had tried to realize the real redirection, but there seemed to be a bug in chrome. When I tried to access a gnocchi file from a loaded tab, a tab loaded with contents from other links, it got redirected to "about:blank", although the extension worked well in the case of a blank tab, or a newly-opened tab. Please see https://code.google.com/p/chromium/issues/detail?id=300685 for more information related to this issue. (Update before Friday night: I have just fixed the issue. It is now real redirection to the file content, instead of about:blank)

I also included the end-to-end (e2e) google crypto library in the project. It is well-known that there is few reliable crypto library implemented in javascript. I took a look at crypto-js (a nice one with friendly interface, also easy to import), and SJCL (started by people at Stanford University). However, due to the inactivity of both libraries, I selected e2e at last. Though newly developed, e2e is maintained and updated by the developers at Google. Besides, it is relatively easy to import e2e using Google's Closure Library. Finally, Google knows chrome best, so e2e is expected to be compatible with chrome.

I will focus on the crypto part of the project next week, in order to have decryption work. Also, if I have time, I am going to do more research on file IO in javascript, too. I slow down my research on that because we are mainly handling text message and html document at this moment, and file IO will be an extra feature in the future, rather than the goal at present. Furthermore, file IO is very very tricky in javascript...

Friday, May 30, 2014

Week 3

I added the detection function to the chrome extension this week.

The extension can now detect whether a gnocchi-encrypted file or a gnocchi-signed file is received from the server, as long as the server follows the Multipurpose Internet Mail Extensions (MIME) protocol and the Security Multiparts for MIME, multipart/signed and multipart/encrypted (see RFC-1847 for more information).

To be more specific, the extension checks the headers received from a server and determines whether a gnocchi file is received according to the header named "content-type". I selected header checking rather than data checking for the following reasons:

  1. Although data checking is more reliable since the information in the headers may not correctly record the content type of a file, we can still ensure security in this case. On one hand, suppose a non-gnochhi file is sent with the header declaring it as a gnocchi file. That file will not be decrypted correctly and it is unlikely for a mis-decrypted file to get passed in the verification process. On the other hand, if a gnocchi file is sent with the header declaring it as a non-gnocchi one, the extension just ignores it, and the user can obtain and decrypt that file from other servers.
  2. It is more efficient to do header checking. Because we do not rely on something like the "gnocchi servers", every sever can serve as the source of a gnocchi file. Thus, the extension checks the headers received upon every url request to detect a gnocchi file. Generally, the size of the headers is quite minimal, while the size of the file data may vary from extremely limited size to extremely large size. Also, headers are received before the data. Having the extension checking the data every time a url request is made may greatly slow down the browser.
  3. Lastly, most of the servers follow the protocols mentioned above, and the extension works for those servers.

For normal surfing, nothing happens:

A gnocchi is detectd:

For next week, I am going to do some research on File IO in javascript. File IO is critical for replacing the encrypted file with the decrypted one. It seems that Google places a lot of restrictions on File IO for extensions, for some security reasons. Admittedly, File IO can be done with html, but I would like to avoid opening a new webpage prompting the user to input the private key. Also, File IO with html cannot completely solve the problem since I need to find a way to turn a local javascript variable recording the decrypted data into a real file.

Friday, May 23, 2014

Week 2

Week 2

I started implementing the chrome extension for the client side this week, with Nic working on the server. Since we do not have anything cryptographic on the server yet (a cryptographic database generator to be implemented in the near future), the client now is mainly serving as something like a test program, rather than a fully developed chrome extension for practical use. However, we did set up the a way for data transmission between the users and the server with the chrome extension. We decided to choose JSON (JavaScript Object Notation) to transmit data between the server and the client for the following reasons:

  1. Compared to XML (Extensible Markup Language), JSON uses opening and closing brackets such as {, [, ], and }, instead of opening and closing tags like <title> and </title>, which takes less space and is more efficient in communication.
  2. JSON is pretty compatible with JavaScript. A well-formatted JSON string obtained from the server can be easily parsed as a JavaScript object by calling JSON.parse(). Because JavaScript is the most popular scripting language for web development at present, compatibility with JavaScript is a great advantage.

To make the extension less dependent on a specific browser (yes, I am talking about less dependence on chrome), I implemented the extension as a webpage-based one. For now, when the user clicks on the icon to start the extension, a local html file is opened in the browser as a simple user interface.

The user can hit "Enter" directly to view a list of the available files on the server,

or enter a valid file name to view it or download it (depending on whether the publisher specifies the file as downloadable or not when the file is uploaded to the server).

Next week, I will make the extension detect the web requests so that it can be automatically invoked when the users try to access an "encrypted" file on the server. In this way, the users do not need to start the extension and enter the file name every time they want to access a file on the server. Also, I will have the extension be able to read the local files selected by users to gain their private keys for decryption.

Friday, May 16, 2014

Week 1

We started our Gnocchi/NoSSL project this week!

For the first week, it was mainly about research and plan for future implementations. The Gnocchi/NoSSL system we are going to implement is for online file distribution with the purpose of keeping private keys offline as much as possible. By avoiding to store the private keys online, Gnocchi/NoSSL protects the material better even when the server is untrusted or compromised.

Our Gnocchi/NoSSL system consists of three parts: the client, the server, and the database generator.

Since the private keys are kept offline, most of the cryptographic work is on the client side. The client first requests for the needed data from the server, trusted or untrusted, and then interprets the data into a proper file system. Because the server may be untrusted, the client is responsible for verifying the integrity and the authenticity of the files received. As for the specific implementation, we are going to implement it as a plugin of the browsers. As the first attempt, it will be a Chrome extension.

The server is basically a common one without much modification. Since we do not rely on the server for integrity and authenticity, the server simply serves as a place for file storage and responds with the correct data upon the client's request.

The database generator is used to produce a signed and authenticated database with the private key by the publisher. To transform an existing file system into a valid database in Gnocchi/NoSSL, the file data blocks and the inodes are associated with their cryptographic hashes, and the resulting database will have a structure similar to the Merkel hash tree, which aims at protecting the integrity of the files.

I also did some research on how to create an extension for Chrome this week.

Building a Chrome extension is pretty straightforward. A Chrome extension usually consists of the following:

1. A manifest file named manifest.json, recording the metadata of the extension

2. Html files for the contents to display by the extension.

3. JS files for the codes to be executed.