92 lines
1.8 KiB
Go
92 lines
1.8 KiB
Go
|
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
|
||
|
}
|