Пример #1
0
// GenerateKeys creates a white-boxed version of the AES key `key`, with any non-determinism generated by `seed`.
func GenerateKeys(key, seed []byte) (out Construction, inputMask, outputMask encoding.BlockAffine) {
	rs := random.NewSource("Toy Construction", seed)

	// Generate two completely random affine transformations, to be put on input and output of SPN.
	inputMask, outputMask = generateAffineMasks(&rs)

	// Steal key schedule logic from the standard AES construction.
	constr := saes.Construction{key}
	roundKeys := constr.StretchedKey()

	// Generate an SPN which has the input and output masks, but is otherwise un-obfuscated.
	out[0] = inputMask
	encoding.XOR(out[0].BlockAdditive[:], out[0].BlockAdditive[:], roundKeys[0])

	for i := 1; i < 10; i++ {
		out[i] = encoding.BlockAffine{
			BlockLinear:   encoding.BlockLinear{round, unRound},
			BlockAdditive: shiftRoundKey(roundKeys[i]),
		}
	}
	out[10] = encoding.BlockAffine{
		BlockLinear:   encoding.BlockLinear{lastRound, firstRound},
		BlockAdditive: shiftRoundKey(roundKeys[10]),
	}
	out[10], _ = encoding.DecomposeBlockAffine(encoding.ComposedBlocks{out[10], outputMask})

	// Sample a self-equivalences of the S-box layer and mix them into adjacent affine layers.
	label := make([]byte, 16)
	copy(label, []byte("Self-Eq"))
	r := rs.Stream(label)

	for i := 1; i < 11; i++ {
		a, bInv := generateSelfEquivalence(r)
		out[i-1], _ = encoding.DecomposeBlockAffine(encoding.ComposedBlocks{out[i-1], a})
		out[i], _ = encoding.DecomposeBlockAffine(encoding.ComposedBlocks{bInv, out[i]})
	}

	return
}
Пример #2
0
// RecoverKey returns the AES key used to generate the given white-box construction.
func RecoverKey(constr *xiao.Construction) []byte {
	round1 := round{
		construction: constr,
		round:        1,
	}

	// Decomposition Phase
	constr1 := aspn.DecomposeSPN(round1, cspn.ASA)

	var (
		first, last = affineLayer(constr1[0].(encoding.BlockAffine)), affineLayer(constr1[2].(encoding.BlockAffine))
		middle      = sboxLayer(constr1[1].(encoding.ConcatenatedBlock))
	)

	// Disambiguation Phase
	// The SPN decomposition naturally leaves the last affine layer without a constant part. We would push it into the
	// middle S-boxes if that wasn't the case.

	// Put the affine layers in diagonal form.
	perm := first.findPermutation()
	permEnc := encoding.NewBlockLinear(perm)

	first.rightCompose(encoding.InverseBlock{permEnc})
	middle.permuteBy(perm, false)
	last.leftCompose(permEnc)

	// Whiten the S-boxes so that they are linearly equivalent to Sbar.
	mask := middle.whiten()
	encoding.XOR(first.BlockAdditive[:], first.BlockAdditive[:], mask[:])

	// Fix the S-boxes so that they are equal to Sbar.
	in, out := middle.cleanLinear()

	first.rightCompose(in)
	last.leftCompose(out)

	// Add ShiftRows matrix to make search possible.
	last.rightCompose(encoding.NewBlockLinear(constr.ShiftRows[2]))

	// Clean off remaining noise from self-equivalences of Sbar.
	left := last.cleanLeft()
	right := encoding.ComposedBlocks{
		middle, left, encoding.InverseBlock{middle},
	}

	first.rightCompose(right)

	// Convert Sbar back to AES's "standard" S-box.
	for pos := 0; pos < 16; pos++ {
		first.BlockAdditive[pos] ^= 0x52
		middle[pos] = encoding.ComposedBytes{encoding.ByteAdditive(0x52), middle[pos]}
	}

	// fmt.Println(encoding.ProbablyEquivalentBlocks(
	//   encoding.ComposedBlocks{first, middle, last},
	//   encoding.ComposedBlocks{aspn.Encoding{round1}, encoding.NewBlockLinear(constr.ShiftRows[2])},
	// ))
	// fmt.Println(encoding.ProbablyEquivalentBlocks(
	//   aspn.Encoding{constr1},
	//   aspn.Encoding{round1},
	// ))
	//
	// Output:
	//   true
	//   true

	roundKey := shiftrows{}.Decode(first.BlockAdditive)
	return backOneRound(roundKey[:], 1)
}
Пример #3
0
// shiftRoundKey adds the fixed SubBytes constant to a round key and returns the result as an encoding.Block.
func shiftRoundKey(key []byte) encoding.BlockAdditive {
	out := [16]byte{}
	encoding.XOR(out[:], subBytesConst, key)
	return encoding.BlockAdditive(out)
}