rclone / rclone/rclone

Rclone crypt improvements (envelope encryption, truncation protection, hashing support)

Open
#7,192 27 comments 29 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement Remote: Crypt
Dominant language
Go
Stars
59.8k
Forks
5.4k
Avg merge
2d 14h
Merged PRs (30d)
48

Description

We're running S3Drive (GUI for S3 on desktop, mobile, web) and recently aligned with Rclone's encryption scheme for better interoperability and features like drive mount and Webdav that we could get out of the box.

Prior to that we've researched research couple different encryption schemes and despite current Rclone encryption shortcomings (from our perspective) we've went for it, knowing that there is a room for improvements.

Disclaimer, I am not a cryptographer, but rather an engineer who by the sheer luck of project choices happen to be more involved with cryptography for the past couple years.

1. No envelope encryption

The biggest shortcoming so far that we see, is that every single Rclone file content is encrypted by a single master key (derived from user provided password). On its own this doesn't pose direct security threat since every file has random 24 bytes nonce, but it limits how you can securely exchange the encrypted file.

One of our features is file sharing, this feature is native to S3 protocol. When encrypted shared file is passed to the receiver they need to obtain the file decryption key. With a current Rclone's setup the decryption key happen to be user's master key. By sharing a single file, the encryption key to ALL FILES is revealed which is very undesirable from a security point of view.

Before we've implemented Rclone's encryption, we've been using AWS client-side encryption: https://docs.aws.amazon.com/amazon-s3-encryption-client/latest/developerguide/encryption-algorithms.html#crypto_features it worked well, but it wasn't in the end feasible for us, mostly due to lack of consistent hardware accelerated streamed AES-GCM support across different platforms (web included).

What was great about AWS's approach is how they've implemented key management and key wrapping.
In other words, each file had a different encryption key (wrapped DEK), which would then be encrypted by the master key.
Sharing a resource would reveal only that single key (DEK). By choosing a key wrapping algorithm it would be possible to create multiple different encryption keys (by simply reencrypting the DEK).

I believe it's something that Rclone could use.

This change would have to be reflected in the ciphertext heading and would increase the length of a ciphertext in the ballpark of 16-32 bytes (depending on the KW algorithm).

2. No truncation protection

Currently, you can remove as many as you want blocks (starting from the end) from the ciphertext and no one would notice. There are multiple ways to address that, but given the Rclone's ciphertext format, the one that would make sense in my opinion is: https://github.com/miscreant/meta/wiki/STREAM
In other words it would be good to reserve 1 byte of nonce for the: last_block flag.
We were recently given a great response in this topic which also might be helpful for you to assess alternative options.
https://crypto.stackexchange.com/a/106992/70896

(Update) 2.5 Hashing support

Currently in order to verify plaintext integrity the whole encrypted object had to be scanned and decrypted and hash has to be calculated. This is costly, especially the bigger the file.

To solve this, encrypted object will have an MD5 hash of a plaintext appended to the footer. The hash itself would be encrypted and authenticated using same AEAD construct as file content.

This in fact is already implemented: https://github.com/rclone/rclone/pull/8105/commits/a5d6af71d0c0e5cc832e1643fa69a80d664e6d56

There is a 1-byte room that stores the hash type just in case in the future we need to migrate to something stronger/better than MD5.

3. Variable encryption settings

Current Rclone's settings are sane defaults which work well on a typical hardware.
They don't work well on Web though, mostly due to poor speed of XSalsa20 and overhead related to fixed 64KB block processing.

3.1 Dynamic chunk size

This could be achieved by adding the 4 byte UINT field to the header ... or could be as small as 1 byte which would be a multiplier of e.g. 64KB (that would support block size up to 16MB).

3.2 Different cipher support

It's XSalsa20 now. I am not a huge fan of AES-GCM, but there isn't really a choice for performant cipher on Web: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt
Could we indicate the cipher type in the header and possibly support AES-GCM (libsodium has consistent API on all platforms)?

4. No path protection

If you copy ciphertext from location: /a to location /b, no one would notice. Ciphertext is not aware where it belongs. Perhaps not a big issue for many and this comes with certain side effects and complexities and might not be feasible for Rclone at all. E.g. simple raw byte copy would no longer be possible (as the heading with new location would have to be updated).
I've thought I will just mention it anyway.

Final word

I am writing this to understand what's Rclone maintainers (nice to meet you Nick @ncw for the first time) view on these improvements, whether they make sense for Rclone and if they're interested in taking time to include these changes in the specification.
I can certainly participate in the planning phase and happy to do more research in terms of optimal choices, although I am sure my competence in Rclone's world falls short.

These improvements is something we would be implementing eventually, but given that benefit of staying compliant with Rclone's approach is so great... we've thought it would be a shame not to ask.
We're thinking of executing this later this year and this would approximately be the time where we (well, likely myself) could get our hands dirty with Go and build some pull requests.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No source files, tests, or entry points are named. Start by reviewing the linked AWS encryption guidance, Miscreant STREAM format, Crypto Stack Exchange answer, and referenced pull request, then follow the maintainer discussion. Done would require an agreed scope and encryption-format specification before implementation can begin.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cryptography, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.