Example #1
0
// RecoverEncodings returns the full affine output encoding of affine-encoded f at the given position, as well as the
// input affine encodings for all neighboring bytes up to a key byte.  Returns (out, []in)
func RecoverEncodings(constr *chow.Construction, round, pos int) (encoding.ByteAffine, []encoding.ByteAffine) {
	Ps := make([]encoding.ByteAffine, 4)  // Approximate input encodings.
	Ds := make([]number.ByteFieldElem, 4) // Array of gamma * MC coefficient
	q := byte(0x00)                       // The constant part of the output encoding.

	L := RecoverL(constr, round, pos)
	Atilde := FindAtilde(constr, L)
	AtildeInv, _ := Atilde.Invert()

	for i := 0; i < 4; i++ {
		j := pos/4*4 + i

		inEnc, _ := RecoverAffineEncoded(
			constr, encoding.IdentityByte{}, round-1, common.UnShiftRows(j), common.UnShiftRows(j),
		)
		_, f := RecoverAffineEncoded(constr, inEnc, round, j, pos)

		var c byte
		Ds[i], c, Ps[i] = FindPartialEncoding(constr, f, L, AtildeInv)
		q ^= c

		if i == 0 {
			q ^= f.Get(0x00)
		}
	}

	DInv, _ := DecomposeAffineEncoding(encoding.ByteMultiplication(FindDuplicate(Ds).Invert()))
	A := Atilde.Compose(DInv)
	AInv, _ := A.Invert()

	return encoding.ByteAffine{encoding.ByteLinear{A, AInv}, q}, Ps
}
Example #2
0
func TestRecoverEncodings(t *testing.T) {
	constr, key := testConstruction()
	fastConstr := fastTestConstruction()

	baseConstr := saes.Construction{key}
	roundKeys := baseConstr.StretchedKey()

	outAff := getOutputAffineEncoding(constr, fastConstr, 1, 0)

	// Manually recover the output encoding.
	Q, Ps := RecoverEncodings(fastConstr, 1, 0)

	if fmt.Sprintf("%x %v", outAff.Linear, outAff.Constant) != fmt.Sprintf("%x %v", Q.Linear, Q.Constant) {
		t.Fatalf("RecoverEncodings recovered the wrong output encoding!")
	}

	// Verify that all Ps composed with their corresponding output encoding equals XOR by a key byte.
	id := matrix.GenerateIdentity(8)
	for pos, P := range Ps {
		outAff := getOutputAffineEncoding(constr, fastConstr, 0, common.UnShiftRows(pos))
		A, b := DecomposeAffineEncoding(encoding.ComposedBytes{outAff, P})

		if fmt.Sprintf("%x", id) != fmt.Sprintf("%x", A) {
			t.Fatalf("Linear part of encoding was not identity!")
		}

		if roundKeys[1][common.UnShiftRows(pos)] != b {
			t.Fatalf("Constant part of encoding was not key byte!")
		}
	}
}
Example #3
0
// RecoverKey returns the AES key used to generate the given white-box construction.
func RecoverKey(constr *chow.Construction) []byte {
	temp := make([]encoding.Byte, 16)

	// Recover all output affine encodings for round 1.
	for pos := 0; pos < 16; pos++ {
		temp[pos], _ = RecoverEncodings(constr, 1, pos)
	}

	// Recover all input affine encodings up to a key byte for round 2.
	// Compose it with the above's output.
	for col := 0; col < 4; col++ {
		_, in := RecoverEncodings(constr, 2, 4*col)

		for row := 0; row < 4; row++ {
			backPos := common.UnShiftRows(4*col + row)
			temp[backPos] = encoding.ComposedBytes{temp[backPos], in[row]}
		}
	}

	// Recover round key for round 2.
	// The output encoding of round 1 composed with the approximate input encoding of round 2 should be an affine
	// transformation with the identity matrix as the linear part and a key byte as the constant part.
	roundKey := make([]byte, 16)
	for pos := 0; pos < 16; pos++ {
		roundKey[pos] = temp[pos].Encode(0)
	}

	// Recover the master key from the round key and return.
	return BackOneRound(BackOneRound(roundKey, 2), 1)
}