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 getMsg() (ct, iv []byte) {
	ct, err := base64.StdEncoding.DecodeString(msgs[util.RandByte()%10])
	if err != nil {
		log.Fatal("Cannot decode", err)
	}
	iv = util.RandAes128()
	block, _ := aes.NewCipher(key)
	ct = util.PadTo(ct, block.BlockSize())
	util.CBCEncrypt(block, iv, ct, ct)
	return ct, iv
}
Encrypt the encoded user profile under the key; "provide" that to the "attacker".
Decrypt the encoded user profile and parse it.
Using only the user input to profile_for() (as an oracle to generate "valid" ciphertexts) and the ciphertexts themselves, make a role=admin profile.
*/

import (
	"crypto/aes"
	"cryptopals/util"
	"fmt"
	"net/url"
)

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

var key = util.RandAes128()

func encryptProfile(email string) []byte {
	block, _ := aes.NewCipher(key)
	profile := profileFor(string(email))
	out := make([]byte, len(profile))
	copy(out, profile)

	out = util.PadTo(out, 16)
	fmt.Println("before enc:", out)
	util.ECBEncrypt(block, out, out)

	return out
}

func decryptProfile(ct []byte) url.Values {
Completely scrambles the block the error occurs in
Produces the identical 1-bit error(/edit) in the next ciphertext block.

Stop and think for a second.
Before you implement this attack, answer this question: why does CBC mode have this property?
*/

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

var (
	key     = util.RandAes128()
	iv      = util.RandAes128()
	prefix  = []byte("comment1=cooking%20MCs;userdata=")
	postfix = []byte(";comment2=%20like%20a%20pound%20of%20bacon")
)

func crypt(userdata []byte) []byte {
	res := bytes.Replace(userdata, []byte("="), []byte("%3D"), -1)
	res = bytes.Replace(res, []byte(";"), []byte("%3B"), -1)
	res = append(prefix, res...)
	res = append(res, postfix...)
	block, _ := aes.NewCipher(key)
	res = util.PadTo(res, 16)
	util.CBCEncrypt(block, iv, res, res)
	return res
}
Completely scrambles the block the error occurs in
Produces the identical 1-bit error(/edit) in the next ciphertext block.

Stop and think for a second.
Before you implement this attack, answer this question: why does CBC mode have this property?
*/

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

var (
	key     = util.RandAes128()
	nonce   = util.RandAes128()
	prefix  = []byte("comment1=cooking%20MCs;userdata=")
	postfix = []byte(";comment2=%20like%20a%20pound%20of%20bacon")
)

func crypt(userdata []byte) []byte {
	res := bytes.Replace(userdata, []byte("="), []byte("%3D"), -1)
	res = bytes.Replace(res, []byte(";"), []byte("%3B"), -1)
	res = append(prefix, res...)
	res = append(res, postfix...)
	block, _ := aes.NewCipher(key)
	res = util.PadTo(res, 16)
	fmt.Println("crypt peek:", string(res))
	util.CTREncrypt(block, nonce, res, res)
	return res