Nowadays encryption is standard practice on web when data is in transition, and there are even a few services which offer client-side encryption and thus are truly end-to-end. Nevertheless for some reason they all require you to create and account by providing your email and password, although this is not strictly necessary for storing and sharing data. In this system the document id, encryption key and HMAC key are generated ad-hoc on the client and only minimal necessary information is revealed to the server. A live demo should be available at noknowledgenotes.nikonyrh.org.
The service is based on well understood and examined AES and SHA-256 security primitives, but the idea can be implemented by using any other encryption and hashing algorithms. A public-key encryption algorithm would be an appealing choice but here a symmetric algorithm was used for simplicity. The server is implemented in PHP and is only a bit over 200 lines long. The provided client is considerably more complex at 600 lines of code (HTML + JavaScript), excluding 3rd party libraries (jQuery, CryptoJS).
The client's hash function is H(a,b,c) = SHA-256(a || SHA-256(a || b || salt) || c) where "a" is the hash output's name such as key_enc, "b" is the username and "c" is the password. In total there are two cryptographic key (AES and HMAC) and a "write token" derived from the username and password, and the document id is derived from just the encryption key. These relationships are shown in Figure 1.
Only the document creator should know the username, password and HMAC key. Server only needs to know the document id and the associated "write token". For someone else to have a read-only access he only needs to know the AES key, from which he/she can derive the document id. Write token is used for the server to check for write permission when the document is being updated but it has no cryptographic purpose. HMAC key prevents the server submitting arbitrary content when a document is requested. Only the person who knows this key can verify content validity and calculate a new hash for new content. Malicious server can only either delete the document or provide an older version but all other tampering would be immediately noticed. Even if the server did not check the write token validity when the document is updated by a 3rd party, the alteration would be noticed because it wouldn't have a correct HMAC key stored alongside with it.
If AES and HMAC keys would be derived from the write token then a read-write access could be easily given without revealing the username and password. This tweak wouldn't require any modifications to the server or the protocol as all this happens on the client side.
Storing the data is fairly trivial, and it can be seen at Figure 2. Plain-text content is first compressed with LZW, then encrypted with 256-bit AES, then HMAC and other metadata such as date are attached and then it is converted into a JSON string. Compression produces a UTF-16 string but AES produces base64-encoded ciphertext so the final JSON has only ASCII characters. The client stores all past HMAC hashes and dates in the document's metadata, but optionally it could store all past versions as well. This wouldn't inflate the final filesize that much because of the compression step.
When the document is being stored on the server, server checks that the request embeds a write token and it has to match to the token which is stored within the server's version of the document. This step enables easy read-only sharing of documents.
Document loading works by simply applying those steps in the reverse order. First a document is requested from the server based on its id and the response's JSON is decoded into a JavaScript object. Document's HMAC is calculated and it is confirmed to match the hash which is stored in the response. If they match then contents are decrypted and uncompressed.
Read-only sharing is achieved by delivering the symmetric AES encryption key to the desired party, from that he can derive the document's id. He is able to retrieve the ciphertext from the server and decrypt it, but its HMAC cannot be confirmed unless the HMAC key is also revealed or if the current hash value is delivered alongside with the AES key.
When the server is asked to create a new document it asks the client to solve a Proof-of-work problem. An unique problem instance is generated and the client is asked to provide such inputs to a salted hash function that it has the server-specified number of leading zeros. By having to solve many easy problems instead of a few harder ones the calculation time variance is greatly reduced. On current settings it takes the JS client 1 - 3 seconds to solve the problem before the new document can be created.
The client could be updated to be visually more pleasing and to offer for example multi-server mirroring. This storage system is ideal for example synchronizing browser bookmarks between computers without revealing your actual bookmarks to the server or any other 3rd party. Clearly this is not meant for taking backups of photos or other multimedia, it is best suited for plain-text, JSON or XML content which generally compresses well. Perhaps even a chat application could be built based on this "protocol" but it wouldn't have some desired properties such as forward secrecy or deniable cryptography. So far no public-private key-pairs have been used because it wasn't deemed necessary. At least it would enable read-only sharing without revealing the encryption key but it wouldn't make much difference on the current system.
Related blog posts:
|
|
|
|
|
|
|
|
|