123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- #! /usr/bin/env perl
- # This file is dual-licensed, meaning that you can use it under your
- # choice of either of the following two licenses:
- #
- # Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
- #
- # Licensed under the Apache License 2.0 (the "License"). You can obtain
- # a copy in the file LICENSE in the source distribution or at
- # https://www.openssl.org/source/license.html
- #
- # or
- #
- # Copyright (c) 2022, Hongren (Zenithal) Zheng <i@zenithal.me>
- # All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions
- # are met:
- # 1. Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # 2. Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- #
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- use strict;
- use warnings;
- use FindBin qw($Bin);
- use lib "$Bin";
- use lib "$Bin/../../perlasm";
- use riscv;
- # $output is the last argument if it looks like a file (it has an extension)
- # $flavour is the first argument if it doesn't look like a file
- my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
- my $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
- $output and open STDOUT,">$output";
- ################################################################################
- # Utility functions to help with keeping track of which registers to stack/
- # unstack when entering / exiting routines.
- ################################################################################
- {
- # Callee-saved registers
- my @callee_saved = map("x$_",(2,8,9,18..27));
- # Caller-saved registers
- my @caller_saved = map("x$_",(1,5..7,10..17,28..31));
- my @must_save;
- sub use_reg {
- my $reg = shift;
- if (grep(/^$reg$/, @callee_saved)) {
- push(@must_save, $reg);
- } elsif (!grep(/^$reg$/, @caller_saved)) {
- # Register is not usable!
- die("Unusable register ".$reg);
- }
- return $reg;
- }
- sub use_regs {
- return map(use_reg("x$_"), @_);
- }
- sub save_regs {
- my $ret = '';
- my $stack_reservation = ($#must_save + 1) * 8;
- my $stack_offset = $stack_reservation;
- if ($stack_reservation % 16) {
- $stack_reservation += 8;
- }
- $ret.=" addi sp,sp,-$stack_reservation\n";
- foreach (@must_save) {
- $stack_offset -= 8;
- $ret.=" sd $_,$stack_offset(sp)\n";
- }
- return $ret;
- }
- sub load_regs {
- my $ret = '';
- my $stack_reservation = ($#must_save + 1) * 8;
- my $stack_offset = $stack_reservation;
- if ($stack_reservation % 16) {
- $stack_reservation += 8;
- }
- foreach (@must_save) {
- $stack_offset -= 8;
- $ret.=" ld $_,$stack_offset(sp)\n";
- }
- $ret.=" addi sp,sp,$stack_reservation\n";
- return $ret;
- }
- sub clear_regs {
- @must_save = ();
- }
- }
- ################################################################################
- # Register assignment for rv64i_zkne_encrypt and rv64i_zknd_decrypt
- ################################################################################
- # Registers to hold AES state (called s0-s3 or y0-y3 elsewhere)
- my ($Q0,$Q1,$Q2,$Q3) = use_regs(6..9);
- # Function arguments (x10-x12 are a0-a2 in the ABI)
- # Input block pointer, output block pointer, key pointer
- my ($INP,$OUTP,$KEYP) = use_regs(10..12);
- # Temporaries
- my ($T0,$T1) = use_regs(13..14);
- # Loop counter
- my ($loopcntr) = use_regs(30);
- ################################################################################
- # void rv64i_zkne_encrypt(const unsigned char *in, unsigned char *out,
- # const AES_KEY *key);
- ################################################################################
- my $code .= <<___;
- .text
- .balign 16
- .globl rv64i_zkne_encrypt
- .type rv64i_zkne_encrypt,\@function
- rv64i_zkne_encrypt:
- ___
- $code .= save_regs();
- $code .= <<___;
- # Load input to block cipher
- ld $Q0,0($INP)
- ld $Q1,8($INP)
- # Load key
- ld $T0,0($KEYP)
- ld $T1,8($KEYP)
- # Load number of rounds
- lwu $loopcntr,240($KEYP)
- # initial transformation
- xor $Q0,$Q0,$T0
- xor $Q1,$Q1,$T1
- # The main loop only executes the first N-1 rounds.
- add $loopcntr,$loopcntr,-1
- # Do Nr - 1 rounds (final round is special)
- 1:
- @{[aes64esm $Q2,$Q0,$Q1]}
- @{[aes64esm $Q3,$Q1,$Q0]}
- # Update key ptr to point to next key in schedule
- add $KEYP,$KEYP,16
- # Grab next key in schedule
- ld $T0,0($KEYP)
- ld $T1,8($KEYP)
- xor $Q0,$Q2,$T0
- xor $Q1,$Q3,$T1
- add $loopcntr,$loopcntr,-1
- bgtz $loopcntr,1b
- # final round
- @{[aes64es $Q2,$Q0,$Q1]}
- @{[aes64es $Q3,$Q1,$Q0]}
- # since not added 16 before
- ld $T0,16($KEYP)
- ld $T1,24($KEYP)
- xor $Q0,$Q2,$T0
- xor $Q1,$Q3,$T1
- sd $Q0,0($OUTP)
- sd $Q1,8($OUTP)
- # Pop registers and return
- ___
- $code .= load_regs();
- $code .= <<___;
- ret
- ___
- ################################################################################
- # void rv64i_zknd_decrypt(const unsigned char *in, unsigned char *out,
- # const AES_KEY *key);
- ################################################################################
- $code .= <<___;
- .text
- .balign 16
- .globl rv64i_zknd_decrypt
- .type rv64i_zknd_decrypt,\@function
- rv64i_zknd_decrypt:
- ___
- $code .= save_regs();
- $code .= <<___;
- # Load input to block cipher
- ld $Q0,0($INP)
- ld $Q1,8($INP)
- # Load number of rounds
- lwu $loopcntr,240($KEYP)
- # Load the last key
- slli $T0,$loopcntr,4
- add $KEYP,$KEYP,$T0
- ld $T0,0($KEYP)
- ld $T1,8($KEYP)
- xor $Q0,$Q0,$T0
- xor $Q1,$Q1,$T1
- # The main loop only executes the first N-1 rounds.
- add $loopcntr,$loopcntr,-1
- # Do Nr - 1 rounds (final round is special)
- 1:
- @{[aes64dsm $Q2,$Q0,$Q1]}
- @{[aes64dsm $Q3,$Q1,$Q0]}
- # Update key ptr to point to next key in schedule
- add $KEYP,$KEYP,-16
- # Grab next key in schedule
- ld $T0,0($KEYP)
- ld $T1,8($KEYP)
- xor $Q0,$Q2,$T0
- xor $Q1,$Q3,$T1
- add $loopcntr,$loopcntr,-1
- bgtz $loopcntr,1b
- # final round
- @{[aes64ds $Q2,$Q0,$Q1]}
- @{[aes64ds $Q3,$Q1,$Q0]}
- add $KEYP,$KEYP,-16
- ld $T0,0($KEYP)
- ld $T1,8($KEYP)
- xor $Q0,$Q2,$T0
- xor $Q1,$Q3,$T1
- sd $Q0,0($OUTP)
- sd $Q1,8($OUTP)
- # Pop registers and return
- ___
- $code .= load_regs();
- $code .= <<___;
- ret
- ___
- clear_regs();
- ################################################################################
- # Register assignment for rv64i_zkn[e/d]_set_[en/de]crypt_key
- ################################################################################
- # Function arguments (x10-x12 are a0-a2 in the ABI)
- # Pointer to user key, number of bits in key, key pointer
- my ($UKEY,$BITS,$KEYP) = use_regs(10..12);
- # Temporaries
- my ($T0,$T1,$T2,$T3,$T4) = use_regs(6..8,13..14);
- ################################################################################
- # utility functions for rv64i_zkne_set_encrypt_key
- ################################################################################
- sub ke128enc {
- my $rnum = 0;
- my $ret = '';
- $ret .= <<___;
- ld $T0,0($UKEY)
- ld $T1,8($UKEY)
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- ___
- while($rnum < 10) {
- $ret .= <<___;
- @{[aes64ks1i $T2,$T1,$rnum]}
- @{[aes64ks2 $T0,$T2,$T0]}
- @{[aes64ks2 $T1,$T0,$T1]}
- add $KEYP,$KEYP,16
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- ___
- $rnum++;
- }
- return $ret;
- }
- sub ke192enc {
- my $rnum = 0;
- my $ret = '';
- $ret .= <<___;
- ld $T0,0($UKEY)
- ld $T1,8($UKEY)
- ld $T2,16($UKEY)
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- sd $T2,16($KEYP)
- ___
- while($rnum < 8) {
- $ret .= <<___;
- @{[aes64ks1i $T3,$T2,$rnum]}
- @{[aes64ks2 $T0,$T3,$T0]}
- @{[aes64ks2 $T1,$T0,$T1]}
- ___
- if ($rnum != 7) {
- # note that (8+1)*24 = 216, (12+1)*16 = 208
- # thus the last 8 bytes can be dropped
- $ret .= <<___;
- @{[aes64ks2 $T2,$T1,$T2]}
- ___
- }
- $ret .= <<___;
- add $KEYP,$KEYP,24
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- ___
- if ($rnum != 7) {
- $ret .= <<___;
- sd $T2,16($KEYP)
- ___
- }
- $rnum++;
- }
- return $ret;
- }
- sub ke256enc {
- my $rnum = 0;
- my $ret = '';
- $ret .= <<___;
- ld $T0,0($UKEY)
- ld $T1,8($UKEY)
- ld $T2,16($UKEY)
- ld $T3,24($UKEY)
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- sd $T2,16($KEYP)
- sd $T3,24($KEYP)
- ___
- while($rnum < 7) {
- $ret .= <<___;
- @{[aes64ks1i $T4,$T3,$rnum]}
- @{[aes64ks2 $T0,$T4,$T0]}
- @{[aes64ks2 $T1,$T0,$T1]}
- add $KEYP,$KEYP,32
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- ___
- if ($rnum != 6) {
- # note that (7+1)*32 = 256, (14+1)*16 = 240
- # thus the last 16 bytes can be dropped
- $ret .= <<___;
- @{[aes64ks1i $T4,$T1,0xA]}
- @{[aes64ks2 $T2,$T4,$T2]}
- @{[aes64ks2 $T3,$T2,$T3]}
- sd $T2,16($KEYP)
- sd $T3,24($KEYP)
- ___
- }
- $rnum++;
- }
- return $ret;
- }
- ################################################################################
- # void rv64i_zkne_set_encrypt_key(const unsigned char *userKey, const int bits,
- # AES_KEY *key)
- ################################################################################
- sub AES_set_common {
- my ($ke128, $ke192, $ke256) = @_;
- my $ret = '';
- $ret .= <<___;
- bnez $UKEY,1f # if (!userKey || !key) return -1;
- bnez $KEYP,1f
- li a0,-1
- ret
- 1:
- # Determine number of rounds from key size in bits
- li $T0,128
- bne $BITS,$T0,1f
- li $T1,10 # key->rounds = 10 if bits == 128
- sw $T1,240($KEYP) # store key->rounds
- $ke128
- j 4f
- 1:
- li $T0,192
- bne $BITS,$T0,2f
- li $T1,12 # key->rounds = 12 if bits == 192
- sw $T1,240($KEYP) # store key->rounds
- $ke192
- j 4f
- 2:
- li $T1,14 # key->rounds = 14 if bits == 256
- li $T0,256
- beq $BITS,$T0,3f
- li a0,-2 # If bits != 128, 192, or 256, return -2
- j 5f
- 3:
- sw $T1,240($KEYP) # store key->rounds
- $ke256
- 4: # return 0
- li a0,0
- 5: # return a0
- ___
- return $ret;
- }
- $code .= <<___;
- .text
- .balign 16
- .globl rv64i_zkne_set_encrypt_key
- .type rv64i_zkne_set_encrypt_key,\@function
- rv64i_zkne_set_encrypt_key:
- ___
- $code .= save_regs();
- $code .= AES_set_common(ke128enc(), ke192enc(),ke256enc());
- $code .= load_regs();
- $code .= <<___;
- ret
- ___
- ################################################################################
- # utility functions for rv64i_zknd_set_decrypt_key
- ################################################################################
- sub ke128dec {
- my $rnum = 0;
- my $ret = '';
- $ret .= <<___;
- ld $T0,0($UKEY)
- ld $T1,8($UKEY)
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- ___
- while($rnum < 10) {
- $ret .= <<___;
- @{[aes64ks1i $T2,$T1,$rnum]}
- @{[aes64ks2 $T0,$T2,$T0]}
- @{[aes64ks2 $T1,$T0,$T1]}
- add $KEYP,$KEYP,16
- ___
- # need to aes64im for [1:N-1] round keys
- # this is from the fact that aes64dsm subwords first then mix column
- # intuitively decryption needs to first mix column then subwords
- # however, for merging datapaths (encryption first subwords then mix column)
- # aes64dsm chooses to inverse the order of them, thus
- # transform should then be done on the round key
- if ($rnum < 9) {
- $ret .= <<___;
- @{[aes64im $T2,$T0]}
- sd $T2,0($KEYP)
- @{[aes64im $T2,$T1]}
- sd $T2,8($KEYP)
- ___
- } else {
- $ret .= <<___;
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- ___
- }
- $rnum++;
- }
- return $ret;
- }
- sub ke192dec {
- my $rnum = 0;
- my $ret = '';
- $ret .= <<___;
- ld $T0,0($UKEY)
- ld $T1,8($UKEY)
- ld $T2,16($UKEY)
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- @{[aes64im $T3,$T2]}
- sd $T3,16($KEYP)
- ___
- while($rnum < 8) {
- $ret .= <<___;
- @{[aes64ks1i $T3,$T2,$rnum]}
- @{[aes64ks2 $T0,$T3,$T0]}
- @{[aes64ks2 $T1,$T0,$T1]}
- add $KEYP,$KEYP,24
- ___
- if ($rnum < 7) {
- $ret .= <<___;
- @{[aes64im $T3,$T0]}
- sd $T3,0($KEYP)
- @{[aes64im $T3,$T1]}
- sd $T3,8($KEYP)
- # the reason is in ke192enc
- @{[aes64ks2 $T2,$T1,$T2]}
- @{[aes64im $T3,$T2]}
- sd $T3,16($KEYP)
- ___
- } else { # rnum == 7
- $ret .= <<___;
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- ___
- }
- $rnum++;
- }
- return $ret;
- }
- sub ke256dec {
- my $rnum = 0;
- my $ret = '';
- $ret .= <<___;
- ld $T0,0($UKEY)
- ld $T1,8($UKEY)
- ld $T2,16($UKEY)
- ld $T3,24($UKEY)
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- @{[aes64im $T4,$T2]}
- sd $T4,16($KEYP)
- @{[aes64im $T4,$T3]}
- sd $T4,24($KEYP)
- ___
- while($rnum < 7) {
- $ret .= <<___;
- @{[aes64ks1i $T4,$T3,$rnum]}
- @{[aes64ks2 $T0,$T4,$T0]}
- @{[aes64ks2 $T1,$T0,$T1]}
- add $KEYP,$KEYP,32
- ___
- if ($rnum < 6) {
- $ret .= <<___;
- @{[aes64ks1i $T4,$T1,0xA]}
- @{[aes64ks2 $T2,$T4,$T2]}
- @{[aes64ks2 $T3,$T2,$T3]}
- @{[aes64im $T4,$T0]}
- sd $T4,0($KEYP)
- @{[aes64im $T4,$T1]}
- sd $T4,8($KEYP)
- @{[aes64im $T4,$T2]}
- sd $T4,16($KEYP)
- @{[aes64im $T4,$T3]}
- sd $T4,24($KEYP)
- ___
- } else {
- $ret .= <<___;
- sd $T0,0($KEYP)
- sd $T1,8($KEYP)
- # last two one dropped
- ___
- }
- $rnum++;
- }
- return $ret;
- }
- ################################################################################
- # void rv64i_zknd_set_decrypt_key(const unsigned char *userKey, const int bits,
- # AES_KEY *key)
- ################################################################################
- $code .= <<___;
- .text
- .balign 16
- .globl rv64i_zknd_set_decrypt_key
- .type rv64i_zknd_set_decrypt_key,\@function
- rv64i_zknd_set_decrypt_key:
- ___
- $code .= save_regs();
- $code .= AES_set_common(ke128dec(), ke192dec(),ke256dec());
- $code .= load_regs();
- $code .= <<___;
- ret
- ___
- print $code;
- close STDOUT or die "error closing STDOUT: $!";
|