File: crypto.go

package info (click to toggle)
golang-gopkg-macaroon.v1 0.0~git20150121.0.ab3940c-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid, stretch
  • size: 128 kB
  • ctags: 146
  • sloc: makefile: 3
file content (91 lines) | stat: -rw-r--r-- 2,132 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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
}