• sh
  • gpg
  • openssl

Recursive encryption of directories

This project was the product of the need I had of fully encrypting the contents of a certain directory with a lot of files and subdirectories. I’m sure that the resulting script may not the fastest tool, but it serves its main goal. Also, beware of using it on untrusted machines, as the password is shown in cleartext on the running processes, like on the following example (note the --passphrase asdf, on the last line):

$ ps -elf | grep -i "encrypt_files"
0 S foo-man+ 31143 27198  0  80   0 -  1128 wait   12:33 pts/20   00:00:00 /bin/sh /usr/local/bin/encrypt_files encryption/
1 S foo-man+ 31154 31143  0  80   0 -  1128 wait   12:33 pts/20   00:00:00 /bin/sh /usr/local/bin/encrypt_files encryption/
0 S foo-man+ 31162 30455  0  80   0 -  3940 pipe_w 12:33 pts/17   00:00:00 grep --color=auto -i encrypt_files
$ pstree -a 31143
encrypt_files /usr/local/bin/encrypt_files encryption/
  └─encrypt_files /usr/local/bin/encrypt_files encryption/
      └─gpg --passphrase asdf --output encryption/hmHc3ntwOx.enc --symmetric encryption/large_file.zip

This little script uses GPG and OpenSSL to encrypt one by one all the files on the given directory, and then shreds all the original files. The name of the directories are encrypted, too.

Of course, the script also supports decryption, with the -d flag.

Example usage

To the examples, the directory structure to be used is the one created with jekyll new encryption_test:

encryption_test/
├── 404.html
├── about.md
├── _config.yml
├── Gemfile
├── .gitignore
├── index.md
└── _posts
    └── 2017-08-30-welcome-to-jekyll.markdown

When we encrypt it, we get the same directory structure, but with encrypted names (note that this run has been made with extra verbosity):

$ encrypt_files encryption_test/ -vv

 ----------------
 Encrypting files
 ----------------

==> Encrypting 'encryption_test/_config.yml'
gpg: using cypher AES
gpg: writing to 'encryption_test/a1ZmOTv7Zg.enc'
 ----> DONE <----
shred: encryption_test/_config.yml: pass 1/3 (random)...
shred: encryption_test/_config.yml: pass 2/3 (random)...
shred: encryption_test/_config.yml: pass 3/3 (random)...
==> Encrypting 'encryption_test/index.md'
gpg: using cypher AES
gpg: writing to 'encryption_test/Uy5MvTDkpX.enc'
 ----> DONE <----
shred: encryption_test/index.md: pass 1/3 (random)...
shred: encryption_test/index.md: pass 2/3 (random)...
shred: encryption_test/index.md: pass 3/3 (random)...
==> Encrypting 'encryption_test/about.md'
gpg: using cypher AES
gpg: writing to 'encryption_test/3vahSDieaZ.enc'
 ----> DONE <----
shred: encryption_test/about.md: pass 1/3 (random)...
shred: encryption_test/about.md: pass 2/3 (random)...
shred: encryption_test/about.md: pass 3/3 (random)...
==> Encrypting 'encryption_test/2017-08-30-welcome-to-jekyll.markdown'
gpg: using cypher AES
gpg: writing to 'encryption_test/jEpgQ53f1B.enc'
 ----> DONE <----
shred: encryption_test/_posts/2017-08-30-welcome-to-jekyll.markdown: pass 1/3 (random)...
shred: encryption_test/_posts/2017-08-30-welcome-to-jekyll.markdown: pass 2/3 (random)...
shred: encryption_test/_posts/2017-08-30-welcome-to-jekyll.markdown: pass 3/3 (random)...
==> Encrypting 'encryption_test/Gemfile'
gpg: using cypher AES
gpg: writing to 'encryption_test/3U3ZPiwlFd.enc'
 ----> DONE <----
shred: encryption_test/Gemfile: pass 1/3 (random)...
shred: encryption_test/Gemfile: pass 2/3 (random)...
shred: encryption_test/Gemfile: pass 3/3 (random)...
==> Encrypting 'encryption_test/404.html'
gpg: using cypher AES
gpg: writing to 'encryption_test/5OKMYJVl9m.enc'
 ----> DONE <----
shred: encryption_test/404.html: pass 1/3 (random)...
shred: encryption_test/404.html: pass 2/3 (random)...
shred: encryption_test/404.html: pass 3/3 (random)...
==> Encrypting 'encryption_test/.gitignore'
gpg: using cypher AES
gpg: writing to 'encryption_test/neoI4uqQy1.enc'
 ----> DONE <----
shred: encryption_test/.gitignore: pass 1/3 (random)...
shred: encryption_test/.gitignore: pass 2/3 (random)...
shred: encryption_test/.gitignore: pass 3/3 (random)...

 ----------------------
 Encrypting directories
 ----------------------

==> Encrypting 'encryption_test/_posts'
 ----> DONE <----
==> Encrypting 'encryption_test/encryption_test'
 ----> DONE <----
New encrypted directory name: 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc'
 ==> DONE <==

Even though it’s not shown, the program asks for a password to encrypt everything, as GPG does; but this prompt is then erased to print new messages.

This is the new directory structure:

$ tree KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY\=\=\=\=\=\=.enc/
KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/
├── 3U3ZPiwlFd.enc
├── 3vahSDieaZ.enc
├── 5OKMYJVl9m.enc
├── a1ZmOTv7Zg.enc
├── KNQWY5DFMRPV657M5PAEBYZOOLGVWWOBN7JQ====.enc
│   └── jEpgQ53f1B.enc
├── neoI4uqQy1.enc
└── Uy5MvTDkpX.enc

Then, to decrypt (this time with only one -v flag), we only have to provide the extra flag for the decryption:

$ encrypt_files -dv KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY\=\=\=\=\=\=.enc/

 ----------------
 Decrypting files
 ----------------

==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/3U3ZPiwlFd.enc'
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: original file name='Gemfile'
 ----> DONE <----
==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/a1ZmOTv7Zg.enc'
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: original file name='_config.yml'
 ----> DONE <----
==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/KNQWY5DFMRPV657M5PAEBYZOOLGVWWOBN7JQ====.enc/jEpgQ53f1B.enc'
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: original file name='2017-08-30-welcome-to-jekyll.markdown'
 ----> DONE <----
==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/5OKMYJVl9m.enc'
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: original file name='404.html'
 ----> DONE <----
==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/neoI4uqQy1.enc'
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: original file name='.gitignore'
 ----> DONE <----
==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/Uy5MvTDkpX.enc'
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: original file name='index.md'
 ----> DONE <----
==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/3vahSDieaZ.enc'
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: original file name='about.md'
 ----> DONE <----

 ----------------------
 Decrypting directories
 ----------------------

==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc/KNQWY5DFMRPV657M5PAEBYZOOLGVWWOBN7JQ====.enc'
 ----> DONE <----
==> Decrypting 'KNQWY5DFMRPV6SQKYTE53CFV2RLCDSGP66HTLWFWO6FKJPYVHY======.enc'
 ----> DONE <----
New decrypted directory name: 'encryption_test'
 ==> DONE <==

And we get again the original directory tree, with the decrypted files:

$ tree encryption_test/
encryption_test/
├── 404.html
├── about.md
├── _config.yml
├── Gemfile
├── index.md
└── _posts
    └── 2017-08-30-welcome-to-jekyll.markdown

This project is not hosted anywhere but here, where it can be downloaded and freely used and modified. Of course, there’s a lot of room for improvement, so you’re very welcome to contribute, if you want to.

More projects