From 1ea631addd0c703861ea192036bc006371ea3286 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 29 Jan 2020 12:05:22 -0500 Subject: [PATCH] Speedup AES-GCM The implementation of AES-GCM in #1473 is much slower than the original version, even when the authentication tag is not being computed. This PR modifies the code in gcm() in order to significantly speed up the encryption/decryption time (when authentication tags are not being computed). --- testssl.sh | 74 +++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/testssl.sh b/testssl.sh index cf06adf..2f8a55d 100755 --- a/testssl.sh +++ b/testssl.sh @@ -11828,25 +11828,21 @@ gcm_mult() { return 0 } -# arg1: a hexadecimal string that is at least 8 bytes in length -# See Section 6.2 of NIST SP 800-38D -inc32() { - local -i i len - local x="$1" - local msb - local -i lsb +# arg1: nonce (must be 96 bits) +# arg2: number of blocks needed for plaintext/ciphertext +# Generate the sequence of counter blocks, which are to be encrypted and then +# XORed with either the plaintext or the ciphertext. The first block that is +# encrypted is used in computing the authentication tag. +generate_gcm_ctr() { + local -i nr_blocks="$1" + local nonce="$2" + local i + local lsb ctr="" - len=${#x} - [[ $len -lt 8 ]] && return 7 - i=$len-8 - msb="${x:0:i}" - lsb="0x${x:i:8}" - if [[ "$lsb" -eq "0xffffffff" ]]; then - lsb=0 - else - lsb+=1 - fi - tm_out "${msb}$(printf "%08X" "$lsb")" + for (( i=1; i <= nr_blocks; i++ )); do + lsb="$(printf "%08X" "$i")" + printf "\x${nonce:0:2}\x${nonce:2:2}\x${nonce:4:2}\x${nonce:6:2}\x${nonce:8:2}\x${nonce:10:2}\x${nonce:12:2}\x${nonce:14:2}\x${nonce:16:2}\x${nonce:18:2}\x${nonce:20:2}\x${nonce:22:2}\x${lsb:0:2}\x${lsb:2:2}\x${lsb:4:2}\x${lsb:6:2}" + done return 0 } @@ -11860,7 +11856,7 @@ inc32() { # This function is based on gcm_setkey, gcm_start, gcm_update, and gcm_finish # in https://github.com/mko-x/SharedAES-GCM gcm() { - local cipher="$1" aes_key="$2" y="${3}00000001" input="$4" aad="$5" mode="$6" + local cipher="$1" aes_key="$2" nonce="$3" input="$4" aad="$5" mode="$6" local compute_tag="$7" local -a -i gcm_ctx_hl=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) local -a -i gcm_ctx_hh=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) @@ -11912,10 +11908,6 @@ gcm() { hh+="$(printf "%016X" ${gcm_ctx_hh[i]}) " done - # gcm_start - # compute the encrypted counter for later use in computing the authentication tag - base_ectr="$(printf "\x${y:0:2}\x${y:2:2}\x${y:4:2}\x${y:6:2}\x${y:8:2}\x${y:10:2}\x${y:12:2}\x${y:14:2}\x${y:16:2}\x${y:18:2}\x${y:20:2}\x${y:22:2}\x${y:24:2}\x${y:26:2}\x${y:28:2}\x${y:30:2}" | $OPENSSL enc "$cipher" -K "$aes_key" -nopad 2>/dev/null | hexdump -v -e '16/1 "%02X"')" - # Feed any additional authenticated data into the computation for the authentication tag. for (( i=0; i < aad_len; i+=use_len )); do [[ $((aad_len-i)) -lt 16 ]] && use_len=$((aad_len-i)) || use_len=16 @@ -11928,25 +11920,33 @@ gcm() { done fi + j=$((1 + input_len/16)) + [[ $((input_len%16)) -ne 0 ]] && j+=1 + ectr="$(generate_gcm_ctr "$j" "$nonce" | $OPENSSL enc "$cipher" -K "$aes_key" -nopad 2>/dev/null | hexdump -v -e '16/1 "%02X"')" + base_ectr="${ectr:0:32}" + ectr="${ectr:32}" + # gcm_update # Encrypt or decrypt the input and feed the ciphertext into the computation for the authentication tag. for (( length=input_len; length > 0; length=length-use_len )); do [[ $length -lt 16 ]] && use_len=$length || use_len=16 - y="$(inc32 "$y")" - ectr="$(printf "\x${y:0:2}\x${y:2:2}\x${y:4:2}\x${y:6:2}\x${y:8:2}\x${y:10:2}\x${y:12:2}\x${y:14:2}\x${y:16:2}\x${y:18:2}\x${y:20:2}\x${y:22:2}\x${y:24:2}\x${y:26:2}\x${y:28:2}\x${y:30:2}" | $OPENSSL enc "$cipher" -K "$aes_key" -nopad 2>/dev/null | hexdump -v -e '16/1 "%02X"')" - - for (( i=0; i < use_len; i++ )); do - tmp="$(printf "%02X" $((0x${ectr:$((2*i)):2} ^ 0x${input:$((2*i)):2})))" - output+="$tmp" - if "$compute_tag"; then - if [[ $mode == encrypt ]]; then - gcm_ctx_buf[i]="$(printf "%02X" $((0x${gcm_ctx_buf[i]} ^ 0x$tmp)))" - else - gcm_ctx_buf[i]="$(printf "%02X" $((0x${gcm_ctx_buf[i]} ^ 0x${input:$((2*i)):2})))" - fi - fi - done + if [[ $use_len -eq 16 ]]; then + tmp="$(printf "%08X%08X%08X%08X" "$((0x${ectr:0:8} ^ 0x${input:0:8}))" "$((0x${ectr:8:8} ^ 0x${input:8:8}))" "$((0x${ectr:16:8} ^ 0x${input:16:8}))" "$((0x${ectr:24:8} ^ 0x${input:24:8}))")" + else + tmp="" + for (( i=0; i < use_len; i++ )); do + tmp+="$(printf "%02X" $((0x${ectr:$((2*i)):2} ^ 0x${input:$((2*i)):2})))" + done + fi + output+="$tmp" + if "$compute_tag"; then + [[ $mode == decrypt ]] && tmp="${input:0:32}" + for (( i=0; i < use_len; i++ )); do + gcm_ctx_buf[i]="$(printf "%02X" $((0x${gcm_ctx_buf[i]} ^ 0x${tmp:$((2*i)):2})))" + done + fi + ectr="${ectr:32}" if "$compute_tag"; then tmp="$(gcm_mult $hl $hh ${gcm_ctx_buf[0]} ${gcm_ctx_buf[1]} ${gcm_ctx_buf[2]} ${gcm_ctx_buf[3]} ${gcm_ctx_buf[4]} ${gcm_ctx_buf[5]} ${gcm_ctx_buf[6]} ${gcm_ctx_buf[7]} ${gcm_ctx_buf[8]} ${gcm_ctx_buf[9]} ${gcm_ctx_buf[10]} ${gcm_ctx_buf[11]} ${gcm_ctx_buf[12]} ${gcm_ctx_buf[13]} ${gcm_ctx_buf[14]} ${gcm_ctx_buf[15]})"