mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-04-04 11:03:39 +00:00
92 lines
2.1 KiB
Go
92 lines
2.1 KiB
Go
|
package macaroon
|
||
|
|
||
|
import (
|
||
|
"crypto/hmac"
|
||
|
"crypto/sha256"
|
||
|
"fmt"
|
||
|
"hash"
|
||
|
"io"
|
||
|
|
||
|
"golang.org/x/crypto/nacl/secretbox"
|
||
|
)
|
||
|
|
||
|
func keyedHash(key *[hashLen]byte, text []byte) *[hashLen]byte {
|
||
|
h := keyedHasher(key)
|
||
|
h.Write([]byte(text))
|
||
|
var sum [hashLen]byte
|
||
|
hashSum(h, &sum)
|
||
|
return &sum
|
||
|
}
|
||
|
|
||
|
func keyedHasher(key *[hashLen]byte) hash.Hash {
|
||
|
return hmac.New(sha256.New, key[:])
|
||
|
}
|
||
|
|
||
|
var keyGen = []byte("macaroons-key-generator")
|
||
|
|
||
|
// makeKey derives a fixed length key from a variable
|
||
|
// length key. The keyGen constant is the same
|
||
|
// as that used in libmacaroons.
|
||
|
func makeKey(variableKey []byte) *[keyLen]byte {
|
||
|
h := hmac.New(sha256.New, keyGen)
|
||
|
h.Write(variableKey)
|
||
|
var key [keyLen]byte
|
||
|
hashSum(h, &key)
|
||
|
return &key
|
||
|
}
|
||
|
|
||
|
// hashSum calls h.Sum to put the sum into
|
||
|
// the given destination. It also sanity
|
||
|
// checks that the result really is the expected
|
||
|
// size.
|
||
|
func hashSum(h hash.Hash, dest *[hashLen]byte) {
|
||
|
r := h.Sum(dest[:0])
|
||
|
if len(r) != len(dest) {
|
||
|
panic("hash size inconsistency")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
keyLen = 32
|
||
|
nonceLen = 24
|
||
|
hashLen = sha256.Size
|
||
|
)
|
||
|
|
||
|
func newNonce(r io.Reader) (*[nonceLen]byte, error) {
|
||
|
var nonce [nonceLen]byte
|
||
|
_, err := r.Read(nonce[:])
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("cannot generate random bytes: %v", err)
|
||
|
}
|
||
|
return &nonce, nil
|
||
|
}
|
||
|
|
||
|
func encrypt(key *[keyLen]byte, text *[hashLen]byte, r io.Reader) ([]byte, error) {
|
||
|
nonce, err := newNonce(r)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
out := make([]byte, 0, len(nonce)+secretbox.Overhead+len(text))
|
||
|
out = append(out, nonce[:]...)
|
||
|
return secretbox.Seal(out, text[:], nonce, key), nil
|
||
|
}
|
||
|
|
||
|
func decrypt(key *[keyLen]byte, ciphertext []byte) (*[hashLen]byte, error) {
|
||
|
if len(ciphertext) < nonceLen+secretbox.Overhead {
|
||
|
return nil, fmt.Errorf("message too short")
|
||
|
}
|
||
|
var nonce [nonceLen]byte
|
||
|
copy(nonce[:], ciphertext)
|
||
|
ciphertext = ciphertext[nonceLen:]
|
||
|
text, ok := secretbox.Open(nil, ciphertext, &nonce, key)
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("decryption failure")
|
||
|
}
|
||
|
if len(text) != hashLen {
|
||
|
return nil, fmt.Errorf("decrypted text is wrong length")
|
||
|
}
|
||
|
var rtext [hashLen]byte
|
||
|
copy(rtext[:], text)
|
||
|
return &rtext, nil
|
||
|
}
|