initial release

This commit is contained in:
Bobby DeSimone 2019-01-02 12:13:36 -08:00
commit d56c889224
No known key found for this signature in database
GPG key ID: AEE4CF12FE86D07E
62 changed files with 8229 additions and 0 deletions

View file

@ -0,0 +1,36 @@
## Generating random seeds
In order of preference:
- `head -c32 /dev/urandom | base64`
- `openssl rand -base64 32 | head -c 32 | base64`
## Encrypting data
TL;DR -- Nonce reuse is a problem. AEAD isn't a clear choice right now.
[Miscreant](https://github.com/miscreant/miscreant.go)
+ AES-GCM-SIV seems to have ideal properties
+ random nonces
- ~30% slower encryption
- [not maintained by a BigCo](https://github.com/miscreant/miscreant.go/graphs/contributors)
[nacl/secretbot](https://godoc.org/golang.org/x/crypto/nacl/secretbox)
+ Fast
+ XSalsa20 wutg Poly1305 MAC provides encryption and authentication together
+ A newer standard and may not be considered acceptable in environments that require high levels of review.
-/+ maintained as an [/x/ package](https://godoc.org/golang.org/x/crypto/nacl/secretbox)
- doesn't use the underlying cipher.AEAD api.
GCM with random nonces
+ Fastest
+ Go standard library, supported by google $
- Easy to get wrong
- IV reuse is a known weakness so keys must be rotated before birthday attack. [NIST SP 800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf) recommends using the same key with random 96-bit nonces (the default nonce length) no more than 2^32 times
Further reading on tradeoffs:
- [Introducing Miscreant](https://tonyarcieri.com/introducing-miscreant-a-multi-language-misuse-resistant-encryption-library)
- [agl's post AES-GCM-SIV](https://www.imperialviolet.org/2017/05/14/aesgcmsiv.html)
- [x/crypto: add chacha20, xchacha20](https://github.com/golang/go/issues/24485s)
- [GCM cannot be used with random nonces](https://github.com/gtank/cryptopasta/issues/14s)
- [proposal: x/crypto/chacha20poly1305: add support for XChaCha20](https://github.com/golang/go/issues/23885)
- [kubernetes](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#providers)

View file

@ -0,0 +1,30 @@
package cryptutil // import "github.com/pomerium/pomerium/internal/cryptutil"
import (
"crypto/hmac"
"crypto/sha512"
"golang.org/x/crypto/bcrypt"
)
// Hash generates a hash of data using HMAC-SHA-512/256. The tag is intended to
// be a natural-language string describing the purpose of the hash, such as
// "hash file for lookup key" or "master secret to client secret". It serves
// as an HMAC "key" and ensures that different purposes will have different
// hash output. This function is NOT suitable for hashing passwords.
func Hash(tag string, data []byte) []byte {
h := hmac.New(sha512.New512_256, []byte(tag))
h.Write(data)
return h.Sum(nil)
}
// HashPassword generates a bcrypt hash of the password using work factor 14.
func HashPassword(password []byte) ([]byte, error) {
return bcrypt.GenerateFromPassword(password, 14)
}
// CheckPasswordHash securely compares a bcrypt hashed password with its possible
// plaintext equivalent. Returns nil on success, or an error on failure.
func CheckPasswordHash(hash, password []byte) error {
return bcrypt.CompareHashAndPassword(hash, password)
}

View file

@ -0,0 +1,80 @@
package cryptutil // import "github.com/pomerium/pomerium/internal/cryptutil"
import (
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"io/ioutil"
"os"
"testing"
)
func TestPasswordHashing(t *testing.T) {
bcryptTests := []struct {
plaintext []byte
hash []byte
}{
{
plaintext: []byte("password"),
hash: []byte("$2a$14$uALAQb/Lwl59oHVbuUa5m.xEFmQBc9ME/IiSgJK/VHtNJJXASCDoS"),
},
}
for _, tt := range bcryptTests {
hashed, err := HashPassword(tt.plaintext)
if err != nil {
t.Error(err)
}
if err = CheckPasswordHash(hashed, tt.plaintext); err != nil {
t.Error(err)
}
}
}
// Benchmarks SHA256 on 16K of random data.
func BenchmarkSHA256(b *testing.B) {
data, err := ioutil.ReadFile("testdata/random")
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(data)))
for i := 0; i < b.N; i++ {
_ = sha256.Sum256(data)
}
}
// Benchmarks SHA512/256 on 16K of random data.
func BenchmarkSHA512_256(b *testing.B) {
data, err := ioutil.ReadFile("testdata/random")
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(data)))
for i := 0; i < b.N; i++ {
_ = sha512.Sum512_256(data)
}
}
func BenchmarkBcrypt(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := HashPassword([]byte("thisisareallybadpassword"))
if err != nil {
b.Error(err)
break
}
}
}
func ExampleHash() {
tag := "hashing file for lookup key"
contents, err := ioutil.ReadFile("testdata/random")
if err != nil {
fmt.Printf("could not read file: %v\n", err)
os.Exit(1)
}
digest := Hash(tag, contents)
fmt.Println(hex.EncodeToString(digest))
// Output: 9f4c795d8ae5c207f19184ccebee6a606c1fdfe509c793614066d613580f03e1
}

BIN
internal/cryptutil/testdata/random vendored Normal file

Binary file not shown.