Пример #1
0
/* Encrypt a set of strings in AES CTR mode using the same nonce
 * Decrypt the resulting ciphertexts without the key or stream
 */
func c20() (actual, expected Result) {
	input, _ := ioutil.ReadFile("input/20.txt")
	output, _ := utils.ReadAndStripFile("output/20.txt")
	expected = string(output)

	strs := strings.Split(string(input), "\n")
	n := len(strs)
	strs = strs[:n-2]
	key := crypto.NewAesKey()
	nonce := uint64(0)

	// Decode strings and find length of the shortest string
	length := 1000
	plaintexts := make([][]byte, len(strs))
	for i, str := range strs {
		decoded, _ := base64.StdEncoding.DecodeString(str)
		if len(decoded) < length {
			length = len(decoded)
		}
		plaintexts[i] = decoded
	}

	var concat []byte
	for i, str := range plaintexts {
		// Truncate each string to common length
		plaintexts[i] = str[:length]

		stream, err := crypto.Ctr(nonce, key)
		if err != nil {
			log.Println(err)
		}

		// Concatenate the ciphertexts
		ciphertext := make([]byte, length)
		stream.XORKeyStream(ciphertext, plaintexts[i])
		concat = append(concat, ciphertext...)
	}

	l := []int{length}

	plaintext, err := crypto.BreakXorRepeating(concat, l)
	if err != nil {
		log.Println(err)
	}

	return string(utils.Strip(plaintext)), expected
}
Пример #2
0
/* CBC bitflipping attack
* Create a function, that given an input, prepends:
* "comment1=cooking%20MCs;userdata="
* and appends:
* ";comment2=%20like%20a%20pound%20of%20bacon"
* , quotes out the ; and =, and pads and encrypts it under AES CBC.
* Another function should decrypt the string and return true if
* ";admin=true;" exists in the string. Modify the ciphertext to
* make the second funcion return true.
 */
func c16() (actual, expected Result) {
	key := crypto.NewAesKey()

	input := "XadminXtrue"
	inputBytes := []byte(input)
	str := profile.ProcessComment(input)

	iv, _ := bytes.Random(aes.BlockSize)
	encrypted, err := crypto.CbcEncrypt([]byte(str), key, iv)
	if err != nil {
		panic(err)
	}

	// Flip the targeted bytes ("X"s in the input string)
	encrypted[16] = encrypted[16] ^ 59 ^ inputBytes[0]
	encrypted[22] = encrypted[22] ^ 61 ^ inputBytes[6]

	hasAdmin := profile.HasAdmin(encrypted, key, iv)
	return hasAdmin, true
}
Пример #3
0
/* Byte-at-a-time ECB decryption
* Create a modified oracle function that decrypts an unknown string encrypted
* under ECB-mode with a consistent, but unknown key.
* AES-128-ECB(known-string || unknown-string, key)
 */
func c12() (actual, expected Result) {
	expected = "Rollin' in my 5.0\nWith my rag-top down so my hair can blow\nThe girlies on standby waving just to say hi\nDid you stop? No, I just drove by\n\x01"

	if crypto.GlobalAesKey == nil {
		crypto.GlobalAesKey = crypto.NewAesKey()
	}
	key := crypto.GlobalAesKey

	blocksize := crypto.DetectBlocksize(key)
	secretBlocks := len(crypto.AppendSecretEncryptEcb([]byte(""), key, false)) / blocksize

	var secret []byte

	createDict := func(plaintext []byte, block int) map[int][]byte {
		dict := make(map[int][]byte)
		for b := 0; b <= 255; b++ {
			extra := []byte{byte(b)}
			plaintext := append(plaintext, extra[0])
			ciphertext := crypto.AppendSecretEncryptEcb(plaintext, key, false)
			dict[b] = ciphertext[block*blocksize : blocksize*(block+1)]
		}
		return dict
	}

	for n := 0; n < secretBlocks; n++ {
		for i := 0; i < blocksize; i++ {
			short := stdBytes.Repeat([]byte("A"), blocksize-(i+1))
			plaintext := append(short, secret...)
			dict := createDict(plaintext, n)
			secretCiphertext := crypto.AppendSecretEncryptEcb(short, key, false)

			for char, lookup := range dict {
				if string(secretCiphertext[n*blocksize:blocksize*(n+1)]) == string(lookup) {
					char := []byte{byte(char)}
					secret = append(secret, char...)
				}
			}
		}
	}
	return string(secret), expected
}
Пример #4
0
/* CBC padding oracle
* Write a CBC padding oracle that decrypts a ciphertext and detects
* if the plaintext is padded properly with PKCS#7. Choose a random line
* from 17.txt, encrypt it, then decrypt it using the oracle.
 */
func c17() (actual, expected Result) {
	input, _ := ioutil.ReadFile("input/17.txt")
	strs := strings.Split(string(input), "\n")
	str := strs[r.Intn(10)]
	decodedStr, _ := base64.StdEncoding.DecodeString(str)

	if crypto.GlobalAesKey == nil {
		crypto.GlobalAesKey = crypto.NewAesKey()
	}
	key := crypto.GlobalAesKey
	iv, _ := bytes.Random(aes.BlockSize)

	ciphertext, err := crypto.CbcEncrypt([]byte(decodedStr), key, iv)
	if err != nil {
		log.Fatal(err)
	}

	blocks, err := bytes.SplitIntoBlocks(ciphertext, aes.BlockSize)
	if err != nil {
		log.Fatal(err)
	}

	var plaintext []byte

	for n := 0; n < len(blocks); n++ {
		block := blocks[n]
		controlled := make([]byte, aes.BlockSize)
		plaintextBlock := make([]byte, aes.BlockSize)
		intermediate := make([]byte, aes.BlockSize)
		prevBlock := make([]byte, aes.BlockSize)

		if n == 0 {
			prevBlock = iv
		} else {
			prevBlock = blocks[n-1]
		}

		for i := aes.BlockSize - 1; i >= 0; i-- {
			paddingLen := aes.BlockSize - i
			paddingByte := byte(paddingLen)

			// Set the last paddingLen bytes of controlled to so that when decrypted,
			// each will be a valid padding byte.
			for j := 0; j < paddingLen; j++ {
				controlled[i+j] = paddingByte ^ intermediate[i+j]
			}

			for b := 0; b <= 256; b++ {
				controlled[i] = byte(b)
				controlled := append(controlled, block...)
				valid, _ := crypto.CbcPaddingOracle(controlled, iv)
				if valid {
					// The padding is valid and we control the ith byte of the
					// block XORed with the intermediate state. XOR is an inverse
					// operation so finding the ith byte of the intermediate state
					// is as simple as:
					intermediate[i] = paddingByte ^ controlled[i]
					break
				}
			}
			plaintextBlock[i] = prevBlock[i] ^ intermediate[i]
		}
		plaintext = append(plaintext, plaintextBlock...)
	}

	decrypted, _ := crypto.CbcDecrypt(ciphertext, key, iv)
	return string(plaintext), string(decrypted)
}
Пример #5
0
/* Byte-at-a-time ECB decryption
* Same goal as #12, but prepend a random # of random bytes to input.
* AES-128-ECB(random-#-bytes || input, key)
 */
func c14() (actual, expected Result) {
	expected = "Rollin' in my 5.0\nWith my rag-top down so my hair can blow\nThe girlies on standby waving just to say hi\nDid you stop? No, I just drove by\n\x01"

	if len(crypto.GlobalAesKey) == 0 {
		crypto.GlobalAesKey = crypto.NewAesKey()
	}
	key := crypto.GlobalAesKey

	blocksize := crypto.DetectBlocksize(key)

	createDict := func(plaintext []byte, prefixLength, block int) map[int][]byte {
		dict := make(map[int][]byte)
		for b := 0; b <= 255; b++ {
			extra := []byte{byte(b)}
			plaintext := append(plaintext, extra[0])
			ciphertext := crypto.AppendSecretEncryptEcb(plaintext, key, true)
			dict[b] = ciphertext[(block*blocksize)+prefixLength : (blocksize*(block+1))+prefixLength]
		}
		return dict
	}

	findPrefixLength := func(blocksize int, key []byte) int {
		// If we send 2-3 blocks of repeating bytes, we will see a repeating block
		for i := blocksize * 2; i <= blocksize*3; i++ {
			encrypted := crypto.AppendSecretEncryptEcb(stdBytes.Repeat([]byte("A"), i), key, true)
			numBlocks := len(encrypted) / blocksize

			// Loop through blocks to find a repeat
			for j := 0; j < numBlocks-1; j++ {
				firstBlock := encrypted[j*blocksize : (j+1)*blocksize]
				secondBlock := encrypted[(j+1)*blocksize : (j+2)*blocksize]

				// Repeating block indicates we added enough bytes to make an even block
				if string(firstBlock) == string(secondBlock) {
					return (j+2)*blocksize - i
				}
			}
		}
		return 0
	}

	// Knowing the length of the random prefix bytes, pad input to make a full block
	var secretBlocks int
	prefix := findPrefixLength(blocksize, key)
	// TODO: There must be a better way to account for prefix/16 rounding down and
	// giving 1 too few blocks
	if prefix%blocksize <= 5 {
		secretBlocks += 1
	}
	pad := blocksize - (prefix % blocksize) // prefix + pad = full block
	prefix += pad

	// Figure out how many blocks to solve
	totalBlocks := len(crypto.AppendSecretEncryptEcb([]byte(""), key, true)) / blocksize
	secretBlocks += totalBlocks - (prefix / 16)
	var secret []byte

	for n := 0; n < secretBlocks; n++ {
		for i := 0; i < blocksize; i++ {
			// Send A*pad to pad the prefix to a full block, + A*blocksize-1,
			// blocksize-2, ... until that block of the secret is solved
			short := stdBytes.Repeat([]byte("A"), pad+blocksize-(i+1))
			plaintext := append(short, secret...)

			// Create a dictionary of ciphertexts for every character
			dict := createDict(plaintext, prefix, n)
			secretCiphertext := crypto.AppendSecretEncryptEcb(short, key, true)

			for char, lookup := range dict {
				targetBlock := secretCiphertext[prefix+(n*blocksize) : prefix+(blocksize*(n+1))]
				if string(targetBlock) == string(lookup) {
					char := []byte{byte(char)}
					secret = append(secret, char...)
				}
			}
		}
	}
	return string(secret), expected
}