Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Crypto for Go Developers

Crypto for Go Developers

GopherCon 2016

You’ve heard "don’t implement your own crypto" and taken it to heart. Great news- you don't have to! Go has very robust crypto packages, but even the standard library offers plenty of ways to make mistakes.

This talk show you the options and explains the right answers.

Video: https://www.youtube.com/watch?v=2r_KMzXB74w
Code: https://github.com/gtank/cryptopasta

George Tankersley

July 11, 2016
Tweet

More Decks by George Tankersley

Other Decks in Programming

Transcript

  1. 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 }
  2. 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 }
  3. 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) } }
  4. 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) } }
  5. 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]).
  6. 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]).
  7. How to use GPG Please don’t use GPG $ man

    gpg | wc -l 3227 $ man gpg | wc -w 16721
  8. Everyday cryptography that isn’t TLS Hashing files Generating random IDs

    API authentication Password storage for websites Signed / encrypted cookies JWTs Signing updates
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. Block cipher modes Go offers CBC, CFB, CTR, OFB, and

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

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

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

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

    GCM modes. Their details are not important. Only GCM provides authenticated encryption.
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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.
  38. 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.
  39. 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.
  40. 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.
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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 }
  54. 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 }
  55. 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
  56. 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
  57. 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
  58. 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.
  59. 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.
  60. 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.
  61. 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
  62. 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
  63. 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 }
  64. 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 }
  65. Now available as a library (surprise!) All of the stuff

    in the presentation, optimized for safe copy & paste https://github.com/gtank/cryptopasta Questions?