dowbwrr3590709
dowbwrr3590709
2019-06-24 09:52

如何解密用Openssl在bash脚本中加密的PHP文件

I have to decrypt a file in my Laravel backend with PHP's openssl_decrypt. The file is encrypted outside Laravel fro ma BASH script and openssl 1.1.

I looked at some explanations that would help me but found nothing that worked. My openssl versions are the same (1.1) for both PHP and the server. I tried many combinations of options but nothing worked.

Here is my BASH encrypting script:

APP_KEY='**************'
FILES_PATH='****/app/files/'
# We're looking for ".decrypted" files, which gonna be encrypted next
FILES_LIST=$(find $FILES_PATH -type f -name '*.decrypted' )
# We base64-decode the key then display it as Hex. string
KEY=$(echo $APP_KEY | base64 -d -i | xxd -p -c 64)

# For each file to encrypt :
while read -r file; do
  # If there is actually a file :
  if [ ! -z "$file" ]; then
    output=${file%.decrypted}
    chunkspath="${output}.chunk."
    chunksname="${chunkspath##*/}*"
    # We have to split the files into 32M. chunks because our server can't decrypt big files without memory leaks in php.
    split -b 32M -d $file -a 3 $chunkspath
    chunkslist=$(find $FILES_PATH -type f -name $chunksname)
    touch $output
    # For each chunk :
    while read -r chunk; do
      # Generate a random IV of 16 bytes (output is 32 characters in Hex.)
      iv=$(openssl rand -hex 16)
      temp="${chunk}.enc"
      openssl AES-256-CBC -K $KEY -iv $iv -in $chunk -out $temp
      # We prefix each chunk with his IV to let the server retrieve it when decrypting. See the PHP code bellow.
      echo -n $iv >> $output
      # Then we append each IV+Chunk in the final output file.
      cat $temp >> $output
      rm $temp $chunk
    done < <(echo "${chunkslist}")
    # I commented the next line to let me run some tests but the original file will have to be removed eventually.
    # rm $file
  fi
done < <(echo "${FILES_LIST}")

echo 'Done'

And here's my PHP's script for decrypting the file:

// This function is inside a Laravel's stream download response 
    function () use ($file, $log) { // $file is the Laravel model representation of a stored file.
        $cipher = 'AES-256-CBC';
        $key = base64_decode(substr(config('app.key'), 7));
        $ivLen = 32; // Actually 16 bytes but 32 characters in hex format
        $chunckLen = 32 * 1024 * 1024; // Chunks are 32Mo long or less for the last one
        $fpIn = fopen(Storage::disk('files')->path($file->path), 'rb');
        while (!feof($fpIn)) {
            // IV and Key must be in binary format
            $iv = hex2bin(fread($fpIn, $ivLen));
            // We read the file chunks by chunks, decrypt it and print it.
            $encrypted = fread($fpIn, $chunckLen);
            $decrypted = openssl_decrypt($encrypted, $cipher, $key, OPENSSL_RAW_DATA, $iv);
            while ($msg = openssl_error_string()) {
                print $msg . "
";
            }
            print($decrypted);
        }
    }

I expect the decrypted file to be readable. With the code above, the output file contains this line: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt I tried with the OPENSSL_ZERO_PADDING options on the openssl_decrypt() method. The output file then contains binary data but the file is not readable (I guess the ecryption did not work as expected). I also tried to set the -nopad option in the bash script but then this error is thrown: 4960:error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:data not multiple of block length:../openssl-1.1.1c/crypto/evp/evp_enc.c:425:. Does someone know what there errors mean ? What did I do wrong ? I'm almost sure I missed something (I'm kind of new in the encryption world...)

Thank you!

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • drxvjnx58751 drxvjnx58751 2年前

    Actually I just realized that the Key used in the script and the one used in Laravel weren't the same... Stupid me. The code above is therefore correct and resolves my problem.

    点赞 评论 复制链接分享