summaryrefslogblamecommitdiffstats
path: root/challenge/c27.go
blob: 3ee2cbe22c0791f82f71b302ef04093e82e2be05 (plain) (tree)
1
                                                             























































                                                                    
                                                                                       




























                                                                               
// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net>
// SPDX-License-Identifier: ISC

package challenge

import (
	"fmt"

	"ricketyspace.net/cryptopals/lib"
)

func C27() {
	// Generate random key.
	key, err := lib.RandomBytes(16)
	if err != nil {
		fmt.Printf("Error: %v", err)
		return
	}

	// Make IV same as `key`.
	iv := key

	// Encrypt `plain` with AES-CBC
	encrypt := func(plain []byte) []byte {
		return lib.AESEncryptCBC(plain, key, iv)
	}

	// Same as lib.AESDecryptCBC but ignores padding error and
	// checks if plain text has high ASCII values.
	//
	// Always returns full plain text; even when there is an
	// error.
	decrypt := func(cipher []byte) ([]byte, error) {
		iter := len(cipher) / 16

		lc := iv
		output := make([]byte, 0)
		for i := 0; i < iter; i++ {
			s := (i * 16)
			e := (i * 16) + 16
			c := cipher[s:e]
			output = append(output, lib.FixedXORBytes(
				lib.AESInvCipher(c, key), lc)...)

			lc = c
		}

		// Undo padding
		plain, err := lib.Pkcs7PaddingUndo(output)
		if err != nil {
			// If padding undo fails, just use `output`.
			plain = output
		}

		// Check if `plain` high ASCII
		for _, p := range plain {
			if p >= 128 {
				return plain, lib.CPError{Err: "Has high ASCII values"}
			}
		}

		return plain, nil
	}

	// Encrypt atleast 3 blocks of plain text.
	c := encrypt(lib.StrToBytes(
		"As soon as you are born they make you feel small"))

	// Modify cipher.
	copy(c[32:48], c[0:16])              // C_3 <- C_1
	copy(c[16:32], lib.FillBytes(0, 16)) // C_2 <- 0

	// Try decrypting.
	p, err := decrypt(c)
	if err != nil {
		// Has high ASCII values; recover key.
		k := lib.FixedXORBytes(p[0:16], p[32:48])
		if lib.BytesEqual(k, key) {
			fmt.Printf("Recovered key: %v\n", k)
			return
		}
	}
	fmt.Printf("Could not recover key\n")
}

// Output:
// Recovered key: [62 228 155 158 92 189 217 142 58 118 162 140 165 41 152 237]