/
enc.go
214 lines (190 loc) · 6.44 KB
/
enc.go
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package anon
import (
"crypto/subtle"
"errors"
"github.com/dedis/kyber"
"github.com/dedis/kyber/util/key"
)
func header(suite Suite, X kyber.Point, x kyber.Scalar,
Xb, xb []byte, anonymitySet Set) []byte {
//fmt.Printf("Xb %s\nxb %s\n",
// hex.EncodeToString(Xb),hex.EncodeToString(xb))
// Encrypt the master scalar key with each public key in the set
S := suite.Point()
hdr := Xb
for i := range anonymitySet {
Y := anonymitySet[i]
S.Mul(x, Y) // compute DH shared secret
seed, _ := S.MarshalBinary()
xof := suite.XOF(seed)
xc := make([]byte, len(xb))
xof.XORKeyStream(xc, xb)
hdr = append(hdr, xc...)
}
return hdr
}
// Create and encrypt a fresh key decryptable only by the given receivers.
// Returns the secret key and the ciphertext.
func encryptKey(suite Suite, anonymitySet Set, hide bool) (k, c []byte) {
// Choose a keypair and encode its representation
kp := new(key.Pair)
var Xb []byte
if hide {
kp.GenHiding(suite)
Xb = kp.Hiding.HideEncode(suite.RandomStream())
} else {
kp.Gen(suite)
Xb, _ = kp.Public.MarshalBinary()
}
xb, _ := kp.Private.MarshalBinary()
// Generate the ciphertext header
return xb, header(suite, kp.Public, kp.Private, Xb, xb, anonymitySet)
}
// Decrypt and verify a key encrypted via encryptKey.
// On success, returns the key and the length of the decrypted header.
func decryptKey(suite Suite, ciphertext []byte, anonymitySet Set,
mine int, privateKey kyber.Scalar,
hide bool) ([]byte, int, error) {
// Decode the (supposed) ephemeral public key from the front
X := suite.Point()
var Xb []byte
if hide {
Xh := X.(kyber.Hiding)
hidelen := Xh.HideLen()
if len(ciphertext) < hidelen {
return nil, 0, errors.New("ciphertext too short")
}
X.(kyber.Hiding).HideDecode(ciphertext[:hidelen])
Xb = ciphertext[:hidelen]
} else {
enclen := X.MarshalSize()
if len(ciphertext) < enclen {
return nil, 0, errors.New("ciphertext too short")
}
if err := X.UnmarshalBinary(ciphertext[:enclen]); err != nil {
return nil, 0, err
}
Xb = ciphertext[:enclen]
}
Xblen := len(Xb)
// Decode the (supposed) master secret with our private key
nkeys := len(anonymitySet)
if mine < 0 || mine >= nkeys {
panic("private-key index out of range")
}
seclen := suite.ScalarLen()
if len(ciphertext) < Xblen+seclen*nkeys {
return nil, 0, errors.New("ciphertext too short")
}
S := suite.Point().Mul(privateKey, X)
seed, _ := S.MarshalBinary()
xof := suite.XOF(seed)
xb := make([]byte, seclen)
secofs := Xblen + seclen*mine
xof.XORKeyStream(xb, ciphertext[secofs:secofs+seclen])
x := suite.Scalar()
if err := x.UnmarshalBinary(xb); err != nil {
return nil, 0, err
}
// Make sure it reproduces the correct ephemeral public key
Xv := suite.Point().Mul(x, nil)
if !X.Equal(Xv) {
return nil, 0, errors.New("invalid ciphertext")
}
// Regenerate and check the rest of the header,
// to ensure that that any of the anonymitySet members could decrypt it
hdr := header(suite, X, x, Xb, xb, anonymitySet)
hdrlen := len(hdr)
if hdrlen != Xblen+seclen*nkeys {
panic("wrong header size")
}
if subtle.ConstantTimeCompare(hdr, ciphertext[:hdrlen]) == 0 {
return nil, 0, errors.New("invalid ciphertext")
}
return xb, hdrlen, nil
}
// constantTimeAllEq returns 1 iff all bytes in slice x have the value y.
// The time taken is a function of the length of the slices
// and is independent of the contents.
func constantTimeAllEq(x []byte, y byte) int {
var z byte
for _, b := range x {
z |= b ^ y
}
return subtle.ConstantTimeByteEq(z, 0)
}
// macSize is how long the hashes are that we extract from the XOF.
// This constant of 16 is taken from the previous implementation's behavior.
const macSize = 16
// Encrypt a message for reading by any member of an explit anonymity set.
// The caller supplies one or more keys representing the anonymity set.
// If the provided set contains only one public key,
// this reduces to conventional single-receiver public-key encryption.
//
// If hide is true,
// Encrypt will produce a uniformly random-looking byte-stream,
// which reveals no metadata other than message length
// to anyone unable to decrypt the message.
// The provided kyber.Suite must support
// uniform-representation encoding of public keys for this to work.
//
func Encrypt(suite Suite, message []byte,
anonymitySet Set, hide bool) []byte {
xb, hdr := encryptKey(suite, anonymitySet, hide)
xof := suite.XOF(xb)
// We now know the ciphertext layout
hdrhi := 0 + len(hdr)
msghi := hdrhi + len(message)
machi := msghi + macSize
ciphertext := make([]byte, machi)
copy(ciphertext, hdr)
// Now encrypt and MAC the message based on the master secret
ctx := ciphertext[hdrhi:msghi]
mac := ciphertext[msghi:machi]
xof.XORKeyStream(ctx, message)
xof = suite.XOF(ctx)
xof.Read(mac)
return ciphertext
}
// Decrypt a message encrypted for a particular anonymity set.
// Returns the cleartext message on success, or an error on failure.
//
// The caller provides the anonymity set for which the message is intended,
// and the private key corresponding to one of the public keys in the set.
// Decrypt verifies that the message is encrypted correctly for this set -
// in particular, that it could be decrypted by ALL of the listed members -
// before returning successfully with the decrypted message.
// This verification ensures that a malicious sender
// cannot de-anonymize a receiver by constructing a ciphertext incorrectly
// so as to be decryptable by only some members of the set.
// As a side-effect, this verification also ensures plaintext-awareness:
// that is, it is infeasible for a sender to construct any ciphertext
// that will be accepted by the receiver without knowing the plaintext.
//
func Decrypt(suite Suite, ciphertext []byte, anonymitySet Set,
mine int, privateKey kyber.Scalar, hide bool) ([]byte, error) {
// Decrypt and check the encrypted key-header.
xb, hdrlen, err := decryptKey(suite, ciphertext, anonymitySet,
mine, privateKey, hide)
if err != nil {
return nil, err
}
// Determine the message layout
xof := suite.XOF(xb)
if len(ciphertext) < hdrlen+macSize {
return nil, errors.New("ciphertext too short")
}
hdrhi := hdrlen
msghi := len(ciphertext) - macSize
// Decrypt the message and check the MAC
ctx := ciphertext[hdrhi:msghi]
mac := ciphertext[msghi:]
msg := make([]byte, len(ctx))
xof.XORKeyStream(msg, ctx)
xof = suite.XOF(ctx)
xof.XORKeyStream(mac, mac)
if constantTimeAllEq(mac, 0) == 0 {
return nil, errors.New("invalid ciphertext: failed MAC check")
}
return msg, nil
}