• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1package main
2
3import (
4	"crypto"
5	"crypto/aes"
6	"crypto/cipher"
7	"crypto/des"
8	"crypto/hmac"
9	_ "crypto/md5"
10	"crypto/rc4"
11	_ "crypto/sha1"
12	_ "crypto/sha256"
13	_ "crypto/sha512"
14	"encoding/hex"
15	"flag"
16	"fmt"
17	"os"
18)
19
20var bulkCipher *string = flag.String("cipher", "", "The bulk cipher to use")
21var mac *string = flag.String("mac", "", "The hash function to use in the MAC")
22var implicitIV *bool = flag.Bool("implicit-iv", false, "If true, generate tests for a cipher using a pre-TLS-1.0 implicit IV")
23var ssl3 *bool = flag.Bool("ssl3", false, "If true, use the SSLv3 MAC and padding rather than TLS")
24
25// rc4Stream produces a deterministic stream of pseudorandom bytes. This is to
26// make this script idempotent.
27type rc4Stream struct {
28	cipher *rc4.Cipher
29}
30
31func newRc4Stream(seed string) (*rc4Stream, error) {
32	cipher, err := rc4.NewCipher([]byte(seed))
33	if err != nil {
34		return nil, err
35	}
36	return &rc4Stream{cipher}, nil
37}
38
39func (rs *rc4Stream) fillBytes(p []byte) {
40	for i := range p {
41		p[i] = 0
42	}
43	rs.cipher.XORKeyStream(p, p)
44}
45
46func getHash(name string) (crypto.Hash, bool) {
47	switch name {
48	case "md5":
49		return crypto.MD5, true
50	case "sha1":
51		return crypto.SHA1, true
52	case "sha256":
53		return crypto.SHA256, true
54	case "sha384":
55		return crypto.SHA384, true
56	default:
57		return 0, false
58	}
59}
60
61func getKeySize(name string) int {
62	switch name {
63	case "aes128":
64		return 16
65	case "aes256":
66		return 32
67	case "3des":
68		return 24
69	default:
70		return 0
71	}
72}
73
74func newBlockCipher(name string, key []byte) (cipher.Block, error) {
75	switch name {
76	case "aes128":
77		return aes.NewCipher(key)
78	case "aes256":
79		return aes.NewCipher(key)
80	case "3des":
81		return des.NewTripleDESCipher(key)
82	default:
83		return nil, fmt.Errorf("unknown cipher '%s'", name)
84	}
85}
86
87var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}
88
89var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
90
91func ssl30MAC(hash crypto.Hash, key, input, ad []byte) []byte {
92	padLength := 48
93	if hash.Size() == 20 {
94		padLength = 40
95	}
96
97	h := hash.New()
98	h.Write(key)
99	h.Write(ssl30Pad1[:padLength])
100	h.Write(ad)
101	h.Write(input)
102	digestBuf := h.Sum(nil)
103
104	h.Reset()
105	h.Write(key)
106	h.Write(ssl30Pad2[:padLength])
107	h.Write(digestBuf)
108	return h.Sum(digestBuf[:0])
109}
110
111type testCase struct {
112	digest     []byte
113	key        []byte
114	nonce      []byte
115	input      []byte
116	ad         []byte
117	ciphertext []byte
118	tag        []byte
119	tag_len    int
120	noSeal     bool
121	fails      bool
122}
123
124// options adds additional options for a test.
125type options struct {
126	// extraPadding causes an extra block of padding to be added.
127	extraPadding bool
128	// maximalPadding causes 256 bytes of padding to be added.
129	maximalPadding bool
130	// wrongPadding causes one of the padding bytes to be wrong.
131	wrongPadding bool
132	// wrongPaddingOffset specifies the byte offset of the incorrect padding
133	// byte.
134	wrongPaddingOffset int
135	// noPadding causes padding is to be omitted. The plaintext + MAC must
136	// be a multiple of the block size.
137	noPadding bool
138	// omitMAC causes the MAC to be omitted.
139	omitMAC bool
140}
141
142func makeTestCase(length int, options options) (*testCase, error) {
143	rand, err := newRc4Stream("input stream")
144	if err != nil {
145		return nil, err
146	}
147
148	input := make([]byte, length)
149	rand.fillBytes(input)
150
151	var adFull []byte
152	if *ssl3 {
153		adFull = make([]byte, 11)
154	} else {
155		adFull = make([]byte, 13)
156	}
157	ad := adFull[:len(adFull)-2]
158	rand.fillBytes(ad)
159	adFull[len(adFull)-2] = uint8(length >> 8)
160	adFull[len(adFull)-1] = uint8(length & 0xff)
161
162	hash, ok := getHash(*mac)
163	if !ok {
164		return nil, fmt.Errorf("unknown hash function '%s'", *mac)
165	}
166
167	macKey := make([]byte, hash.Size())
168	rand.fillBytes(macKey)
169
170	var digest []byte
171	if *ssl3 {
172		if hash != crypto.SHA1 && hash != crypto.MD5 {
173			return nil, fmt.Errorf("invalid hash for SSLv3: '%s'", *mac)
174		}
175		digest = ssl30MAC(hash, macKey, input, adFull)
176	} else {
177		h := hmac.New(hash.New, macKey)
178		h.Write(adFull)
179		h.Write(input)
180		digest = h.Sum(nil)
181	}
182
183	size := getKeySize(*bulkCipher)
184	if size == 0 {
185		return nil, fmt.Errorf("unknown cipher '%s'", *bulkCipher)
186	}
187	encKey := make([]byte, size)
188	rand.fillBytes(encKey)
189
190	var fixedIV []byte
191	var nonce []byte
192	var sealed []byte
193	var noSeal, fails bool
194	block, err := newBlockCipher(*bulkCipher, encKey)
195	if err != nil {
196		return nil, err
197	}
198
199	iv := make([]byte, block.BlockSize())
200	rand.fillBytes(iv)
201	if *implicitIV || *ssl3 {
202		fixedIV = iv
203	} else {
204		nonce = iv
205	}
206
207	cbc := cipher.NewCBCEncrypter(block, iv)
208
209	sealed = make([]byte, 0, len(input)+len(digest)+cbc.BlockSize())
210	sealed = append(sealed, input...)
211	if options.omitMAC {
212		noSeal = true
213		fails = true
214	} else {
215		sealed = append(sealed, digest...)
216	}
217	paddingLen := cbc.BlockSize() - (len(sealed) % cbc.BlockSize())
218	if options.noPadding {
219		if paddingLen != cbc.BlockSize() {
220			return nil, fmt.Errorf("invalid length for noPadding")
221		}
222		noSeal = true
223		fails = true
224	} else {
225		if options.extraPadding || options.maximalPadding {
226			if options.extraPadding {
227				paddingLen += cbc.BlockSize()
228			} else {
229				if paddingLen != cbc.BlockSize() {
230					return nil, fmt.Errorf("invalid length for maximalPadding")
231				}
232				paddingLen = 256
233			}
234			noSeal = true
235			if *ssl3 {
236				// SSLv3 padding must be minimal.
237				fails = true
238			}
239		}
240		if *ssl3 {
241			sealed = append(sealed, make([]byte, paddingLen-1)...)
242			sealed = append(sealed, byte(paddingLen-1))
243		} else {
244			pad := make([]byte, paddingLen)
245			for i := range pad {
246				pad[i] = byte(paddingLen - 1)
247			}
248			sealed = append(sealed, pad...)
249		}
250		if options.wrongPadding {
251			if options.wrongPaddingOffset >= paddingLen {
252				return nil, fmt.Errorf("invalid wrongPaddingOffset")
253			}
254			sealed[len(sealed)-paddingLen+options.wrongPaddingOffset]++
255			noSeal = true
256			if !*ssl3 {
257				// TLS specifies the all the padding bytes.
258				fails = true
259			}
260		}
261	}
262	cbc.CryptBlocks(sealed, sealed)
263
264	key := make([]byte, 0, len(macKey)+len(encKey)+len(fixedIV))
265	key = append(key, macKey...)
266	key = append(key, encKey...)
267	key = append(key, fixedIV...)
268	t := &testCase{
269		digest:     digest,
270		key:        key,
271		nonce:      nonce,
272		input:      input,
273		ad:         ad,
274		ciphertext: sealed[:len(input)],
275		tag:        sealed[len(input):],
276		tag_len:    hash.Size(),
277		noSeal:     noSeal,
278		fails:      fails,
279	}
280	return t, nil
281}
282
283func printTestCase(t *testCase) {
284	fmt.Printf("# DIGEST: %s\n", hex.EncodeToString(t.digest))
285	fmt.Printf("KEY: %s\n", hex.EncodeToString(t.key))
286	fmt.Printf("NONCE: %s\n", hex.EncodeToString(t.nonce))
287	fmt.Printf("IN: %s\n", hex.EncodeToString(t.input))
288	fmt.Printf("AD: %s\n", hex.EncodeToString(t.ad))
289	fmt.Printf("CT: %s\n", hex.EncodeToString(t.ciphertext))
290	fmt.Printf("TAG: %s\n", hex.EncodeToString(t.tag))
291	fmt.Printf("TAG_LEN: %d\n", t.tag_len)
292	if t.noSeal {
293		fmt.Printf("NO_SEAL: 01\n")
294	}
295	if t.fails {
296		fmt.Printf("FAILS: 01\n")
297	}
298}
299
300func addTestCase(length int, options options) {
301	t, err := makeTestCase(length, options)
302	if err != nil {
303		fmt.Fprintf(os.Stderr, "%s\n", err)
304		os.Exit(1)
305	}
306	printTestCase(t)
307	fmt.Printf("\n")
308}
309
310func main() {
311	flag.Parse()
312
313	commandLine := fmt.Sprintf("go run make_legacy_aead_tests.go -cipher %s -mac %s", *bulkCipher, *mac)
314	if *implicitIV {
315		commandLine += " -implicit-iv"
316	}
317	if *ssl3 {
318		commandLine += " -ssl3"
319	}
320	fmt.Printf("# Generated by\n")
321	fmt.Printf("#   %s\n", commandLine)
322	fmt.Printf("#\n")
323	fmt.Printf("# Note: aead_test's input format splits the ciphertext and tag positions of the\n")
324	fmt.Printf("# sealed input. But these legacy AEADs are MAC-then-encrypt and so the 'TAG' may\n")
325	fmt.Printf("# also include padding. We write the byte length of the MAC to 'TAG_LEN' and\n")
326	fmt.Printf("# include the unencrypted MAC in the 'DIGEST' tag above # each test case.\n")
327	fmt.Printf("# each test case.\n")
328	fmt.Printf("\n")
329
330	// For CBC-mode ciphers, emit tests for padding flexibility.
331	fmt.Printf("# Test with non-minimal padding.\n")
332	addTestCase(5, options{extraPadding: true})
333
334	fmt.Printf("# Test with bad padding values.\n")
335	addTestCase(5, options{wrongPadding: true})
336
337	hash, ok := getHash(*mac)
338	if !ok {
339		panic("unknown hash")
340	}
341
342	fmt.Printf("# Test with no padding.\n")
343	addTestCase(64-hash.Size(), options{noPadding: true})
344
345	fmt.Printf("# Test with maximal padding.\n")
346	addTestCase(64-hash.Size(), options{maximalPadding: true})
347
348	fmt.Printf("# Test if the unpadded input is too short for a MAC, but not publicly so.\n")
349	addTestCase(0, options{omitMAC: true, maximalPadding: true})
350
351	fmt.Printf("# Test that each byte of incorrect padding is noticed.\n")
352	for i := 0; i < 256; i++ {
353		addTestCase(64-hash.Size(), options{
354			maximalPadding:     true,
355			wrongPadding:       true,
356			wrongPaddingOffset: i,
357		})
358	}
359
360	// Generate long enough of input to cover a non-zero num_starting_blocks
361	// value in the constant-time CBC logic.
362	for l := 0; l < 500; l += 5 {
363		addTestCase(l, options{})
364	}
365}
366