1
2
3 package packet
4
5 import (
6 "bytes"
7 "crypto/rand"
8 "encoding/hex"
9 "io"
10 mathrand "math/rand"
11 "testing"
12
13 "github.com/ProtonMail/go-crypto/openpgp/errors"
14 )
15
16
17
18
19 var maxChunkSizeExp = 62
20
21 const maxPlaintextLength = 1 << 18
22
23 func TestAeadRFCParse(t *testing.T) {
24 for _, sample := range samplesAeadEncryptedDataPacket {
25 key, _ := hex.DecodeString(sample.cek)
26 packetBytes, _ := hex.DecodeString(sample.full)
27 packetReader := bytes.NewBuffer(packetBytes)
28 packet := new(AEADEncrypted)
29 ptype, _, contentsReader, err := readHeader(packetReader)
30 if ptype != packetTypeAEADEncrypted || err != nil {
31 t.Error("Error reading packet header")
32 }
33 if err = packet.parse(contentsReader); err != nil {
34 t.Error(err)
35 }
36
37 rc, err := packet.decrypt(key)
38 if err != nil {
39 t.Error(err)
40 }
41 got, err := readDecryptedStream(rc)
42 if err != nil {
43 t.Error(err)
44 }
45
46 want, _ := hex.DecodeString(sample.plaintext)
47 if !bytes.Equal(got, want) {
48 t.Errorf("Error opening:\ngot\n%s\nwant\n%s", got, want)
49 }
50 }
51 }
52
53
54
55
56
57 func TestAeadEmptyStream(t *testing.T) {
58 key := randomKey(16)
59 config := randomConfig()
60 raw, _, err := randomStream(key, 0, config)
61 if err != nil {
62 t.Error(err)
63 }
64
65 corruptBytes := make([]byte, len(raw.Bytes()))
66 copy(corruptBytes, raw.Bytes())
67 for bytes.Equal(corruptBytes, raw.Bytes()) {
68 corruptBytes[mathrand.Intn(len(corruptBytes)-5)+5] = byte(mathrand.Intn(256))
69 }
70 corrupt := bytes.NewBuffer(corruptBytes)
71
72
73 packet := new(AEADEncrypted)
74 ptype, _, contentsReader, err := readHeader(raw)
75 if ptype != packetTypeAEADEncrypted || err != nil {
76 t.Error("Error reading packet header")
77 }
78 if err = packet.parse(contentsReader); err != nil {
79 t.Error(err)
80 }
81
82 rc, err := packet.decrypt(key)
83
84 _, err = readDecryptedStream(rc)
85 if err != nil {
86 t.Error(err)
87 }
88
89
90 packet = new(AEADEncrypted)
91 ptype, _, contentsReader, err = readHeader(corrupt)
92 if ptype != packetTypeAEADEncrypted || err != nil {
93 t.Error("Error reading packet header")
94 }
95 if err = packet.parse(contentsReader); err != nil {
96 t.Error(err)
97 }
98
99 rc, err = packet.decrypt(key)
100
101 _, err = readDecryptedStream(rc)
102 if err == nil {
103 t.Errorf("No error raised when reading corrupt stream with empty plaintext")
104 }
105 }
106
107
108 func TestAeadNilConfigStream(t *testing.T) {
109
110 key := randomKey(16)
111 randomLength := mathrand.Intn(maxPlaintextLength) + 1
112 raw, plain, err := randomStream(key, randomLength, nil)
113 if err != nil {
114 t.Error(err)
115 }
116
117
118 packet := new(AEADEncrypted)
119
120 ptype, _, contentsReader, err := readHeader(raw)
121 if ptype != packetTypeAEADEncrypted || err != nil {
122 t.Error("Error reading packet header")
123 }
124
125 if err = packet.parse(contentsReader); err != nil {
126 t.Error(err)
127 }
128
129 rc, err := packet.decrypt(key)
130
131 got, err := readDecryptedStream(rc)
132 if err != nil {
133 t.Error(err)
134 }
135
136 want := plain
137 if !bytes.Equal(got, want) {
138 t.Errorf("Error encrypting/decrypting random stream with nil config")
139 }
140 }
141
142
143 func TestAeadStreamRandomizeSlow(t *testing.T) {
144 key := randomKey(16)
145 config := randomConfig()
146 randomLength := mathrand.Intn(maxPlaintextLength) + 1
147 raw, plain, err := randomStream(key, randomLength, config)
148 if err != nil {
149 t.Error(err)
150 }
151
152
153 packet := new(AEADEncrypted)
154 ptype, _, contentsReader, err := readHeader(raw)
155 if ptype != packetTypeAEADEncrypted || err != nil {
156 t.Error("Error reading packet header")
157 }
158
159 if err = packet.parse(contentsReader); err != nil {
160 t.Error(err)
161 }
162
163 rc, err := packet.decrypt(key)
164
165 got, err := readDecryptedStream(rc)
166 if err != nil {
167 t.Error(err)
168 }
169
170 if err = rc.Close(); err != nil {
171 t.Error(err)
172 }
173 want := plain
174 if !bytes.Equal(got, want) {
175 t.Errorf("Error encrypting/decrypting random stream")
176 }
177 }
178
179
180 func TestAeadCorruptStreamRandomizeSlow(t *testing.T) {
181 key := randomKey(16)
182 config := randomConfig()
183 randomLength := mathrand.Intn(maxPlaintextLength) + 1
184 raw, plain, err := randomStream(key, randomLength, config)
185 if err != nil {
186 t.Error(err)
187 }
188
189
190 for j := 0; j < 10; j++ {
191 index := mathrand.Intn(len(raw.Bytes()))
192 if index < 8 || len(plain) == 0 {
193
194 continue
195 }
196 raw.Bytes()[index] = 255 - raw.Bytes()[index]
197 }
198 packet := new(AEADEncrypted)
199 ptype, _, contentsReader, err := readHeader(raw)
200 if ptype != packetTypeAEADEncrypted || err != nil {
201 t.Error("Error reading packet header")
202 }
203
204 if err = packet.parse(contentsReader); err != nil {
205
206 return
207 }
208 rc, err := packet.decrypt(key)
209 got, err := readDecryptedStream(rc)
210 if err == nil || err == io.EOF {
211 t.Errorf("No error raised when decrypting corrupt stream")
212 }
213 if bytes.Equal(got, plain) {
214 t.Errorf("Error: Successfully decrypted corrupt stream")
215 }
216 }
217
218
219 func TestAeadTruncatedStreamRandomizeSlow(t *testing.T) {
220 key := randomKey(16)
221 config := randomConfig()
222 randomLength := mathrand.Intn(maxPlaintextLength)
223 if randomLength < 16 {
224 return
225 }
226
227 raw, plain, err := randomStream(key, randomLength, config)
228 if err != nil {
229 t.Error(err)
230 }
231
232
233 var truncatedRaw []byte
234 cut := 0
235 for cut == 0 {
236 cut = mathrand.Intn(randomLength / 2)
237 }
238 truncatedRaw = raw.Bytes()[:len(raw.Bytes())-cut]
239 truncated := bytes.NewBuffer(truncatedRaw)
240
241 packet := new(AEADEncrypted)
242 ptype, _, truncatedContentsReader, err := readHeader(truncated)
243 if ptype != packetTypeAEADEncrypted || err != nil {
244 t.Error("Error reading packet header")
245 }
246
247 if err = packet.parse(truncatedContentsReader); err != nil {
248 t.Error(err)
249 }
250 rc, err := packet.decrypt(key)
251 if err != nil {
252 return
253 }
254 got, err := readDecryptedStream(rc)
255 if err == nil || err == io.EOF {
256 t.Errorf("No truncate error raised when decrypting truncated stream")
257 }
258 if bytes.Equal(got, plain) {
259 t.Errorf("Error: Successfully decrypted truncated stream")
260 }
261 }
262
263
264 func TestAeadUnclosedStreamRandomizeSlow(t *testing.T) {
265 key := randomKey(16)
266 config := randomConfig()
267 ptLen := mathrand.Intn(maxPlaintextLength)
268
269 plain := make([]byte, ptLen)
270 _, err := rand.Read(plain)
271 if err != nil {
272 t.Error(err)
273 }
274
275 rawCipher := bytes.NewBuffer(nil)
276 writeCloser, err := SerializeAEADEncrypted(rawCipher, key, config)
277 if err != nil {
278 t.Error(err)
279 }
280
281 if _, err = writeCloser.Write(plain); err != nil {
282 t.Error(err)
283 }
284
285
286 packet := new(AEADEncrypted)
287 _, _, contentsReader, err := readHeader(rawCipher)
288 if err != nil {
289 return
290 }
291
292 if err = packet.parse(contentsReader); err != nil {
293 return
294 }
295 rc, err := packet.decrypt(key)
296 if err != nil {
297 return
298 }
299 got, err := readDecryptedStream(rc)
300 if err == nil || err == io.EOF {
301 t.Errorf("No error raised when decrypting unclosed stream")
302 }
303 if bytes.Equal(got, plain) {
304 t.Errorf("Error: Successfully decrypted unclosed stream")
305 }
306 }
307
308
309
310
311
312 func randomKey(length int) []byte {
313 key := make([]byte, length)
314 _, err := rand.Read(key)
315 if err != nil {
316 panic("can't read from rand")
317 }
318 return key
319 }
320
321 func randomConfig() *Config {
322 var aeadCompatibleCiphers = []CipherFunction{
323 CipherAES128,
324 CipherAES192,
325 CipherAES256,
326 }
327 var modes = []AEADMode{
328 AEADModeEAX,
329 AEADModeOCB,
330 }
331
332
333 chunkSizeExp := 6 + mathrand.Intn(maxChunkSizeExp-5)
334 chunkSize := uint64(1 << uint(chunkSizeExp))
335
336 ciph := aeadCompatibleCiphers[mathrand.Intn(len(aeadCompatibleCiphers))]
337 aeadConf := AEADConfig{
338 ChunkSize: uint64(chunkSize),
339 DefaultMode: modes[mathrand.Intn(len(modes))],
340 }
341 config := &Config{
342 AEADConfig: &aeadConf,
343 DefaultCipher: ciph,
344 }
345 return config
346 }
347
348
349
350 func randomStream(key []byte, ptLen int, config *Config) (*bytes.Buffer, []byte, error) {
351
352 plaintext := make([]byte, ptLen)
353 _, err := rand.Read(plaintext)
354 if err != nil {
355 return nil, nil, err
356 }
357
358
359 rawCipher := bytes.NewBuffer(nil)
360 writeCloser, err := SerializeAEADEncrypted(rawCipher, key, config)
361 if err != nil {
362 return nil, nil, err
363 }
364
365 _, err = writeCloser.Write(plaintext)
366 if err != nil {
367 return nil, nil, err
368 }
369
370 if err = writeCloser.Close(); err != nil {
371 return nil, nil, err
372 }
373
374 return rawCipher, plaintext, nil
375 }
376
377 func readDecryptedStream(rc io.ReadCloser) (got []byte, err error) {
378 for {
379
380 decrypted := make([]byte, mathrand.Intn(200))
381 n, err := rc.Read(decrypted)
382 decrypted = decrypted[:n]
383 got = append(got, decrypted...)
384 if err != nil {
385 if err == io.EOF {
386
387 break
388 } else {
389
390 return nil, err
391 }
392 }
393 }
394 return got, err
395 }
396
397
398
399
400 func SerializeAEADEncrypted(w io.Writer, key []byte, config *Config) (io.WriteCloser, error) {
401 writeCloser := noOpCloser{w}
402 writer, err := serializeStreamHeader(writeCloser, packetTypeAEADEncrypted)
403 if err != nil {
404 return nil, err
405 }
406
407
408 aeadConf := config.AEAD()
409 prefix := []byte{
410 0xD4,
411 aeadEncryptedVersion,
412 byte(config.Cipher()),
413 byte(aeadConf.Mode()),
414 aeadConf.ChunkSizeByte(),
415 }
416 n, err := writer.Write(prefix[1:])
417 if err != nil || n < 4 {
418 return nil, errors.AEADError("could not write AEAD headers")
419 }
420
421 nonceLen := aeadConf.Mode().IvLength()
422 nonce := make([]byte, nonceLen)
423 n, err = rand.Read(nonce)
424 if err != nil {
425 panic("Could not sample random nonce")
426 }
427 _, err = writer.Write(nonce)
428 if err != nil {
429 return nil, err
430 }
431 blockCipher := CipherFunction(config.Cipher()).new(key)
432 alg := aeadConf.Mode().new(blockCipher)
433
434 chunkSize := decodeAEADChunkSize(aeadConf.ChunkSizeByte())
435 return &aeadEncrypter{
436 aeadCrypter: aeadCrypter{
437 aead: alg,
438 chunkSize: chunkSize,
439 associatedData: prefix,
440 chunkIndex: make([]byte, 8),
441 initialNonce: nonce,
442 packetTag: packetTypeAEADEncrypted,
443 },
444 writer: writer,
445 }, nil
446 }
447
View as plain text