I’m new to the community and considering the paid version. I am most interested in the encryption add-on as integration of encryption for cloud services is decidedly lacking. I have read everything available on the encryption process with odrive. However, there are a few additional questions that I have.
I understand the encryption process is to generate a random salt, and then calculate a 256 bit key using pdkdf2, given the salt and a passphrase. In addition, I understand the plain text is then hashed using SHA256 and AES/CBC is used to encrypt the (?hashed plaintext) with the key and initialization vector.
My questions are (note, some may be redundant - in that in answering one you may answer the others):
Can you please explain the decryption process?
Is the encryption symmetric or asymmetric? Is there a public and private key? Your explanation on the website gives the impression that this is symmetric encryption. If so, (see next)
Where is the key stored? This is super important. Is the key stored on the odrive server? Or is it stored on the local drive. Is the key itself encrypted? How?
Are the file names encrypted? How about the directories?
Are the file sizes consistent? Or are they randomly increased/decreased?
While there are many encryption apps out there that work with cloud storage, they don’t integrate well with multiple providers; and each have their drawbacks. It would be great to have an all-encompassing solution in the form of odrive IF the encryption is done well. Boxcryptor is the dominant closed-source player and their encryption process is well outlined on their website. Cryptomator is the dominant open-source solution and they also fully spell out their encryption and decryption process. Overall, I’m far less concerned that a hacker would be able to decrypt an encrypted file using brute force. I’m much more worried about the peripheral issues involved with encryption because hackers are much more likely to target ways of hijacking keys and passwords. A clear explanation of the process is critical because with encryption, if it’s not spelled out directly, one has to assume the worst case scenario. So your answers, and any additional details you can think of, would be greatly appreciated.
Generate a 128-bit key (K) using PBKDF2 with S and the user’s passphrase (P), 5000 iterations, and HMAC-SHA256 for PRF
Generate a random 128-bit initialization vector (IV)
Compute a hash (H) of the file data using SHA256
Plaintext (PT) is: (file data + H + PKCS #7 padding to the next multiple of 16 bytes)
Generate the ciphertext (CT) using AES-CBC to encrypt PT using the K and IV
Get the 8-bit internal odrive Encryption version designation (V)
Write to output file V+S+IV+CT
Decrypting:
Read V, S, and IV from the beginning of the encrypted file
Derive K using S and P
Decrypt the CT using K and IV to plaintext (PT)
Unpad the PT
Strip H from the end of PT
Calculate new hash (H2) of the resulting PT and compare to H
AES is symmetric encryption
The key is never stored. The key is derived from the salt and passphrase, as described above. The passphrase is stored on the local system, once you enter it for the first time. It is stored to prevent needing to continually enter the passphrase.
The passphrase is kept in the keychain on Mac and in an encrypted registry entry on Windows using Microsoft’s CryptoAPI.
File names and folder name encryption/decryption
Encrypting:
Generate a random 64-bit salt (S)
Generate a 128-bit key ( K ) using PBKDF2 with S and the user’s passphrase (P), 5000 iterations, and HMAC-SHA256 for PRF
Generate a random 128-bit initialization vector (IV)
Plaintext (PT) is: (4 zero bytes + the filename + PKCS #7 padding to the next multiple of 16 bytes)
Get the ciphertext (CT) using AES-CBC to encrypt the PT using the K and IV
Get the 8-bit internal odrive Encryption version designation (V)
URL-safe, base64 encode (V+S+IV+CT)
Decrypting:
Decode URL-safe, base64 filename
Read V, S, and IV from the beginning of the decoded filename
Derive K using S and P
Decrypt the CT using K and IV
Check that the new filename starts with 4 zero bytes
Strip zero bytes and padding
Files sizes increase due to the additional information prepended to the ciphertext and the hash appended to the plaintext before encrypting. The plaintext also needs to be padded to a multiple of the block size, and the amount of padding will vary, depending on the size of the original file.
@shaiguitar Looks like you’re running into the same issue I’m having with my Node implementation. We don’t know what the iterations parameter is for PBKDF2.
Also, don’t forget that the last 32 bytes of the decrypted data is an SHA256 hash of the rest of the data, which represents the original file.
@Tony, just realized you added another step, padding the data to get to a multiple of 16 bytes. How do we know what the original size of the file was so we know how much padding to take off? Does the padding have a specific format? Is it PKCS#7?
Hi @jordanbtucker,
Yes it is PKCS#7, so the decimal value of the repeating character used for padding tells us how many times that character repeats at the end of the plaintext.
@Tony, thanks for all of the info, I’m pretty sure I can build a decryption client with this now. You can probably just specify that the encryption process uses PKCS#7 padding rather than go into detail about the multiples of 16. PKCS#7 always adds padding even if the data size is already a multiple of 16 bytes, so your detail is slightly misrepresentative. I recommend just saying AES-256-CBC with PKCS#7 padding. Thanks again.
Hi @jordanbtucker,
I changed it to “the next multiple of 16”. I left it in since there was a question about file size variance and most people are not going to be familiar with the PKCS #7 syntax.
This doesn’t seem to be working, at least not for decrypting the filename. I haven’t tried decrypting the data, yet.
I’ve got a file named test.txt encrypted with the password password123. The resulting filename is MaUi8C8YFNhN5dzbjNtqgXx3Cm-PwyUYxR1Rl4JauHHrjrTMo0k9poE=.
This decodes to the 41 byte string 0x31a522f02f1814d84de5dcdb8cdb6a817c770a6f8fc32518c51d5197825ab871eb8eb4cca3493da681.
The first byte (0x31) is always the same no matter what file I’ve encrypted, so it appears to be the 8-bit version information.
The remaining 40 bytes should contain the salt (8 bytes), IV (16 bytes), and ciphertext (16 bytes in this case), which adds up to 40 bytes. So far so good.
Using PBKDF2 with the password (password123), the salt (0xa522f02f1814d84d), 5000 iterations, a key length of 16 bytes, and HMAC-SHA256, I get the key 0x4b959fc25e54be35221a4193259f485e8475ba7393e166de1e74efb84c19cee8.
Using AES-256-CBC with the key and IV to decrypt the ciphertext (0x1d5197825ab871eb8eb4cca3493da681) I get the plaintext 0xf3be885bbf706d9dca5672e2825921db.
You can see three issues with this plaintext:
It doesn’t begin with four zero-value bytes (0x00000000).
It doesn’t have valid padding. Since the length of the zero-value bytes is 4 and the length of test.txt is 8 for a total plaintext length of 12, there should be four bytes of padding (0x04040404).
It doesn’t contain the original filename test.txt.
The padded plaintext should be '\0\0\0\0test.txt\x04\x04\x04\x04' or 0x00000000746573742e74787404040404.
Hi @jordanbtucker,
Your code looks correct so I went back and double-checked our encryption code… and I see what the issue is, and it’s our fault.
I said (and our material on the website says) a 256 bit key, but version 1 encryption actually has a 128 bit key. Version 2 has a 256 bit key, which is where the mixup stems. I believe we switched to 256 in V2 mostly because it “looks better” and not for any practical security reasons, to be honest. Plus, the key derivation overhead for a 256 bit key vs a 128 bit key ended up being fairly negligible.
I will correct the above info and put in a request to change the website info, at least until V2 is released.
I’m using the paid version of Odrive (love it) and the encryption feature for nearly everything I put in the cloud. To me, it seems like with all of the information given about the encryption/decryption process, if the Odrive Team just built a simple standalone decryption tool and open sourced it on Github this would go a HUGE way in alleviating most people’s concerns! We just want a guaranteed way to get at our data, on our own terms, in case god forbid Odrive disappear in the middle of the night and we no longer have access to prior installers or computers with them for whatever reason.
I’ve uploaded TB’s of data so far and while I have offline decrypted copies in backup it’d still be a nice warm fuzzy blanket knowing such a tool existed and I had access to it. I really have to think the Odrive Team could produce this quickly, put it out and put an end to 95% of this topic for good when combined with the encryption FAQ. Kind of crazy the community is having to reverse engineer and build this TBH and shows you what the demand is.
Looking forward to whats coming in the future and supporting the product.
This is not an “official” odrive tool, but I spent some time throwing together a python app that will decrypt a given odrive encrypted file (V1): https://github.com/amagliul/odrive-decryptor
Just curious, how does odrive know my decryption passphrase for encrypted folder when I use odrive to login for the first time?
If I download a new odrive folder from scratch, it can decrypt my upstream data. How does it get the key if I used oauth? I assume the app should have the key somehow but I didn’t manually enter it in.
On a brand new system, where odrive has never been installed before, odrive will prompt you for the passphrase when you try to expand an Encryptor folder.
If you are seeing that odrive is able to decrypt your content without prompting then that system must already have the encryption registry entry/keychain entry from a past install on that system.