Dropbox came out with an article recently on how it stores it's passwords. You can find the short article here: https://blogs.dropbox.com/tech/2016/09/h...passwords/
The article itself explains everything about their choices in algorithms and why they layer the encryption like they do. What this post will do is translate their work into Go.
Firstly, we start by taking in a password and converting it into SHA512 hash. Afterwards we then hash it through bcrypt with a work factor of 10. Dropbox also mentions that they use a salt with bcrypt, but the Go team's implementation of bcrypt includes salt generation as viewed here: https://github.com/golang/crypto/blob/ma...pt.go#L129
This can all be done neatly in a single function with a []byte, error output.
The bcrypt default cost is 10, so this is nice and readable. Firstly we just take a byte slice as our only argument to keep it simple. Then we create our hash, check and make sure there are no errors, and finally bcrypt the Sum of that hash. Returning a nice byte slice we can plug straight into the next step.
For some brevity, we won't be writing any code that actually reads the secret key for AES from its file. We'll just be lazy and put that key as a constant in our code. If you are actually going to implement this in any code, set it up properly and have the secret key in a file outside of the code and the database.
Now to the actual part of encrypting the hash. When they say AES-256, we'll be using 256 bit AES-GCM. This also gives us the check that not only is our data encrypted, but that is has integrity checks as well. Although this doesn't guard against nonce misuse / collisions, we won't be too concerned with that. I suspect that with all the users Dropbox has, they might have to worry about it and have a different implementation or use AES-GCM-SIV. I don't know what they use since it isn't specified in the article.
Anyways, here is what we will use to encrypt the data via AES-GCM. AES automatically will select 256-bit by using the appropriate key size. We'll just bum the Encrypt function from here: https://github.com/gtank/cryptopasta/blo...encrypt.go
This repo specializes in having crypto code for these basic scenarios at the ready. That and the author has a lot of credentials creating and breaking secure crypto, so I trust it.
We're only bumming the Encrypt function, the rest we will make as we need it. All we need to do is put in our pepper (again, that shouldn't be in the code, this is just a demo) and have a way to pass that through our system. With all that in place, here is what the encryption code looks like in its entirety.
With that, we have what we will be putting in the database. All you need to do is now extract out the key from the database, decode the AES outer shell, and then compare any incoming hashed password guess against what you have and that's it.
The article itself explains everything about their choices in algorithms and why they layer the encryption like they do. What this post will do is translate their work into Go.
Firstly, we start by taking in a password and converting it into SHA512 hash. Afterwards we then hash it through bcrypt with a work factor of 10. Dropbox also mentions that they use a salt with bcrypt, but the Go team's implementation of bcrypt includes salt generation as viewed here: https://github.com/golang/crypto/blob/ma...pt.go#L129
This can all be done neatly in a single function with a []byte, error output.
The bcrypt default cost is 10, so this is nice and readable. Firstly we just take a byte slice as our only argument to keep it simple. Then we create our hash, check and make sure there are no errors, and finally bcrypt the Sum of that hash. Returning a nice byte slice we can plug straight into the next step.
For some brevity, we won't be writing any code that actually reads the secret key for AES from its file. We'll just be lazy and put that key as a constant in our code. If you are actually going to implement this in any code, set it up properly and have the secret key in a file outside of the code and the database.
Now to the actual part of encrypting the hash. When they say AES-256, we'll be using 256 bit AES-GCM. This also gives us the check that not only is our data encrypted, but that is has integrity checks as well. Although this doesn't guard against nonce misuse / collisions, we won't be too concerned with that. I suspect that with all the users Dropbox has, they might have to worry about it and have a different implementation or use AES-GCM-SIV. I don't know what they use since it isn't specified in the article.
Anyways, here is what we will use to encrypt the data via AES-GCM. AES automatically will select 256-bit by using the appropriate key size. We'll just bum the Encrypt function from here: https://github.com/gtank/cryptopasta/blo...encrypt.go
This repo specializes in having crypto code for these basic scenarios at the ready. That and the author has a lot of credentials creating and breaking secure crypto, so I trust it.
We're only bumming the Encrypt function, the rest we will make as we need it. All we need to do is put in our pepper (again, that shouldn't be in the code, this is just a demo) and have a way to pass that through our system. With all that in place, here is what the encryption code looks like in its entirety.
With that, we have what we will be putting in the database. All you need to do is now extract out the key from the database, decode the AES outer shell, and then compare any incoming hashed password guess against what you have and that's it.


