vpaes-x86.pl 27 KB

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