122 lines
5.7 KiB
Text
122 lines
5.7 KiB
Text
|
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
|