Slide 1

Slide 1 text

Crypto for Go Developers George Tankersley (@_gtank) CoreOS

Slide 2

Slide 2 text

Don’t write your own crypto

Slide 3

Slide 3 text

This is Daniel J. Bernstein. He designs the algorithms.

Slide 4

Slide 4 text

You don’t need to write your own crypto

Slide 5

Slide 5 text

https://commons.wikimedia.org/wiki/File:Lego_dublo_arto_alanenpaa_2.JPG Building blocks

Slide 6

Slide 6 text

https://commons.wikimedia.org/wiki/File:Lego_dublo_arto_alanenpaa_2.JPG Building blocks

Slide 7

Slide 7 text

TLS for data in motion GPG for data at rest

Slide 8

Slide 8 text

How to use TLS As a client var minimalTLSConfig = &tls.Config{ MinVersion: tls.VersionTLS12, } var tlsTransport = &http.Transport{ TLSClientConfig: minimalTLSConfig, } var httpClient = &http.Client{ Transport: tlsTransport, Timeout: 10 * time.Second, } func MakeRequest() error { resp, err := httpClient.Get("https://www.google.com") if err != nil { return err } // have fun }

Slide 9

Slide 9 text

How to use TLS As a client var minimalTLSConfig = &tls.Config{ MinVersion: tls.VersionTLS12, } var tlsTransport = &http.Transport{ TLSClientConfig: minimalTLSConfig, } var httpClient = &http.Client{ Transport: tlsTransport, Timeout: 10 * time.Second, } func MakeRequest() error { resp, err := httpClient.Get("https://www.google.com") if err != nil { return err } // have fun }

Slide 10

Slide 10 text

How to use TLS As a server var minimalTLSConfig = &tls.Config{ MinVersion: tls.VersionTLS12, PreferServerCipherSuites: true, } var srv = &http.Server{ Addr: "localhost:8080", TLSConfig: minimalTLSConfig, } func handleReq(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, world") } func main() { http.HandleFunc("/", handleReq) err := srv.ListenAndServeTLS("cert.pem","key.pem") if err != nil { log.Fatal(err) } }

Slide 11

Slide 11 text

How to use TLS As a server var minimalTLSConfig = &tls.Config{ MinVersion: tls.VersionTLS12, PreferServerCipherSuites: true, } var srv = &http.Server{ Addr: "localhost:8080", TLSConfig: minimalTLSConfig, } func handleReq(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, world") } func main() { http.HandleFunc("/", handleReq) err := srv.ListenAndServeTLS("cert.pem","key.pem") if err != nil { log.Fatal(err) } }

Slide 12

Slide 12 text

TLS for data in motion GPG for data at rest

Slide 13

Slide 13 text

How to use GPG Please don’t use GPG $ man gpg GPG(1) GNU Privacy Guard 1.4 GPG(1) NAME gpg - OpenPGP encryption and signing tool SYNOPSIS gpg [--homedir dir] [--options file] [options] command [args] DESCRIPTION gpg is the OpenPGP only version of the GNU Privacy Guard (GnuPG). It is a tool to provide digital encryption and signing services using the OpenPGP standard. gpg features complete key management and all bells and whistles you can expect from a decent OpenPGP implementation. This is the standalone version of gpg. For desktop use you should consider using gpg2 from the GnuPG-2 package ([On some platforms gpg2 is installed under the name gpg]).

Slide 14

Slide 14 text

How to use GPG Please don’t use GPG $ man gpg GPG(1) GNU Privacy Guard 1.4 GPG(1) NAME gpg - OpenPGP encryption and signing tool SYNOPSIS gpg [--homedir dir] [--options file] [options] command [args] DESCRIPTION gpg is the OpenPGP only version of the GNU Privacy Guard (GnuPG). It is a tool to provide digital encryption and signing services using the OpenPGP standard. gpg features complete key management and all bells and whistles you can expect from a decent OpenPGP implementation. This is the standalone version of gpg. For desktop use you should consider using gpg2 from the GnuPG-2 package ([On some platforms gpg2 is installed under the name gpg]).

Slide 15

Slide 15 text

How to use GPG Please don’t use GPG $ man gpg | wc -l 3227 $ man gpg | wc -w 16721

Slide 16

Slide 16 text

This is not a talk about TLS and GPG

Slide 17

Slide 17 text

Everyday cryptography that isn’t TLS Hashing files Generating random IDs API authentication Password storage for websites Signed / encrypted cookies JWTs Signing updates

Slide 18

Slide 18 text

Just because it’s in crypto/ doesn’t mean it’s good

Slide 19

Slide 19 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 20

Slide 20 text

Encryption

Slide 21

Slide 21 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 22

Slide 22 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 23

Slide 23 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 24

Slide 24 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 25

Slide 25 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 26

Slide 26 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 27

Slide 27 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 28

Slide 28 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 29

Slide 29 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 30

Slide 30 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 31

Slide 31 text

How to use AES Recall: the purpose of encryption is to hide the content of your data. import ( "crypto/aes" “crypto/rand” "fmt" ) func main() { buf := []byte("The quick brown fox jumps over the lazy dog") // Generate highly secure random AES key key := make([]byte, 32) _, err := rand.Read(key) if err != nil { panic(err) } aesCipher, _ := aes.NewCipher(key) // Encrypt in-place. aesCipher.Encrypt(buf, buf) fmt.Printf("%s\n", buf) } NOT

Slide 32

Slide 32 text

How to use AES Recall: the purpose of encryption is to hide the content of your data. import ( "crypto/aes" “crypto/rand” "fmt" ) func main() { buf := []byte("The quick brown fox jumps over the lazy dog") // Generate highly secure random AES key key := make([]byte, 32) _, err := rand.Read(key) if err != nil { panic(err) } aesCipher, _ := aes.NewCipher(key) // Encrypt in-place. aesCipher.Encrypt(buf, buf) fmt.Printf("%s\n", buf) } NOT

Slide 33

Slide 33 text

How to use AES Recall: the purpose of encryption is to hide the content of your data. import ( "crypto/aes" “crypto/rand” "fmt" ) func main() { buf := []byte("The quick brown fox jumps over the lazy dog") // Generate highly secure random AES key key := make([]byte, 32) _, err := rand.Read(key) if err != nil { panic(err) } aesCipher, _ := aes.NewCipher(key) // Encrypt in-place. aesCipher.Encrypt(buf, buf) fmt.Printf("%s\n", buf) } NOT

Slide 34

Slide 34 text

How to use AES Recall: the purpose of encryption is to hide the content of your data. import ( "crypto/aes" “crypto/rand” "fmt" ) func main() { buf := []byte("The quick brown fox jumps over the lazy dog") // Generate highly secure random AES key key := make([]byte, 32) _, err := rand.Read(key) if err != nil { panic(err) } aesCipher, _ := aes.NewCipher(key) // Encrypt in-place. aesCipher.Encrypt(buf, buf) fmt.Printf("%s\n", buf) } NOT

Slide 35

Slide 35 text

How to use AES Recall: the purpose of encryption is to hide the content of your data. Input: The quick brown fox jumps over the lazy dog. Expect: �) �0��G1e���BQ�ʶ�c�R+t5�6Oܽ� � $ go run encrypt.go ws)���efox jumps over the lazy dog. NOT

Slide 36

Slide 36 text

How to use AES Recall: the purpose of encryption is to hide the content of your data. Input: The quick brown fox jumps over the lazy dog. Expect: �) �0��G1e���BQ�ʶ�c�R+t5�6Oܽ� � $ go run encrypt.go ws)���efox jumps over the lazy dog. NOT

Slide 37

Slide 37 text

Never use a cipher.Block directly

Slide 38

Slide 38 text

Instead, use a block cipher mode

Slide 39

Slide 39 text

Block cipher modes Go offers CBC, CFB, CTR, OFB, and GCM modes. Their details are not important. Only GCM provides authenticated encryption.

Slide 40

Slide 40 text

Block cipher modes Go offers CBC, CFB, CTR, OFB, and GCM modes. Their details are not important. Only GCM provides authenticated encryption.

Slide 41

Slide 41 text

Block cipher modes Go offers CBC, CFB, CTR, OFB, and GCM modes. Their details are not important. Only GCM provides authenticated encryption.

Slide 42

Slide 42 text

Block cipher modes Go offers CBC, CFB, CTR, OFB, and GCM modes. Their details are not important. Only GCM provides authenticated encryption.

Slide 43

Slide 43 text

Block cipher modes Go offers CBC, CFB, CTR, OFB, and GCM modes. Their details are not important. Only GCM provides authenticated encryption.

Slide 44

Slide 44 text

How to encrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Encrypt(data []byte, key [32]byte) ([]byte, error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) _, err = rand.Read(nonce) if err != nil { return nil, err } return gcm.Seal(nonce, nonce, data, nil), nil } Choose a block cipher mode Generate a randomized nonce

Slide 45

Slide 45 text

How to encrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Encrypt(data []byte, key [32]byte) ([]byte, error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) _, err = rand.Read(nonce) if err != nil { return nil, err } return gcm.Seal(nonce, nonce, data, nil), nil } Choose a block cipher mode Generate a randomized nonce

Slide 46

Slide 46 text

How to encrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Encrypt(data []byte, key [32]byte) ([]byte, error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) _, err = rand.Read(nonce) if err != nil { return nil, err } return gcm.Seal(nonce, nonce, data, nil), nil } Choose a block cipher mode Generate a randomized nonce

Slide 47

Slide 47 text

How to encrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Encrypt(data []byte, key [32]byte) ([]byte, error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) _, err = rand.Read(nonce) if err != nil { return nil, err } return gcm.Seal(nonce, nonce, data, nil), nil } Choose a block cipher mode Generate a randomized nonce

Slide 48

Slide 48 text

How to encrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Encrypt(data []byte, key [32]byte) ([]byte, error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) _, err = rand.Read(nonce) if err != nil { return nil, err } return gcm.Seal(nonce, nonce, data, nil), nil } Choose a block cipher mode Generate a randomized nonce

Slide 49

Slide 49 text

How to encrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Encrypt(data []byte, key [32]byte) ([]byte, error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) _, err = rand.Read(nonce) if err != nil { return nil, err } return gcm.Seal(nonce, nonce, data, nil), nil } Choose a block cipher mode Generate a randomized nonce

Slide 50

Slide 50 text

How to decrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Decrypt(ciphertext []byte, key [32]byte) (plaintext [] byte, err error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } return gcm.Open(nil, ciphertext[:gcm.NonceSize()], ciphertext[gcm.NonceSize():], nil, ) } Choose a block cipher mode We stored the nonce at the beginning of the encrypted data.

Slide 51

Slide 51 text

How to decrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Decrypt(ciphertext []byte, key [32]byte) (plaintext [] byte, err error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } return gcm.Open(nil, ciphertext[:gcm.NonceSize()], ciphertext[gcm.NonceSize():], nil, ) } Choose a block cipher mode We stored the nonce at the beginning of the encrypted data.

Slide 52

Slide 52 text

How to decrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Decrypt(ciphertext []byte, key [32]byte) (plaintext [] byte, err error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } return gcm.Open(nil, ciphertext[:gcm.NonceSize()], ciphertext[gcm.NonceSize():], nil, ) } Choose a block cipher mode We stored the nonce at the beginning of the encrypted data.

Slide 53

Slide 53 text

How to decrypt Initialize the block cipher import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) func Decrypt(ciphertext []byte, key [32]byte) (plaintext [] byte, err error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } return gcm.Open(nil, ciphertext[:gcm.NonceSize()], ciphertext[gcm.NonceSize():], nil, ) } Choose a block cipher mode We stored the nonce at the beginning of the encrypted data.

Slide 54

Slide 54 text

Hashes

Slide 55

Slide 55 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 56

Slide 56 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 57

Slide 57 text

A word about hashes Using hash functions directly is fraught with peril ● Length extension ● Rainbow tables ● Small number of possibilities (phone numbers) ● Salt? Pepper? Like encryption, we use a construction on top of the basic algorithm Instead of hash you should think HMAC

Slide 58

Slide 58 text

How to hash data import ( "crypto/hmac" "crypto/sha512" ) func Hash(tag string, data []byte) []byte { h := hmac.New(sha512.New512_256, []byte(tag)) h.Write(data) return h.Sum(nil) } func ExampleHash() error { tag := "hashing file for storage key" contents, err := ioutil.ReadFile("testfile") if err != nil { Return error } digest := Hash(tag, contents) fmt.Println(hex.EncodeToString(digest)) } // Output: // 9f4c795d8ae5c207f19184ccebee6a606c1fdfe509c793614066d613580f03e1

Slide 59

Slide 59 text

How to hash data import ( "crypto/hmac" "crypto/sha512" ) func Hash(tag string, data []byte) []byte { h := hmac.New(sha512.New512_256, []byte(tag)) h.Write(data) return h.Sum(nil) } func ExampleHash() error { tag := "hashing file for storage key" contents, err := ioutil.ReadFile("testfile") if err != nil { Return error } digest := Hash(tag, contents) fmt.Println(hex.EncodeToString(digest)) } // Output: // 9f4c795d8ae5c207f19184ccebee6a606c1fdfe509c793614066d613580f03e1

Slide 60

Slide 60 text

How to hash data import ( "crypto/hmac" "crypto/sha512" ) func Hash(tag string, data []byte) []byte { h := hmac.New(sha512.New512_256, []byte(tag)) h.Write(data) return h.Sum(nil) } func ExampleHash() error { tag := "hashing file for storage key" contents, err := ioutil.ReadFile("testfile") if err != nil { Return error } digest := Hash(tag, contents) fmt.Println(hex.EncodeToString(digest)) } // Output: // 9f4c795d8ae5c207f19184ccebee6a606c1fdfe509c793614066d613580f03e1

Slide 61

Slide 61 text

How to hash data You can treat output from different tags as independent hash functions! fileDigest := Hash("fileNode", []byte("hello, world")) metaDigest := Hash("metadataNode", []byte("hello, world")) fmt.Printf("%x\n%x\n", fileDigest, metaDigest) $ go run example.go e7332dd5f5b8f6b5af2403677805acaeca4820a7e319afc8951823de3d5ff25e fe8894f9b7c9f0111680a3f85d94929e6d3c6f1ac379aeea1992023d277a4555

Slide 62

Slide 62 text

Hashing passwords

Slide 63

Slide 63 text

How to hash passwords Passwords are a completely different situation. Never use SHA2 or HMAC for passwords. Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt. import ( "golang.org/x/crypto/bcrypt" ) func HashPassword(password []byte) ([]byte, error) { return bcrypt.GenerateFromPassword(password, 14) } func CheckPasswordHash(hash, password []byte) error { return bcrypt.CompareHashAndPassword(hash, password) } func Example() { myPassword := []byte("password") hashed, err := HashPassword(myPassword) if err != nil { return } fmt.Println(string(hashed)) } // Output: // $2a$14$pCOIhZBzlW7URPHjZ8AFqu2DjsJ1LapFZaHq3mDksYzrgP3q6p4OO

Slide 64

Slide 64 text

How to hash passwords Passwords are a completely different situation. Never use SHA2 or HMAC for passwords. Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt. import ( "golang.org/x/crypto/bcrypt" ) func HashPassword(password []byte) ([]byte, error) { return bcrypt.GenerateFromPassword(password, 14) } func CheckPasswordHash(hash, password []byte) error { return bcrypt.CompareHashAndPassword(hash, password) } func Example() { myPassword := []byte("password") hashed, err := HashPassword(myPassword) if err != nil { return } fmt.Println(string(hashed)) } // Output: // $2a$14$pCOIhZBzlW7URPHjZ8AFqu2DjsJ1LapFZaHq3mDksYzrgP3q6p4OO

Slide 65

Slide 65 text

How to hash passwords Passwords are a completely different situation. Never use SHA2 or HMAC for passwords. Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt. import ( "golang.org/x/crypto/bcrypt" ) func HashPassword(password []byte) ([]byte, error) { return bcrypt.GenerateFromPassword(password, 14) } func CheckPasswordHash(hash, password []byte) error { return bcrypt.CompareHashAndPassword(hash, password) } func Example() { myPassword := []byte("password") hashed, err := HashPassword(myPassword) if err != nil { return } fmt.Println(string(hashed)) } // Output: // $2a$14$pCOIhZBzlW7URPHjZ8AFqu2DjsJ1LapFZaHq3mDksYzrgP3q6p4OO

Slide 66

Slide 66 text

Signatures

Slide 67

Slide 67 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 68

Slide 68 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 69

Slide 69 text

Generate an ECDSA key Math is happening import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" ) func NewSigningKey() (*ecdsa.PrivateKey, error) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand. Reader) return key, err }

Slide 70

Slide 70 text

Generate an ECDSA key Math is happening import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" ) func NewSigningKey() (*ecdsa.PrivateKey, error) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand. Reader) return key, err }

Slide 71

Slide 71 text

How to sign data Hash the data and sign the hash using the package-level Sign func Sign(data []byte, priv *ecdsa.PrivateKey) ([]byte, error) { digest := sha256.Sum256(data) r, s, err := ecdsa.Sign(rand.Reader, priv, digest[:]) if err != nil { return nil, err } // encode the signature {R, S} params := priv.Curve.Params() curveByteSize := params.P.BitLen() / 8 rBytes, sBytes := r.Bytes(), s.Bytes() signature := make([]byte, curveByteSize*2) copy(signature[curveByteSize-len(rBytes):], rBytes) copy(signature[curveByteSize*2-len(sBytes):], sBytes) return signature, nil } For compatibility with JWTs, store signatures as a big-endian array of two large integers in R,S order

Slide 72

Slide 72 text

How to sign data Hash the data and sign the hash using the package-level Sign func Sign(data []byte, priv *ecdsa.PrivateKey) ([]byte, error) { digest := sha256.Sum256(data) r, s, err := ecdsa.Sign(rand.Reader, priv, digest[:]) if err != nil { return nil, err } // encode the signature {R, S} params := priv.Curve.Params() curveByteSize := params.P.BitLen() / 8 rBytes, sBytes := r.Bytes(), s.Bytes() signature := make([]byte, curveByteSize*2) copy(signature[curveByteSize-len(rBytes):], rBytes) copy(signature[curveByteSize*2-len(sBytes):], sBytes) return signature, nil } For compatibility with JWTs, store signatures as a big-endian array of two large integers in R,S order

Slide 73

Slide 73 text

How to sign data Hash the data and sign the hash using the package-level Sign func Sign(data []byte, priv *ecdsa.PrivateKey) ([]byte, error) { digest := sha256.Sum256(data) r, s, err := ecdsa.Sign(rand.Reader, priv, digest[:]) if err != nil { return nil, err } // encode the signature {R, S} params := priv.Curve.Params() curveByteSize := params.P.BitLen() / 8 rBytes, sBytes := r.Bytes(), s.Bytes() signature := make([]byte, curveByteSize*2) copy(signature[curveByteSize-len(rBytes):], rBytes) copy(signature[curveByteSize*2-len(sBytes):], sBytes) return signature, nil } For compatibility with JWTs, store signatures as a big-endian array of two large integers in R,S order

Slide 74

Slide 74 text

How to verify data Again, we have to hash the data import ( "crypto/ecdsa" "crypto/sha256" "math/big" ) // Returns true if it's valid and false if not. func Verify(data, sig []byte, pub *ecdsa.PublicKey) bool { digest := sha256.Sum256(data) curveByteSize := pub.Curve.Params().P.BitLen() / 8 r, s := new(big.Int), new(big.Int) r.SetBytes(signature[:curveByteSize]) s.SetBytes(signature[curveByteSize:]) return ecdsa.Verify(pub, digest[:], r, s) } This is the same signature marshaling we just used.

Slide 75

Slide 75 text

How to verify data Again, we have to hash the data import ( "crypto/ecdsa" "crypto/sha256" "math/big" ) // Returns true if it's valid and false if not. func Verify(data, sig []byte, pub *ecdsa.PublicKey) bool { digest := sha256.Sum256(data) curveByteSize := pub.Curve.Params().P.BitLen() / 8 r, s := new(big.Int), new(big.Int) r.SetBytes(signature[:curveByteSize]) s.SetBytes(signature[curveByteSize:]) return ecdsa.Verify(pub, digest[:], r, s) } This is the same signature marshaling we just used.

Slide 76

Slide 76 text

How to verify data Again, we have to hash the data import ( "crypto/ecdsa" "crypto/sha256" "math/big" ) // Returns true if it's valid and false if not. func Verify(data, sig []byte, pub *ecdsa.PublicKey) bool { digest := sha256.Sum256(data) curveByteSize := pub.Curve.Params().P.BitLen() / 8 r, s := new(big.Int), new(big.Int) r.SetBytes(signature[:curveByteSize]) s.SetBytes(signature[curveByteSize:]) return ecdsa.Verify(pub, digest[:], r, s) } This is the same signature marshaling we just used.

Slide 77

Slide 77 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 78

Slide 78 text

The crypto/ package is vast and full of legacy Encryption ● DES ● 3DES ● RC4 ● TEA ● XTEA ● Blowfish ● Twofish ● CAST5 ● Salsa20 ● AES Hashes ● MD4 ● MD5 ● RIPEMD160 ● SHA1 ● SHA2 ● SHA3 Signatures ● RSA ○ PKCS1v15 ○ PSS ● ECDSA ○ P256 ○ P384 ○ P521 ● Ed25519

Slide 79

Slide 79 text

Did you get all that?

Slide 80

Slide 80 text

Because there’s more!

Slide 81

Slide 81 text

Bonus: Random numbers You want crypto/rand As of Go 1.6, be careful with goimports! import ( "crypto/aes" "crypto/cipher" "crypto/rand" "io” ) func DontDoThisAnymore() [32]byte { key := [32]byte{} _, err := rand.Read(key[:]) if err != nil { panic(err) } return key } func NewEncryptionKey() [32]byte { key := [32]byte{} _, err := io.ReadFull(rand.Reader, key[:]) if err != nil { panic(err) } return key }

Slide 82

Slide 82 text

Bonus: Random numbers You want crypto/rand As of Go 1.6, be careful with goimports! import ( "crypto/aes" "crypto/cipher" "crypto/rand" "io” ) func DontDoThisAnymore() [32]byte { key := [32]byte{} _, err := rand.Read(key[:]) if err != nil { panic(err) } return key } func NewEncryptionKey() [32]byte { key := [32]byte{} _, err := io.ReadFull(rand.Reader, key[:]) if err != nil { panic(err) } return key }

Slide 83

Slide 83 text

Now available as a library (surprise!) All of the stuff in the presentation, optimized for safe copy & paste https://github.com/gtank/cryptopasta Questions?