18// cookies are stored in a 3 part (value + timestamp + signature) to enforce that the values are as originally set.
19// additionally, the 'value' is encrypted so it's opaque to the browser
21// Validate ensures a cookie is properly signed
22func Validate(cookie *http.Cookie, seed string, expiration time.Duration) (value string, t time.Time, ok bool) {
23 // value, timestamp, sig
24 parts := strings.Split(cookie.Value, "|")
28 sig := cookieSignature(seed, cookie.Name, parts[0], parts[1])
29 if checkHmac(parts[2], sig) {
30 ts, err := strconv.Atoi(parts[1])
34 // The expiration timestamp set when the cookie was created
35 // isn't sent back by the browser. Hence, we check whether the
36 // creation timestamp stored in the cookie falls within the
37 // window defined by (Now()-expiration, Now()].
38 t = time.Unix(int64(ts), 0)
39 if t.After(time.Now().Add(expiration*-1)) && t.Before(time.Now().Add(time.Minute*5)) {
40 // it's a valid cookie. now get the contents
41 rawValue, err := base64.URLEncoding.DecodeString(parts[0])
43 value = string(rawValue)
52// SignedValue returns a cookie that is signed and can later be checked with Validate
53func SignedValue(seed string, key string, value string, now time.Time) string {
54 encodedValue := base64.URLEncoding.EncodeToString([]byte(value))
55 timeStr := fmt.Sprintf("%d", now.Unix())
56 sig := cookieSignature(seed, key, encodedValue, timeStr)
57 cookieVal := fmt.Sprintf("%s|%s|%s", encodedValue, timeStr, sig)
61func cookieSignature(args ...string) string {
62 h := hmac.New(sha1.New, []byte(args[0]))
63 for _, arg := range args[1:] {
68 return base64.URLEncoding.EncodeToString(b)
71func checkHmac(input, expected string) bool {
72 inputMAC, err1 := base64.URLEncoding.DecodeString(input)
74 expectedMAC, err2 := base64.URLEncoding.DecodeString(expected)
76 return hmac.Equal(inputMAC, expectedMAC)
82// Cipher provides methods to encrypt and decrypt cookie values
87// NewCipher returns a new aes Cipher for encrypting cookie values
88func NewCipher(secret []byte) (*Cipher, error) {
89 c, err := aes.NewCipher(secret)
93 return &Cipher{Block: c}, err
96// Encrypt a value for use in a cookie
97func (c *Cipher) Encrypt(value string) (string, error) {
98 ciphertext := make([]byte, aes.BlockSize+len(value))
99 iv := ciphertext[:aes.BlockSize]
100 if _, err := io.ReadFull(rand.Reader, iv); err != nil {
101 return "", fmt.Errorf("failed to create initialization vector %s", err)
104 stream := cipher.NewCFBEncrypter(c.Block, iv)
105 stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(value))
106 return base64.StdEncoding.EncodeToString(ciphertext), nil
109// Decrypt a value from a cookie to it's original string
110func (c *Cipher) Decrypt(s string) (string, error) {
111 encrypted, err := base64.StdEncoding.DecodeString(s)
113 return "", fmt.Errorf("failed to decrypt cookie value %s", err)
116 if len(encrypted) < aes.BlockSize {
117 return "", fmt.Errorf("encrypted cookie value should be "+
118 "at least %d bytes, but is only %d bytes",
119 aes.BlockSize, len(encrypted))
122 iv := encrypted[:aes.BlockSize]
123 encrypted = encrypted[aes.BlockSize:]
124 stream := cipher.NewCFBDecrypter(c.Block, iv)
125 stream.XORKeyStream(encrypted, encrypted)
127 return string(encrypted), nil
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list