Send encrypts your files in the browser. This is good for your privacy because it means only you and the people you share the key with can decrypt it. For me, as a software engineer, the challenge with doing it this way is the limited API set available in the browser to “go full circle”. There’s a few things that make it a difficult problem.

The biggest limitation on Send today is the size of the file. This is because we load the entire thing into memory and encrypt it all at once. It’s a simple and effective way to handle small files but it makes large files prone to failure from running out of memory. What size of file is too big also varies by device. We’d like everyone to be able to send large files securely regardless of what device they use. So how can we do it?

The first challenge is to not load and encrypt the file all at once. RFC 8188 specifies a standard for an encrypted content encoding over HTTP that is designed for streaming. This ensures we won’t run out of memory during encryption and decryption by breaking the file into smaller chunks. Implementing the RFC as a Stream give us a nice way to represent our encrypted content.

With a stream instead of a Blob we run into another challenge when it’s time to upload. Streams are not fully supported by the fetch API in all the browsers we want to support yet, including Firefox. We can work around this though, with WebSockets.

Now we’re able to encrypt, upload, download, and decrypt large files without using too much memory. Unfortunately, there’s one more problem to face before we’re able to save a file. There’s no easy way to download a stream from javascript to the local filesystem. The standard way to download data from memory as a file is with createObjectURL, which needs a blob. To stream the decrypted data as a download requires a trip through a ServiceWorker. StreamSaver.js is a nice implementation of the technique. Here again we run into browser support as a limiting factor. There isn’t a work around that doesn’t require having the whole file in memory, which is another case of our original problem. But, streams will be stable in Firefox soon so we’ll be able to support large files as soon as they’re available.

In the end, it’s quite complicated to do end-to-end encryption of large files in the browser compared to small ones, but it is possible. It’s one of many improvements we’re working on for Send this summer that we’re excited about.

As always, you’re welcome to join us on GitHub, and thank you to everyone who’s contributed so far.