# Sym — Light Weight Symmetric Encryption for Humans
[![Gitter](https://img.shields.io/gitter/room/gitterHQ/gitter.svg)](https://gitter.im/kigster/sym)
[![Gem Version](https://badge.fury.io/rb/sym.svg)](https://badge.fury.io/rb/sym)
[![Downloads](http://ruby-gem-downloads-badge.herokuapp.com/sym?type=total)](https://rubygems.org/gems/sym)
[![Documentation](http://inch-ci.org/github/kigster/sym.png)](http://inch-ci.org/github/kigster/sym)
[![Build Status](https://travis-ci.org/kigster/sym.svg?branch=master)](https://travis-ci.org/kigster/sym)
[![Code Climate](https://codeclimate.com/github/kigster/sym/badges/gpa.svg)](https://codeclimate.com/github/kigster/sym)
[![Test Coverage](https://codeclimate.com/github/kigster/sym/badges/coverage.svg)](https://codeclimate.com/github/kigster/sym/coverage)
[![Issue Count](https://codeclimate.com/github/kigster/sym/badges/issue_count.svg)](https://codeclimate.com/github/kigster/sym)
## Description
> __sym__ is a command line utility and a Ruby API that makes it _trivial to encrypt and decrypt sensitive data_. Unlike many other existing encryption tools, __sym__ focuses on usability and streamlined interface (CLI), with the goal of making encryption easy and transparent. The result? There is no excuse for keeping your application secrets unencrypted :)
### Motivation
The primary goal of this tool is to streamline and simplify handling of relatively sensitive data in the most trasparent and easy to use way as possible, without sacrificing security.
Most common use-cases include:
* __Encrypting/decrypting of application secrets__, so that the encrypted secrets can be safely checked into the git repository and distributed, and yet without much of the added headache that this often requires
* __Secure message transfer between any number of receipients__
* __General purpose encryption/decryption with a single encryption key__, optionally itself re-encrypted with a password.
__Sym__ is a layer built on top of the [`OpenSSL`](https://www.openssl.org/) library, and, hopefully, makes encryption more accessible to every-day developers, QA, and dev-ops folks, engaged in deploying applications.
### What's Included
This gem includes two primary components:
* [Ruby API](#rubyapi) for enabling encryption/decryption of any data within any Ruby class, with extremely easy-to-use methods
* [Rich command line interface CLI](#cli) with many additional features to streamline handling of encrypted data.
_Symmetric Encryption_ simply means that we are using the same private key to encrypt and decrypt. In addition to the private key, the encryption uses an IV vector. The library completely hides `iv` generation from the user, and automatically generates a random `iv` per encryption.
### Massive Time Savers
So how does `sym` substantiate its claim that it *streamlines* the encryption process? I thought about it, and turns out there are quite a few reasons:
* By using Mac OS-X Keychain, `sym` offers a simple yet secure way of storing the key on a local machine, much more secure then storing it on a file system.
* By using a password cache (`-c`) via an in-memory provider such as `memcached` or `drb`, `sym` invocations take advantage of password cache, and only ask for a password once per a configurable time period.
* By using `SYM_ARGS` environment variable, where common flags can be saved.
* By reading a key from the default key source file `~/.sym.key` which requires no flags at all.
* By utilizing the `--negate` option to quickly encrypt a regular file, or decrypt an encrypted file with extension `.enc`.
* By using the `-t` (edit) mode, that opens an encrypted file in your `$EDITOR`, and replaces the encrypted version upon save & exit.
As you can see, we really tried to build a tool that provides good security for application secrets, including password-based encryption, but does not annoyingly ask for password every time. With `--edit` option, and `--negate` options you can treat encrypted files like regular files.
> Encrypting application secrets had never been easier! –– Socrates [LOL, -ed.]
### How It Works
1. You generate a new encryption key, that will be used to both encrypt and decrypt the data. The key is 256 bits, or 32 bytes, or 45 bytes when base64-encoded, and can be generated with `sym -g`.
* You can optionally password protect the key with `sym -gp`
* You can save the key into a file with `sym -gpo key-file`
* Or you can save it into the OS-X Keychain, with `sym -gpx keychain-name`
* You can also cache the password, with `sym -gpcx keychain-name`
* Normally, `sym` will also print the resulting key to STDOUT.
* You can prevent the key from being printed to STDOUT with `-q/--quiet`.
2. You then take a piece of sensitive __data__ that you want to encrypt. This can be a file or a string.
3. You can then use the key to encrypt sensitive __data__, with `sym -e [key-spec] [data-spec]`, passing it the key in several accepted ways. Smart flag `-k` automatically interpretes the source of the key, by trying:
* a file with a pathname.
* or environment variable
* or OS-X Keychain password entry
* or you can paste the key interactively with `-i`
4. Input data can be read from a file with `-f file`, or read from STDIN, or a passed on the command line with `-s string`
4. Output is the encrypted data, which is printed to STDOUT by the default, or it can be saved to a file with `-o `
5. Encrypted file can be later decrypted with `sym -d [key-spec] [data-spec]`
Sample session that uses Mac OS-X Keychain to store the password-protected key.
```bash
# Gen a new key, password-encrypt it, cache the password, save
# result in the key chain entry 'my-new-key' (but don't print it '-q')
❯ sym -gpqcx my-new-key
New Password : •••••••••
Confirm Password : •••••••••
❯ sym -eck my-new-key -s 'My secret data' -o secret.enc
Coin::Vault listening at: druby://127.0.0.1:24924
Password: •••••••••
❯ cat secret.enc
BAhTOh1TeW06OkRhdGE6OldyYXBFefDFFD.....
❯ sym -dck my-new-key -f secret.enc
My secret data
# Now, let's save our keychain key in the default key file:
❯ sym -ck my-new-key -o ~/.sym.key
# Now we can decrypt/encrypt with this key at will
❯ sym -n secret.enc
# created a decrypted file `secret`
# Lets now save common flags in the SYM_ARGS bash variable:
❯ export SYM_ARGS="-ck my-new-key"
❯ sym -df secret.enc
My secret data
```
The line that says `Coin::Vault listening at: druby://127.0.0.1:24924` is the indication that the local dRB server used for caching passwords has been started. Password caching is off by default, but is enabled with `-c` flag. In the example above, the decryption step fetched the password from the cache, and so the user was not required to re-enter the password.
__Direct Editing Encrypted Files__
Instead of decrypting data anytime you need to change it, you can use the shortcut flag `-t` (for "edi**t**"), which decrypts your data into a temporary file, automatically opening it with an `$EDITOR`.
Example:
sym -t -f config/application/secrets.yml.enc -k ~/.key
> This is one of those time-saving features that can make a difference in making encryption feel easy and transparent.
For more information see the section on [inline editing](#inline).
## Installation
If you plan on using the library in your Ruby project with Bundler managing its dependencies, just include the following line in your `Gemfile`:
gem 'sym'
And then run `bundle`.
Or install it into the global namespace with `gem install` command:
$ gem install sym
$ sym -h
$ sym -E # see examples
__BASH Completion__
Optionally, after gem installation, you can also install bash-completion of gem's command line options, but running the following command (and feel free to use any of the "dot" files you prefer):
sym -B/--bash-support ~/.bashrc
Should you choose to install it (this part is optional), you will be able to use "tab-tab" after typing `sym`, and you'll be able to choose from all of the supported flags.
## Using `sym` with the Command Line
### Private Keys
The private key is the cornerstone of the symmetric encryption. Using `sym`, the key can be:
* generated and printed to STDOUT, or saved to Mac OS-X KeyChain or a file
* fetched from the Keychain in subsequent operations
* password-protected during generation (or import) with the `-p` flag.
* password can be cached using either `memcached` or `dRB` server, if the `-c` flag is provided.
* must be kept very well protected and secure from attackers.
The __unencrypted private__ key will be in the form of a base64-encoded string, 45 characters long.
__Encrypted (with password) private key__ will be considerably longer, perhaps 200-300 characters long.
#### Generating Private Keys
Let's generate a new key, and copy it to the clipboard (using `pbcopy` command on Mac OS-X):
sym -g | pbcopy
Or save a new key into a bash variable
KEY=$(sym -g)
Or save it to a file:
sym -go ~/.key
Or create a password-protected key (`-p`), and save it to a file (`-o`), cache the password (`-c`), and don't print the new key to STDOUT (`-q` for quiet):
sym -gpcqo ~/.secret
New Password: ••••••••••
Confirm Password: ••••••••••
##### Key Sources
You can subsequently use the private key by passing either of these options to the `-k` flag (*sym attempts to resolve the key automatically, by trying each option and moving to the next until the key is found*):
1. the `-k value` flag, where the *value* is one of:
* a file path
* an environment variable name
* an actual base64-encoded key (not recommended for security reasons)
* a keychain name
2. pasting or typing the key with the `-i` (interactive) flag
3. a default key file, in your home folder, `~/.sym.key`, used only when no other flags were passed in.
#### Using KeyChain Access on Mac OS-X
KeyChain storage is a huge time saver. It allows you to securely store the key the keychain, meaning the key can not be easily extracted by an attacker without a login to your account. Just having access to the disk is not enough.
Apple had released a `security` command line tool, which this library uses to securely store a key/value pair of the key name and the actual private key in your OS-X KeyChain. The advantages of this method are numerous:
* The private key won't be lying around your file system unencrypted, so if your Mac is ever stolen, you don't need to worry about the keys running wild.
* If you sync your keychain with the iCloud you will have access to it on other machines
As mentioned previously, to add the key to the KeyChain on the Mac, use `-x ` flag with `-g` flag when generating a key. The `key name` is what you call this particular key, based on how you plan to use it. For example, you may call it `staging`, etc.
The following command generates the private key and immediately stores it in the KeyChain access under the name provided:
sym -gx staging # the key is passwordless
sym -gpcx staging # this key is password protected, with the password cached
Next, whenever you need to *use* this key, you can specify the key with `-k staging`.
Finally, you can delete a key from KeyChain access by running:
keychain delete
Below we describe the purpose of the executable `keychain` shipped with sym.
#### KeyChain Key Management
`keychain` is an additional executable installed with the gem, which can be used to read (find), update (add), and delete keychain entries used by `sym`.
It's help message is self-explanatory:
Usage: keychain [ add | find | delete ]
#### Moving a Key to the Keychain
You can easily move an existing key from a file or a string to a keychain by combining -k or -k to read the key, with -x to write it.
sym -k $keysource -x mykey
#### Adding Password to Existing Key
You can add a password to a key by combining one of the key description flags (-k, -i) and then also -p. Use `-q` to hide new key from the STDOUT, and `c` to cache the password.
sym -k $mykey -pqcx moo
The above example will take an unencrypted key passed in `$mykey`, ask for a password and save password protected key into the keychain with name "moo."
#### Password Caching
Nobody likes to re-type passwords over and over again, and for this reason *Sym* supports password caching via either a locally running `memcached` instance (the default, if available), or a locally started `dRB` (distributed Ruby) server based on the `Coin` gem.
Specifics of configuring both Cache Providers is left to the `Configuration` class, an example of which is shown below in the Ruby API section.
In order to control password caching, the following flags are available:
* `-c` turns on caching
* `-u seconds` sets the expiration for cached passwords
* `-r memcached | drb` controls which of the providers is used. Without this flag, *sym* auto-detects caching provider by first checking for `memcached`, and then starting the `dRB` server.
#### Saving Common Flags in an Environment Variable
You can optionally store frequently used flags for `sym` in the `SYM_ARGS` environment variable. For example, to always cache passwords, and to always use the same encryption key from the keychain named "production", set the following in your `~/.bashrc`:
```
export SYM_ARGS="-cx production"
```
This will be automatically appended to the command line if the `-A/--sym-args` flag is provided, and so to encrypt/decrypt anything with password caching enabled and using that particular key, you would simply type:
```bash
# -cx production are added from SYM_ARGS
sym -Aef file -o file.enc
# And to decrypt:
sym -Adf file.enc -o file.original
# Or edit the encrypted file:
sym -Atf file.enc
```
#### Complete CLI Usage
This may be a good time to take a look at the full help message for the `sym` tool, shown naturally with a `-h` or `--help` option.
```
Sym (2.5.1) – encrypt/decrypt data with a private key
Usage:
# Generate a new key, optionally password protected, and save it
# in one of: keychain, file, or STDOUT (-q turns off STDOUT)
sym -g [ -p/--password ] [ -x keychain | -o file | ] [ -q ]
# To specify encryption key, provide the key as
# 1) a string, 2) a file path, 3) an OS-X Keychain, 4) env variable name
# 5) use -i to paste/type the key interactively
# 6) default key file (if present) at /Users/kig/.sym.key
KEY-SPEC = -k/--key [ key | file | keychain | environment_variable ]
-i/--interactive
# Encrypt/Decrypt from STDIN/file/args, to STDOUT/file:
sym -e/--encrypt KEY-SPEC [-f [file | - ] | -s string ] [-o file]
sym -d/--decrypt KEY-SPEC [-f [file | - ] | -s string ] [-o file]
# Auto-detect mode based on a special file extension ".enc"
sym -n/--negate KEY-SPEC file[.enc]
# Edit an encrypted file in $EDITOR
sym -t/--edit KEY-SPEC -f file [ -b/--backup ]
# Save commonly used flags in a BASH variable. Below we save the KeyChain
# "staging" as the default key name, and enable password caching.
export SYM_ARGS="-ck staging"
# Then activate $SYM_ARGS by using -A/--sym-args flag:
sym -Aef file
Modes:
-e, --encrypt encrypt mode
-d, --decrypt decrypt mode
-t, --edit edit encrypted file in an $EDITOR
-n, --negate [file] encrypts any regular file into file.enc
conversely decrypts file.enc into file.
Create a new private key:
-g, --generate generate a new private key
-p, --password encrypt the key with a password
-x, --keychain [key-name] write the key to OS-X Keychain
Read existing private key from:
-k, --key [key-spec] private key, key file, or keychain
-i, --interactive Paste or type the key interactively
Password Cache:
-c, --cache-passwords enable password cache
-u, --cache-timeout [seconds] expire passwords after
-r, --cache-provider [provider] cache provider, one of memcached, drb
Data to Encrypt/Decrypt:
-s, --string [string] specify a string to encrypt/decrypt
-f, --file [file] filename to read from
-o, --output [file] filename to write to
Flags:
-b, --backup create a backup file in the edit mode
-v, --verbose show additional information
-q, --quiet do not print to STDOUT
-T, --trace print a backtrace of any errors
-D, --debug print debugging information
-V, --version print library version
-N, --no-color disable color output
-A, --sym-args read more CLI arguments from $SYM_ARGS
Utility:
-B, --bash-support [file] append bash completion & utils to a file
such as ~/.bash_profile or ~/.bashrc
Help & Examples:
-E, --examples show several examples
-h, --help show help
```
### CLI Usage Examples
__Generating the Key__:
Generate a new private key into an environment variable:
export KEY=$(sym -g)
echo $KEY
# => 75ngenJpB6zL47/8Wo7Ne6JN1pnOsqNEcIqblItpfg4=
Generate a new password-protected key & save to a file:
sym -gpqo ~/.key
New Password : ••••••••••
Confirm Password : ••••••••••
Encrypt a plain text string with a key, and save the output to a file:
sym -e -s "secret string" -k $KEY -o file.enc
cat file.enc
# => Y09MNDUyczU1S0UvelgrLzV0RTYxZz09CkBDMEw4Q0R0TmpnTm9md1QwNUNy%T013PT0K
Decrypt a previously encrypted string:
sym -d -s $(cat file.enc) -k $KEY
# => secret string
Encrypt a file and save it to `sym.enc`:
sym -e -f app-sym.yml -o app-sym.enc -k $KEY
Decrypt an encrypted file and print it to STDOUT:
sym -df app-sym.enc -k $KEY
#### Inline Editing
The `sym` CLI tool supports one particularly interesting mode, that streamlines handling of encrypted files. The mode is called __edit mode__, and is activated with the `-t` flag.
In this mode `sym` can decrypt the file, and open the result in an `$EDITOR`. Once you make any changes, and save it (exiting the editor), `sym` will automatically diff the new and old content, and if different – will save encrypt it and overwrite the original file.
> NOTE: this mode does not seem to work with GUI editors such as Atom or TextMate. Since `sym` waits for the editor process to complete, GUI editors "complete" immediately upon starting a windowed application.
In this mode several flags are of importance:
-b (--backup) – will create a backup of the original file
-v (--verbose) - will show additional info about file sizes
Here is a full command that opens a file specified by `-f | --file`, using the key specified in `-k | --keyfile`, in the editor defined by the `$EDITOR` environment variable (or if not set – defaults to `/bin/vi`)".
To edit an encrypted file in `$EDITOR`, while asking to paste the key (`-i | --interactive`), while creating a backup file (`-b | --backup`):
sym -tibf data.enc
# => Private Key: ••••••••••••••••••••••••••••••••••••••••••••
#
# => Diff:
# 3c3
# # (c) 2015 Konstantin Gredeskoul. All rights reserved.
# ---
# # (c) 2016 Konstantin Gredeskoul. All rights reserved.
## Ruby API
To use this library, you must include the main `Sym` module into your library.
Any class including `Sym` will be decorated with new class methods `#private_key` and `#create_private_key`, as well as instance methods `#encr`, and `#decr`.
`#create_private_key` will generate a new key each time it's called, while `#private_key` will either assign an existing key (if a value is passed) or generate and save a new key in the class instance variable. Therefore each class including `Sym` will use its key (unless the key is assigned).
The following example illustrates this point:
```ruby
require 'sym'
class TestClass
include Sym
end
@key = TestClass.create_private_key
@key.eql?(TestClass.private_key) # => false
# A new key was created and saved in #private_key accessor.
class SomeClass
include Sym
private_key TestClass.private_key
end
@key.eql?(SomeClass.private_key) # => true (it was assigned)
```
### Encryption and Decryption Operations
So how would we use this library from another Ruby project to encrypt and decrypt values?
After including the `Sym` module in a ruby class, the class will now have the `#encr` and `#decr` instance methods, as well as `#secret` and `#create_private_key class methods.
Therefore you could write something like this below, protecting a sensitive string using a class-level secret.
```ruby
require 'sym'
class TestClass
include Sym
private_key ENV['SECRET']
def sensitive_value=(value)
@sensitive_value = encr(value, self.class.private_key)
end
def sensitive_value
decr(@sensitive_value, self.class.private_key)
end
end
```
### Full Application API
Since the command line interface offers more than just encryption/decryption, it is available via `Sym::Application` class.
The class is instantiated with a hash that would be otherwise generated by `Slop.parse(argv)` – ie, typical `options`.
Here is an example:
```ruby
require 'sym/application'
key = Sym::Application.new(generate: true).execute
# => returns a new private key
```
### Configuration
The library offers a typical `Sym::Configuration` class which can be used to tweak some of the internals of the gem. Its meant for an advanced user who knows what he or she is doing. The code snippet shown below is an actual part of the Configuration class, but you can override it by including it in your code that uses and initializes this library, right after the `require.` The `Configuration` class is a Singleton, so changes to it will propagate to any subsequent calls to the gem.
```ruby
require 'zlib'
require 'sym'
Sym::Configuration.configure do |config|
config.password_cipher = 'AES-128-CBC'
config.data_cipher = 'AES-256-CBC'
config.private_key_cipher = config.data_cipher
config.compression_enabled = true
config.compression_level = Zlib::BEST_COMPRESSION
config.encrypted_file_extension = 'enc'
config.default_key_file = "#{ENV['HOME']}/.sym.key"
config.password_cache_timeout = 300
# When nil is selected, providers are auto-detected.
config.password_cache_default_provider = nil
config.password_cache_arguments = {
drb: {
opts: {
uri: 'druby://127.0.0.1:24924'
}
},
memcached: {
args: %w(127.0.0.1:11211),
opts: { namespace: 'sym',
compress: true,
expires_in: config.password_cache_timeout
}
}
}
end
```
As you can see, it's possible to change the default cipher type, although not all ciphers will be code-compatible with the current algorithm, and may require additional code changes.
## Encryption Features & Cipher Used
The `sym` executable as well as the Ruby API provide:
* Symmetric data encryption with:
* the Cipher `AES-256-cBC` used by the US Government
* 256-bit private key, that
* can be generated and is a *base64-encoded* string about 45 characters long. The *decoded* key is always 32 characters (or 256 bytes) long.
* can be optionally password-encrypted using the 128-bit key, and then be automatically detected (and password requested) when the key is used
* can optionally have its password cached for 15 minutes locally on the machine using `memcached` or using a `dRB` server
* Rich command line interface with some innovative features, such as inline editing of an encrypted file, using your favorite `$EDITOR`.
* Data handling:
* Automatic compression of the data upon encryption
* Automatic base64 encryption to make all encrypted strings fit onto a single line.
* This makes the format suitable for YAML or JSON configuration files, where only the values are encrypted.
* Rich Ruby API
* (OS-X Only): Ability to create, add and delete generic password entries from the Mac OS-X KeyChain, and to leverage the KeyChain to store sensitive private keys.
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run `bundle exec rake install`.
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
### Contributing
Bug reports and pull requests are welcome on GitHub at [https://github.com/kigster/sym](https://github.com/kigster/sym).
## License
`Sym` library is © 2016-2017 Konstantin Gredeskoul.
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
The library is designed to be a layer on top of [`OpenSSL`](https://www.openssl.org/), distributed under the [Apache Style license](https://www.openssl.org/source/license.txt).
## Acknowledgements
[Konstantin Gredeskoul](http:/kig.re) is the primary developer of this library. Contributions from others are strongly encouraged and very welcome. Any pull requests will be reviewed promptly.
Contributors:
* Wissam Jarjoui (Shippo)
* Megan Mathews
* Barry Anderson