1#! /usr/bin/env perl 2# Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved. 3# 4# Licensed under the OpenSSL license (the "License"). You may not use 5# this file except in compliance with the License. You can obtain a copy 6# in the file LICENSE in the source distribution or at 7# https://www.openssl.org/source/license.html 8 9 10###################################################################### 11## Constant-time SSSE3 AES core implementation. 12## version 0.1 13## 14## By Mike Hamburg (Stanford University), 2009 15## Public domain. 16## 17## For details see http://shiftleft.org/papers/vector_aes/ and 18## http://crypto.stanford.edu/vpaes/. 19 20###################################################################### 21# September 2011. 22# 23# Port vpaes-x86_64.pl as 32-bit "almost" drop-in replacement for 24# aes-586.pl. "Almost" refers to the fact that AES_cbc_encrypt 25# doesn't handle partial vectors (doesn't have to if called from 26# EVP only). "Drop-in" implies that this module doesn't share key 27# schedule structure with the original nor does it make assumption 28# about its alignment... 29# 30# Performance summary. aes-586.pl column lists large-block CBC 31# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per 32# byte processed with 128-bit key, and vpaes-x86.pl column - [also 33# large-block CBC] encrypt/decrypt. 34# 35# aes-586.pl vpaes-x86.pl 36# 37# Core 2(**) 28.1/41.4/18.3 21.9/25.2(***) 38# Nehalem 27.9/40.4/18.1 10.2/11.9 39# Atom 70.7/92.1/60.1 61.1/75.4(***) 40# Silvermont 45.4/62.9/24.1 49.2/61.1(***) 41# 42# (*) "Hyper-threading" in the context refers rather to cache shared 43# among multiple cores, than to specifically Intel HTT. As vast 44# majority of contemporary cores share cache, slower code path 45# is common place. In other words "with-hyper-threading-off" 46# results are presented mostly for reference purposes. 47# 48# (**) "Core 2" refers to initial 65nm design, a.k.a. Conroe. 49# 50# (***) Less impressive improvement on Core 2 and Atom is due to slow 51# pshufb, yet it's respectable +28%/64% improvement on Core 2 52# and +15% on Atom (as implied, over "hyper-threading-safe" 53# code path). 54# 55# <appro@openssl.org> 56 57$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; 58push(@INC,"${dir}","${dir}../../../perlasm"); 59require "x86asm.pl"; 60 61$output = pop; 62open OUT,">$output"; 63*STDOUT=*OUT; 64 65&asm_init($ARGV[0],$x86only = $ARGV[$#ARGV] eq "386"); 66 67$PREFIX="vpaes"; 68 69my ($round, $base, $magic, $key, $const, $inp, $out)= 70 ("eax", "ebx", "ecx", "edx","ebp", "esi","edi"); 71 72&preprocessor_ifdef("BORINGSSL_DISPATCH_TEST") 73&external_label("BORINGSSL_function_hit"); 74&preprocessor_endif(); 75&static_label("_vpaes_consts"); 76&static_label("_vpaes_schedule_low_round"); 77 78&set_label("_vpaes_consts",64); 79$k_inv=-0x30; # inv, inva 80 &data_word(0x0D080180,0x0E05060F,0x0A0B0C02,0x04070309); 81 &data_word(0x0F0B0780,0x01040A06,0x02050809,0x030D0E0C); 82 83$k_s0F=-0x10; # s0F 84 &data_word(0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F); 85 86$k_ipt=0x00; # input transform (lo, hi) 87 &data_word(0x5A2A7000,0xC2B2E898,0x52227808,0xCABAE090); 88 &data_word(0x317C4D00,0x4C01307D,0xB0FDCC81,0xCD80B1FC); 89 90$k_sb1=0x20; # sb1u, sb1t 91 &data_word(0xCB503E00,0xB19BE18F,0x142AF544,0xA5DF7A6E); 92 &data_word(0xFAE22300,0x3618D415,0x0D2ED9EF,0x3BF7CCC1); 93$k_sb2=0x40; # sb2u, sb2t 94 &data_word(0x0B712400,0xE27A93C6,0xBC982FCD,0x5EB7E955); 95 &data_word(0x0AE12900,0x69EB8840,0xAB82234A,0xC2A163C8); 96$k_sbo=0x60; # sbou, sbot 97 &data_word(0x6FBDC700,0xD0D26D17,0xC502A878,0x15AABF7A); 98 &data_word(0x5FBB6A00,0xCFE474A5,0x412B35FA,0x8E1E90D1); 99 100$k_mc_forward=0x80; # mc_forward 101 &data_word(0x00030201,0x04070605,0x080B0A09,0x0C0F0E0D); 102 &data_word(0x04070605,0x080B0A09,0x0C0F0E0D,0x00030201); 103 &data_word(0x080B0A09,0x0C0F0E0D,0x00030201,0x04070605); 104 &data_word(0x0C0F0E0D,0x00030201,0x04070605,0x080B0A09); 105 106$k_mc_backward=0xc0; # mc_backward 107 &data_word(0x02010003,0x06050407,0x0A09080B,0x0E0D0C0F); 108 &data_word(0x0E0D0C0F,0x02010003,0x06050407,0x0A09080B); 109 &data_word(0x0A09080B,0x0E0D0C0F,0x02010003,0x06050407); 110 &data_word(0x06050407,0x0A09080B,0x0E0D0C0F,0x02010003); 111 112$k_sr=0x100; # sr 113 &data_word(0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C); 114 &data_word(0x0F0A0500,0x030E0904,0x07020D08,0x0B06010C); 115 &data_word(0x0B020900,0x0F060D04,0x030A0108,0x070E050C); 116 &data_word(0x070A0D00,0x0B0E0104,0x0F020508,0x0306090C); 117 118$k_rcon=0x140; # rcon 119 &data_word(0xAF9DEEB6,0x1F8391B9,0x4D7C7D81,0x702A9808); 120 121$k_s63=0x150; # s63: all equal to 0x63 transformed 122 &data_word(0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B); 123 124$k_opt=0x160; # output transform 125 &data_word(0xD6B66000,0xFF9F4929,0xDEBE6808,0xF7974121); 126 &data_word(0x50BCEC00,0x01EDBD51,0xB05C0CE0,0xE10D5DB1); 127 128$k_deskew=0x180; # deskew tables: inverts the sbox's "skew" 129 &data_word(0x47A4E300,0x07E4A340,0x5DBEF91A,0x1DFEB95A); 130 &data_word(0x83EA6900,0x5F36B5DC,0xF49D1E77,0x2841C2AB); 131## 132## Decryption stuff 133## Key schedule constants 134## 135$k_dksd=0x1a0; # decryption key schedule: invskew x*D 136 &data_word(0xA3E44700,0xFEB91A5D,0x5A1DBEF9,0x0740E3A4); 137 &data_word(0xB5368300,0x41C277F4,0xAB289D1E,0x5FDC69EA); 138$k_dksb=0x1c0; # decryption key schedule: invskew x*B 139 &data_word(0x8550D500,0x9A4FCA1F,0x1CC94C99,0x03D65386); 140 &data_word(0xB6FC4A00,0x115BEDA7,0x7E3482C8,0xD993256F); 141$k_dkse=0x1e0; # decryption key schedule: invskew x*E + 0x63 142 &data_word(0x1FC9D600,0xD5031CCA,0x994F5086,0x53859A4C); 143 &data_word(0x4FDC7BE8,0xA2319605,0x20B31487,0xCD5EF96A); 144$k_dks9=0x200; # decryption key schedule: invskew x*9 145 &data_word(0x7ED9A700,0xB6116FC8,0x82255BFC,0x4AED9334); 146 &data_word(0x27143300,0x45765162,0xE9DAFDCE,0x8BB89FAC); 147 148## 149## Decryption stuff 150## Round function constants 151## 152$k_dipt=0x220; # decryption input transform 153 &data_word(0x0B545F00,0x0F505B04,0x114E451A,0x154A411E); 154 &data_word(0x60056500,0x86E383E6,0xF491F194,0x12771772); 155 156$k_dsb9=0x240; # decryption sbox output *9*u, *9*t 157 &data_word(0x9A86D600,0x851C0353,0x4F994CC9,0xCAD51F50); 158 &data_word(0xECD74900,0xC03B1789,0xB2FBA565,0x725E2C9E); 159$k_dsbd=0x260; # decryption sbox output *D*u, *D*t 160 &data_word(0xE6B1A200,0x7D57CCDF,0x882A4439,0xF56E9B13); 161 &data_word(0x24C6CB00,0x3CE2FAF7,0x15DEEFD3,0x2931180D); 162$k_dsbb=0x280; # decryption sbox output *B*u, *B*t 163 &data_word(0x96B44200,0xD0226492,0xB0F2D404,0x602646F6); 164 &data_word(0xCD596700,0xC19498A6,0x3255AA6B,0xF3FF0C3E); 165$k_dsbe=0x2a0; # decryption sbox output *E*u, *E*t 166 &data_word(0x26D4D000,0x46F29296,0x64B4F6B0,0x22426004); 167 &data_word(0xFFAAC100,0x0C55A6CD,0x98593E32,0x9467F36B); 168$k_dsbo=0x2c0; # decryption sbox final output 169 &data_word(0x7EF94000,0x1387EA53,0xD4943E2D,0xC7AA6DB9); 170 &data_word(0x93441D00,0x12D7560F,0xD8C58E9C,0xCA4B8159); 171&asciz ("Vector Permutation AES for x86/SSSE3, Mike Hamburg (Stanford University)"); 172&align (64); 173 174&function_begin_B("_vpaes_preheat"); 175 &add ($const,&DWP(0,"esp")); 176 &movdqa ("xmm7",&QWP($k_inv,$const)); 177 &movdqa ("xmm6",&QWP($k_s0F,$const)); 178 &ret (); 179&function_end_B("_vpaes_preheat"); 180 181## 182## _aes_encrypt_core 183## 184## AES-encrypt %xmm0. 185## 186## Inputs: 187## %xmm0 = input 188## %xmm6-%xmm7 as in _vpaes_preheat 189## (%edx) = scheduled keys 190## 191## Output in %xmm0 192## Clobbers %xmm1-%xmm5, %eax, %ebx, %ecx, %edx 193## 194## 195&function_begin_B("_vpaes_encrypt_core"); 196 &mov ($magic,16); 197 &mov ($round,&DWP(240,$key)); 198 &movdqa ("xmm1","xmm6") 199 &movdqa ("xmm2",&QWP($k_ipt,$const)); 200 &pandn ("xmm1","xmm0"); 201 &pand ("xmm0","xmm6"); 202 &movdqu ("xmm5",&QWP(0,$key)); 203 &pshufb ("xmm2","xmm0"); 204 &movdqa ("xmm0",&QWP($k_ipt+16,$const)); 205 &pxor ("xmm2","xmm5"); 206 &psrld ("xmm1",4); 207 &add ($key,16); 208 &pshufb ("xmm0","xmm1"); 209 &lea ($base,&DWP($k_mc_backward,$const)); 210 &pxor ("xmm0","xmm2"); 211 &jmp (&label("enc_entry")); 212 213 214&set_label("enc_loop",16); 215 # middle of middle round 216 &movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sb1u 217 &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sb1t 218 &pshufb ("xmm4","xmm2"); # 4 = sb1u 219 &pshufb ("xmm0","xmm3"); # 0 = sb1t 220 &pxor ("xmm4","xmm5"); # 4 = sb1u + k 221 &movdqa ("xmm5",&QWP($k_sb2,$const)); # 4 : sb2u 222 &pxor ("xmm0","xmm4"); # 0 = A 223 &movdqa ("xmm1",&QWP(-0x40,$base,$magic));# .Lk_mc_forward[] 224 &pshufb ("xmm5","xmm2"); # 4 = sb2u 225 &movdqa ("xmm2",&QWP($k_sb2+16,$const));# 2 : sb2t 226 &movdqa ("xmm4",&QWP(0,$base,$magic)); # .Lk_mc_backward[] 227 &pshufb ("xmm2","xmm3"); # 2 = sb2t 228 &movdqa ("xmm3","xmm0"); # 3 = A 229 &pxor ("xmm2","xmm5"); # 2 = 2A 230 &pshufb ("xmm0","xmm1"); # 0 = B 231 &add ($key,16); # next key 232 &pxor ("xmm0","xmm2"); # 0 = 2A+B 233 &pshufb ("xmm3","xmm4"); # 3 = D 234 &add ($magic,16); # next mc 235 &pxor ("xmm3","xmm0"); # 3 = 2A+B+D 236 &pshufb ("xmm0","xmm1"); # 0 = 2B+C 237 &and ($magic,0x30); # ... mod 4 238 &sub ($round,1); # nr-- 239 &pxor ("xmm0","xmm3"); # 0 = 2A+3B+C+D 240 241&set_label("enc_entry"); 242 # top of round 243 &movdqa ("xmm1","xmm6"); # 1 : i 244 &movdqa ("xmm5",&QWP($k_inv+16,$const));# 2 : a/k 245 &pandn ("xmm1","xmm0"); # 1 = i<<4 246 &psrld ("xmm1",4); # 1 = i 247 &pand ("xmm0","xmm6"); # 0 = k 248 &pshufb ("xmm5","xmm0"); # 2 = a/k 249 &movdqa ("xmm3","xmm7"); # 3 : 1/i 250 &pxor ("xmm0","xmm1"); # 0 = j 251 &pshufb ("xmm3","xmm1"); # 3 = 1/i 252 &movdqa ("xmm4","xmm7"); # 4 : 1/j 253 &pxor ("xmm3","xmm5"); # 3 = iak = 1/i + a/k 254 &pshufb ("xmm4","xmm0"); # 4 = 1/j 255 &movdqa ("xmm2","xmm7"); # 2 : 1/iak 256 &pxor ("xmm4","xmm5"); # 4 = jak = 1/j + a/k 257 &pshufb ("xmm2","xmm3"); # 2 = 1/iak 258 &movdqa ("xmm3","xmm7"); # 3 : 1/jak 259 &pxor ("xmm2","xmm0"); # 2 = io 260 &pshufb ("xmm3","xmm4"); # 3 = 1/jak 261 &movdqu ("xmm5",&QWP(0,$key)); 262 &pxor ("xmm3","xmm1"); # 3 = jo 263 &jnz (&label("enc_loop")); 264 265 # middle of last round 266 &movdqa ("xmm4",&QWP($k_sbo,$const)); # 3 : sbou .Lk_sbo 267 &movdqa ("xmm0",&QWP($k_sbo+16,$const));# 3 : sbot .Lk_sbo+16 268 &pshufb ("xmm4","xmm2"); # 4 = sbou 269 &pxor ("xmm4","xmm5"); # 4 = sb1u + k 270 &pshufb ("xmm0","xmm3"); # 0 = sb1t 271 &movdqa ("xmm1",&QWP(0x40,$base,$magic));# .Lk_sr[] 272 &pxor ("xmm0","xmm4"); # 0 = A 273 &pshufb ("xmm0","xmm1"); 274 &ret (); 275&function_end_B("_vpaes_encrypt_core"); 276 277## 278## Decryption core 279## 280## Same API as encryption core. 281## 282&function_begin_B("_vpaes_decrypt_core"); 283 &lea ($base,&DWP($k_dsbd,$const)); 284 &mov ($round,&DWP(240,$key)); 285 &movdqa ("xmm1","xmm6"); 286 &movdqa ("xmm2",&QWP($k_dipt-$k_dsbd,$base)); 287 &pandn ("xmm1","xmm0"); 288 &mov ($magic,$round); 289 &psrld ("xmm1",4) 290 &movdqu ("xmm5",&QWP(0,$key)); 291 &shl ($magic,4); 292 &pand ("xmm0","xmm6"); 293 &pshufb ("xmm2","xmm0"); 294 &movdqa ("xmm0",&QWP($k_dipt-$k_dsbd+16,$base)); 295 &xor ($magic,0x30); 296 &pshufb ("xmm0","xmm1"); 297 &and ($magic,0x30); 298 &pxor ("xmm2","xmm5"); 299 &movdqa ("xmm5",&QWP($k_mc_forward+48,$const)); 300 &pxor ("xmm0","xmm2"); 301 &add ($key,16); 302 &lea ($magic,&DWP($k_sr-$k_dsbd,$base,$magic)); 303 &jmp (&label("dec_entry")); 304 305&set_label("dec_loop",16); 306## 307## Inverse mix columns 308## 309 &movdqa ("xmm4",&QWP(-0x20,$base)); # 4 : sb9u 310 &movdqa ("xmm1",&QWP(-0x10,$base)); # 0 : sb9t 311 &pshufb ("xmm4","xmm2"); # 4 = sb9u 312 &pshufb ("xmm1","xmm3"); # 0 = sb9t 313 &pxor ("xmm0","xmm4"); 314 &movdqa ("xmm4",&QWP(0,$base)); # 4 : sbdu 315 &pxor ("xmm0","xmm1"); # 0 = ch 316 &movdqa ("xmm1",&QWP(0x10,$base)); # 0 : sbdt 317 318 &pshufb ("xmm4","xmm2"); # 4 = sbdu 319 &pshufb ("xmm0","xmm5"); # MC ch 320 &pshufb ("xmm1","xmm3"); # 0 = sbdt 321 &pxor ("xmm0","xmm4"); # 4 = ch 322 &movdqa ("xmm4",&QWP(0x20,$base)); # 4 : sbbu 323 &pxor ("xmm0","xmm1"); # 0 = ch 324 &movdqa ("xmm1",&QWP(0x30,$base)); # 0 : sbbt 325 326 &pshufb ("xmm4","xmm2"); # 4 = sbbu 327 &pshufb ("xmm0","xmm5"); # MC ch 328 &pshufb ("xmm1","xmm3"); # 0 = sbbt 329 &pxor ("xmm0","xmm4"); # 4 = ch 330 &movdqa ("xmm4",&QWP(0x40,$base)); # 4 : sbeu 331 &pxor ("xmm0","xmm1"); # 0 = ch 332 &movdqa ("xmm1",&QWP(0x50,$base)); # 0 : sbet 333 334 &pshufb ("xmm4","xmm2"); # 4 = sbeu 335 &pshufb ("xmm0","xmm5"); # MC ch 336 &pshufb ("xmm1","xmm3"); # 0 = sbet 337 &pxor ("xmm0","xmm4"); # 4 = ch 338 &add ($key,16); # next round key 339 &palignr("xmm5","xmm5",12); 340 &pxor ("xmm0","xmm1"); # 0 = ch 341 &sub ($round,1); # nr-- 342 343&set_label("dec_entry"); 344 # top of round 345 &movdqa ("xmm1","xmm6"); # 1 : i 346 &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k 347 &pandn ("xmm1","xmm0"); # 1 = i<<4 348 &pand ("xmm0","xmm6"); # 0 = k 349 &psrld ("xmm1",4); # 1 = i 350 &pshufb ("xmm2","xmm0"); # 2 = a/k 351 &movdqa ("xmm3","xmm7"); # 3 : 1/i 352 &pxor ("xmm0","xmm1"); # 0 = j 353 &pshufb ("xmm3","xmm1"); # 3 = 1/i 354 &movdqa ("xmm4","xmm7"); # 4 : 1/j 355 &pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k 356 &pshufb ("xmm4","xmm0"); # 4 = 1/j 357 &pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k 358 &movdqa ("xmm2","xmm7"); # 2 : 1/iak 359 &pshufb ("xmm2","xmm3"); # 2 = 1/iak 360 &movdqa ("xmm3","xmm7"); # 3 : 1/jak 361 &pxor ("xmm2","xmm0"); # 2 = io 362 &pshufb ("xmm3","xmm4"); # 3 = 1/jak 363 &movdqu ("xmm0",&QWP(0,$key)); 364 &pxor ("xmm3","xmm1"); # 3 = jo 365 &jnz (&label("dec_loop")); 366 367 # middle of last round 368 &movdqa ("xmm4",&QWP(0x60,$base)); # 3 : sbou 369 &pshufb ("xmm4","xmm2"); # 4 = sbou 370 &pxor ("xmm4","xmm0"); # 4 = sb1u + k 371 &movdqa ("xmm0",&QWP(0x70,$base)); # 0 : sbot 372 &movdqa ("xmm2",&QWP(0,$magic)); 373 &pshufb ("xmm0","xmm3"); # 0 = sb1t 374 &pxor ("xmm0","xmm4"); # 0 = A 375 &pshufb ("xmm0","xmm2"); 376 &ret (); 377&function_end_B("_vpaes_decrypt_core"); 378 379######################################################## 380## ## 381## AES key schedule ## 382## ## 383######################################################## 384&function_begin_B("_vpaes_schedule_core"); 385 &add ($const,&DWP(0,"esp")); 386 &movdqu ("xmm0",&QWP(0,$inp)); # load key (unaligned) 387 &movdqa ("xmm2",&QWP($k_rcon,$const)); # load rcon 388 389 # input transform 390 &movdqa ("xmm3","xmm0"); 391 &lea ($base,&DWP($k_ipt,$const)); 392 &movdqa (&QWP(4,"esp"),"xmm2"); # xmm8 393 &call ("_vpaes_schedule_transform"); 394 &movdqa ("xmm7","xmm0"); 395 396 &test ($out,$out); 397 &jnz (&label("schedule_am_decrypting")); 398 399 # encrypting, output zeroth round key after transform 400 &movdqu (&QWP(0,$key),"xmm0"); 401 &jmp (&label("schedule_go")); 402 403&set_label("schedule_am_decrypting"); 404 # decrypting, output zeroth round key after shiftrows 405 &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); 406 &pshufb ("xmm3","xmm1"); 407 &movdqu (&QWP(0,$key),"xmm3"); 408 &xor ($magic,0x30); 409 410&set_label("schedule_go"); 411 &cmp ($round,192); 412 &ja (&label("schedule_256")); 413 &je (&label("schedule_192")); 414 # 128: fall though 415 416## 417## .schedule_128 418## 419## 128-bit specific part of key schedule. 420## 421## This schedule is really simple, because all its parts 422## are accomplished by the subroutines. 423## 424&set_label("schedule_128"); 425 &mov ($round,10); 426 427&set_label("loop_schedule_128"); 428 &call ("_vpaes_schedule_round"); 429 &dec ($round); 430 &jz (&label("schedule_mangle_last")); 431 &call ("_vpaes_schedule_mangle"); # write output 432 &jmp (&label("loop_schedule_128")); 433 434## 435## .aes_schedule_192 436## 437## 192-bit specific part of key schedule. 438## 439## The main body of this schedule is the same as the 128-bit 440## schedule, but with more smearing. The long, high side is 441## stored in %xmm7 as before, and the short, low side is in 442## the high bits of %xmm6. 443## 444## This schedule is somewhat nastier, however, because each 445## round produces 192 bits of key material, or 1.5 round keys. 446## Therefore, on each cycle we do 2 rounds and produce 3 round 447## keys. 448## 449&set_label("schedule_192",16); 450 &movdqu ("xmm0",&QWP(8,$inp)); # load key part 2 (very unaligned) 451 &call ("_vpaes_schedule_transform"); # input transform 452 &movdqa ("xmm6","xmm0"); # save short part 453 &pxor ("xmm4","xmm4"); # clear 4 454 &movhlps("xmm6","xmm4"); # clobber low side with zeros 455 &mov ($round,4); 456 457&set_label("loop_schedule_192"); 458 &call ("_vpaes_schedule_round"); 459 &palignr("xmm0","xmm6",8); 460 &call ("_vpaes_schedule_mangle"); # save key n 461 &call ("_vpaes_schedule_192_smear"); 462 &call ("_vpaes_schedule_mangle"); # save key n+1 463 &call ("_vpaes_schedule_round"); 464 &dec ($round); 465 &jz (&label("schedule_mangle_last")); 466 &call ("_vpaes_schedule_mangle"); # save key n+2 467 &call ("_vpaes_schedule_192_smear"); 468 &jmp (&label("loop_schedule_192")); 469 470## 471## .aes_schedule_256 472## 473## 256-bit specific part of key schedule. 474## 475## The structure here is very similar to the 128-bit 476## schedule, but with an additional "low side" in 477## %xmm6. The low side's rounds are the same as the 478## high side's, except no rcon and no rotation. 479## 480&set_label("schedule_256",16); 481 &movdqu ("xmm0",&QWP(16,$inp)); # load key part 2 (unaligned) 482 &call ("_vpaes_schedule_transform"); # input transform 483 &mov ($round,7); 484 485&set_label("loop_schedule_256"); 486 &call ("_vpaes_schedule_mangle"); # output low result 487 &movdqa ("xmm6","xmm0"); # save cur_lo in xmm6 488 489 # high round 490 &call ("_vpaes_schedule_round"); 491 &dec ($round); 492 &jz (&label("schedule_mangle_last")); 493 &call ("_vpaes_schedule_mangle"); 494 495 # low round. swap xmm7 and xmm6 496 &pshufd ("xmm0","xmm0",0xFF); 497 &movdqa (&QWP(20,"esp"),"xmm7"); 498 &movdqa ("xmm7","xmm6"); 499 &call ("_vpaes_schedule_low_round"); 500 &movdqa ("xmm7",&QWP(20,"esp")); 501 502 &jmp (&label("loop_schedule_256")); 503 504## 505## .aes_schedule_mangle_last 506## 507## Mangler for last round of key schedule 508## Mangles %xmm0 509## when encrypting, outputs out(%xmm0) ^ 63 510## when decrypting, outputs unskew(%xmm0) 511## 512## Always called right before return... jumps to cleanup and exits 513## 514&set_label("schedule_mangle_last",16); 515 # schedule last round key from xmm0 516 &lea ($base,&DWP($k_deskew,$const)); 517 &test ($out,$out); 518 &jnz (&label("schedule_mangle_last_dec")); 519 520 # encrypting 521 &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); 522 &pshufb ("xmm0","xmm1"); # output permute 523 &lea ($base,&DWP($k_opt,$const)); # prepare to output transform 524 &add ($key,32); 525 526&set_label("schedule_mangle_last_dec"); 527 &add ($key,-16); 528 &pxor ("xmm0",&QWP($k_s63,$const)); 529 &call ("_vpaes_schedule_transform"); # output transform 530 &movdqu (&QWP(0,$key),"xmm0"); # save last key 531 532 # cleanup 533 &pxor ("xmm0","xmm0"); 534 &pxor ("xmm1","xmm1"); 535 &pxor ("xmm2","xmm2"); 536 &pxor ("xmm3","xmm3"); 537 &pxor ("xmm4","xmm4"); 538 &pxor ("xmm5","xmm5"); 539 &pxor ("xmm6","xmm6"); 540 &pxor ("xmm7","xmm7"); 541 &ret (); 542&function_end_B("_vpaes_schedule_core"); 543 544## 545## .aes_schedule_192_smear 546## 547## Smear the short, low side in the 192-bit key schedule. 548## 549## Inputs: 550## %xmm7: high side, b a x y 551## %xmm6: low side, d c 0 0 552## %xmm13: 0 553## 554## Outputs: 555## %xmm6: b+c+d b+c 0 0 556## %xmm0: b+c+d b+c b a 557## 558&function_begin_B("_vpaes_schedule_192_smear"); 559 &pshufd ("xmm1","xmm6",0x80); # d c 0 0 -> c 0 0 0 560 &pshufd ("xmm0","xmm7",0xFE); # b a _ _ -> b b b a 561 &pxor ("xmm6","xmm1"); # -> c+d c 0 0 562 &pxor ("xmm1","xmm1"); 563 &pxor ("xmm6","xmm0"); # -> b+c+d b+c b a 564 &movdqa ("xmm0","xmm6"); 565 &movhlps("xmm6","xmm1"); # clobber low side with zeros 566 &ret (); 567&function_end_B("_vpaes_schedule_192_smear"); 568 569## 570## .aes_schedule_round 571## 572## Runs one main round of the key schedule on %xmm0, %xmm7 573## 574## Specifically, runs subbytes on the high dword of %xmm0 575## then rotates it by one byte and xors into the low dword of 576## %xmm7. 577## 578## Adds rcon from low byte of %xmm8, then rotates %xmm8 for 579## next rcon. 580## 581## Smears the dwords of %xmm7 by xoring the low into the 582## second low, result into third, result into highest. 583## 584## Returns results in %xmm7 = %xmm0. 585## Clobbers %xmm1-%xmm5. 586## 587&function_begin_B("_vpaes_schedule_round"); 588 # extract rcon from xmm8 589 &movdqa ("xmm2",&QWP(8,"esp")); # xmm8 590 &pxor ("xmm1","xmm1"); 591 &palignr("xmm1","xmm2",15); 592 &palignr("xmm2","xmm2",15); 593 &pxor ("xmm7","xmm1"); 594 595 # rotate 596 &pshufd ("xmm0","xmm0",0xFF); 597 &palignr("xmm0","xmm0",1); 598 599 # fall through... 600 &movdqa (&QWP(8,"esp"),"xmm2"); # xmm8 601 602 # low round: same as high round, but no rotation and no rcon. 603&set_label("_vpaes_schedule_low_round"); 604 # smear xmm7 605 &movdqa ("xmm1","xmm7"); 606 &pslldq ("xmm7",4); 607 &pxor ("xmm7","xmm1"); 608 &movdqa ("xmm1","xmm7"); 609 &pslldq ("xmm7",8); 610 &pxor ("xmm7","xmm1"); 611 &pxor ("xmm7",&QWP($k_s63,$const)); 612 613 # subbyte 614 &movdqa ("xmm4",&QWP($k_s0F,$const)); 615 &movdqa ("xmm5",&QWP($k_inv,$const)); # 4 : 1/j 616 &movdqa ("xmm1","xmm4"); 617 &pandn ("xmm1","xmm0"); 618 &psrld ("xmm1",4); # 1 = i 619 &pand ("xmm0","xmm4"); # 0 = k 620 &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k 621 &pshufb ("xmm2","xmm0"); # 2 = a/k 622 &pxor ("xmm0","xmm1"); # 0 = j 623 &movdqa ("xmm3","xmm5"); # 3 : 1/i 624 &pshufb ("xmm3","xmm1"); # 3 = 1/i 625 &pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k 626 &movdqa ("xmm4","xmm5"); # 4 : 1/j 627 &pshufb ("xmm4","xmm0"); # 4 = 1/j 628 &pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k 629 &movdqa ("xmm2","xmm5"); # 2 : 1/iak 630 &pshufb ("xmm2","xmm3"); # 2 = 1/iak 631 &pxor ("xmm2","xmm0"); # 2 = io 632 &movdqa ("xmm3","xmm5"); # 3 : 1/jak 633 &pshufb ("xmm3","xmm4"); # 3 = 1/jak 634 &pxor ("xmm3","xmm1"); # 3 = jo 635 &movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sbou 636 &pshufb ("xmm4","xmm2"); # 4 = sbou 637 &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sbot 638 &pshufb ("xmm0","xmm3"); # 0 = sb1t 639 &pxor ("xmm0","xmm4"); # 0 = sbox output 640 641 # add in smeared stuff 642 &pxor ("xmm0","xmm7"); 643 &movdqa ("xmm7","xmm0"); 644 &ret (); 645&function_end_B("_vpaes_schedule_round"); 646 647## 648## .aes_schedule_transform 649## 650## Linear-transform %xmm0 according to tables at (%ebx) 651## 652## Output in %xmm0 653## Clobbers %xmm1, %xmm2 654## 655&function_begin_B("_vpaes_schedule_transform"); 656 &movdqa ("xmm2",&QWP($k_s0F,$const)); 657 &movdqa ("xmm1","xmm2"); 658 &pandn ("xmm1","xmm0"); 659 &psrld ("xmm1",4); 660 &pand ("xmm0","xmm2"); 661 &movdqa ("xmm2",&QWP(0,$base)); 662 &pshufb ("xmm2","xmm0"); 663 &movdqa ("xmm0",&QWP(16,$base)); 664 &pshufb ("xmm0","xmm1"); 665 &pxor ("xmm0","xmm2"); 666 &ret (); 667&function_end_B("_vpaes_schedule_transform"); 668 669## 670## .aes_schedule_mangle 671## 672## Mangle xmm0 from (basis-transformed) standard version 673## to our version. 674## 675## On encrypt, 676## xor with 0x63 677## multiply by circulant 0,1,1,1 678## apply shiftrows transform 679## 680## On decrypt, 681## xor with 0x63 682## multiply by "inverse mixcolumns" circulant E,B,D,9 683## deskew 684## apply shiftrows transform 685## 686## 687## Writes out to (%edx), and increments or decrements it 688## Keeps track of round number mod 4 in %ecx 689## Preserves xmm0 690## Clobbers xmm1-xmm5 691## 692&function_begin_B("_vpaes_schedule_mangle"); 693 &movdqa ("xmm4","xmm0"); # save xmm0 for later 694 &movdqa ("xmm5",&QWP($k_mc_forward,$const)); 695 &test ($out,$out); 696 &jnz (&label("schedule_mangle_dec")); 697 698 # encrypting 699 &add ($key,16); 700 &pxor ("xmm4",&QWP($k_s63,$const)); 701 &pshufb ("xmm4","xmm5"); 702 &movdqa ("xmm3","xmm4"); 703 &pshufb ("xmm4","xmm5"); 704 &pxor ("xmm3","xmm4"); 705 &pshufb ("xmm4","xmm5"); 706 &pxor ("xmm3","xmm4"); 707 708 &jmp (&label("schedule_mangle_both")); 709 710&set_label("schedule_mangle_dec",16); 711 # inverse mix columns 712 &movdqa ("xmm2",&QWP($k_s0F,$const)); 713 &lea ($inp,&DWP($k_dksd,$const)); 714 &movdqa ("xmm1","xmm2"); 715 &pandn ("xmm1","xmm4"); 716 &psrld ("xmm1",4); # 1 = hi 717 &pand ("xmm4","xmm2"); # 4 = lo 718 719 &movdqa ("xmm2",&QWP(0,$inp)); 720 &pshufb ("xmm2","xmm4"); 721 &movdqa ("xmm3",&QWP(0x10,$inp)); 722 &pshufb ("xmm3","xmm1"); 723 &pxor ("xmm3","xmm2"); 724 &pshufb ("xmm3","xmm5"); 725 726 &movdqa ("xmm2",&QWP(0x20,$inp)); 727 &pshufb ("xmm2","xmm4"); 728 &pxor ("xmm2","xmm3"); 729 &movdqa ("xmm3",&QWP(0x30,$inp)); 730 &pshufb ("xmm3","xmm1"); 731 &pxor ("xmm3","xmm2"); 732 &pshufb ("xmm3","xmm5"); 733 734 &movdqa ("xmm2",&QWP(0x40,$inp)); 735 &pshufb ("xmm2","xmm4"); 736 &pxor ("xmm2","xmm3"); 737 &movdqa ("xmm3",&QWP(0x50,$inp)); 738 &pshufb ("xmm3","xmm1"); 739 &pxor ("xmm3","xmm2"); 740 &pshufb ("xmm3","xmm5"); 741 742 &movdqa ("xmm2",&QWP(0x60,$inp)); 743 &pshufb ("xmm2","xmm4"); 744 &pxor ("xmm2","xmm3"); 745 &movdqa ("xmm3",&QWP(0x70,$inp)); 746 &pshufb ("xmm3","xmm1"); 747 &pxor ("xmm3","xmm2"); 748 749 &add ($key,-16); 750 751&set_label("schedule_mangle_both"); 752 &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); 753 &pshufb ("xmm3","xmm1"); 754 &add ($magic,-16); 755 &and ($magic,0x30); 756 &movdqu (&QWP(0,$key),"xmm3"); 757 &ret (); 758&function_end_B("_vpaes_schedule_mangle"); 759 760# 761# Interface to OpenSSL 762# 763&function_begin("${PREFIX}_set_encrypt_key"); 764 record_function_hit(5); 765 766 &mov ($inp,&wparam(0)); # inp 767 &lea ($base,&DWP(-56,"esp")); 768 &mov ($round,&wparam(1)); # bits 769 &and ($base,-16); 770 &mov ($key,&wparam(2)); # key 771 &xchg ($base,"esp"); # alloca 772 &mov (&DWP(48,"esp"),$base); 773 774 &mov ($base,$round); 775 &shr ($base,5); 776 &add ($base,5); 777 &mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5; 778 &mov ($magic,0x30); 779 &mov ($out,0); 780 781 &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); 782 &call ("_vpaes_schedule_core"); 783&set_label("pic_point"); 784 785 &mov ("esp",&DWP(48,"esp")); 786 &xor ("eax","eax"); 787&function_end("${PREFIX}_set_encrypt_key"); 788 789&function_begin("${PREFIX}_set_decrypt_key"); 790 &mov ($inp,&wparam(0)); # inp 791 &lea ($base,&DWP(-56,"esp")); 792 &mov ($round,&wparam(1)); # bits 793 &and ($base,-16); 794 &mov ($key,&wparam(2)); # key 795 &xchg ($base,"esp"); # alloca 796 &mov (&DWP(48,"esp"),$base); 797 798 &mov ($base,$round); 799 &shr ($base,5); 800 &add ($base,5); 801 &mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5; 802 &shl ($base,4); 803 &lea ($key,&DWP(16,$key,$base)); 804 805 &mov ($out,1); 806 &mov ($magic,$round); 807 &shr ($magic,1); 808 &and ($magic,32); 809 &xor ($magic,32); # nbist==192?0:32; 810 811 &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); 812 &call ("_vpaes_schedule_core"); 813&set_label("pic_point"); 814 815 &mov ("esp",&DWP(48,"esp")); 816 &xor ("eax","eax"); 817&function_end("${PREFIX}_set_decrypt_key"); 818 819&function_begin("${PREFIX}_encrypt"); 820 record_function_hit(4); 821 822 &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); 823 &call ("_vpaes_preheat"); 824&set_label("pic_point"); 825 &mov ($inp,&wparam(0)); # inp 826 &lea ($base,&DWP(-56,"esp")); 827 &mov ($out,&wparam(1)); # out 828 &and ($base,-16); 829 &mov ($key,&wparam(2)); # key 830 &xchg ($base,"esp"); # alloca 831 &mov (&DWP(48,"esp"),$base); 832 833 &movdqu ("xmm0",&QWP(0,$inp)); 834 &call ("_vpaes_encrypt_core"); 835 &movdqu (&QWP(0,$out),"xmm0"); 836 837 &mov ("esp",&DWP(48,"esp")); 838&function_end("${PREFIX}_encrypt"); 839 840&function_begin("${PREFIX}_decrypt"); 841 &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); 842 &call ("_vpaes_preheat"); 843&set_label("pic_point"); 844 &mov ($inp,&wparam(0)); # inp 845 &lea ($base,&DWP(-56,"esp")); 846 &mov ($out,&wparam(1)); # out 847 &and ($base,-16); 848 &mov ($key,&wparam(2)); # key 849 &xchg ($base,"esp"); # alloca 850 &mov (&DWP(48,"esp"),$base); 851 852 &movdqu ("xmm0",&QWP(0,$inp)); 853 &call ("_vpaes_decrypt_core"); 854 &movdqu (&QWP(0,$out),"xmm0"); 855 856 &mov ("esp",&DWP(48,"esp")); 857&function_end("${PREFIX}_decrypt"); 858 859&function_begin("${PREFIX}_cbc_encrypt"); 860 &mov ($inp,&wparam(0)); # inp 861 &mov ($out,&wparam(1)); # out 862 &mov ($round,&wparam(2)); # len 863 &mov ($key,&wparam(3)); # key 864 &sub ($round,16); 865 &jc (&label("cbc_abort")); 866 &lea ($base,&DWP(-56,"esp")); 867 &mov ($const,&wparam(4)); # ivp 868 &and ($base,-16); 869 &mov ($magic,&wparam(5)); # enc 870 &xchg ($base,"esp"); # alloca 871 &movdqu ("xmm1",&QWP(0,$const)); # load IV 872 &sub ($out,$inp); 873 &mov (&DWP(48,"esp"),$base); 874 875 &mov (&DWP(0,"esp"),$out); # save out 876 &mov (&DWP(4,"esp"),$key) # save key 877 &mov (&DWP(8,"esp"),$const); # save ivp 878 &mov ($out,$round); # $out works as $len 879 880 &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); 881 &call ("_vpaes_preheat"); 882&set_label("pic_point"); 883 &cmp ($magic,0); 884 &je (&label("cbc_dec_loop")); 885 &jmp (&label("cbc_enc_loop")); 886 887&set_label("cbc_enc_loop",16); 888 &movdqu ("xmm0",&QWP(0,$inp)); # load input 889 &pxor ("xmm0","xmm1"); # inp^=iv 890 &call ("_vpaes_encrypt_core"); 891 &mov ($base,&DWP(0,"esp")); # restore out 892 &mov ($key,&DWP(4,"esp")); # restore key 893 &movdqa ("xmm1","xmm0"); 894 &movdqu (&QWP(0,$base,$inp),"xmm0"); # write output 895 &lea ($inp,&DWP(16,$inp)); 896 &sub ($out,16); 897 &jnc (&label("cbc_enc_loop")); 898 &jmp (&label("cbc_done")); 899 900&set_label("cbc_dec_loop",16); 901 &movdqu ("xmm0",&QWP(0,$inp)); # load input 902 &movdqa (&QWP(16,"esp"),"xmm1"); # save IV 903 &movdqa (&QWP(32,"esp"),"xmm0"); # save future IV 904 &call ("_vpaes_decrypt_core"); 905 &mov ($base,&DWP(0,"esp")); # restore out 906 &mov ($key,&DWP(4,"esp")); # restore key 907 &pxor ("xmm0",&QWP(16,"esp")); # out^=iv 908 &movdqa ("xmm1",&QWP(32,"esp")); # load next IV 909 &movdqu (&QWP(0,$base,$inp),"xmm0"); # write output 910 &lea ($inp,&DWP(16,$inp)); 911 &sub ($out,16); 912 &jnc (&label("cbc_dec_loop")); 913 914&set_label("cbc_done"); 915 &mov ($base,&DWP(8,"esp")); # restore ivp 916 &mov ("esp",&DWP(48,"esp")); 917 &movdqu (&QWP(0,$base),"xmm1"); # write IV 918&set_label("cbc_abort"); 919&function_end("${PREFIX}_cbc_encrypt"); 920 921&asm_finish(); 922 923close STDOUT or die "error closing STDOUT: $!"; 924