| package fernet |
| |
| import ( |
| "crypto/rand" |
| "encoding/base64" |
| "encoding/hex" |
| "errors" |
| "io" |
| ) |
| |
| var ( |
| errKeyLen = errors.New("fernet: key decodes to wrong size") |
| errNoKeys = errors.New("fernet: no keys provided") |
| ) |
| |
| // Key represents a key. |
| type Key [32]byte |
| |
| func (k *Key) cryptBytes() []byte { |
| return k[len(k)/2:] |
| } |
| |
| func (k *Key) signBytes() []byte { |
| return k[:len(k)/2] |
| } |
| |
| // Generate initializes k with pseudorandom data from package crypto/rand. |
| func (k *Key) Generate() error { |
| _, err := io.ReadFull(rand.Reader, k[:]) |
| return err |
| } |
| |
| // Encode returns the URL-safe base64 encoding of k. |
| func (k *Key) Encode() string { |
| return encoding.EncodeToString(k[:]) |
| } |
| |
| // DecodeKey decodes a key from s and returns it. The key can be in |
| // hexadecimal, standard base64, or URL-safe base64. |
| func DecodeKey(s string) (*Key, error) { |
| var b []byte |
| var err error |
| if s == "" { |
| return nil, errors.New("empty key") |
| } |
| if len(s) == hex.EncodedLen(len(Key{})) { |
| b, err = hex.DecodeString(s) |
| } else { |
| b, err = base64.StdEncoding.DecodeString(s) |
| if err != nil { |
| b, err = base64.URLEncoding.DecodeString(s) |
| } |
| } |
| if err != nil { |
| return nil, err |
| } |
| if len(b) != len(Key{}) { |
| return nil, errKeyLen |
| } |
| k := new(Key) |
| copy(k[:], b) |
| return k, nil |
| } |
| |
| // DecodeKeys decodes each element of a using DecodeKey and returns the |
| // resulting keys. Requires at least one key. |
| func DecodeKeys(a ...string) ([]*Key, error) { |
| if len(a) == 0 { |
| return nil, errNoKeys |
| } |
| var err error |
| ks := make([]*Key, len(a)) |
| for i, s := range a { |
| ks[i], err = DecodeKey(s) |
| if err != nil { |
| return nil, err |
| } |
| } |
| return ks, nil |
| } |
| |
| // MustDecodeKeys is like DecodeKeys, but panics if an error occurs. |
| // It simplifies safe initialization of global variables holding |
| // keys. |
| func MustDecodeKeys(a ...string) []*Key { |
| k, err := DecodeKeys(a...) |
| if err != nil { |
| panic(err) |
| } |
| return k |
| } |