package main

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/des"
	"crypto/hmac"
	_ "crypto/md5"
	"crypto/rc4"
	_ "crypto/sha1"
	_ "crypto/sha256"
	_ "crypto/sha512"
	"encoding/hex"
	"flag"
	"fmt"
	"os"
)

var bulkCipher *string = flag.String("cipher", "", "The bulk cipher to use")
var mac *string = flag.String("mac", "", "The hash function to use in the MAC")
var implicitIV *bool = flag.Bool("implicit-iv", false, "If true, generate tests for a cipher using a pre-TLS-1.0 implicit IV")

// rc4Stream produces a deterministic stream of pseudorandom bytes. This is to
// make this script idempotent.
type rc4Stream struct {
	cipher *rc4.Cipher
}

func newRc4Stream(seed string) (*rc4Stream, error) {
	cipher, err := rc4.NewCipher([]byte(seed))
	if err != nil {
		return nil, err
	}
	return &rc4Stream{cipher}, nil
}

func (rs *rc4Stream) fillBytes(p []byte) {
	for i := range p {
		p[i] = 0
	}
	rs.cipher.XORKeyStream(p, p)
}

func getHash(name string) (crypto.Hash, bool) {
	switch name {
	case "md5":
		return crypto.MD5, true
	case "sha1":
		return crypto.SHA1, true
	case "sha256":
		return crypto.SHA256, true
	case "sha384":
		return crypto.SHA384, true
	default:
		return 0, false
	}
}

func getKeySize(name string) int {
	switch name {
	case "aes128":
		return 16
	case "aes256":
		return 32
	case "3des":
		return 24
	default:
		return 0
	}
}

func newBlockCipher(name string, key []byte) (cipher.Block, error) {
	switch name {
	case "aes128":
		return aes.NewCipher(key)
	case "aes256":
		return aes.NewCipher(key)
	case "3des":
		return des.NewTripleDESCipher(key)
	default:
		return nil, fmt.Errorf("unknown cipher '%s'", name)
	}
}

type testCase struct {
	digest     []byte
	key        []byte
	nonce      []byte
	input      []byte
	ad         []byte
	ciphertext []byte
	tag        []byte
	tag_len    int
	noSeal     bool
	fails      bool
}

// options adds additional options for a test.
type options struct {
	// extraPadding causes an extra block of padding to be added.
	extraPadding bool
	// maximalPadding causes 256 bytes of padding to be added.
	maximalPadding bool
	// wrongPadding causes one of the padding bytes to be wrong.
	wrongPadding bool
	// wrongPaddingOffset specifies the byte offset of the incorrect padding
	// byte.
	wrongPaddingOffset int
	// noPadding causes padding is to be omitted. The plaintext + MAC must
	// be a multiple of the block size.
	noPadding bool
	// omitMAC causes the MAC to be omitted.
	omitMAC bool
}

func makeTestCase(length int, options options) (*testCase, error) {
	rand, err := newRc4Stream("input stream")
	if err != nil {
		return nil, err
	}

	input := make([]byte, length)
	rand.fillBytes(input)

	adFull := make([]byte, 13)
	ad := adFull[:len(adFull)-2]
	rand.fillBytes(ad)
	adFull[len(adFull)-2] = uint8(length >> 8)
	adFull[len(adFull)-1] = uint8(length & 0xff)

	hash, ok := getHash(*mac)
	if !ok {
		return nil, fmt.Errorf("unknown hash function '%s'", *mac)
	}

	macKey := make([]byte, hash.Size())
	rand.fillBytes(macKey)

	h := hmac.New(hash.New, macKey)
	h.Write(adFull)
	h.Write(input)
	digest := h.Sum(nil)

	size := getKeySize(*bulkCipher)
	if size == 0 {
		return nil, fmt.Errorf("unknown cipher '%s'", *bulkCipher)
	}
	encKey := make([]byte, size)
	rand.fillBytes(encKey)

	var fixedIV []byte
	var nonce []byte
	var sealed []byte
	var noSeal, fails bool
	block, err := newBlockCipher(*bulkCipher, encKey)
	if err != nil {
		return nil, err
	}

	iv := make([]byte, block.BlockSize())
	rand.fillBytes(iv)
	if *implicitIV {
		fixedIV = iv
	} else {
		nonce = iv
	}

	cbc := cipher.NewCBCEncrypter(block, iv)

	sealed = make([]byte, 0, len(input)+len(digest)+cbc.BlockSize())
	sealed = append(sealed, input...)
	if options.omitMAC {
		noSeal = true
		fails = true
	} else {
		sealed = append(sealed, digest...)
	}
	paddingLen := cbc.BlockSize() - (len(sealed) % cbc.BlockSize())
	if options.noPadding {
		if paddingLen != cbc.BlockSize() {
			return nil, fmt.Errorf("invalid length for noPadding")
		}
		noSeal = true
		fails = true
	} else {
		if options.extraPadding || options.maximalPadding {
			if options.extraPadding {
				paddingLen += cbc.BlockSize()
			} else {
				if paddingLen != cbc.BlockSize() {
					return nil, fmt.Errorf("invalid length for maximalPadding")
				}
				paddingLen = 256
			}
			noSeal = true
		}
		pad := make([]byte, paddingLen)
		for i := range pad {
			pad[i] = byte(paddingLen - 1)
		}
		sealed = append(sealed, pad...)
		if options.wrongPadding {
			if options.wrongPaddingOffset >= paddingLen {
				return nil, fmt.Errorf("invalid wrongPaddingOffset")
			}
			sealed[len(sealed)-paddingLen+options.wrongPaddingOffset]++
			noSeal = true
			// TLS specifies the all the padding bytes.
			fails = true
		}
	}
	cbc.CryptBlocks(sealed, sealed)

	key := make([]byte, 0, len(macKey)+len(encKey)+len(fixedIV))
	key = append(key, macKey...)
	key = append(key, encKey...)
	key = append(key, fixedIV...)
	t := &testCase{
		digest:     digest,
		key:        key,
		nonce:      nonce,
		input:      input,
		ad:         ad,
		ciphertext: sealed[:len(input)],
		tag:        sealed[len(input):],
		tag_len:    hash.Size(),
		noSeal:     noSeal,
		fails:      fails,
	}
	return t, nil
}

func printTestCase(t *testCase) {
	fmt.Printf("# DIGEST: %s\n", hex.EncodeToString(t.digest))
	fmt.Printf("KEY: %s\n", hex.EncodeToString(t.key))
	fmt.Printf("NONCE: %s\n", hex.EncodeToString(t.nonce))
	fmt.Printf("IN: %s\n", hex.EncodeToString(t.input))
	fmt.Printf("AD: %s\n", hex.EncodeToString(t.ad))
	fmt.Printf("CT: %s\n", hex.EncodeToString(t.ciphertext))
	fmt.Printf("TAG: %s\n", hex.EncodeToString(t.tag))
	fmt.Printf("TAG_LEN: %d\n", t.tag_len)
	if t.noSeal {
		fmt.Printf("NO_SEAL: 01\n")
	}
	if t.fails {
		fmt.Printf("FAILS: 01\n")
	}
}

func addTestCase(length int, options options) {
	t, err := makeTestCase(length, options)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
	printTestCase(t)
	fmt.Printf("\n")
}

func main() {
	flag.Parse()

	commandLine := fmt.Sprintf("go run make_legacy_aead_tests.go -cipher %s -mac %s", *bulkCipher, *mac)
	if *implicitIV {
		commandLine += " -implicit-iv"
	}
	fmt.Printf("# Generated by\n")
	fmt.Printf("#   %s\n", commandLine)
	fmt.Printf("#\n")
	fmt.Printf("# Note: aead_test's input format splits the ciphertext and tag positions of the\n")
	fmt.Printf("# sealed input. But these legacy AEADs are MAC-then-encrypt and so the 'TAG' may\n")
	fmt.Printf("# also include padding. We write the byte length of the MAC to 'TAG_LEN' and\n")
	fmt.Printf("# include the unencrypted MAC in the 'DIGEST' tag above # each test case.\n")
	fmt.Printf("# each test case.\n")
	fmt.Printf("\n")

	// For CBC-mode ciphers, emit tests for padding flexibility.
	fmt.Printf("# Test with non-minimal padding.\n")
	addTestCase(5, options{extraPadding: true})

	fmt.Printf("# Test with bad padding values.\n")
	addTestCase(5, options{wrongPadding: true})

	hash, ok := getHash(*mac)
	if !ok {
		panic("unknown hash")
	}

	fmt.Printf("# Test with no padding.\n")
	addTestCase(64-hash.Size(), options{noPadding: true})

	fmt.Printf("# Test with maximal padding.\n")
	addTestCase(64-hash.Size(), options{maximalPadding: true})

	fmt.Printf("# Test if the unpadded input is too short for a MAC, but not publicly so.\n")
	addTestCase(0, options{omitMAC: true, maximalPadding: true})

	fmt.Printf("# Test that each byte of incorrect padding is noticed.\n")
	for i := 0; i < 256; i++ {
		addTestCase(64-hash.Size(), options{
			maximalPadding:     true,
			wrongPadding:       true,
			wrongPaddingOffset: i,
		})
	}

	// Generate long enough of input to cover a non-zero num_starting_blocks
	// value in the constant-time CBC logic.
	for l := 0; l < 500; l += 5 {
		addTestCase(l, options{})
	}
}
