1#! /usr/bin/env perl 2# This file is dual-licensed, meaning that you can use it under your 3# choice of either of the following two licenses: 4# 5# Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. 6# 7# Licensed under the Apache License 2.0 (the "License"). You can obtain 8# a copy in the file LICENSE in the source distribution or at 9# https://www.openssl.org/source/license.html 10# 11# or 12# 13# Copyright (c) 2022, Hongren (Zenithal) Zheng <i@zenithal.me> 14# All rights reserved. 15# 16# Redistribution and use in source and binary forms, with or without 17# modification, are permitted provided that the following conditions 18# are met: 19# 1. Redistributions of source code must retain the above copyright 20# notice, this list of conditions and the following disclaimer. 21# 2. Redistributions in binary form must reproduce the above copyright 22# notice, this list of conditions and the following disclaimer in the 23# documentation and/or other materials provided with the distribution. 24# 25# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 37use strict; 38use warnings; 39 40use FindBin qw($Bin); 41use lib "$Bin"; 42use lib "$Bin/../../perlasm"; 43use riscv; 44 45# $output is the last argument if it looks like a file (it has an extension) 46# $flavour is the first argument if it doesn't look like a file 47my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef; 48my $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef; 49 50$output and open STDOUT,">$output"; 51 52################################################################################ 53# Utility functions to help with keeping track of which registers to stack/ 54# unstack when entering / exiting routines. 55################################################################################ 56{ 57 # Callee-saved registers 58 my @callee_saved = map("x$_",(2,8,9,18..27)); 59 # Caller-saved registers 60 my @caller_saved = map("x$_",(1,5..7,10..17,28..31)); 61 my @must_save; 62 sub use_reg { 63 my $reg = shift; 64 if (grep(/^$reg$/, @callee_saved)) { 65 push(@must_save, $reg); 66 } elsif (!grep(/^$reg$/, @caller_saved)) { 67 # Register is not usable! 68 die("Unusable register ".$reg); 69 } 70 return $reg; 71 } 72 sub use_regs { 73 return map(use_reg("x$_"), @_); 74 } 75 sub save_regs { 76 my $ret = ''; 77 my $stack_reservation = ($#must_save + 1) * 8; 78 my $stack_offset = $stack_reservation; 79 if ($stack_reservation % 16) { 80 $stack_reservation += 8; 81 } 82 $ret.=" addi sp,sp,-$stack_reservation\n"; 83 foreach (@must_save) { 84 $stack_offset -= 8; 85 $ret.=" sd $_,$stack_offset(sp)\n"; 86 } 87 return $ret; 88 } 89 sub load_regs { 90 my $ret = ''; 91 my $stack_reservation = ($#must_save + 1) * 8; 92 my $stack_offset = $stack_reservation; 93 if ($stack_reservation % 16) { 94 $stack_reservation += 8; 95 } 96 foreach (@must_save) { 97 $stack_offset -= 8; 98 $ret.=" ld $_,$stack_offset(sp)\n"; 99 } 100 $ret.=" addi sp,sp,$stack_reservation\n"; 101 return $ret; 102 } 103 sub clear_regs { 104 @must_save = (); 105 } 106} 107 108################################################################################ 109# Register assignment for rv64i_zkne_encrypt and rv64i_zknd_decrypt 110################################################################################ 111 112# Registers to hold AES state (called s0-s3 or y0-y3 elsewhere) 113my ($Q0,$Q1,$Q2,$Q3) = use_regs(6..9); 114 115# Function arguments (x10-x12 are a0-a2 in the ABI) 116# Input block pointer, output block pointer, key pointer 117my ($INP,$OUTP,$KEYP) = use_regs(10..12); 118 119# Temporaries 120my ($T0,$T1) = use_regs(13..14); 121 122# Loop counter 123my ($loopcntr) = use_regs(30); 124 125################################################################################ 126# void rv64i_zkne_encrypt(const unsigned char *in, unsigned char *out, 127# const AES_KEY *key); 128################################################################################ 129my $code .= <<___; 130.text 131.balign 16 132.globl rv64i_zkne_encrypt 133.type rv64i_zkne_encrypt,\@function 134rv64i_zkne_encrypt: 135___ 136 137$code .= save_regs(); 138 139$code .= <<___; 140 141 # Load input to block cipher 142 ld $Q0,0($INP) 143 ld $Q1,8($INP) 144 145 # Load key 146 ld $T0,0($KEYP) 147 ld $T1,8($KEYP) 148 149 # Load number of rounds 150 lwu $loopcntr,240($KEYP) 151 152 # initial transformation 153 xor $Q0,$Q0,$T0 154 xor $Q1,$Q1,$T1 155 156 # The main loop only executes the first N-1 rounds. 157 add $loopcntr,$loopcntr,-1 158 159 # Do Nr - 1 rounds (final round is special) 1601: 161 @{[aes64esm $Q2,$Q0,$Q1]} 162 @{[aes64esm $Q3,$Q1,$Q0]} 163 164 # Update key ptr to point to next key in schedule 165 add $KEYP,$KEYP,16 166 167 # Grab next key in schedule 168 ld $T0,0($KEYP) 169 ld $T1,8($KEYP) 170 xor $Q0,$Q2,$T0 171 xor $Q1,$Q3,$T1 172 173 add $loopcntr,$loopcntr,-1 174 bgtz $loopcntr,1b 175 176 # final round 177 @{[aes64es $Q2,$Q0,$Q1]} 178 @{[aes64es $Q3,$Q1,$Q0]} 179 180 # since not added 16 before 181 ld $T0,16($KEYP) 182 ld $T1,24($KEYP) 183 xor $Q0,$Q2,$T0 184 xor $Q1,$Q3,$T1 185 186 sd $Q0,0($OUTP) 187 sd $Q1,8($OUTP) 188 189 # Pop registers and return 190___ 191 192$code .= load_regs(); 193 194$code .= <<___; 195 ret 196___ 197 198################################################################################ 199# void rv64i_zknd_decrypt(const unsigned char *in, unsigned char *out, 200# const AES_KEY *key); 201################################################################################ 202$code .= <<___; 203.text 204.balign 16 205.globl rv64i_zknd_decrypt 206.type rv64i_zknd_decrypt,\@function 207rv64i_zknd_decrypt: 208___ 209 210$code .= save_regs(); 211 212$code .= <<___; 213 214 # Load input to block cipher 215 ld $Q0,0($INP) 216 ld $Q1,8($INP) 217 218 # Load number of rounds 219 lwu $loopcntr,240($KEYP) 220 221 # Load the last key 222 slli $T0,$loopcntr,4 223 add $KEYP,$KEYP,$T0 224 ld $T0,0($KEYP) 225 ld $T1,8($KEYP) 226 227 xor $Q0,$Q0,$T0 228 xor $Q1,$Q1,$T1 229 230 # The main loop only executes the first N-1 rounds. 231 add $loopcntr,$loopcntr,-1 232 233 # Do Nr - 1 rounds (final round is special) 2341: 235 @{[aes64dsm $Q2,$Q0,$Q1]} 236 @{[aes64dsm $Q3,$Q1,$Q0]} 237 238 # Update key ptr to point to next key in schedule 239 add $KEYP,$KEYP,-16 240 241 # Grab next key in schedule 242 ld $T0,0($KEYP) 243 ld $T1,8($KEYP) 244 xor $Q0,$Q2,$T0 245 xor $Q1,$Q3,$T1 246 247 add $loopcntr,$loopcntr,-1 248 bgtz $loopcntr,1b 249 250 # final round 251 @{[aes64ds $Q2,$Q0,$Q1]} 252 @{[aes64ds $Q3,$Q1,$Q0]} 253 254 add $KEYP,$KEYP,-16 255 ld $T0,0($KEYP) 256 ld $T1,8($KEYP) 257 xor $Q0,$Q2,$T0 258 xor $Q1,$Q3,$T1 259 260 sd $Q0,0($OUTP) 261 sd $Q1,8($OUTP) 262 # Pop registers and return 263___ 264 265$code .= load_regs(); 266 267$code .= <<___; 268 ret 269___ 270 271clear_regs(); 272 273################################################################################ 274# Register assignment for rv64i_zkn[e/d]_set_[en/de]crypt_key 275################################################################################ 276 277# Function arguments (x10-x12 are a0-a2 in the ABI) 278# Pointer to user key, number of bits in key, key pointer 279my ($UKEY,$BITS,$KEYP) = use_regs(10..12); 280 281# Temporaries 282my ($T0,$T1,$T2,$T3,$T4) = use_regs(6..8,13..14); 283 284################################################################################ 285# utility functions for rv64i_zkne_set_encrypt_key 286################################################################################ 287sub ke128enc { 288 my $rnum = 0; 289 my $ret = ''; 290$ret .= <<___; 291 ld $T0,0($UKEY) 292 ld $T1,8($UKEY) 293 sd $T0,0($KEYP) 294 sd $T1,8($KEYP) 295___ 296 while($rnum < 10) { 297$ret .= <<___; 298 @{[aes64ks1i $T2,$T1,$rnum]} 299 @{[aes64ks2 $T0,$T2,$T0]} 300 @{[aes64ks2 $T1,$T0,$T1]} 301 add $KEYP,$KEYP,16 302 sd $T0,0($KEYP) 303 sd $T1,8($KEYP) 304___ 305 $rnum++; 306 } 307 return $ret; 308} 309 310sub ke192enc { 311 my $rnum = 0; 312 my $ret = ''; 313$ret .= <<___; 314 ld $T0,0($UKEY) 315 ld $T1,8($UKEY) 316 ld $T2,16($UKEY) 317 sd $T0,0($KEYP) 318 sd $T1,8($KEYP) 319 sd $T2,16($KEYP) 320___ 321 while($rnum < 8) { 322$ret .= <<___; 323 @{[aes64ks1i $T3,$T2,$rnum]} 324 @{[aes64ks2 $T0,$T3,$T0]} 325 @{[aes64ks2 $T1,$T0,$T1]} 326___ 327 if ($rnum != 7) { 328 # note that (8+1)*24 = 216, (12+1)*16 = 208 329 # thus the last 8 bytes can be dropped 330$ret .= <<___; 331 @{[aes64ks2 $T2,$T1,$T2]} 332___ 333 } 334$ret .= <<___; 335 add $KEYP,$KEYP,24 336 sd $T0,0($KEYP) 337 sd $T1,8($KEYP) 338___ 339 if ($rnum != 7) { 340$ret .= <<___; 341 sd $T2,16($KEYP) 342___ 343 } 344 $rnum++; 345 } 346 return $ret; 347} 348 349sub ke256enc { 350 my $rnum = 0; 351 my $ret = ''; 352$ret .= <<___; 353 ld $T0,0($UKEY) 354 ld $T1,8($UKEY) 355 ld $T2,16($UKEY) 356 ld $T3,24($UKEY) 357 sd $T0,0($KEYP) 358 sd $T1,8($KEYP) 359 sd $T2,16($KEYP) 360 sd $T3,24($KEYP) 361___ 362 while($rnum < 7) { 363$ret .= <<___; 364 @{[aes64ks1i $T4,$T3,$rnum]} 365 @{[aes64ks2 $T0,$T4,$T0]} 366 @{[aes64ks2 $T1,$T0,$T1]} 367 add $KEYP,$KEYP,32 368 sd $T0,0($KEYP) 369 sd $T1,8($KEYP) 370___ 371 if ($rnum != 6) { 372 # note that (7+1)*32 = 256, (14+1)*16 = 240 373 # thus the last 16 bytes can be dropped 374$ret .= <<___; 375 @{[aes64ks1i $T4,$T1,0xA]} 376 @{[aes64ks2 $T2,$T4,$T2]} 377 @{[aes64ks2 $T3,$T2,$T3]} 378 sd $T2,16($KEYP) 379 sd $T3,24($KEYP) 380___ 381 } 382 $rnum++; 383 } 384 return $ret; 385} 386 387################################################################################ 388# void rv64i_zkne_set_encrypt_key(const unsigned char *userKey, const int bits, 389# AES_KEY *key) 390################################################################################ 391sub AES_set_common { 392 my ($ke128, $ke192, $ke256) = @_; 393 my $ret = ''; 394$ret .= <<___; 395 bnez $UKEY,1f # if (!userKey || !key) return -1; 396 bnez $KEYP,1f 397 li a0,-1 398 ret 3991: 400 # Determine number of rounds from key size in bits 401 li $T0,128 402 bne $BITS,$T0,1f 403 li $T1,10 # key->rounds = 10 if bits == 128 404 sw $T1,240($KEYP) # store key->rounds 405$ke128 406 j 4f 4071: 408 li $T0,192 409 bne $BITS,$T0,2f 410 li $T1,12 # key->rounds = 12 if bits == 192 411 sw $T1,240($KEYP) # store key->rounds 412$ke192 413 j 4f 4142: 415 li $T1,14 # key->rounds = 14 if bits == 256 416 li $T0,256 417 beq $BITS,$T0,3f 418 li a0,-2 # If bits != 128, 192, or 256, return -2 419 j 5f 4203: 421 sw $T1,240($KEYP) # store key->rounds 422$ke256 4234: # return 0 424 li a0,0 4255: # return a0 426___ 427 return $ret; 428} 429$code .= <<___; 430.text 431.balign 16 432.globl rv64i_zkne_set_encrypt_key 433.type rv64i_zkne_set_encrypt_key,\@function 434rv64i_zkne_set_encrypt_key: 435___ 436$code .= save_regs(); 437$code .= AES_set_common(ke128enc(), ke192enc(),ke256enc()); 438$code .= load_regs(); 439$code .= <<___; 440 ret 441___ 442 443################################################################################ 444# utility functions for rv64i_zknd_set_decrypt_key 445################################################################################ 446sub ke128dec { 447 my $rnum = 0; 448 my $ret = ''; 449$ret .= <<___; 450 ld $T0,0($UKEY) 451 ld $T1,8($UKEY) 452 sd $T0,0($KEYP) 453 sd $T1,8($KEYP) 454___ 455 while($rnum < 10) { 456$ret .= <<___; 457 @{[aes64ks1i $T2,$T1,$rnum]} 458 @{[aes64ks2 $T0,$T2,$T0]} 459 @{[aes64ks2 $T1,$T0,$T1]} 460 add $KEYP,$KEYP,16 461___ 462 # need to aes64im for [1:N-1] round keys 463 # this is from the fact that aes64dsm subwords first then mix column 464 # intuitively decryption needs to first mix column then subwords 465 # however, for merging datapaths (encryption first subwords then mix column) 466 # aes64dsm chooses to inverse the order of them, thus 467 # transform should then be done on the round key 468 if ($rnum < 9) { 469$ret .= <<___; 470 @{[aes64im $T2,$T0]} 471 sd $T2,0($KEYP) 472 @{[aes64im $T2,$T1]} 473 sd $T2,8($KEYP) 474___ 475 } else { 476$ret .= <<___; 477 sd $T0,0($KEYP) 478 sd $T1,8($KEYP) 479___ 480 } 481 $rnum++; 482 } 483 return $ret; 484} 485 486sub ke192dec { 487 my $rnum = 0; 488 my $ret = ''; 489$ret .= <<___; 490 ld $T0,0($UKEY) 491 ld $T1,8($UKEY) 492 ld $T2,16($UKEY) 493 sd $T0,0($KEYP) 494 sd $T1,8($KEYP) 495 @{[aes64im $T3,$T2]} 496 sd $T3,16($KEYP) 497___ 498 while($rnum < 8) { 499$ret .= <<___; 500 @{[aes64ks1i $T3,$T2,$rnum]} 501 @{[aes64ks2 $T0,$T3,$T0]} 502 @{[aes64ks2 $T1,$T0,$T1]} 503 add $KEYP,$KEYP,24 504___ 505 if ($rnum < 7) { 506$ret .= <<___; 507 @{[aes64im $T3,$T0]} 508 sd $T3,0($KEYP) 509 @{[aes64im $T3,$T1]} 510 sd $T3,8($KEYP) 511 # the reason is in ke192enc 512 @{[aes64ks2 $T2,$T1,$T2]} 513 @{[aes64im $T3,$T2]} 514 sd $T3,16($KEYP) 515___ 516 } else { # rnum == 7 517$ret .= <<___; 518 sd $T0,0($KEYP) 519 sd $T1,8($KEYP) 520___ 521 } 522 $rnum++; 523 } 524 return $ret; 525} 526 527sub ke256dec { 528 my $rnum = 0; 529 my $ret = ''; 530$ret .= <<___; 531 ld $T0,0($UKEY) 532 ld $T1,8($UKEY) 533 ld $T2,16($UKEY) 534 ld $T3,24($UKEY) 535 sd $T0,0($KEYP) 536 sd $T1,8($KEYP) 537 @{[aes64im $T4,$T2]} 538 sd $T4,16($KEYP) 539 @{[aes64im $T4,$T3]} 540 sd $T4,24($KEYP) 541___ 542 while($rnum < 7) { 543$ret .= <<___; 544 @{[aes64ks1i $T4,$T3,$rnum]} 545 @{[aes64ks2 $T0,$T4,$T0]} 546 @{[aes64ks2 $T1,$T0,$T1]} 547 add $KEYP,$KEYP,32 548___ 549 if ($rnum < 6) { 550$ret .= <<___; 551 @{[aes64ks1i $T4,$T1,0xA]} 552 @{[aes64ks2 $T2,$T4,$T2]} 553 @{[aes64ks2 $T3,$T2,$T3]} 554 @{[aes64im $T4,$T0]} 555 sd $T4,0($KEYP) 556 @{[aes64im $T4,$T1]} 557 sd $T4,8($KEYP) 558 @{[aes64im $T4,$T2]} 559 sd $T4,16($KEYP) 560 @{[aes64im $T4,$T3]} 561 sd $T4,24($KEYP) 562___ 563 } else { 564$ret .= <<___; 565 sd $T0,0($KEYP) 566 sd $T1,8($KEYP) 567 # last two one dropped 568___ 569 } 570 $rnum++; 571 } 572 return $ret; 573} 574 575################################################################################ 576# void rv64i_zknd_set_decrypt_key(const unsigned char *userKey, const int bits, 577# AES_KEY *key) 578################################################################################ 579$code .= <<___; 580.text 581.balign 16 582.globl rv64i_zknd_set_decrypt_key 583.type rv64i_zknd_set_decrypt_key,\@function 584rv64i_zknd_set_decrypt_key: 585___ 586$code .= save_regs(); 587$code .= AES_set_common(ke128dec(), ke192dec(),ke256dec()); 588$code .= load_regs(); 589$code .= <<___; 590 ret 591___ 592 593print $code; 594close STDOUT or die "error closing STDOUT: $!"; 595