blob: f92439301cee1a4ad88568ca968ba2635ffaa2e2 [file] [log] [blame]
Suharsh Sivakumard308c7e2014-10-03 12:46:50 -07001package util
2
3import (
4 "bytes"
5 "crypto/hmac"
6 "crypto/sha256"
7 "fmt"
8)
9
10// Macaroon encapsulates an arbitrary slice of data with an HMAC for integrity protection.
11// Term borrowed from http://research.google.com/pubs/pub41892.html.
12type Macaroon string
13
14// NewMacaroon creates an opaque token that encodes "data".
15//
16// Input can be extracted from the returned token only if the key provided to NewMacaroon is known.
17func NewMacaroon(key, data []byte) Macaroon {
18 return Macaroon(b64encode(append(data, computeHMAC(key, data)...)))
19}
20
21// Decode returns the input if the macaroon is decodable with the provided key.
22func (m Macaroon) Decode(key []byte) (input []byte, err error) {
23 decoded, err := b64decode(string(m))
24 if err != nil {
25 return nil, err
26 }
27 data := decoded[:len(decoded)-sha256.Size]
28 decodedHMAC := decoded[len(decoded)-sha256.Size:]
29 if !bytes.Equal(decodedHMAC, computeHMAC(key, data)) {
30 return nil, fmt.Errorf("invalid macaroon, HMAC does not match")
31 }
32 return data, nil
33}
34
35func computeHMAC(key, data []byte) []byte {
36 hm := hmac.New(sha256.New, key)
37 hm.Write(data)
38 return hm.Sum(nil)
39}