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 noSeal bool 120 fails bool 121} 122 123// options adds additional options for a test. 124type options struct { 125 // extraPadding causes an extra block of padding to be added. 126 extraPadding bool 127 // maximalPadding causes 256 bytes of padding to be added. 128 maximalPadding bool 129 // wrongPadding causes one of the padding bytes to be wrong. 130 wrongPadding bool 131 // wrongPaddingOffset specifies the byte offset of the incorrect padding 132 // byte. 133 wrongPaddingOffset int 134 // noPadding causes padding is to be omitted. The plaintext + MAC must 135 // be a multiple of the block size. 136 noPadding bool 137 // omitMAC causes the MAC to be omitted. 138 omitMAC bool 139} 140 141func makeTestCase(length int, options options) (*testCase, error) { 142 rand, err := newRc4Stream("input stream") 143 if err != nil { 144 return nil, err 145 } 146 147 input := make([]byte, length) 148 rand.fillBytes(input) 149 150 var adFull []byte 151 if *ssl3 { 152 adFull = make([]byte, 11) 153 } else { 154 adFull = make([]byte, 13) 155 } 156 ad := adFull[:len(adFull)-2] 157 rand.fillBytes(ad) 158 adFull[len(adFull)-2] = uint8(length >> 8) 159 adFull[len(adFull)-1] = uint8(length & 0xff) 160 161 hash, ok := getHash(*mac) 162 if !ok { 163 return nil, fmt.Errorf("unknown hash function '%s'", *mac) 164 } 165 166 macKey := make([]byte, hash.Size()) 167 rand.fillBytes(macKey) 168 169 var digest []byte 170 if *ssl3 { 171 if hash != crypto.SHA1 && hash != crypto.MD5 { 172 return nil, fmt.Errorf("invalid hash for SSLv3: '%s'", *mac) 173 } 174 digest = ssl30MAC(hash, macKey, input, adFull) 175 } else { 176 h := hmac.New(hash.New, macKey) 177 h.Write(adFull) 178 h.Write(input) 179 digest = h.Sum(nil) 180 } 181 182 size := getKeySize(*bulkCipher) 183 if size == 0 { 184 return nil, fmt.Errorf("unknown cipher '%s'", *bulkCipher) 185 } 186 encKey := make([]byte, size) 187 rand.fillBytes(encKey) 188 189 var fixedIV []byte 190 var nonce []byte 191 var sealed []byte 192 var noSeal, fails bool 193 block, err := newBlockCipher(*bulkCipher, encKey) 194 if err != nil { 195 return nil, err 196 } 197 198 iv := make([]byte, block.BlockSize()) 199 rand.fillBytes(iv) 200 if *implicitIV || *ssl3 { 201 fixedIV = iv 202 } else { 203 nonce = iv 204 } 205 206 cbc := cipher.NewCBCEncrypter(block, iv) 207 208 sealed = make([]byte, 0, len(input)+len(digest)+cbc.BlockSize()) 209 sealed = append(sealed, input...) 210 if options.omitMAC { 211 noSeal = true 212 fails = true 213 } else { 214 sealed = append(sealed, digest...) 215 } 216 paddingLen := cbc.BlockSize() - (len(sealed) % cbc.BlockSize()) 217 if options.noPadding { 218 if paddingLen != cbc.BlockSize() { 219 return nil, fmt.Errorf("invalid length for noPadding") 220 } 221 noSeal = true 222 fails = true 223 } else { 224 if options.extraPadding || options.maximalPadding { 225 if options.extraPadding { 226 paddingLen += cbc.BlockSize() 227 } else { 228 if paddingLen != cbc.BlockSize() { 229 return nil, fmt.Errorf("invalid length for maximalPadding") 230 } 231 paddingLen = 256 232 } 233 noSeal = true 234 if *ssl3 { 235 // SSLv3 padding must be minimal. 236 fails = true 237 } 238 } 239 if *ssl3 { 240 sealed = append(sealed, make([]byte, paddingLen-1)...) 241 sealed = append(sealed, byte(paddingLen-1)) 242 } else { 243 pad := make([]byte, paddingLen) 244 for i := range pad { 245 pad[i] = byte(paddingLen - 1) 246 } 247 sealed = append(sealed, pad...) 248 } 249 if options.wrongPadding { 250 if options.wrongPaddingOffset >= paddingLen { 251 return nil, fmt.Errorf("invalid wrongPaddingOffset") 252 } 253 sealed[len(sealed)-paddingLen+options.wrongPaddingOffset]++ 254 noSeal = true 255 if !*ssl3 { 256 // TLS specifies the all the padding bytes. 257 fails = true 258 } 259 } 260 } 261 cbc.CryptBlocks(sealed, sealed) 262 263 key := make([]byte, 0, len(macKey)+len(encKey)+len(fixedIV)) 264 key = append(key, macKey...) 265 key = append(key, encKey...) 266 key = append(key, fixedIV...) 267 t := &testCase{ 268 digest: digest, 269 key: key, 270 nonce: nonce, 271 input: input, 272 ad: ad, 273 ciphertext: sealed[:len(sealed)-hash.Size()], 274 tag: sealed[len(sealed)-hash.Size():], 275 noSeal: noSeal, 276 fails: fails, 277 } 278 return t, nil 279} 280 281func printTestCase(t *testCase) { 282 fmt.Printf("# DIGEST: %s\n", hex.EncodeToString(t.digest)) 283 fmt.Printf("KEY: %s\n", hex.EncodeToString(t.key)) 284 fmt.Printf("NONCE: %s\n", hex.EncodeToString(t.nonce)) 285 fmt.Printf("IN: %s\n", hex.EncodeToString(t.input)) 286 fmt.Printf("AD: %s\n", hex.EncodeToString(t.ad)) 287 fmt.Printf("CT: %s\n", hex.EncodeToString(t.ciphertext)) 288 fmt.Printf("TAG: %s\n", hex.EncodeToString(t.tag)) 289 if t.noSeal { 290 fmt.Printf("NO_SEAL: 01\n") 291 } 292 if t.fails { 293 fmt.Printf("FAILS: 01\n") 294 } 295} 296 297func addTestCase(length int, options options) { 298 t, err := makeTestCase(length, options) 299 if err != nil { 300 fmt.Fprintf(os.Stderr, "%s\n", err) 301 os.Exit(1) 302 } 303 printTestCase(t) 304 fmt.Printf("\n") 305} 306 307func main() { 308 flag.Parse() 309 310 commandLine := fmt.Sprintf("go run make_legacy_aead_tests.go -cipher %s -mac %s", *bulkCipher, *mac) 311 if *implicitIV { 312 commandLine += " -implicit-iv" 313 } 314 if *ssl3 { 315 commandLine += " -ssl3" 316 } 317 fmt.Printf("# Generated by\n") 318 fmt.Printf("# %s\n", commandLine) 319 fmt.Printf("#\n") 320 fmt.Printf("# Note: aead_test's input format splits the ciphertext and tag positions of the sealed\n") 321 fmt.Printf("# input. But these legacy AEADs are MAC-then-encrypt and may include padding, so this\n") 322 fmt.Printf("# split isn't meaningful. The unencrypted MAC is included in the 'DIGEST' tag above\n") 323 fmt.Printf("# each test case.\n") 324 fmt.Printf("\n") 325 326 // For CBC-mode ciphers, emit tests for padding flexibility. 327 fmt.Printf("# Test with non-minimal padding.\n") 328 addTestCase(5, options{extraPadding: true}) 329 330 fmt.Printf("# Test with bad padding values.\n") 331 addTestCase(5, options{wrongPadding: true}) 332 333 hash, ok := getHash(*mac) 334 if !ok { 335 panic("unknown hash") 336 } 337 338 fmt.Printf("# Test with no padding.\n") 339 addTestCase(64-hash.Size(), options{noPadding: true}) 340 341 fmt.Printf("# Test with maximal padding.\n") 342 addTestCase(64-hash.Size(), options{maximalPadding: true}) 343 344 fmt.Printf("# Test if the unpadded input is too short for a MAC, but not publicly so.\n") 345 addTestCase(0, options{omitMAC: true, maximalPadding: true}) 346 347 fmt.Printf("# Test that each byte of incorrect padding is noticed.\n") 348 for i := 0; i < 256; i++ { 349 addTestCase(64-hash.Size(), options{ 350 maximalPadding: true, 351 wrongPadding: true, 352 wrongPaddingOffset: i, 353 }) 354 } 355 356 // Generate long enough of input to cover a non-zero num_starting_blocks 357 // value in the constant-time CBC logic. 358 for l := 0; l < 500; l += 5 { 359 addTestCase(l, options{}) 360 } 361} 362