Skip to content

Commit daa0fd4

Browse files
committed
Add fuzz tests for gcm
1 parent 9ed5950 commit daa0fd4

1 file changed

Lines changed: 150 additions & 0 deletions

File tree

pkg/crypto/ciphersuite/gcm_test.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
2+
// SPDX-License-Identifier: MIT
3+
4+
package ciphersuite
5+
6+
import (
7+
"crypto/sha256"
8+
"testing"
9+
10+
"github.com/pion/dtls/v3/pkg/protocol"
11+
"github.com/pion/dtls/v3/pkg/protocol/recordlayer"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
func FuzzGCM_RoundTrip(f *testing.F) {
16+
f.Add([]byte{}, []byte("x"), uint64(0), uint16(0))
17+
f.Add([]byte{7, 8, 9}, []byte("alpha"), uint64(5), uint16(1))
18+
f.Add(make([]byte, 2048), []byte("left"), uint64(0x0a0b0c0d0e0f), uint16(3))
19+
20+
f.Fuzz(func(t *testing.T, plain []byte, seed []byte, seq uint64, epoch uint16) {
21+
if len(plain) > 1<<14 {
22+
plain = plain[:1<<14]
23+
}
24+
25+
h := sha256.Sum256(seed)
26+
localKey := h[:16]
27+
localWriteIV := h[16:20]
28+
29+
gcmAEAD, err := NewGCM(localKey, localWriteIV, localKey, localWriteIV)
30+
require.NoError(t, err)
31+
32+
hdr := recordlayer.Header{
33+
ContentType: protocol.ContentTypeApplicationData,
34+
Version: protocol.Version1_2,
35+
Epoch: epoch,
36+
SequenceNumber: seq,
37+
}
38+
39+
headerRaw, err := hdr.Marshal()
40+
require.NoError(t, err)
41+
42+
raw := make([]byte, len(headerRaw)+len(plain))
43+
copy(raw, headerRaw)
44+
copy(raw[len(headerRaw):], plain)
45+
46+
enc, err := gcmAEAD.Encrypt(&recordlayer.RecordLayer{Header: hdr}, raw)
47+
require.NoError(t, err)
48+
49+
dec, err := gcmAEAD.Decrypt(recordlayer.Header{}, enc)
50+
require.NoError(t, err)
51+
52+
var parsedHdr recordlayer.Header
53+
require.NoError(t, parsedHdr.Unmarshal(dec))
54+
got := dec[parsedHdr.Size():]
55+
56+
require.Equal(t, plain, got)
57+
})
58+
}
59+
60+
func FuzzGCM_Bidirectional_RoundTrip(f *testing.F) {
61+
f.Add([]byte("hello"), []byte("seedA"), uint64(1), uint16(0),
62+
[]byte("world"), []byte("seedB"), uint64(2), uint16(1))
63+
64+
f.Add([]byte{}, []byte("zero"), uint64(0), uint16(0),
65+
[]byte{1, 2, 3, 4}, []byte("other"), uint64(5), uint16(2))
66+
67+
f.Add(make([]byte, 2048), []byte("AAA"), uint64(123456), uint16(3),
68+
make([]byte, 17), []byte("BBB"), uint64(789), uint16(4))
69+
70+
f.Fuzz(func(t *testing.T,
71+
pA []byte, sA []byte, seqA uint64, epochA uint16,
72+
pB []byte, sB []byte, seqB uint64, epochB uint16,
73+
) {
74+
if len(pA) > 1<<14 {
75+
pA = pA[:1<<14]
76+
}
77+
78+
if len(pB) > 1<<14 {
79+
pB = pB[:1<<14]
80+
}
81+
82+
hA := sha256.Sum256(sA)
83+
hB := sha256.Sum256(sB)
84+
localKeyA, localWriteIVA := hA[:16], hA[16:20]
85+
localKeyB, localWriteIVB := hB[:16], hB[16:20]
86+
87+
// A uses (keyA,ivA) to send and expects (keyB, ivB) for receive.
88+
gcmA, err := NewGCM(localKeyA, localWriteIVA, localKeyB, localWriteIVB)
89+
require.NoError(t, err)
90+
91+
// B uses (keyB,ivB) to send and expects (keyA, ivA) for receive.
92+
gcmB, err := NewGCM(localKeyB, localWriteIVB, localKeyA, localWriteIVA)
93+
require.NoError(t, err)
94+
95+
// A -> B
96+
hdrA := recordlayer.Header{
97+
ContentType: protocol.ContentTypeApplicationData,
98+
Version: protocol.Version1_2,
99+
Epoch: epochA,
100+
SequenceNumber: seqA,
101+
}
102+
103+
headerRawA, err := hdrA.Marshal()
104+
require.NoError(t, err)
105+
106+
rawA := make([]byte, len(headerRawA)+len(pA))
107+
copy(rawA, headerRawA)
108+
copy(rawA[len(headerRawA):], pA)
109+
110+
encA, err := gcmA.Encrypt(&recordlayer.RecordLayer{Header: hdrA}, rawA)
111+
require.NoError(t, err)
112+
113+
decAonB, err := gcmB.Decrypt(recordlayer.Header{}, encA)
114+
require.NoError(t, err)
115+
116+
// parse header from decrypted bytes to compute payload offset safely.
117+
var parsedHdrA recordlayer.Header
118+
require.NoError(t, parsedHdrA.Unmarshal(decAonB))
119+
120+
gotA := decAonB[parsedHdrA.Size():]
121+
require.Equal(t, pA, gotA)
122+
123+
// B -> A
124+
hdrB := recordlayer.Header{
125+
ContentType: protocol.ContentTypeApplicationData,
126+
Version: protocol.Version1_2,
127+
Epoch: epochB,
128+
SequenceNumber: seqB,
129+
}
130+
131+
headerRawB, err := hdrB.Marshal()
132+
require.NoError(t, err)
133+
134+
rawB := make([]byte, len(headerRawB)+len(pB))
135+
copy(rawB, headerRawB)
136+
copy(rawB[len(headerRawB):], pB)
137+
138+
encB, err := gcmB.Encrypt(&recordlayer.RecordLayer{Header: hdrB}, rawB)
139+
require.NoError(t, err)
140+
141+
decBonA, err := gcmA.Decrypt(recordlayer.Header{}, encB)
142+
require.NoError(t, err)
143+
144+
var parsedHdrB recordlayer.Header
145+
require.NoError(t, parsedHdrB.Unmarshal(decBonA))
146+
147+
gotB := decBonA[parsedHdrB.Size():]
148+
require.Equal(t, pB, gotB)
149+
})
150+
}

0 commit comments

Comments
 (0)