packet.go 3.28 KB
Newer Older
1
package keysharecore
2
3
4
5
6

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
7
	"crypto/subtle"
8
9
10
	"encoding/binary"

	"github.com/privacybydesign/gabi/big"
11
12

	"github.com/go-errors/errors"
13
14
)

15
type (
16
	// Contains pin (bytes 0-63), secret (bytes 64-127), and identifier (bytes 128-159)
17
18
19
20
	//  The binary structure of this packet can have security implications through its interaction with the
	//  encryption layer applied before storing it. As such, we keep it here more explicit than
	//  is standard in go. When modifying this structure, analyse whether such changes can have a
	//  security impact through error side channels.
21
	unencryptedUser [64 + 64 + 32]byte
22

23
	// Size is that of unencrypted packet + 12 bytes for nonce + 16 bytes for tag + 4 bytes for key ID
24
	User [64 + 64 + 32 + 12 + 16 + 4]byte
25
)
26
27
28
29

var (
	ErrKeyshareSecretTooBig   = errors.New("Keyshare secret too big to store")
	ErrKeyshareSecretNegative = errors.New("Keyshare secret negative")
30
	ErrNoSuchKey              = errors.New("Key identifier unknown")
31
32
)

33
func (p *unencryptedUser) pin() [64]byte {
34
35
36
37
38
	var result [64]byte
	copy(result[:], p[0:64])
	return result
}

39
func (p *unencryptedUser) setPin(pw [64]byte) {
40
41
42
	copy(p[0:64], pw[:])
}

43
func (p *unencryptedUser) keyshareSecret() *big.Int {
44
45
46
47
	result := new(big.Int)
	return result.SetBytes(p[64:128])
}

48
func (p *unencryptedUser) setKeyshareSecret(val *big.Int) error {
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
	if val.Sign() == -1 {
		return ErrKeyshareSecretNegative
	}

	data := val.Bytes()
	if len(data) > 64 {
		return ErrKeyshareSecretTooBig
	}
	zerolen := 64 - len(data)
	for i := 0; i < zerolen; i++ {
		p[64+i] = 0
	}
	copy(p[64+zerolen:], data)

	return nil
}

66
func (p *unencryptedUser) id() [32]byte {
67
68
69
70
71
	var result [32]byte
	copy(result[:], p[128:160])
	return result
}

72
func (p *unencryptedUser) setID(id [32]byte) {
73
74
75
	copy(p[128:160], id[:])
}

76
77
func (c *Core) encryptUser(p unencryptedUser) (User, error) {
	var result User
78
79

	// Store key id
80
	binary.LittleEndian.PutUint32(result[0:], c.decryptionKeyID)
81
82
83
84

	// Generate and store nonce
	_, err := rand.Read(result[4:16])
	if err != nil {
85
		return User{}, err
86
87
88
	}

	// Encrypt packet
89
	gcm, err := newGCM(c.decryptionKey)
90
	if err != nil {
91
		return User{}, err
92
93
94
95
96
97
	}
	gcm.Seal(result[:16], result[4:16], p[:], nil)

	return result, nil
}

98
func (c *Core) decryptUser(p User) (unencryptedUser, error) {
99
100
101
102
	// determine key id
	id := binary.LittleEndian.Uint32(p[0:])

	// Fetch key
103
	key, ok := c.decryptionKeys[id]
104
	if !ok {
105
		return unencryptedUser{}, ErrNoSuchKey
106
107
108
	}

	// try and decrypt packet
109
	gcm, err := newGCM(key)
110
	if err != nil {
111
		return unencryptedUser{}, err
112
	}
113
	var result unencryptedUser
114
115
	_, err = gcm.Open(result[:0], p[4:16], p[16:], nil)
	if err != nil {
116
		return unencryptedUser{}, err
117
118
119
	}
	return result, nil
}
120

121
func (c *Core) decryptUserIfPinOK(ep User, pin string) (unencryptedUser, error) {
122
123
	paddedPin, err := padPin(pin)
	if err != nil {
124
		return unencryptedUser{}, err
125
126
	}

127
	p, err := c.decryptUser(ep)
128
	if err != nil {
129
		return unencryptedUser{}, err
130
131
132
	}

	refPin := p.pin()
133
	if subtle.ConstantTimeCompare(refPin[:], paddedPin[:]) != 1 {
134
		return unencryptedUser{}, ErrInvalidPin
135
136
137
138
	}
	return p, nil
}

139
func newGCM(key AESKey) (cipher.AEAD, error) {
140
141
142
143
144
145
146
147
148
149
	keyedAes, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}
	gcm, err := cipher.NewGCM(keyedAes)
	if err != nil {
		return nil, err
	}
	return gcm, nil
}