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
}
# 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]})"