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).
This commit is contained in:
David Cooper 2020-01-29 12:05:22 -05:00
parent 3da67437f3
commit 1ea631addd

View File

@ -11828,25 +11828,21 @@ gcm_mult() {
return 0 return 0
} }
# arg1: a hexadecimal string that is at least 8 bytes in length # arg1: nonce (must be 96 bits)
# See Section 6.2 of NIST SP 800-38D # arg2: number of blocks needed for plaintext/ciphertext
inc32() { # Generate the sequence of counter blocks, which are to be encrypted and then
local -i i len # XORed with either the plaintext or the ciphertext. The first block that is
local x="$1" # encrypted is used in computing the authentication tag.
local msb generate_gcm_ctr() {
local -i lsb local -i nr_blocks="$1"
local nonce="$2"
local i
local lsb ctr=""
len=${#x} for (( i=1; i <= nr_blocks; i++ )); do
[[ $len -lt 8 ]] && return 7 lsb="$(printf "%08X" "$i")"
i=$len-8 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}"
msb="${x:0:i}" done
lsb="0x${x:i:8}"
if [[ "$lsb" -eq "0xffffffff" ]]; then
lsb=0
else
lsb+=1
fi
tm_out "${msb}$(printf "%08X" "$lsb")"
return 0 return 0
} }
@ -11860,7 +11856,7 @@ inc32() {
# This function is based on gcm_setkey, gcm_start, gcm_update, and gcm_finish # This function is based on gcm_setkey, gcm_start, gcm_update, and gcm_finish
# in https://github.com/mko-x/SharedAES-GCM # in https://github.com/mko-x/SharedAES-GCM
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 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_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) 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]}) " hh+="$(printf "%016X" ${gcm_ctx_hh[i]}) "
done 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. # Feed any additional authenticated data into the computation for the authentication tag.
for (( i=0; i < aad_len; i+=use_len )); do for (( i=0; i < aad_len; i+=use_len )); do
[[ $((aad_len-i)) -lt 16 ]] && use_len=$((aad_len-i)) || use_len=16 [[ $((aad_len-i)) -lt 16 ]] && use_len=$((aad_len-i)) || use_len=16
@ -11928,25 +11920,33 @@ gcm() {
done done
fi 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 # gcm_update
# Encrypt or decrypt the input and feed the ciphertext into the computation for the authentication tag. # 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 for (( length=input_len; length > 0; length=length-use_len )); do
[[ $length -lt 16 ]] && use_len=$length || use_len=16 [[ $length -lt 16 ]] && use_len=$length || use_len=16
y="$(inc32 "$y")" if [[ $use_len -eq 16 ]]; then
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"')" 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
for (( i=0; i < use_len; i++ )); do tmp=""
tmp="$(printf "%02X" $((0x${ectr:$((2*i)):2} ^ 0x${input:$((2*i)):2})))" for (( i=0; i < use_len; i++ )); do
output+="$tmp" tmp+="$(printf "%02X" $((0x${ectr:$((2*i)):2} ^ 0x${input:$((2*i)):2})))"
if "$compute_tag"; then done
if [[ $mode == encrypt ]]; then fi
gcm_ctx_buf[i]="$(printf "%02X" $((0x${gcm_ctx_buf[i]} ^ 0x$tmp)))" output+="$tmp"
else if "$compute_tag"; then
gcm_ctx_buf[i]="$(printf "%02X" $((0x${gcm_ctx_buf[i]} ^ 0x${input:$((2*i)):2})))" [[ $mode == decrypt ]] && tmp="${input:0:32}"
fi for (( i=0; i < use_len; i++ )); do
fi gcm_ctx_buf[i]="$(printf "%02X" $((0x${gcm_ctx_buf[i]} ^ 0x${tmp:$((2*i)):2})))"
done done
fi
ectr="${ectr:32}"
if "$compute_tag"; then 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]})" 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]})"