Bash脚本中OpenSSL加解密报错:wrong final block length问题求助
我写了两个Bash脚本用来加密/解密环境变量:
setit.sh:接收两个参数,将第二个字符串用OpenSSL v3.4.2加密后设置为第一个参数命名的环境变量getit.sh:接收环境变量名参数,解密并输出其值
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."
示例用法: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
示例用法:./getit.sh MY_VAR
错误现象
setit.sh运行正常,但执行getit.sh时出现解密错误:
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.
怀疑和填充问题有关,但不确定具体原因,求解决。
原因分析
问题出在getit.sh的这一行:
ENCRYPTED_VALUE="${!VAR_NAME}\n"
你给环境变量的值额外添加了\n(换行符转义序列),但echo默认不会解析转义序列,所以实际变量值里会包含字面量\n字符,而不是换行符。这会导致后续用IFS=':'分割时,ENCRYPTED部分被混入了\n,传给OpenSSL解密时,数据长度不符合AES块大小要求,触发"wrong final block length"错误。
另外,echo "$VAR_NAME = $ENCRYPTED_VALUE"这一步也会让输出看起来有换行,但实际变量值被篡改了。
修复方案
修改getit.sh中获取环境变量值的代码,去掉多余的\n:
修复后的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 (去掉多余的\n) ENCRYPTED_VALUE="${!VAR_NAME}" 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
验证步骤
- 重新执行
source ./setit.sh MY_VAR secret_value设置环境变量 - 运行修复后的
./getit.sh MY_VAR,应该能正常输出解密后的secret_value
内容的提问来源于stack exchange,提问作者Daveh0

