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
copy & paste-friendly golang crypto
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 commCategory: Golang / Miscellaneous |
Watchers: 67 |
Star: 1.8k |
Fork: 98 |
Last update: Jan 21, 2023 |
Fix nonce by changing it from a random byte array to an incrementing counter that is converted into a byte array.
Resolves #14
Should have samples of creating a server with strong ciphers. Seems to a common thing to do with go.
Passing keys as arrays rather than slices or pointers to arrays seems like a good way to spray key material all over the stack. I'd suggest using pointers in those cases so you at least have the ability to zero the memory if desired.
The readme recommends "256-bit AES-GCM with random 96-bit nonces". 256-bit AES-GCM is good, and 96-bit nonces are the safest choice. However, random nonces aren't as safe. The birthday bound is 2**48, which isn't sufficient. Instead, I recommend creating a random mask and then using a counter that is XOR'd with that mask as nonces. This is what ChaCha20-Poly1305 ciphersuites do in TLS 1.2 and later and what AES-GCM ciphersuites in TLS 1.3 and later will do. I believe this is also what OpenSSH AES-GCM cipher suites do.
I've recently had occasion to use crypto.hmac, and it might be worth a demo in here
Hi, we are a research group to help developers build secure applications. We designed a cryptographic misuse detector (i.e., CryptoGo) on Go language. We found your great public repository from Github, and several security issues detected by CryptoGo are shown in the following. Note that the cryptographic algorithms are categorized with two aspects: security strength and security vulnerability based on NIST Special Publication 800-57 and other public publications. Moreover, CryptoGo defined certain rules derived from the APIs of Go cryptographic library and other popular cryptographic misuse detectors. The specific security issues we found are as follows: Location: encrypt.go:38; Broken rule: R-04: Constant key in AES; We wish the above security issues could truly help you to build a secure application. If you have any concern or suggestion, please feel free to contact us, we are looking forward to your reply. Thanks.
Currently, BCrypt is used as the default password hashing and validation method. However, BCrypt has several shortcomings (listing the two most popular ones):
- A maximum password length of 72 bytes (applicable to x/crypto/bcrypt)
- Lack of memory-hardness
Argon2 has been around for some time now and won the PHC in 2015. It is standardized by the IETF while bcrypt is not (scrypt is but consensus (source missing) goes towards Argon2). Argon2 is available as a pure go implementation at golang.org/x/crypto/argon2
Additionally, Argon2 has a lot of details that need to be implemented. For example the standardized string format (which includes the type, version, salt, ...) needs to be properly encoded. Choosing parameters is another question where best-practice defaults are interesting.
There is a blog post on implementing Argon2 in Go. However, I can not vouch for the contents of the post as I am not an expert in Argon2. It seems though as if the blog post has been reviewed by the author of golang.org/x/crypto/argon2
:
Thanks to Andreas Auernhammer, author of the golang.org/x/crypto/argon2 package, for checking over this post before publication.
I therefore want to suggest to add Argon2 to this repository and provide a best-practice implementation for hashing and comparing passwords and storing password hashes.
I'd be happy to contribute but I want to stress, again, that I'm not an expert in this area.
Hello, I was wondering why would one use NewEncryptionKey
? As far as I know one creates/stores somewhere EncryptionKey
and reuses it for every encryption/decryption (EncryptionKey
has to be the same to decode token which has been encoded using the EncryptionKey
).
The process of encoding and decoding is not entirely clear, it would be useful to provide some examples of encoding/decoding text, something like this:
var encKey = os.Getenv("ENC_KEY")
// [32]byte{'_','_','r','a','n','d','o','m','_','s','t','r','o','n','g','_','e','n','c','r','y','p','t','i','o','n','_','k','e','y','_','_'}
text := "some text to encrypt"
encText, err := cryptopasta.Encrypt([]byte(text), &encKey)
if err != nil {
//handle error
}
fmt.Println("plain text:", text)
fmt.Println("encrypted text", encText)
decryptedText, err := cryptopasta.Encrypt(encText, &encKey)
if err != nil {
//handle error
}
fmt.Println("decrypted text:", decryptedText)
Is the example correct? Are there any other things to be aware of?
Following this, I see that you do not set read/write time outs on the server in the tls_test.go
:o perhaps set some sane defaults?