1 package main 2 3 import ( 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 20 var bulkCipher *string = flag.String("cipher", "", "The bulk cipher to use") 21 var mac *string = flag.String("mac", "", "The hash function to use in the MAC") 22 var implicitIV *bool = flag.Bool("implicit-iv", false, "If true, generate tests for a cipher using a pre-TLS-1.0 implicit IV") 23 var 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. 27 type rc4Stream struct { 28 cipher *rc4.Cipher 29 } 30 31 func 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 39 func (rs *rc4Stream) fillBytes(p []byte) { 40 for i := range p { 41 p[i] = 0 42 } 43 rs.cipher.XORKeyStream(p, p) 44 } 45 46 func 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 61 func 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 74 func 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 87 var 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 89 var 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 91 func 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 111 type 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. 125 type 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 142 func 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 283 func 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 300 func 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 310 func 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