Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Written by Aaron D. Gifford -

A simple Ruby script for encrypting/decrypting files using 256-bit AES
and a master key derived from a password/passphrase via the PBKDF2

I wrote this script for use on several systems where I needed to
regularly encrypt/decrypt one or more files using a password or
passphrase.  The method used should be reasonably secure for the uses I
required.  I have NOT adapted the script (yet) for non-POSIX
environments (Windows) however.

This script was originally written and tested using Ruby 1.9.x. HOWEVER
it may no longer be compatible with older versions.  The author uses it
with Ruby version 2.4.3 on a FreeBSD 11.1 system.    No attempts to
adapt or test it on any other Ruby versions have been made.


Before a file is encrypted, some cryptographically secure random data
is obtained:

  SALT  = securely generated random salt data
  F_KEY = securely generated random key data
  F_IV  = securely generated random initialization vector data

The F_KEY and F_IV will be used to encrypt the plaintext file.  In
order to keep them secure, they will be encrypted using a master key
and initialization vector derived from the passphrase supplied by
the user and the SALT.

  PASS  = passphrase supplied by the user of the utility
  M_KEY = master key derived as described below
  M_IV  = master initilization vector derived as described below

In order to derive M_KEY and M_IV, the PBKDF2 algorithm as described
in RFC2898 is used, passing PASS and SALT to it, using the configured
hash (SHA-512 by default) and number of iterations (4096 by default).

Once M_KEY and M_IV are obtained, 256-bit AES in CBC mode is used to
encrypt F_KEY + F_IV to obtain:

  C_F_KEY = ciphertext encrypted version of F_KEY, encrypted using M_KEY and  M_IV
  C_F_IV  = ciphertext encrypted version of F_IV, encrypted using M_KEY and M_IV

A new file is opened, and SALT + C_F_KEY + C_F_IV are written.  A number
of zero bytes are written to make space to store the HMAC that will be

Then the contents of the plaintext file are then encrypted using F_KEY and F_IV
and written to the new file following the file header described above.

A HMAC is calculated on SALT + C_F_KEY + C_F_IV + encrypted file text.
Then the PBKDF2 function is applied to PASS + HMAC using the same SALT
to provide a MAC of sorts.

The HMAC isn't used directly because it would be easier to attempt to
apply a dictionary attack against the passphrase, at least for smaller
encrypted files, without PBKDF2's multiple iterations which increase
computation time for each passphrase guess.  This new HMAC/PBKDF2 hybrid
MAC is written over the top of the zero-bytes previously allocated, and
the file is closed.

Version 1.x of this library and utility stored the HMAC directly instead
utilizing this hybrid MAC scheme.

This new file is the encrypted file.  The old plaintext file is overwritten and

The HMAC uses the same PASS passphrase and the same hash algorithm that
PBKDF2 uses (SHA-512 by default).

To recover the file, an HMAC is calculated on the encrypted file contents,
excluding the HMAC/PBKDF2 hybrid MAC data.  The PBKDF2 function is applied
supplying PASS + HMAC as the passphrase and the SALT from the file to
calculate the hybrid HMAC/PBKDF2 MAC.  This hybrid MAC is then compared to
the one from the encrypted file.  If the calculated MAC doesn't match the
supplied MAC, then either the file has been corrupted, or the passphrase
is incorrect.

If the MACs match, the encrypted master key material C_F_KEY and C_F_IV
are read from the file.  M_KEY and M_IV are generated using PBKDF2
and PASS with SALT.  F_KEY and F_IV are decrypted using M_KEY and M_IV.
With the file encryption key and initialization vector, the file contents
are then decrypted, revealing the original file plaintext.

The encrypted file can then be safely removed.  The provided utility has
the option of then creating a separate file containing a newly-generated
salt and a PBKDF2 generated sum using the new salt and the original
passphrase.  This provides the user the ability to ask for a passphrase
and compare it (using PBKDF2 and the salt) to the original passphrase
without revealing the original passphrase.

The filesafe utility by default does exactly this, so that if a file
is re-encrypted (which will always use a freshly generated salt and
key), the user is asked for the original passphrase once again.  Should
the user decide to use a new phrase, the temporary file may be safely


Version 4.0.0 removes use of the 'pbkdf2' gem and uses OpenSSL's PBKDF2
function instead.  Some older OpenSSL versions might not fully support
this, and so version 4.x of this gem might not work there.


This script is licensed under an MIT-style license.  See the LICENSE.txt file.


This script requires or relies on:
  openssl       -- encryption/HMAC/hash/PBKDF2 algorithms
  securerandom  -- cryptographically secure random data
  tempfile      -- for temporary file creation

It uses the following gems:
  highline      -- for reading a password/passphrase from a terminal


The latest version can be found at the author's web site:



Please report bugs by going to the author's web site and clicking on the
"Contact Me" link in the left-hand menu.  The direct URL is:



A simple Ruby script for encrypting/decrypting files using 256-bit AES and a PBKDF2 password/passphrase derived key







No releases published


No packages published