1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * AES (Rijndael) cipher - encrypt
3e28a4053SRui Paulo  *
4e28a4053SRui Paulo  * Modifications to public domain implementation:
5e28a4053SRui Paulo  * - cleanup
6e28a4053SRui Paulo  * - use C pre-processor to make it easier to change S table access
7e28a4053SRui Paulo  * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
8e28a4053SRui Paulo  *   cost of reduced throughput (quite small difference on Pentium 4,
9e28a4053SRui Paulo  *   10-25% when using -O1 or -O2 optimization)
10e28a4053SRui Paulo  *
11f05cddf9SRui Paulo  * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
12e28a4053SRui Paulo  *
13f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
14f05cddf9SRui Paulo  * See README for more details.
15e28a4053SRui Paulo  */
16e28a4053SRui Paulo 
17e28a4053SRui Paulo #include "includes.h"
18e28a4053SRui Paulo 
19e28a4053SRui Paulo #include "common.h"
20e28a4053SRui Paulo #include "crypto.h"
21e28a4053SRui Paulo #include "aes_i.h"
22e28a4053SRui Paulo 
rijndaelEncrypt(const u32 rk[],int Nr,const u8 pt[16],u8 ct[16])23f05cddf9SRui Paulo static void rijndaelEncrypt(const u32 rk[], int Nr, const u8 pt[16], u8 ct[16])
24e28a4053SRui Paulo {
25e28a4053SRui Paulo 	u32 s0, s1, s2, s3, t0, t1, t2, t3;
26e28a4053SRui Paulo #ifndef FULL_UNROLL
27e28a4053SRui Paulo 	int r;
28e28a4053SRui Paulo #endif /* ?FULL_UNROLL */
29e28a4053SRui Paulo 
30e28a4053SRui Paulo 	/*
31e28a4053SRui Paulo 	 * map byte array block to cipher state
32e28a4053SRui Paulo 	 * and add initial round key:
33e28a4053SRui Paulo 	 */
34e28a4053SRui Paulo 	s0 = GETU32(pt     ) ^ rk[0];
35e28a4053SRui Paulo 	s1 = GETU32(pt +  4) ^ rk[1];
36e28a4053SRui Paulo 	s2 = GETU32(pt +  8) ^ rk[2];
37e28a4053SRui Paulo 	s3 = GETU32(pt + 12) ^ rk[3];
38e28a4053SRui Paulo 
39e28a4053SRui Paulo #define ROUND(i,d,s) \
40e28a4053SRui Paulo d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
41e28a4053SRui Paulo d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
42e28a4053SRui Paulo d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
43e28a4053SRui Paulo d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
44e28a4053SRui Paulo 
45e28a4053SRui Paulo #ifdef FULL_UNROLL
46e28a4053SRui Paulo 
47e28a4053SRui Paulo 	ROUND(1,t,s);
48e28a4053SRui Paulo 	ROUND(2,s,t);
49e28a4053SRui Paulo 	ROUND(3,t,s);
50e28a4053SRui Paulo 	ROUND(4,s,t);
51e28a4053SRui Paulo 	ROUND(5,t,s);
52e28a4053SRui Paulo 	ROUND(6,s,t);
53e28a4053SRui Paulo 	ROUND(7,t,s);
54e28a4053SRui Paulo 	ROUND(8,s,t);
55e28a4053SRui Paulo 	ROUND(9,t,s);
56f05cddf9SRui Paulo 	if (Nr > 10) {
57f05cddf9SRui Paulo 		ROUND(10,s,t);
58f05cddf9SRui Paulo 		ROUND(11,t,s);
59f05cddf9SRui Paulo 		if (Nr > 12) {
60f05cddf9SRui Paulo 			ROUND(12,s,t);
61f05cddf9SRui Paulo 			ROUND(13,t,s);
62f05cddf9SRui Paulo 		}
63f05cddf9SRui Paulo 	}
64e28a4053SRui Paulo 
65e28a4053SRui Paulo 	rk += Nr << 2;
66e28a4053SRui Paulo 
67e28a4053SRui Paulo #else  /* !FULL_UNROLL */
68e28a4053SRui Paulo 
69e28a4053SRui Paulo 	/* Nr - 1 full rounds: */
70e28a4053SRui Paulo 	r = Nr >> 1;
71e28a4053SRui Paulo 	for (;;) {
72e28a4053SRui Paulo 		ROUND(1,t,s);
73e28a4053SRui Paulo 		rk += 8;
74e28a4053SRui Paulo 		if (--r == 0)
75e28a4053SRui Paulo 			break;
76e28a4053SRui Paulo 		ROUND(0,s,t);
77e28a4053SRui Paulo 	}
78e28a4053SRui Paulo 
79e28a4053SRui Paulo #endif /* ?FULL_UNROLL */
80e28a4053SRui Paulo 
81e28a4053SRui Paulo #undef ROUND
82e28a4053SRui Paulo 
83e28a4053SRui Paulo 	/*
84e28a4053SRui Paulo 	 * apply last round and
85e28a4053SRui Paulo 	 * map cipher state to byte array block:
86e28a4053SRui Paulo 	 */
87e28a4053SRui Paulo 	s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
88e28a4053SRui Paulo 	PUTU32(ct     , s0);
89e28a4053SRui Paulo 	s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
90e28a4053SRui Paulo 	PUTU32(ct +  4, s1);
91e28a4053SRui Paulo 	s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
92e28a4053SRui Paulo 	PUTU32(ct +  8, s2);
93e28a4053SRui Paulo 	s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
94e28a4053SRui Paulo 	PUTU32(ct + 12, s3);
95e28a4053SRui Paulo }
96e28a4053SRui Paulo 
97e28a4053SRui Paulo 
aes_encrypt_init(const u8 * key,size_t len)98e28a4053SRui Paulo void * aes_encrypt_init(const u8 *key, size_t len)
99e28a4053SRui Paulo {
100e28a4053SRui Paulo 	u32 *rk;
101f05cddf9SRui Paulo 	int res;
102*4bc52338SCy Schubert 
103*4bc52338SCy Schubert 	if (TEST_FAIL())
104*4bc52338SCy Schubert 		return NULL;
105*4bc52338SCy Schubert 
106e28a4053SRui Paulo 	rk = os_malloc(AES_PRIV_SIZE);
107e28a4053SRui Paulo 	if (rk == NULL)
108e28a4053SRui Paulo 		return NULL;
109f05cddf9SRui Paulo 	res = rijndaelKeySetupEnc(rk, key, len * 8);
110f05cddf9SRui Paulo 	if (res < 0) {
111f05cddf9SRui Paulo 		os_free(rk);
112f05cddf9SRui Paulo 		return NULL;
113f05cddf9SRui Paulo 	}
114f05cddf9SRui Paulo 	rk[AES_PRIV_NR_POS] = res;
115e28a4053SRui Paulo 	return rk;
116e28a4053SRui Paulo }
117e28a4053SRui Paulo 
118e28a4053SRui Paulo 
aes_encrypt(void * ctx,const u8 * plain,u8 * crypt)11985732ac8SCy Schubert int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
120e28a4053SRui Paulo {
121f05cddf9SRui Paulo 	u32 *rk = ctx;
122f05cddf9SRui Paulo 	rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt);
12385732ac8SCy Schubert 	return 0;
124e28a4053SRui Paulo }
125e28a4053SRui Paulo 
126e28a4053SRui Paulo 
aes_encrypt_deinit(void * ctx)127e28a4053SRui Paulo void aes_encrypt_deinit(void *ctx)
128e28a4053SRui Paulo {
129e28a4053SRui Paulo 	os_memset(ctx, 0, AES_PRIV_SIZE);
130e28a4053SRui Paulo 	os_free(ctx);
131e28a4053SRui Paulo }
132