I have 2 Bash scripts. The first takes 2 strings as arguments and creates an env variable with the name of the 1st string and sets it's value to the value of the 2nd string encrypted with openssl (v3.4.2). The 2nd takes 1 string as an argument and outputs the decrypted value of the environment variable whose name is the value of the string passed as an argument.
setit.sh
#!/bin/bash
if [ $# -ne 2 ]; then
echo "Usage: $0 <variable_name> <string_to_encrypt>"
exit 1
fi
VAR_NAME=$1
STRING_TO_ENCRYPT=$2
# Generate a random salt and passphrase
SALT=$(openssl rand -hex 8)
PASSPHRASE=$(openssl rand -hex 12)
# Encrypt the string
ENCRYPTED=$(echo -n "$STRING_TO_ENCRYPT" | openssl enc -aes-256-cbc -a -salt -pbkdf2 -pass pass:"$PASSPHRASE" -S "$SALT")
# Combine salt, passphrase, and encrypted string
RESULT="${SALT}:${PASSPHRASE}:${ENCRYPTED}"
# Set the environment variable
export "$VAR_NAME=$RESULT"
echo "Environment variable $VAR_NAME has been set with the encrypted value."
Sample Usage
source ./setit.sh MY_VAR secret_value
getit.sh
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage: $0 <variable_name>"
exit 1
fi
VAR_NAME=$1
# Check if the environment variable exists
if [ -z "${!VAR_NAME}" ]; then
echo "Error: Environment variable $VAR_NAME does not exist."
exit 1
fi
# Get the value of the environment variable
ENCRYPTED_VALUE="${!VAR_NAME}\n"
echo "$VAR_NAME = $ENCRYPTED_VALUE"
# Extract salt, passphrase, and encrypted string
IFS=':' read -r SALT PASSPHRASE ENCRYPTED <<< "$ENCRYPTED_VALUE"
# Decrypt the string
DECRYPTED=$(echo -n "$ENCRYPTED" | openssl enc -aes-256-cbc -d -a -pbkdf2 -pass pass:"$PASSPHRASE" -S "$SALT")
# Check if decryption was successful
if [ $? -eq 0 ]; then
echo "Decrypted value of $VAR_NAME:"
echo "$DECRYPTED"
else
echo "Error: Decryption failed. The encrypted value may be corrupted or tampered with."
exit 1
fi
Sample Usage
./getit.sh MY_VAR
The first script seems to work as expected, but when I run the 2nd script to decrypt the value, I get the following error:
bad decrypt 0031185FF87F0000:error:1C80006B:Provider routines:ossl_cipher_generic_block_final:wrong final block length:providers/implementations/ciphers/ciphercommon.c:444: Error: Decryption failed. The encrypted value may be corrupted or tampered with.
The wrong final blocklength
part tells me that it might be a padding issue, but i'm not entirely sure.
Two changes to make to getit.sh
:
\n
when defining ENCRYPTED_VALUE
; ENCRYPTED_VALUE="${!VAR_NAME}\n"
adds the literal characters \
and n
on the end of the string which corrupts the encrypted dataecho
(sans the -n
) when piping $ENCRYPTED_VALUE
to openssl
; I'm guessing openssl
needs to see a linefeed (\n
) as a line terminator when reading input from the pipe and that openssl
is smart enough to ignore said linefeed as part of the encrypted dataThe new code lines:
ENCRYPTED_VALUE="${!VAR_NAME}"
DECRYPTED=$(echo $ENCRYPTED" | openssl enc -aes-256-cbc -d -a -pbkdf2 -pass pass:"$PASSPHRASE" -S "$SALT")
Taking for a test drive:
$ ./getit.sh MY_VAR
MY_VAR = 031280154d75151a:f52579d70b1439fbaa6d0fe3:03C8TtDzoByFsiyAsLdBkw==
Decrypted value of MY_VAR:
secret_value