How to create compressed and/or encrypted bash scripts

The immediate use of bash scripting is to automate tasks, but there are a lot of applications and tools in the commandline that are powerful enough and easy to use to have the need to use other languages such as python, perl, etc. that are harder to learn just to implement workflows of other tools.

When you try to make these scripts to be usable for third parties, its complexity increases as the amount of code that makes checks, verifications, etc. grows. At the end, you have created scripts that are reasonably big. Moreover, when you want to transfer these applications to others, you may want to avoid its re-distribution.

So this time I explored…

How to create compressed and/or encrypted bash scripts

TL;DR: An extended version of a code that gzips and encodes a script, that is run depending on a password (or license) is in the repository named LSC – License Shell Code.

Bash scripting is a powerful language to develop applications that manage servers, but also to automate processes in Linux, to execute batch tasks, or to other tasks that can be executed in the Linux commandline e.g. implement workflows in scientific applications (processing the output from one application to prepare it for other application).

But if your script grows a lot, maybe you want to compress it. Moreover, compressing the code is like somehow obfuscating the code. So it reduces the chance of re-using your code for other applications without permission (for the case of common end-users that do not master bash scripting).

Compressing the script and running it

Having a bash script in file example, compressing it is very simple. You can just see the next commands that create the example script and generates a gzipped version:

$ cat > example <<EOT
#!/bin/bash
echo "hello world"
EOT
$ cat > compressedscript <<EOT
#!/bin/bash
eval "\$(echo "$(cat example | gzip | base64)" | base64 -d | gunzip)"
EOT

Now the compressed script looks like this one:

#!/bin/bash
eval "$(echo "H4sIAOMSmVsAA1NW1E/KzNNPSizO4EpNzshXUMpIzcnJVyjPL8pJUeICAFeChBYfAAAA" | base64 -d | gunzip)"

And executing it is as simple as chmodding it and running it:

$ chmod +x compressedscript
$ ./compressedscript
hello world

As you can see, the process is very simple. We just embedded the gzipped source code (*) in a new script and took profit from the ability of the eval function.

(*) We needed to uuencode the gzipped file to be able to embed it in a plain text file.

Encrypting the script

Now that we know that the eval function works for our purposes, we can generalize the function of our proof of concept, to embed more complex things. For example, we can encrypt our script…

To encrypt things, we can use openssl as shown in this post. Briefly, we can encrypt a file with a command like the next one:

$ openssl enc -aes-256-cbc -salt -in file.txt -out file.txt.enc

And decode a encoded file with a command like the next one:

$ openssl enc -aes-256-cbc -d -in file.txt.enc -out file.txt

We apply encryption to our case, appart from gzipping our script. The resulting code is very similar to the previous case, but adding the encryption step:

$ cat > compressedscript <<EOT
#!/bin/bash
read -p "Please provide a password: " PASSWORD
eval "\$(echo "$(cat example | gzip | openssl enc -aes-256-cbc -in /dev/stdin -out /dev/stdout -k "mypasswd" | base64 | tr -d '\n')" | base64 -d | openssl enc -d -aes-256-cbc -in /dev/stdin -out /dev/stdout -k "\$PASSWORD" | gunzip)"
EOT

The resulting content for the new compressedscript file is the next one:

#!/bin/bash
read -p "Please provide a password: " PASSWORD
eval "$(echo "U2FsdGVkX18gnaQ3jFPBfhalu0/riWaRirtWHcFWgFqGFuzf3s98T/Y65Km2oe4jqGaAXlDCBX6+oWwWgqMIOBfG/O3P7qgmLTRpkzvShwc=" | base64 -d | openssl enc -d -aes-256-cbc -in /dev/stdin -out /dev/stdout -k "$PASSWORD" | gunzip)"

If we run that script, it will prompt for a password to decode de script (in our case it is “mypasswd”), and then it will be ran:

$ ./compressedscript
Please provide a password: mypasswd
hello world
$ ./compressedscript
Please provide a password: otherpasswd
bad decrypt
140040196646552:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:529:

gzip: stdin: not in gzip format

As shown in the code above, if other password is introduced, the code will not be ran.

Further reading

An extended version of the code of this post is included in LSC – License Shell Code. LSC is an application that generate shell applications (from existing ones) that need a license code to be run.

NOTES: Providing your users with a LICENSE code give them a more professional distribution, and a more tailored solution. Getting the code also implies a knowledge of what they are doing and so it also includes a first barrier (both from the point of the knowledge and from the ethics).