Hacker News new | past | comments | ask | show | jobs | submit login
Copy and paste-friendly Go crypto (github.com/gtank)
141 points by FiloSottile on July 16, 2016 | hide | past | favorite | 33 comments



I was actually at this talk (excellent way to go over this kind of topic!) and I have just a small thing to add.

You'll notice the "Asymmetric Signature" section mentions using ESDSA on P-256 because "the Go implementation of P-256 is constant time to protect against side-channel attacks." However, someone mentioned that this may not be on all platforms because it is hand-coded assembly. After a quick check of the Go source code, this is indeed true. In fact, the constant time guarantee assembly version is only available on amd64 compatible systems[1]. Just something to take note of.

[1] https://golang.org/src/crypto/elliptic/

Edit: Formatting and grammar and spelling, oh my.


Well, the Go implementation of P-256 is meant to be constant-time, even if we don't get a hard guarantee that the compiler won't screw that up somewhere somehow. On the other hand, the generic implementation of the other curves is almost comically vulnerable to timing attacks---compare [1] to [2].

[1] https://github.com/golang/go/blob/master/src/crypto/elliptic...

[2] https://github.com/golang/go/blob/master/src/crypto/elliptic...


Author here, glad you enjoyed the talk!

Looking into it more I noticed that there's a Go implementation[1] that is noted to be constant-time with a !amd64 build tag. So it isn't just the assembly one.

[1] https://golang.org/src/crypto/elliptic/p256.go


Wow, I completely missed that (largely because I assumed a Go implementation could not guarantee constant time), sorry about that and thanks for looking deeper than I did.

On that note, how much of a guarantee is there in the Go implementation? I assume in most cases it's going to be constant time, but isn't that a little harder to guarantee when compared to the asm version? And if not why not just use the Go implementation everywhere for consistency?


The asm version is much more performant. The Go version is a port of the version in NSS, but the compiler is free to screw it up in various ways. Furthermore correctness is always a concern: cleverness in unsaturated arithmetic code can be hard.


Your recommendations and defaults are sane, and the code looks solid, thanks for publishing.

I just don't know why you call this 'copy and paste-friendly'. This is essentially a minimalistic library, not a bunch of code examples (ie. "usage").

Stackoverflow (as awful as roll-your-own-crypto is,) is great for seeing code examples in context of a domain problem, rather than a crypographic primitive.

This is a decent wrapper for goland stdlib's crypto, but doesn't particularly help a person who's trying to understand how to apply crypto to their particular usecase, and would therefore be most susceptible to googling it.


1. How do I protect my password, umm, I heard I have to hash it.

2. Goes to https://github.com/gtank/cryptopasta/blob/master/hash.go#L41

3. This `HashPassword()` and `CheckPasswordHash()` functions look interesting

4. Copy/Pasted into the project, it just works!


Don't copy and paste code! Instead, use a well maintained library.


Such as nacl/secretbox for encryption instead of rolling your own AES-GCM

https://godoc.org/golang.org/x/crypto/nacl/secretbox


I'm not sure, but isn't this post about showing how to use such libraries?


No: "Copy and paste-friendly Go crypto"


This is a really great idea! I would like to see it for other langs too.


NaCl is basically this, but as a library instead of copy/paste. It's available in most languages if you look around.

https://nacl.cr.yp.to/index.html


https://golang.org/x/crypto/nacl for the Gophers among us (it provides only box/secret_box, though)


You could argue that https://tweetnacl.cr.yp.to/ is well-suited to cut-and-paste crypto.


You can basically `go get` this and use it as it is though. I'm not entirely sure why they spin it as copy-pasta crypto.



P-256 is not a safe curve! http://safecurves.cr.yp.to


> You should not go below work factor 12.

Out of curiosity, how do people determine 12 is the right work factor? When should/will this go to 13?


It is relative to cpu performance.

https://en.wikipedia.org/wiki/Bcrypt


What is the current recommendation for iteration count for pbkdf2?


What your slowest hardware can handle in a reasonable timeframe


In the encrypt examples I always wonder why they assume that you have a fixed 32 bit key (password). Shouldn't they include a padding function?

Is use this one:

edit: deleted in case some is so crazy to use it :)


Wait. Stop. You are writing your own crypto.

AES keys are 256 (or 128) bit, fixed size, and should be random-looking data. The code here uses [32]byte intentionally so you won't use anything else.

If you have a password instead, that is NOT suitable for use as a key directly, whichever the length, because it has low entropy by definition. So you want to stretch it (and whiten it) with something like scrypt. It's a bit of the same argument as password hashing.

Also, you don't want to discover what happens if you have strong patterns like padding in your key (it should be fine, but it's the kind of attacks that come before a full break). And you don't want to cut short a password longer than 32 characters.

This is the issue, btw: https://github.com/gtank/cryptopasta/issues/7

Don't copy-paste crypto from HN.


I know! That's why I am asking. I have found surprisingly difficult to find a package that does this.


> I know! That's why I am asking. I have found surprisingly difficult to find a package that does this.

scrypt, with an output length that suits your use-case? (as Filippo points out)

Note: I wrote https://github.com/elithrar/simple-scrypt, which wraps Go's scrypt package and gives it a friendlier API (mimicking the bcrypt one). Handles salt generation for you and has sane default parameters, outputting a 32-byte derived key by default. e.g.

    func deriveKey(key []byte) ([]byte, error) {
        return scrypt.GenerateFromPassword([]byte("plaintext"), scrypt.DefaultParams)
    }
You can pass your own params, or modify the defaults to get a different key length depending on your use-case.


yes, that is what I was looking for. Thank you!


I'm not sure what you looked at, but the first example I found used a 32 byte key (256 bits = 8 * 32). From the readme :

> 5. Key generation functions will panic if they can't read enough random bytes to generate the key. Key generation is critical, and if crypto/rand fails at that stage then you should stop doing cryptography on that machine immediately.

Having less than a full encryption key is a fatal error! Not something to be padded around.

Apologies if there are some examples for key derivation from a password that somehow doesn't use only part of an array initialized to zero (which would be bad, adding random unitialized data to the kdf - good luck decrypting!).


But what if I want to encrypt "my secret" with "password1234"?. You can't require everybody to memorize exactly 32 bit passwords


As natedub indicates, to turn a password into a key you need to use a password-based key-derivation function; PBKDF2 is standardised, sane and reasonably quick; scrypt and bcrypt get more love these days, but I think any of them would be sufficient.

A cryptographic key (unlike a password) needs to be exactly a certain length, and ideally be completely random (if not, at least indistinguishable from random): a password might be exactly that length, but it will _not_ be completely random (heck, if you can type it then certain bit patterns simply won't occur …).

The fact that '012345789ABCDEF012345789ABCDEF' and unhex('cd8fa5ecf22379c429f56fdaae511144f9b7704247a244859b943299eb57fb1d') have the same length in bytes is coincidental; they really are two very different types.


Passwords are not keys, but you can generate a key from a password with a Password-Based Key Derivation Function.

See https://en.wikipedia.org/wiki/PBKDF2


Stop saying 32 bit, please. It's 32 byte, or 256 bit.

Furthermore, use a KDF to stretch your password into a key suitable for encryption.


Sorry, of course I mean 32 byte.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: