1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  * All rights reserved.
5  * Copyright (c) 2001-2007, Tom St Denis
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  * this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
32  *
33  * LibTomCrypt is a library that provides various cryptographic
34  * algorithms in a highly modular and flexible manner.
35  *
36  * The library is free for all purposes without any express
37  * guarantee it works.
38  *
39  * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
40  */
41 
42 /*
43  * AES cipher for ARMv8 with Crypto Extensions
44  *
45  * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
46  */
47 
48 #include <compiler.h>
49 #include <crypto/crypto_accel.h>
50 #include <tomcrypt_private.h>
51 
52 #define EXPANDED_AES_KEY_WORD_COUNT	60
53 #define EXPANDED_AES_KEY_LEN		(EXPANDED_AES_KEY_WORD_COUNT * \
54 					 sizeof(uint32_t))
55 
rijndael_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)56 int rijndael_setup(const unsigned char *key, int keylen, int num_rounds,
57 	      symmetric_key *skey)
58 {
59 	unsigned int round_count = 0;
60 
61 	LTC_ARGCHK(key);
62 	LTC_ARGCHK(skey);
63 
64 	if (keylen != 16 && keylen != 24 && keylen != 32)
65 		return CRYPT_INVALID_KEYSIZE;
66 
67 	skey->rijndael.eK = LTC_ALIGN_BUF(skey->rijndael.K, 16);
68 	skey->rijndael.dK = skey->rijndael.eK + EXPANDED_AES_KEY_WORD_COUNT;
69 
70 	if (crypto_accel_aes_expand_keys(key, keylen, skey->rijndael.eK,
71 					 skey->rijndael.dK,
72 					 EXPANDED_AES_KEY_LEN,
73 					 &round_count))
74 		return CRYPT_INVALID_ARG;
75 
76 	if (num_rounds && (unsigned int)num_rounds != round_count)
77 		return CRYPT_INVALID_ROUNDS;
78 
79 	skey->rijndael.Nr = round_count;
80 
81 	return CRYPT_OK;
82 }
83 
rijndael_done(symmetric_key * skey __unused)84 void rijndael_done(symmetric_key *skey __unused)
85 {
86 }
87 
rijndael_keysize(int * keysize)88 int rijndael_keysize(int *keysize)
89 {
90 	LTC_ARGCHK(keysize);
91 
92 	if (*keysize < 16)
93 		return CRYPT_INVALID_KEYSIZE;
94 	else if (*keysize < 24)
95 		*keysize = 16;
96 	else if (*keysize < 32)
97 		*keysize = 24;
98 	else
99 		*keysize = 32;
100 
101 	return CRYPT_OK;
102 }
103 
aes_ecb_encrypt_nblocks(const unsigned char * pt,unsigned char * ct,unsigned long blocks,const symmetric_key * skey)104 static int aes_ecb_encrypt_nblocks(const unsigned char *pt, unsigned char *ct,
105 				   unsigned long blocks,
106 				   const symmetric_key *skey)
107 {
108 	LTC_ARGCHK(pt);
109 	LTC_ARGCHK(ct);
110 	LTC_ARGCHK(skey);
111 
112 	crypto_accel_aes_ecb_enc(ct, pt, skey->rijndael.eK, skey->rijndael.Nr,
113 				 blocks);
114 	return CRYPT_OK;
115 }
116 
aes_ecb_decrypt_nblocks(const unsigned char * ct,unsigned char * pt,unsigned long blocks,const symmetric_key * skey)117 static int aes_ecb_decrypt_nblocks(const unsigned char *ct, unsigned char *pt,
118 				   unsigned long blocks,
119 				   const symmetric_key *skey)
120 {
121 	LTC_ARGCHK(pt);
122 	LTC_ARGCHK(ct);
123 	LTC_ARGCHK(skey);
124 
125 	crypto_accel_aes_ecb_dec(pt, ct, skey->rijndael.dK, skey->rijndael.Nr,
126 				 blocks);
127 
128 	return CRYPT_OK;
129 }
130 
rijndael_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)131 int rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
132 			 const symmetric_key *skey)
133 {
134 	return aes_ecb_encrypt_nblocks(pt, ct, 1, skey);
135 }
136 
rijndael_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)137 int rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
138 			 const symmetric_key *skey)
139 {
140 	return aes_ecb_decrypt_nblocks(ct, pt, 1, skey);
141 }
142 
aes_cbc_encrypt_nblocks(const unsigned char * pt,unsigned char * ct,unsigned long blocks,unsigned char * IV,symmetric_key * skey)143 static int aes_cbc_encrypt_nblocks(const unsigned char *pt, unsigned char *ct,
144 				   unsigned long blocks, unsigned char *IV,
145 				   symmetric_key *skey)
146 {
147 	LTC_ARGCHK(pt);
148 	LTC_ARGCHK(ct);
149 	LTC_ARGCHK(IV);
150 	LTC_ARGCHK(skey);
151 
152 	crypto_accel_aes_cbc_enc(ct, pt, skey->rijndael.eK, skey->rijndael.Nr,
153 				 blocks, IV);
154 
155 	return CRYPT_OK;
156 }
157 
aes_cbc_decrypt_nblocks(const unsigned char * ct,unsigned char * pt,unsigned long blocks,unsigned char * IV,symmetric_key * skey)158 static int aes_cbc_decrypt_nblocks(const unsigned char *ct, unsigned char *pt,
159 				   unsigned long blocks, unsigned char *IV,
160 				   symmetric_key *skey)
161 {
162 	LTC_ARGCHK(pt);
163 	LTC_ARGCHK(ct);
164 	LTC_ARGCHK(IV);
165 	LTC_ARGCHK(skey);
166 
167 	crypto_accel_aes_cbc_dec(pt, ct, skey->rijndael.dK, skey->rijndael.Nr,
168 				 blocks, IV);
169 
170 	return CRYPT_OK;
171 }
172 
173 #ifdef LTC_CTR_MODE
aes_ctr_encrypt_nblocks(const unsigned char * pt,unsigned char * ct,unsigned long blocks,unsigned char * IV,int mode,symmetric_key * skey)174 static int aes_ctr_encrypt_nblocks(const unsigned char *pt, unsigned char *ct,
175 				   unsigned long blocks, unsigned char *IV,
176 				   int mode, symmetric_key *skey)
177 {
178 	LTC_ARGCHK(pt);
179 	LTC_ARGCHK(ct);
180 	LTC_ARGCHK(IV);
181 	LTC_ARGCHK(skey);
182 
183 	if (mode == CTR_COUNTER_LITTLE_ENDIAN) {
184 		/* Accelerated algorithm supports big endian only */
185 		return CRYPT_ERROR;
186 	}
187 
188 	crypto_accel_aes_ctr_be_enc(ct, pt, skey->rijndael.eK,
189 				    skey->rijndael.Nr, blocks, IV);
190 
191 	return CRYPT_OK;
192 }
193 #endif
194 
aes_xts_encrypt_nblocks(const unsigned char * pt,unsigned char * ct,unsigned long blocks,unsigned char * tweak,const symmetric_key * skey1,const symmetric_key * skey2)195 static int aes_xts_encrypt_nblocks(const unsigned char *pt, unsigned char *ct,
196 				   unsigned long blocks, unsigned char *tweak,
197 				   const symmetric_key *skey1,
198 				   const symmetric_key *skey2)
199 {
200 	LTC_ARGCHK(pt);
201 	LTC_ARGCHK(ct);
202 	LTC_ARGCHK(tweak);
203 	LTC_ARGCHK(skey1);
204 	LTC_ARGCHK(skey2);
205 	LTC_ARGCHK(skey1->rijndael.Nr == skey2->rijndael.Nr);
206 
207 
208 	crypto_accel_aes_xts_enc(ct, pt, skey1->rijndael.eK,
209 				 skey1->rijndael.Nr, blocks,
210 				 skey2->rijndael.eK, tweak);
211 
212 	return CRYPT_OK;
213 }
214 
aes_xts_decrypt_nblocks(const unsigned char * ct,unsigned char * pt,unsigned long blocks,unsigned char * tweak,const symmetric_key * skey1,const symmetric_key * skey2)215 static int aes_xts_decrypt_nblocks(const unsigned char *ct, unsigned char *pt,
216 				   unsigned long blocks, unsigned char *tweak,
217 				   const symmetric_key *skey1,
218 				   const symmetric_key *skey2)
219 {
220 	LTC_ARGCHK(pt);
221 	LTC_ARGCHK(ct);
222 	LTC_ARGCHK(tweak);
223 	LTC_ARGCHK(skey1);
224 	LTC_ARGCHK(skey2);
225 	LTC_ARGCHK(skey1->rijndael.Nr == skey2->rijndael.Nr);
226 
227 	crypto_accel_aes_xts_dec(pt, ct, skey1->rijndael.dK,
228 				 skey1->rijndael.Nr, blocks,
229 				 skey2->rijndael.eK, tweak);
230 
231 	return CRYPT_OK;
232 }
233 
234 const struct ltc_cipher_descriptor aes_desc = {
235 	.name = "aes",
236 	.ID = 6,
237 	.min_key_length = 16,
238 	.max_key_length = 32,
239 	.block_length = 16,
240 	.default_rounds = 10,
241 	.setup = rijndael_setup,
242 	.ecb_encrypt = rijndael_ecb_encrypt,
243 	.ecb_decrypt = rijndael_ecb_decrypt,
244 	.done = rijndael_done,
245 	.keysize = rijndael_keysize,
246 	.accel_ecb_encrypt = aes_ecb_encrypt_nblocks,
247 	.accel_ecb_decrypt = aes_ecb_decrypt_nblocks,
248 	.accel_cbc_encrypt = aes_cbc_encrypt_nblocks,
249 	.accel_cbc_decrypt = aes_cbc_decrypt_nblocks,
250 #ifdef LTC_CTR_MODE
251 	.accel_ctr_encrypt = aes_ctr_encrypt_nblocks,
252 #endif
253 	.accel_xts_encrypt = aes_xts_encrypt_nblocks,
254 	.accel_xts_decrypt = aes_xts_decrypt_nblocks,
255 };
256