cookie-protector.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package mint
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/rand"
  6. "crypto/sha256"
  7. "fmt"
  8. "io"
  9. "golang.org/x/crypto/hkdf"
  10. )
  11. // CookieProtector is used to create and verify a cookie
  12. type CookieProtector interface {
  13. // NewToken creates a new token
  14. NewToken([]byte) ([]byte, error)
  15. // DecodeToken decodes a token
  16. DecodeToken([]byte) ([]byte, error)
  17. }
  18. const cookieSecretSize = 32
  19. const cookieNonceSize = 32
  20. // The DefaultCookieProtector is a simple implementation for the CookieProtector.
  21. type DefaultCookieProtector struct {
  22. secret []byte
  23. }
  24. var _ CookieProtector = &DefaultCookieProtector{}
  25. // NewDefaultCookieProtector creates a source for source address tokens
  26. func NewDefaultCookieProtector() (CookieProtector, error) {
  27. secret := make([]byte, cookieSecretSize)
  28. if _, err := rand.Read(secret); err != nil {
  29. return nil, err
  30. }
  31. return &DefaultCookieProtector{secret: secret}, nil
  32. }
  33. // NewToken encodes data into a new token.
  34. func (s *DefaultCookieProtector) NewToken(data []byte) ([]byte, error) {
  35. nonce := make([]byte, cookieNonceSize)
  36. if _, err := rand.Read(nonce); err != nil {
  37. return nil, err
  38. }
  39. aead, aeadNonce, err := s.createAEAD(nonce)
  40. if err != nil {
  41. return nil, err
  42. }
  43. return append(nonce, aead.Seal(nil, aeadNonce, data, nil)...), nil
  44. }
  45. // DecodeToken decodes a token.
  46. func (s *DefaultCookieProtector) DecodeToken(p []byte) ([]byte, error) {
  47. if len(p) < cookieNonceSize {
  48. return nil, fmt.Errorf("Token too short: %d", len(p))
  49. }
  50. nonce := p[:cookieNonceSize]
  51. aead, aeadNonce, err := s.createAEAD(nonce)
  52. if err != nil {
  53. return nil, err
  54. }
  55. return aead.Open(nil, aeadNonce, p[cookieNonceSize:], nil)
  56. }
  57. func (s *DefaultCookieProtector) createAEAD(nonce []byte) (cipher.AEAD, []byte, error) {
  58. h := hkdf.New(sha256.New, s.secret, nonce, []byte("mint cookie source"))
  59. key := make([]byte, 32) // use a 32 byte key, in order to select AES-256
  60. if _, err := io.ReadFull(h, key); err != nil {
  61. return nil, nil, err
  62. }
  63. aeadNonce := make([]byte, 12)
  64. if _, err := io.ReadFull(h, aeadNonce); err != nil {
  65. return nil, nil, err
  66. }
  67. c, err := aes.NewCipher(key)
  68. if err != nil {
  69. return nil, nil, err
  70. }
  71. aead, err := cipher.NewGCM(c)
  72. if err != nil {
  73. return nil, nil, err
  74. }
  75. return aead, aeadNonce, nil
  76. }