func encryptOracle(src []byte) []byte {
	key := util.RandAes128()
	block, _ := aes.NewCipher(key)
	out := make([]byte, len(src))
	copy(out, src)

	// random prepend and append
	prefixSize := util.RandByte()%10 + 5
	postfixSize := util.RandByte()%10 + 5
	postfix := util.RandBytes(int(postfixSize))
	out = append(util.RandBytes(int(prefixSize)), out...)
	out = append(out, postfix...)
	// padding
	out = util.PadTo(out, 16)
	// fmt.Println("before enc", out)

	// random encryption mode
	mode := util.RandByte()
	if mode%2 == 0 {
		// ecb
		fmt.Println("ecb")
		util.ECBEncrypt(block, out, out)
	} else {
		// cbc
		fmt.Println("cbc")
		iv := util.RandAes128()
		util.CBCEncrypt(block, iv, out, out)
	}
	return out
}
func main() {
	{
		// testing that crypto works back and forth
		t := []byte("some secret stuff AAAA")
		ct := make([]byte, len(t))
		MTEncrypt(0, ct, t)
		t2 := make([]byte, len(t))
		MTEncrypt(0, t2, ct)
		fmt.Println(bytes.Equal(t, t2))
	}
	{
		// generate random bytes with AAA's appended
		t := util.RandBytes(int(util.RandByte()))
		knownText := "AAAAAAAAAAAAA"
		t = append(t, []byte(knownText)...)
		ct := make([]byte, len(t))
		MTEncrypt(int(util.RandByte())*int(util.RandByte()), ct, t)
		for i := 0; i < 0xFFFF; i++ {
			z := make([]byte, len(ct))
			MTEncrypt(i, z, ct)
			if string(z[len(z)-len(knownText):]) == knownText {
				fmt.Println("Found the key:", i)
				break
			}
		}
	}
	{
		// generate "random" "password reset token"
		mt := util.NewMT19337(uint64(time.Now().Unix()))
		token := mt.Next()
		time.Sleep(1 * time.Second)
		fmt.Println("Is MT19337 token: ", isMT19337Token(token))
	}
}
func aesCrypt(s *big.Int, t []byte) (ct, iv []byte) {
	sum := sha1.Sum([]byte(s.String()))
	blockA, _ := aes.NewCipher(sum[0:16])
	tPadded := util.PadTo(t, 16)
	ct = make([]byte, len(tPadded))
	iv = util.RandBytes(16)
	util.CBCEncrypt(blockA, iv, ct, tPadded)
	return
}
func main() {
	// C & S
	N, _ := big.NewInt(0).SetString(NStr, 0)
	g := big.NewInt(2)
	k := big.NewInt(3)
	// i := []byte("*****@*****.**")
	p := []byte("secret-pass")

	// S
	salt := util.RandBytes(16)
	xH := sha256.Sum256(append(salt, p...))
	x := big.NewInt(0).SetBytes(xH[0:32])
	fmt.Printf("%s \n%x\n\n", x, x)
	v := big.NewInt(0).Exp(g, x, N)
	v.Mod(v, N)
	fmt.Printf("v = %x\n", v)

	// C->S: I, A=g**a % N
	A, a := util.GenExpPair(N, g)

	// S->C: salt, B=kv + g**b % N
	b := util.RandomBig(N)
	B := big.NewInt(0).Exp(g, b, N)
	kv := big.NewInt(0).Mul(k, v)
	B.Add(kv, B)
	B.Mod(B, N)

	// S, C
	uH := sha256.Sum256([]byte(A.String() + B.String()))
	u := big.NewInt(0).SetBytes(uH[0:32])

	// C
	xHClient := sha256.Sum256(append(salt, p...))
	xClient := big.NewInt(0).SetBytes(xHClient[0:32])
	// S = (B - k * g**x)**(a + u * x) % N
	left := big.NewInt(0)
	left.Exp(g, xClient, N)
	left.Mul(k, left)
	left.Sub(B, left)
	right := big.NewInt(0)
	right.Mul(u, xClient)
	right.Add(a, right)
	sClient := big.NewInt(0).Exp(left, right, N)
	sClient.Mod(sClient, N) // S
	KClient := sha256.Sum256(sClient.Bytes())
	fmt.Printf("KClient = %x\n", KClient)

	HMacClient := util.HMacSha256(KClient[:32], salt)
	fmt.Printf("HMAC Client = %x\n", HMacClient)

	// S
	// sServer = (A * v**u) ** b % N
	left.Exp(v, u, N)
	left.Mul(A, left)
	sServer := big.NewInt(0).Exp(left, b, N)
	KServer := sha256.Sum256(sServer.Bytes())
	fmt.Printf("KServer = %x\n", KServer)

	HMacServer := util.HMacSha256(KServer[:32], salt)
	fmt.Printf("HMAC Server = %x\n", HMacServer)
}
Think "STIMULUS" and "RESPONSE".
*/

import (
	"bytes"
	"crypto/aes"
	"cryptopals/util"
	"fmt"
)

type oracleFunc func(src []byte) []byte

var (
	key       = util.RandAes128()
	prefixLen = int(util.RandByte())%32 + 1
	prefix    = util.RandBytes(prefixLen)
)

func encryptOracle(src []byte) []byte {
	block, _ := aes.NewCipher(key)
	out := make([]byte, len(src))
	copy(out, src)

	target := []byte("secret bytes. nobody is gonna read them.")
	out = append(prefix, out...)
	out = append(out, target...)
	out = util.PadTo(out, 16)
	// fmt.Println("before enc", out)
	util.ECBEncrypt(block, out, out)

	return out