Skip to content

Instantly share code, notes, and snippets.

@chilts
Last active October 18, 2016 21:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chilts/7c31c2ec84939034bdfec324d02aa5f2 to your computer and use it in GitHub Desktop.
Save chilts/7c31c2ec84939034bdfec324d02aa5f2 to your computer and use it in GitHub Desktop.
"How Dropbox securely stores your passwords" in terrible, insecure, horrible GoLang (GoLang is not terrible, my code is).

+++ WARNING +++

This is just a little test. It should NOT be used for your passwords unless you know what you're doing. I (on the other hand) do NOT know what I'm doing, so please, don't trust this code.

+++ WARNING +++

How Dropbox securely stores your passwords

From : https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords/

The Challenge

All I wanted to do was try and copy what Dropbox did for their passwords, in Go. Whether this is correct or not, I have no idea. It was a coding challenge only.

But ... I'd love it if you could fork this and make it better and more correct. Ping me at @andychilton.

Example Runs

$ go run pw.go 
2016/10/03 22:48:09 Hashed = 6bd54875a5abdc46ab6b871e7271b1174239422f55416965364b76364f61687439485762616f4863545a6b31763734556d6d55715276496267744f53

$ go run pw.go 
2016/10/03 23:01:04 Hashed = 439903360a1292949e1eb7e29d8b9d8d724953655a4344506d446e55754d59435556314962494f6e2f6e664932382f797a71726d71354b6f58494875

$ go run pw.go 
2016/10/03 23:01:07 Hashed = 8955d598ed168fa7e6df501cc30dd80e6a53566d36425955506f4534755667525152574f46674f734d6c3262764d3358416462337743495679426869

Author

Andrew Chilton. (Yes, I know my website is currently not serving on https. Go figure.)

License

I know this is Dropbox's idea but they blogged about it publicly, so I tried it. Everything I've put here is the following license:

(Ends)

package main
import (
"crypto/aes"
"crypto/sha512"
"encoding/hex"
"io"
"log"
"golang.org/x/crypto/bcrypt"
)
// Dropbox performs password hashing, bcrypting, and encryption as described in
// https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords/
func Dropbox(pw string, key []byte) ([]byte, error) {
// SHA512
h := sha512.New()
io.WriteString(h, pw)
sha512Bytes := h.Sum(nil)
// log.Printf("SHA512 = %x\n", sha512Bytes)
// now base64 encode this, since bcrypt stops at null bytes
base64 := hex.EncodeToString(sha512Bytes)
// now bcrypt it
bcryptBytes, err := bcrypt.GenerateFromPassword([]byte(base64), 10)
if err != nil {
return nil, err
}
// log.Printf("bcrypt = %x\n", bcryptBytes)
// AES256
cipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
cipher.Encrypt(bcryptBytes, bcryptBytes)
// log.Printf("aes256 = %x\n", bcryptBytes)
// all good
return bcryptBytes, nil
}
func main() {
// This is the silliest password ever, choose something better.
password := "password"
// This is the silliest key ever, choose something better.
// ToDo: I'm not sure if this is of the correct length for AES256?
key := []byte("ABCDEFGHIJKLMNOP")
// hash the password
bytes, err := Dropbox(password, key)
if err != nil {
log.Fatal(err)
}
log.Printf("Hashed = %x\n", bytes)
}
@devd
Copy link

devd commented Oct 3, 2016

cool!

For ease of elucidation, the blogpost elided a couple of details. We base64 encode the output of SHA512 since bcrypt will stop at a null byte. We also use a versioned encryption scheme to help with key rotation etc. Also, we use an authenticated encryption scheme over plain AES (so something like seal from aes_gcm package is closer to what we do). These might be worth adding here, IMO. thanks!

@chilts
Copy link
Author

chilts commented Oct 18, 2016

Cool, thanks @devd. I have base64 encoded the output of the sha512. I'm still grokking a few things related to what you mean by the AES stuff, seal and ars_gcm. :)

I've been thinking about the versioned scheme. I guess it could be something like a type which knows about every scheme you've ever done, and essentially loops through each to check if the password is correct. Also, the same type, if given a password always encodes for the latest version. By version, that not only includes how, but also valid keys too. I dunno ... am just thinking out loud.

@chilts
Copy link
Author

chilts commented Oct 18, 2016

And I've been thinking about how to have multiple password schemes and upgrading if needed. Looks like this package does that qutie well : https://godoc.org/gopkg.in/hlandau/passlib.v1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment