1/* 2 --------------------------------------------------------------------------- 3 Copyright (c) 2003, Dr Brian Gladman, Worcester, UK. All rights reserved. 4 5 LICENSE TERMS 6 7 The free distribution and use of this software in both source and binary 8 form is allowed (with or without changes) provided that: 9 10 1. distributions of this source code include the above copyright 11 notice, this list of conditions and the following disclaimer; 12 13 2. distributions in binary form include the above copyright 14 notice, this list of conditions and the following disclaimer 15 in the documentation and/or other associated materials; 16 17 3. the copyright holder's name is not used to endorse products 18 built using this software without specific written permission. 19 20 ALTERNATIVELY, provided that this notice is retained in full, this product 21 may be distributed under the terms of the GNU General Public License (GPL), 22 in which case the provisions of the GPL apply INSTEAD OF those given above. 23 24 DISCLAIMER 25 26 This software is provided 'as is' with no explicit or implied warranties 27 in respect of its properties, including, but not limited to, correctness 28 and/or fitness for purpose. 29 --------------------------------------------------------------------------- 30 Issue 31/01/2006 31 32 These subroutines implement multiple block AES modes for ECB, CBC, CFB, 33 OFB and CTR encryption, The code provides support for the VIA Advanced 34 Cryptography Engine (ACE). 35 36 NOTE: In the following subroutines, the AES contexts (ctx) must be 37 16 byte aligned if VIA ACE is being used 38*/ 39 40//#include <memory.h> 41#include <kern/assert.h> 42 43#include "aesopt.h" 44 45#if defined( AES_MODES ) 46#if defined(__cplusplus) 47extern "C" 48{ 49#endif 50 51#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) 52#pragma intrinsic(memcpy) 53#define in_line __inline 54#else 55#define in_line 56#endif 57 58#define BFR_BLOCKS 8 59 60/* These values are used to detect long word alignment in order to */ 61/* speed up some buffer operations. This facility may not work on */ 62/* some machines so this define can be commented out if necessary */ 63 64#define FAST_BUFFER_OPERATIONS 65#pragma warning( disable : 4311 4312 ) 66 67#define lp08(x) ((uint_8t*)(x)) 68#define lp32(x) ((uint_32t*)(x)) 69#define addr_mod_04(x) ((unsigned long)(x) & 3) 70#define addr_mod_16(x) ((unsigned long)(x) & 15) 71 72#if defined( USE_VIA_ACE_IF_PRESENT ) 73 74#include "via_ace.h" 75 76#pragma pack(16) 77 78aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA; 79aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA; 80aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA; 81aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA; 82aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA; 83aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA; 84 85/* NOTE: These control word macros must only be used after */ 86/* a key has been set up because they depend on key size */ 87 88#if NEH_KEY_TYPE == NEH_LOAD 89#define kd_adr(c) ((uint_8t*)(c)->ks) 90#elif NEH_KEY_TYPE == NEH_GENERATE 91#define kd_adr(c) ((uint_8t*)(c)->ks + (c)->inf.b[0]) 92#else 93#define kd_adr(c) ((uint_8t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0)) 94#endif 95 96#else 97 98#define aligned_array(type, name, no, stride) type name[no] 99#define aligned_auto(type, name, no, stride) type name[no] 100 101#endif 102 103#if defined( _MSC_VER ) && _MSC_VER > 1200 104 105#define via_cwd(cwd, ty, dir, len) unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4)) 106 107#else 108 109#define via_cwd(cwd, ty, dir, len) \ 110 aligned_auto(unsigned long, cwd, 4, 16); \ 111 cwd[1] = cwd[2] = cwd[3] = 0; \ 112 cwd[0] = neh_##dir##_##ty##_key(len) 113 114#endif 115 116/* implemented in case of wrong call for fixed tables */ 117void gen_tabs(void) 118{ 119} 120 121aes_rval aes_mode_reset(aes_encrypt_ctx ctx[1]) 122{ 123 ctx->inf.b[2] = 0; 124 return 0; 125} 126 127aes_rval aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, 128 int len, const aes_encrypt_ctx ctx[1]) 129{ int nb = len >> 4; 130 131 if(len & (AES_BLOCK_SIZE - 1)) 132 return 1; 133 134#if defined( USE_VIA_ACE_IF_PRESENT ) 135 136 if(ctx->inf.b[1] == 0xff) 137 { uint_8t *ksp = (uint_8t*)(ctx->ks); 138 via_cwd(cwd, hybrid, enc, 2* ctx->inf.b[0] - 192); 139 140 if(addr_mod_16(ctx)) 141 return 1; 142 143 if(!addr_mod_16(ibuf) && !addr_mod_16(obuf)) 144 { 145 via_ecb_op5(ksp,cwd,ibuf,obuf,nb); 146 } 147 else 148 { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); 149 uint_8t *ip, *op; 150 151 while(nb) 152 { 153 int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); 154 155 ip = (addr_mod_16(ibuf) ? buf : (uint_8t*)ibuf); 156 op = (addr_mod_16(obuf) ? buf : obuf); 157 158 if(ip != ibuf) 159 memcpy(buf, ibuf, m * AES_BLOCK_SIZE); 160 161 via_ecb_op5(ksp,cwd,ip,op,m); 162 163 if(op != obuf) 164 memcpy(obuf, buf, m * AES_BLOCK_SIZE); 165 166 ibuf += m * AES_BLOCK_SIZE; 167 obuf += m * AES_BLOCK_SIZE; 168 nb -= m; 169 } 170 } 171 172 return 0; 173 } 174 175#endif 176 177#if !defined( ASSUME_VIA_ACE_PRESENT ) 178 while(nb--) 179 { 180 aes_encrypt(ibuf, obuf, ctx); 181 ibuf += AES_BLOCK_SIZE; 182 obuf += AES_BLOCK_SIZE; 183 } 184#endif 185 return 0; 186} 187 188aes_rval aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, 189 int len, const aes_decrypt_ctx ctx[1]) 190{ int nb = len >> 4; 191 192 if(len & (AES_BLOCK_SIZE - 1)) 193 return 1; 194 195#if defined( USE_VIA_ACE_IF_PRESENT ) 196 197 if(ctx->inf.b[1] == 0xff) 198 { uint_8t *ksp = kd_adr(ctx); 199 via_cwd(cwd, hybrid, dec, 2* ctx->inf.b[0] - 192); 200 201 if(addr_mod_16(ctx)) 202 return 1; 203 204 if(!addr_mod_16(ibuf) && !addr_mod_16(obuf)) 205 { 206 via_ecb_op5(ksp,cwd,ibuf,obuf,nb); 207 } 208 else 209 { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); 210 uint_8t *ip, *op; 211 212 while(nb) 213 { 214 int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); 215 216 ip = (addr_mod_16(ibuf) ? buf : (uint_8t*)ibuf); 217 op = (addr_mod_16(obuf) ? buf : obuf); 218 219 if(ip != ibuf) 220 memcpy(buf, ibuf, m * AES_BLOCK_SIZE); 221 222 via_ecb_op5(ksp,cwd,ip,op,m); 223 224 if(op != obuf) 225 memcpy(obuf, buf, m * AES_BLOCK_SIZE); 226 227 ibuf += m * AES_BLOCK_SIZE; 228 obuf += m * AES_BLOCK_SIZE; 229 nb -= m; 230 } 231 } 232 233 return 0; 234 } 235 236#endif 237 238#if !defined( ASSUME_VIA_ACE_PRESENT ) 239 while(nb--) 240 { 241 aes_decrypt(ibuf, obuf, ctx); 242 ibuf += AES_BLOCK_SIZE; 243 obuf += AES_BLOCK_SIZE; 244 } 245#endif 246 return 0; 247} 248 249aes_rval aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, 250 int len, unsigned char *iv, const aes_encrypt_ctx ctx[1]) 251{ int nb = len >> 4; 252 253 if(len & (AES_BLOCK_SIZE - 1)) 254 return 1; 255 256#if defined( USE_VIA_ACE_IF_PRESENT ) 257 258 if(ctx->inf.b[1] == 0xff) 259 { uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; 260 aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); 261 via_cwd(cwd, hybrid, enc, 2* ctx->inf.b[0] - 192); 262 263 if(addr_mod_16(ctx)) 264 return 1; 265 266 if(addr_mod_16(iv)) /* ensure an aligned iv */ 267 { 268 ivp = liv; 269 memcpy(liv, iv, AES_BLOCK_SIZE); 270 } 271 272 if(!addr_mod_16(ibuf) && !addr_mod_16(obuf) && !addr_mod_16(iv)) 273 { 274 via_cbc_op7(ksp,cwd,ibuf,obuf,nb,ivp,ivp); 275 } 276 else 277 { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); 278 uint_8t *ip, *op; 279 280 while(nb) 281 { 282 int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); 283 284 ip = (addr_mod_16(ibuf) ? buf : (uint_8t*)ibuf); 285 op = (addr_mod_16(obuf) ? buf : obuf); 286 287 if(ip != ibuf) 288 memcpy(buf, ibuf, m * AES_BLOCK_SIZE); 289 290 via_cbc_op7(ksp,cwd,ip,op,m,ivp,ivp); 291 292 if(op != obuf) 293 memcpy(obuf, buf, m * AES_BLOCK_SIZE); 294 295 ibuf += m * AES_BLOCK_SIZE; 296 obuf += m * AES_BLOCK_SIZE; 297 nb -= m; 298 } 299 } 300 301 if(iv != ivp) 302 memcpy(iv, ivp, AES_BLOCK_SIZE); 303 304 return 0; 305 } 306 307#endif 308 309#if !defined( ASSUME_VIA_ACE_PRESENT ) 310# ifdef FAST_BUFFER_OPERATIONS 311 if(!addr_mod_04(ibuf) && !addr_mod_04(iv)) 312 while(nb--) 313 { 314 lp32(iv)[0] ^= lp32(ibuf)[0]; 315 lp32(iv)[1] ^= lp32(ibuf)[1]; 316 lp32(iv)[2] ^= lp32(ibuf)[2]; 317 lp32(iv)[3] ^= lp32(ibuf)[3]; 318 aes_encrypt(iv, iv, ctx); 319 memcpy(obuf, iv, AES_BLOCK_SIZE); 320 ibuf += AES_BLOCK_SIZE; 321 obuf += AES_BLOCK_SIZE; 322 } 323 else 324# endif 325 while(nb--) 326 { 327 iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1]; 328 iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3]; 329 iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5]; 330 iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7]; 331 iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9]; 332 iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11]; 333 iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13]; 334 iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15]; 335 aes_encrypt(iv, iv, ctx); 336 memcpy(obuf, iv, AES_BLOCK_SIZE); 337 ibuf += AES_BLOCK_SIZE; 338 obuf += AES_BLOCK_SIZE; 339 } 340#endif 341 return 0; 342} 343 344aes_rval aes_encrypt_cbc(const unsigned char *in_blk, const unsigned char *in_iv, unsigned int num_blk, 345 unsigned char *out_blk, const aes_encrypt_ctx cx[1]) 346{ 347 unsigned char tmp_iv[16]; 348 int i; 349 350 for (i = 0; i < 16; i++) 351 tmp_iv[i] = *(in_iv + i); 352 353 return aes_cbc_encrypt(in_blk, out_blk, num_blk<<4, tmp_iv, cx); 354 355} 356 357aes_rval aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, 358 int len, unsigned char *iv, const aes_decrypt_ctx ctx[1]) 359{ unsigned char tmp[AES_BLOCK_SIZE]; 360 int nb = len >> 4; 361 362 if(len & (AES_BLOCK_SIZE - 1)) 363 return 1; 364 365#if defined( USE_VIA_ACE_IF_PRESENT ) 366 367 if(ctx->inf.b[1] == 0xff) 368 { uint_8t *ksp = kd_adr(ctx), *ivp = iv; 369 aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); 370 via_cwd(cwd, hybrid, dec, 2* ctx->inf.b[0] - 192); 371 372 if(addr_mod_16(ctx)) 373 return 1; 374 375 if(addr_mod_16(iv)) /* ensure an aligned iv */ 376 { 377 ivp = liv; 378 memcpy(liv, iv, AES_BLOCK_SIZE); 379 } 380 381 if(!addr_mod_16(ibuf) && !addr_mod_16(obuf) && !addr_mod_16(iv)) 382 { 383 via_cbc_op6(ksp,cwd,ibuf,obuf,nb,ivp); 384 } 385 else 386 { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); 387 uint_8t *ip, *op; 388 389 while(nb) 390 { 391 int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); 392 393 ip = (addr_mod_16(ibuf) ? buf : (uint_8t*)ibuf); 394 op = (addr_mod_16(obuf) ? buf : obuf); 395 396 if(ip != ibuf) 397 memcpy(buf, ibuf, m * AES_BLOCK_SIZE); 398 399 via_cbc_op6(ksp,cwd,ip,op,m,ivp); 400 401 if(op != obuf) 402 memcpy(obuf, buf, m * AES_BLOCK_SIZE); 403 404 ibuf += m * AES_BLOCK_SIZE; 405 obuf += m * AES_BLOCK_SIZE; 406 nb -= m; 407 } 408 } 409 410 if(iv != ivp) 411 memcpy(iv, ivp, AES_BLOCK_SIZE); 412 413 return 0; 414 } 415#endif 416 417#if !defined( ASSUME_VIA_ACE_PRESENT ) 418# ifdef FAST_BUFFER_OPERATIONS 419 if(!addr_mod_04(obuf) && !addr_mod_04(iv)) 420 while(nb--) 421 { 422 memcpy(tmp, ibuf, AES_BLOCK_SIZE); 423 aes_decrypt(ibuf, obuf, ctx); 424 lp32(obuf)[0] ^= lp32(iv)[0]; 425 lp32(obuf)[1] ^= lp32(iv)[1]; 426 lp32(obuf)[2] ^= lp32(iv)[2]; 427 lp32(obuf)[3] ^= lp32(iv)[3]; 428 memcpy(iv, tmp, AES_BLOCK_SIZE); 429 ibuf += AES_BLOCK_SIZE; 430 obuf += AES_BLOCK_SIZE; 431 } 432 else 433# endif 434 while(nb--) 435 { 436 memcpy(tmp, ibuf, AES_BLOCK_SIZE); 437 aes_decrypt(ibuf, obuf, ctx); 438 obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1]; 439 obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3]; 440 obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5]; 441 obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7]; 442 obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9]; 443 obuf[10] ^= iv[10]; obuf[11] ^= iv[11]; 444 obuf[12] ^= iv[12]; obuf[13] ^= iv[13]; 445 obuf[14] ^= iv[14]; obuf[15] ^= iv[15]; 446 memcpy(iv, tmp, AES_BLOCK_SIZE); 447 ibuf += AES_BLOCK_SIZE; 448 obuf += AES_BLOCK_SIZE; 449 } 450#endif 451 return 0; 452} 453 454aes_rval aes_decrypt_cbc(const unsigned char *in_blk, const unsigned char *in_iv, unsigned int num_blk, 455 unsigned char *out_blk, const aes_decrypt_ctx cx[1]) 456{ 457 unsigned char tmp_iv[16]; 458 int i; 459 460 for (i = 0; i < 16; i++) 461 tmp_iv[i] = *(in_iv + i); 462 463 return aes_cbc_decrypt(in_blk, out_blk, num_blk<<4, tmp_iv, cx); 464 465} 466 467 468#if defined(__cplusplus) 469} 470#endif 471#endif 472