Example #1
0
func TestMaskedEncrypt(t *testing.T) {
	cand, real := make([]byte, 16), make([]byte, 16)

	// Calculate the candidate output.
	constr, inputMask, outputMask := GenerateEncryptionKeys(key, seed, common.MatchingMasks{})

	inputInv, _ := inputMask.Invert()
	outputInv, _ := outputMask.Invert()

	in := make([]byte, 16)
	copy(in, inputInv.Mul(matrix.Row(input))) // Apply input encoding.

	constr.Encrypt(cand, in)
	constr.Encrypt(cand, cand)

	copy(cand, outputInv.Mul(matrix.Row(cand))) // Remove output encoding.

	// Calculate the real output.
	c, _ := aes.NewCipher(key)
	c.Encrypt(real, input)
	c.Encrypt(real, real)

	if !bytes.Equal(real, cand) {
		t.Fatalf("Real disagrees with result! %x != %x", real, cand)
	}
}
Example #2
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("Ful Construction", seed)

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

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

	// Generate an SPN which has the input and output masks, but is otherwise un-obfuscated.
	out[0] = decomposition[0].compose(&blockAffine{
		linear:   matrix.GenerateIdentity(128),
		constant: matrix.Row(roundKeys[0]),
	}).compose(input)
	copy(out[1:5], decomposition[1:5])

	for i := 1; i < 10; i++ {
		out[4*i+0] = decomposition[0].compose(&blockAffine{
			linear:   round,
			constant: matrix.Row(roundKeys[i]).Add(subBytesConst),
		}).compose(out[4*i+0])
		copy(out[4*i+1:4*i+5], decomposition[1:5])
	}

	out[40] = output.compose(&blockAffine{
		linear:   lastRound,
		constant: matrix.Row(roundKeys[10]).Add(subBytesConst),
	}).compose(out[40])

	// Sample 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 := 0; i < 40; i++ {
		a, bInv := generateSelfEquivalence(r, stateSize[i%4], compressSize[i%4])
		out[i] = a.compose(out[i])
		out[i+1] = out[i+1].compose(bInv)
	}

	return out, input.BlockAffine(), output.BlockAffine()
}
Example #3
0
func TestDecrypt(t *testing.T) {
	for n, vec := range test_vectors.GetAESVectors(testing.Short()) {
		constr, inputMask, outputMask := GenerateDecryptionKeys(
			vec.Key, vec.Key, common.IndependentMasks{common.RandomMask, common.RandomMask},
		)

		inputInv, _ := inputMask.Invert()
		outputInv, _ := outputMask.Invert()

		in, out := make([]byte, 16), make([]byte, 16)

		copy(in, inputInv.Mul(matrix.Row(vec.Out))) // Apply input encoding.

		constr.Decrypt(out, in)

		copy(out, outputInv.Mul(matrix.Row(out))) // Remove output encoding.

		if !bytes.Equal(vec.In, out) {
			t.Fatalf("Real disagrees with result in test vector %v! %x != %x", n, vec.In, out)
		}
	}
}
Example #4
0
func (bm BlockMatrix) Get(i byte) (out [16]byte) {
	r := make([]byte, 16)
	r[bm.Position] = i

	res := bm.Linear.Mul(matrix.Row(r))
	copy(out[:], res)

	for i, c := range bm.Constant {
		out[i] ^= c
	}

	return
}
Example #5
0
// Parse parses a byte array into a white-box construction. It returns an error if the byte slice isn't long enough.
func Parse(in []byte) (constr Construction, err error) {
	if len(in) != fullSize {
		err = errors.New("Parsing the key failed.")
		return
	}

	for round := 0; round < 11; round++ {
		forwards := matrix.Matrix{}
		constant := [16]byte{}

		for row := 0; row < 128; row++ {
			forwards = append(forwards, matrix.Row(in[:16]))
			in = in[16:]
		}
		copy(constant[:], in[:16])
		in = in[16:]

		constr[round] = encoding.NewBlockAffine(forwards, constant)
	}

	return
}