122 lines
5.7 KiB
Plaintext
122 lines
5.7 KiB
Plaintext
TL;DR- Copy & paste your crypto code from here instead of Stack Overflow.
|
||
|
||
This library demonstrates a suite of basic cryptography from the Go standard
|
||
library. To the extent possible, it tries to hide complexity and help you avoid
|
||
common mistakes. The recommendations were chosen as a compromise between
|
||
cryptographic qualities, the Go standard lib, and my existing use cases.
|
||
|
||
Some particular design choices I've made:
|
||
|
||
1. SHA-512/256 has been chosen as the default hash for the examples. It's
|
||
faster on 64-bit machines and immune to length extension. If it doesn't work
|
||
in your case, replace instances of it with ordinary SHA-256.
|
||
|
||
2. The specific ECDSA parameters were chosen to be compatible with RFC7518[1]
|
||
while using the best implementation of ECDSA available. Go's P-256 is
|
||
constant-time (which prevents certain types of attacks) while its P-384 and
|
||
P-521 are not.
|
||
|
||
3. Key parameters are arrays rather than slices so the compiler can help you
|
||
avoid mixing up the arguments. The signing and marshaling functions use the
|
||
crypto/ecdsa key types directly for the same reason.
|
||
|
||
4. Public/private keypairs for signing are marshaled into and out of PEM
|
||
format, making them relatively portable to other crypto software you're
|
||
likely to use (openssl, cfssl, etc).
|
||
|
||
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.
|
||
|
||
6. The license is a CC0 public domain dedication, with the intent that you can
|
||
just copy bits of this directly into your code and never be required to
|
||
acknowledge my copyright, provide source code, or do anything else commonly
|
||
associated with open licenses.
|
||
|
||
|
||
The specific recommendations are:
|
||
|
||
|
||
Encryption - 256-bit AES-GCM with random 96-bit nonces
|
||
|
||
Using AES-GCM (instead of AES-CBC, AES-CFB, or AES-CTR, all of which Go also
|
||
offers) provides authentication in addition to confidentiality. This means that
|
||
the content of your data is hidden and that any modification of the encrypted
|
||
data will result in a failure to decrypt. This rules out entire classes of
|
||
possible attacks. Randomized nonces remove the choices around nonce generation
|
||
and management, which are another common source of error in crypto
|
||
implementations.
|
||
|
||
The interfaces in this library allow only the use of 256-bit keys.
|
||
|
||
|
||
Hashing - HMAC-SHA512/256
|
||
|
||
Using hash functions directly is fraught with various perils – it's common for
|
||
developers to accidentally write code that is subject to easy collision or
|
||
length extension attacks. HMAC is a function built on top of hashes and it
|
||
doesn't have those problems. Using SHA-512/256 as the underlying hash function
|
||
means the process will be faster on 64-bit machines, but the output will be the
|
||
same length as the more familiar SHA-256.
|
||
|
||
This interface encourages you to scope your hashes with an English-language
|
||
string (a "tag") that describes the purpose of the hash. Tagged hashes are a
|
||
common "security hygiene" measure to ensure that hashing the same data for
|
||
different purposes will produce different outputs.
|
||
|
||
|
||
Password hashing - bcrypt with work factor 14
|
||
|
||
Use this to store users' passwords and check them for login (e.g. in a web
|
||
backend). While they both have "hashing" in the name, password hashing is an
|
||
entirely different situation from ordinary hashing and requires its own
|
||
specialized algorithm. bcrypt is a hash function designed for password storage.
|
||
It can be made selectively slower (based on a "work factor") to increase the
|
||
difficulty of brute-force password cracking attempts.
|
||
|
||
As of 2016, a work factor of 14 should be well on the side of future-proofing
|
||
over performance. If it turns out to be too slow for your needs, you can try
|
||
using 13 or even 12. You should not go below work factor 12.
|
||
|
||
|
||
Symmetric Signatures / Message Authentication - HMAC-SHA512/256
|
||
|
||
When two parties share a secret key, they can use message authentication to
|
||
make sure that a piece of data hasn't been altered. You can think of it as a
|
||
"symmetric signature" - it proves both that the data is unchanged and that
|
||
someone who knows the shared secret key generated it. Anyone who does not know
|
||
the secret key can neither validate the data nor make valid alterations.
|
||
|
||
This comes up most often in the context of web stuff, such as:
|
||
|
||
1. Authenticating requests to your API. The most widely known example is
|
||
probably the Amazon AWS API, which requires you to sign requests with
|
||
HMAC-SHA256. In this type of use, the "secret key" is a token that the API
|
||
provider issues to authorized API users.
|
||
|
||
2. Validating authenticated tokens (cookies, JWTs, etc) that are issued by a
|
||
service but are stored by a user. In this case, the service wants to ensure
|
||
that a user doesn't modify the data contained in the token.
|
||
|
||
As with encryption, you should always use a 256-bit random key to
|
||
authenticate messages.
|
||
|
||
|
||
Asymmetric Signatures - ECDSA on P-256 with SHA-256 message digests
|
||
|
||
These are the classic public/private keypair signatures that you probably think
|
||
of when you hear the word "signature". The holder of a private key can sign
|
||
data that anyone who has the corresponding public key can verify.
|
||
|
||
Go takes very good care of us here. In particular, the Go implementation of
|
||
P-256 is constant time to protect against side-channel attacks, and the Go
|
||
implementation of ECDSA generates safe nonces to protect against the type of
|
||
repeated-nonce attack that broke the PS3.
|
||
|
||
In terms of JWTs, this algorithm is called "ES256". The functions
|
||
"EncodeSignatureJWT" and "DecodeSignatureJWT" will convert the basic signature
|
||
format to and from the encoding specified by RFC7515[2]
|
||
|
||
[1] https://tools.ietf.org/html/rfc7518#section-3.1
|
||
[2] https://tools.ietf.org/html/rfc7515#appendix-A.3
|