Software APIs
aes.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 /**
5  * NOTE: The only intended use of this code is to serve as a PRNG for generating
6  * input data for SCA experiments and penetration testing.
7  * The library is not hardened against any type of attacks, and it should not be
8  * used for any purpose other than stated.
9  *
10  * During the SCA experiments, encryptions are verified on the host side by
11  * running the same encryption using PyCryptodome package and comparing the
12  * result.
13  *
14  * Implementation of round-functions is based on a transposed-state technique
15  * for 32-bit architecture presented in:
16  *
17  * [1] Bertoni et. al., Efficient Software Implementation of AES on 32-Bit
18  * Platforms, CHES 2002.
19  *
20  * https://link.springer.com/content/pdf/10.1007/3-540-36400-5_13.pdf
21  *
22  */
23 #include "aes.h"
24 
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 
30 
31 enum {
32  kAesNumRounds = 10,
33  kAesNumKeyBytes = 16,
34  kAesNumTextBytes = 16,
35  kAesNumStateBytes = 16,
36  kAesNumStateWords = 4
37 };
38 
39 static void aes_add_round_key(uint32_t *state, const uint32_t *round_key) {
40  state[0] ^= round_key[0];
41  state[1] ^= round_key[1];
42  state[2] ^= round_key[2];
43  state[3] ^= round_key[3];
44 }
45 
46 static void aes_sub_bytes(uint32_t *state) {
47  // SubBytes on a transposed state
48  // Section 3.1 of [1]
49  for (size_t i = 0; i < 4; ++i) {
50  state[i] = (uint32_t)kSbox[state[i] & 0xff] |
51  ((uint32_t)kSbox[(state[i] >> 8) & 0xff] << 8) |
52  ((uint32_t)kSbox[(state[i] >> 16) & 0xff] << 16) |
53  ((uint32_t)kSbox[(state[i] >> 24) & 0xff] << 24);
54  }
55 }
56 
57 static uint32_t aes_mul2(uint32_t s) {
58  // Multiplication by 2 in Rijndael field.
59  // Each byte of the 32b input word is multiplied.
60  uint32_t t;
61  t = (uint32_t)kMul2[s & 0xff] | ((uint32_t)kMul2[(s >> 8) & 0xff] << 8) |
62  ((uint32_t)kMul2[(s >> 16) & 0xff] << 16) |
63  ((uint32_t)kMul2[(s >> 24) & 0xff] << 24);
64  return t;
65 }
66 
67 static void aes_shift_rows(uint32_t *state) {
68  // ShiftRows on a transposed state
69  // Section 3.1 of [1]
70  state[1] = (state[1] >> 8) | (state[1] << 24);
71  state[2] = (state[2] >> 16) | (state[2] << 16);
72  state[3] = (state[3] >> 24) | (state[3] << 8);
73 }
74 
75 static void aes_mix_columns(uint32_t *state) {
76  // MixColumns on a transposed state
77  // Section 3.1 of [1]
78  uint32_t temp[kAesNumStateWords];
79 
80  memcpy(temp, state, kAesNumStateBytes);
81 
82  state[0] = temp[1] ^ temp[2] ^ temp[3];
83  state[1] = temp[0] ^ temp[2] ^ temp[3];
84  state[2] = temp[0] ^ temp[1] ^ temp[3];
85  state[3] = temp[0] ^ temp[1] ^ temp[2];
86 
87  temp[0] = aes_mul2(temp[0]);
88  temp[1] = aes_mul2(temp[1]);
89  temp[2] = aes_mul2(temp[2]);
90  temp[3] = aes_mul2(temp[3]);
91 
92  state[0] ^= temp[0] ^ temp[1];
93  state[1] ^= temp[1] ^ temp[2];
94  state[2] ^= temp[2] ^ temp[3];
95  state[3] ^= temp[3] ^ temp[0];
96 }
97 
98 static void aes_transpose_to_32(uint8_t *in_data, uint32_t *out_data) {
99  out_data[0] = (uint32_t)in_data[0] | ((uint32_t)in_data[4] << 8) |
100  ((uint32_t)in_data[8] << 16) | ((uint32_t)in_data[12] << 24);
101  out_data[1] = (uint32_t)in_data[1] | ((uint32_t)in_data[5] << 8) |
102  ((uint32_t)in_data[9] << 16) | ((uint32_t)in_data[13] << 24);
103  out_data[2] = (uint32_t)in_data[2] | ((uint32_t)in_data[6] << 8) |
104  ((uint32_t)in_data[10] << 16) | ((uint32_t)in_data[14] << 24);
105  out_data[3] = (uint32_t)in_data[3] | ((uint32_t)in_data[7] << 8) |
106  ((uint32_t)in_data[11] << 16) | ((uint32_t)in_data[15] << 24);
107 }
108 
109 static void aes_transpose_from_32(uint32_t *in_data, uint8_t *out_data) {
110  out_data[0] = (uint8_t)(in_data[0] & 0xff);
111  out_data[1] = (uint8_t)(in_data[1] & 0xff);
112  out_data[2] = (uint8_t)(in_data[2] & 0xff);
113  out_data[3] = (uint8_t)(in_data[3] & 0xff);
114  out_data[4] = (uint8_t)(in_data[0] >> 8) & 0xff;
115  out_data[5] = (uint8_t)(in_data[1] >> 8) & 0xff;
116  out_data[6] = (uint8_t)(in_data[2] >> 8) & 0xff;
117  out_data[7] = (uint8_t)(in_data[3] >> 8) & 0xff;
118  out_data[8] = (uint8_t)(in_data[0] >> 16) & 0xff;
119  out_data[9] = (uint8_t)(in_data[1] >> 16) & 0xff;
120  out_data[10] = (uint8_t)(in_data[2] >> 16) & 0xff;
121  out_data[11] = (uint8_t)(in_data[3] >> 16) & 0xff;
122  out_data[12] = (uint8_t)(in_data[0] >> 24) & 0xff;
123  out_data[13] = (uint8_t)(in_data[1] >> 24) & 0xff;
124  out_data[14] = (uint8_t)(in_data[2] >> 24) & 0xff;
125  out_data[15] = (uint8_t)(in_data[3] >> 24) & 0xff;
126 }
127 
128 static uint8_t aes_rcon_next(uint8_t rcon) {
129  // rcon cannot be 0
130  if (rcon != 0) {
131  // update round constant
132  return kMul2[rcon];
133  } else {
134  // init round constant to first-round value
135  return 0x1;
136  }
137 }
138 
139 static void aes_key_expand(uint8_t *round_key, uint8_t *rcon) {
140  uint8_t temp[kAesNumStateWords];
141  uint8_t old_key[kAesNumKeyBytes];
142 
143  // copy key to temp
144  memcpy(old_key, round_key, kAesNumKeyBytes);
145 
146  // shift last word
147  temp[0] = old_key[13];
148  temp[1] = old_key[14];
149  temp[2] = old_key[15];
150  temp[3] = old_key[12];
151 
152  // sub bytes in last word
153  temp[0] = kSbox[temp[0]];
154  temp[1] = kSbox[temp[1]];
155  temp[2] = kSbox[temp[2]];
156  temp[3] = kSbox[temp[3]];
157 
158  // update rcon
159  *rcon = aes_rcon_next(*rcon);
160 
161  // get new words
162  round_key[0] = temp[0] ^ old_key[0] ^ *rcon;
163  round_key[1] = temp[1] ^ old_key[1];
164  round_key[2] = temp[2] ^ old_key[2];
165  round_key[3] = temp[3] ^ old_key[3];
166 
167  for (size_t i = 4; i < kAesNumKeyBytes; ++i) {
168  round_key[i] = round_key[i - 4] ^ old_key[i];
169  }
170 }
171 
172 void aes_key_schedule(uint32_t *round_keys, const uint8_t *key) {
173  // Derives all round keys for AES128
174  // Each key is storred in 4 32-bit words in a transposed-state form.
175  uint8_t rcon = 0;
176  uint8_t key_temp[kAesNumKeyBytes];
177  uint32_t key_temp_32[kAesNumStateWords];
178 
179  memcpy(key_temp, key, kAesNumKeyBytes);
180  aes_transpose_to_32(key_temp, key_temp_32);
181  memcpy(round_keys, key_temp_32, kAesNumKeyBytes);
182  for (size_t i = 1; i < kAesNumRounds + 1; ++i) {
183  aes_key_expand(key_temp, &rcon);
184  aes_transpose_to_32(key_temp, key_temp_32);
185  memcpy(round_keys + i * kAesNumStateWords, key_temp_32, kAesNumKeyBytes);
186  }
187 }
188 
189 void aes_sw_encrypt_block(const uint8_t *plain_text, const uint32_t *round_keys,
190  uint8_t *cipher_text) {
191  uint32_t state[kAesNumStateWords];
192 
193  // initially transpose state
194  uint8_t pt[kAesNumTextBytes];
195  memcpy(pt, plain_text, kAesNumTextBytes);
196  aes_transpose_to_32(pt, state);
197 
198  // encrypt
199  aes_add_round_key(state, round_keys);
200  for (int j = 0; j < kAesNumRounds - 1; ++j) {
201  aes_sub_bytes(state);
202  aes_shift_rows(state);
203  aes_mix_columns(state);
204  aes_add_round_key(state, round_keys + (j + 1) * kAesNumStateWords);
205  }
206  aes_sub_bytes(state);
207  aes_shift_rows(state);
208  aes_add_round_key(state, round_keys + kAesNumStateWords * kAesNumRounds);
209 
210  // transpose the result back into the byte form
211  aes_transpose_from_32(state, cipher_text);
212 }