encryptor-2.0.0/ 0000755 0000041 0000041 00000000000 12670216620 013570 5 ustar www-data www-data encryptor-2.0.0/Rakefile 0000644 0000041 0000041 00000001062 12670216620 015234 0 ustar www-data www-data require 'rake'
require 'rake/testtask'
require 'rdoc/task'
require "bundler/gem_tasks"
desc 'Test the encryptor gem'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the encryptor gem'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Encryptor'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end
desc 'Default: run unit tests.'
task default: :test
encryptor-2.0.0/Gemfile 0000644 0000041 0000041 00000000047 12670216620 015064 0 ustar www-data www-data source 'https://rubygems.org'
gemspec
encryptor-2.0.0/MIT-LICENSE 0000644 0000041 0000041 00000002062 12670216620 015224 0 ustar www-data www-data Copyright (c) 2011 Sean Huber - shuber@huberry.com
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. encryptor-2.0.0/data.tar.gz.sig 0000444 0000041 0000041 00000000400 12670216620 016401 0 ustar www-data www-data A\D|<2bUPKOt#g'n7$Quzʎ%W&9ƶԵϝv0m0HL(PW~sC6e@
s;R83ɋ!q87,NyfyvH&w;@J%na٢Ac[3T7BsH/gh+Z7<'<^ҳ)rCVhi55LߑyX}pศ08V;M> encryptor-2.0.0/.travis.yml 0000644 0000041 0000041 00000000515 12670216620 015702 0 ustar www-data www-data sudo: false
language: ruby
cache: bundler
matrix:
fast_finish: true
include:
- rvm: 2.0.0
- rvm: 2.1
- rvm: 2.2
- rvm: 2.3.0
- rvm: jruby
- rvm: rbx
allow_failures:
- rvm: jruby
exclude:
- rvm: 1.9.3
addons:
code_climate:
repo_token: 5dcb75d5b6c58e2a5f6dc850eb2c1d4e0dbf262e69981db00b765a66bfc9ef10
encryptor-2.0.0/lib/ 0000755 0000041 0000041 00000000000 12670216620 014336 5 ustar www-data www-data encryptor-2.0.0/lib/encryptor.rb 0000644 0000041 0000041 00000010603 12670216620 016710 0 ustar www-data www-data require 'openssl'
require 'encryptor/version'
# A simple wrapper for the standard OpenSSL library
module Encryptor
extend self
# The default options to use when calling the encrypt and decrypt methods
#
# Defaults to { algorithm: 'aes-256-gcm',
# auth_data: '',
# insecure_mode: false,
# hmac_iterations: 2000 }
#
# Run 'openssl list-cipher-commands' in your terminal to view a list all cipher algorithms that are supported on your platform
def default_options
@default_options ||= { algorithm: 'aes-256-gcm',
auth_data: '',
insecure_mode: false,
hmac_iterations: 2000 }
end
# Encrypts a :value with a specified :key and :iv.
#
# Optionally accepts :salt, :auth_data, :algorithm, :hmac_iterations, and :insecure_mode options.
#
# Example
#
# encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
# # or
# encrypted_value = Encryptor.encrypt('some string to encrypt', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
def encrypt(*args, &block)
crypt :encrypt, *args, &block
end
# Decrypts a :value with a specified :key and :iv.
#
# Optionally accepts :salt, :auth_data, :algorithm, :hmac_iterations, and :insecure_mode options.
#
# Example
#
# decrypted_value = Encryptor.decrypt(value: 'some encrypted string', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
# # or
# decrypted_value = Encryptor.decrypt('some encrypted string', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
def decrypt(*args, &block)
crypt :decrypt, *args, &block
end
protected
def crypt(cipher_method, *args) #:nodoc:
options = default_options.merge(value: args.first).merge(args.last.is_a?(Hash) ? args.last : {})
raise ArgumentError.new('must specify a key') if options[:key].to_s.empty?
cipher = OpenSSL::Cipher.new(options[:algorithm])
cipher.send(cipher_method)
unless options[:insecure_mode]
raise ArgumentError.new("key must be #{cipher.key_len} bytes or longer") if options[:key].bytesize < cipher.key_len
raise ArgumentError.new('must specify an iv') if options[:iv].to_s.empty?
raise ArgumentError.new("iv must be #{cipher.iv_len} bytes or longer") if options[:iv].bytesize < cipher.iv_len
end
if options[:iv]
cipher.iv = options[:iv]
if options[:salt].nil?
# Use a non-salted cipher.
# This behaviour is retained for backwards compatibility. This mode
# is not secure and new deployments should use the :salt options
# wherever possible.
cipher.key = options[:key]
else
# Use an explicit salt (which can be persisted into a database on a
# per-column basis, for example). This is the preferred (and more
# secure) mode of operation.
cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(options[:key], options[:salt], options[:hmac_iterations], cipher.key_len)
end
else
# This is deprecated and needs to be changed.
cipher.pkcs5_keyivgen(options[:key])
end
yield cipher, options if block_given?
value = options[:value]
if cipher.authenticated?
if encryption?(cipher_method)
cipher.auth_data = options[:auth_data]
else
value = extract_cipher_text(options[:value])
cipher.auth_tag = extract_auth_tag(options[:value])
# auth_data must be set after auth_tag has been set when decrypting
# See http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-auth_data-3D
cipher.auth_data = options[:auth_data]
end
end
result = cipher.update(value)
result << cipher.final
result << cipher.auth_tag if cipher.authenticated? && encryption?(cipher_method)
result
end
def encryption?(cipher_method)
cipher_method == :encrypt
end
def extract_cipher_text(value)
value[0..-17]
end
def extract_auth_tag(value)
value[-16..-1]
end
end
encryptor-2.0.0/lib/encryptor/ 0000755 0000041 0000041 00000000000 12670216620 016363 5 ustar www-data www-data encryptor-2.0.0/lib/encryptor/string.rb 0000644 0000041 0000041 00000001324 12670216620 020216 0 ustar www-data www-data module Encryptor
# Adds encrypt and decrypt methods to strings
module String
# Returns a new string containing the encrypted version of itself
def encrypt(options = {})
Encryptor.encrypt(options.merge(value: self))
end
# Replaces the contents of a string with the encrypted version of itself
def encrypt!(options ={})
replace encrypt(options)
end
# Returns a new string containing the decrypted version of itself
def decrypt(options = {})
Encryptor.decrypt(options.merge(value: self))
end
# Replaces the contents of a string with the decrypted version of itself
def decrypt!(options = {})
replace decrypt(options)
end
end
end encryptor-2.0.0/lib/encryptor/version.rb 0000644 0000041 0000041 00000000561 12670216620 020377 0 ustar www-data www-data module Encryptor
# Contains information about this gem's version
module Version
MAJOR = 2
MINOR = 0
PATCH = 0
# Returns a version string by joining MAJOR, MINOR, and PATCH with '.'
#
# Example
#
# Version.to_s # '1.0.2'
def self.to_s
[MAJOR, MINOR, PATCH].join('.')
end
end
end
encryptor-2.0.0/test/ 0000755 0000041 0000041 00000000000 12670216620 014547 5 ustar www-data www-data encryptor-2.0.0/test/encryptor_string_test.rb 0000644 0000041 0000041 00000006012 12670216620 021545 0 ustar www-data www-data require 'test_helper'
class EncryptorStringTest < Minitest::Test
original_value = StringWithEncryptor.new
key = SecureRandom.random_bytes(64)
iv = SecureRandom.random_bytes(64)
salt = Time.now.to_i.to_s
original_value << SecureRandom.random_bytes(64)
auth_data = SecureRandom.random_bytes(64)
wrong_auth_tag = SecureRandom.random_bytes(16)
OpenSSLHelper::ALGORITHMS.each do |algorithm|
encrypted_value_with_iv = StringWithEncryptor.new
encrypted_value_without_iv = StringWithEncryptor.new
encrypted_value_with_iv << Encryptor.encrypt(value: original_value, key: key, iv: iv, salt: salt, algorithm: algorithm)
encrypted_value_without_iv << Encryptor.encrypt(value: original_value, key: key, algorithm: algorithm, insecure_mode: true)
define_method "test_should_call_encrypt_on_a_string_with_the_#{algorithm}_algorithm_with_iv" do
assert_equal encrypted_value_with_iv, original_value.encrypt(key: key, iv: iv, salt: salt, algorithm: algorithm)
end
define_method "test_should_call_encrypt_on_a_string_with_the_#{algorithm}_algorithm_without_iv" do
assert_equal encrypted_value_without_iv, original_value.encrypt(key: key, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_call_decrypt_on_a_string_with_the_#{algorithm}_algorithm_with_iv" do
assert_equal original_value, encrypted_value_with_iv.decrypt(key: key, iv: iv, salt: salt, algorithm: algorithm)
end
define_method "test_should_call_decrypt_on_a_string_with_the_#{algorithm}_algorithm_without_iv" do
assert_equal original_value, encrypted_value_without_iv.decrypt(key: key, algorithm: algorithm, insecure_mode: true)
end
define_method "test_string_encrypt!_on_a_string_with_the_#{algorithm}_algorithm_with_iv" do
original_value_dup = original_value.dup
original_value_dup.encrypt!(key: key, iv: iv, salt: salt, algorithm: algorithm)
assert_equal original_value.encrypt(key: key, iv: iv, salt: salt, algorithm: algorithm), original_value_dup
end
define_method "test_string_encrypt!_on_a_string_with_the_#{algorithm}_algorithm_without_iv" do
original_value_dup = original_value.dup
original_value_dup.encrypt!(key: key, algorithm: algorithm, insecure_mode: true)
assert_equal original_value.encrypt(key: key, algorithm: algorithm, insecure_mode: true), original_value_dup
end
define_method "test_string_decrypt!_on_a_string_with_the_#{algorithm}_algorithm_with_iv" do
encrypted_value_with_iv_dup = encrypted_value_with_iv.dup
encrypted_value_with_iv_dup.decrypt!(key: key, iv: iv, salt: salt, algorithm: algorithm)
assert_equal original_value, encrypted_value_with_iv_dup
end
define_method "test_string_decrypt!_on_a_string_with_the_#{algorithm}_algorithm_without_iv" do
encrypted_value_without_iv_dup = encrypted_value_without_iv.dup
encrypted_value_without_iv_dup.decrypt!(key: key, algorithm: algorithm, insecure_mode: true)
assert_equal original_value, encrypted_value_without_iv_dup
end
end
end
encryptor-2.0.0/test/test_helper.rb 0000644 0000041 0000041 00000001207 12670216620 017412 0 ustar www-data www-data require 'simplecov'
require 'simplecov-rcov'
require "codeclimate-test-reporter"
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
SimpleCov::Formatter::HTMLFormatter,
SimpleCov::Formatter::RcovFormatter,
CodeClimate::TestReporter::Formatter
]
SimpleCov.start do
add_filter 'test'
end
CodeClimate::TestReporter.start
require 'minitest/autorun'
require 'minitest/unit'
require 'digest/sha2'
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$:.unshift(File.dirname(__FILE__))
require 'encryptor'
require 'openssl_helper'
require 'encryptor/string'
class StringWithEncryptor < String
include Encryptor::String
end
encryptor-2.0.0/test/openssl_helper.rb 0000644 0000041 0000041 00000001715 12670216620 020122 0 ustar www-data www-data module OpenSSLHelper
# For test debugging
puts "OpenSSL Version: #{OpenSSL::OPENSSL_VERSION}"
algorithms = OpenSSL::Cipher.ciphers
case RUBY_PLATFORM.to_sym
when :java
security_class = java.lang.Class.for_name('javax.crypto.JceSecurity')
restricted_field = security_class.get_declared_field('isRestricted')
restricted_field.accessible = true
restricted_field.set(nil, false)
# if key length is less than 24 bytes:
# OpenSSL::Cipher::CipherError: key length too short
# if key length is 24 bytes or more:
# OpenSSL::Cipher::CipherError: DES key too long - should be 8 bytes: possibly you need to install Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files for your JRE
algorithms -= %w(des-ede3 DES-EDE3)
else
algorithms &= %x(openssl list-cipher-commands).split
end
ALGORITHMS = algorithms.freeze
AUTHENTICATED_ENCRYPTION_ALGORITHMS = ['aes-128-gcm','aes-192-gcm','aes-256-gcm']
end
encryptor-2.0.0/test/legacy_encryptor_string_test.rb 0000644 0000041 0000041 00000005714 12670216620 023101 0 ustar www-data www-data require 'test_helper'
class LegacyEncryptorStringTest < Minitest::Test
key = SecureRandom.random_bytes(64)
iv = SecureRandom.random_bytes(64)
original_value = StringWithEncryptor.new
original_value << SecureRandom.random_bytes(64)
OpenSSLHelper::ALGORITHMS.each do |algorithm|
encrypted_value_with_iv = StringWithEncryptor.new
encrypted_value_with_iv << Encryptor.encrypt(value: original_value, key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
encrypted_value_without_iv = StringWithEncryptor.new
encrypted_value_without_iv << Encryptor.encrypt(value: original_value, key: key, algorithm: algorithm, insecure_mode: true)
define_method "test_should_call_encrypt_on_a_string_with_the_#{algorithm}_algorithm_with_iv" do
assert_equal encrypted_value_with_iv, original_value.encrypt(key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_call_encrypt_on_a_string_with_the_#{algorithm}_algorithm_without_iv" do
assert_equal encrypted_value_without_iv, original_value.encrypt(key: key, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_call_decrypt_on_a_string_with_the_#{algorithm}_algorithm_with_iv" do
assert_equal original_value, encrypted_value_with_iv.decrypt(key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_call_decrypt_on_a_string_with_the_#{algorithm}_algorithm_without_iv" do
assert_equal original_value, encrypted_value_without_iv.decrypt(key: key, algorithm: algorithm, insecure_mode: true)
end
define_method "test_string_encrypt!_on_a_string_with_the_#{algorithm}_algorithm_with_iv" do
original_value_dup = original_value.dup
original_value_dup.encrypt!(key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
assert_equal original_value.encrypt(key: key, iv: iv, algorithm: algorithm, insecure_mode: true), original_value_dup
end
define_method "test_string_encrypt!_on_a_string_with_the_#{algorithm}_algorithm_without_iv" do
original_value_dup = original_value.dup
original_value_dup.encrypt!(key: key, algorithm: algorithm, insecure_mode: true)
assert_equal original_value.encrypt(key: key, algorithm: algorithm, insecure_mode: true), original_value_dup
end
define_method "test_string_decrypt!_on_a_string_with_the_#{algorithm}_algorithm_with_iv" do
encrypted_value_with_iv_dup = encrypted_value_with_iv.dup
encrypted_value_with_iv_dup.decrypt!(key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
assert_equal original_value, encrypted_value_with_iv_dup
end
define_method "test_string_decrypt!_on_a_string_with_the_#{algorithm}_algorithm_without_iv" do
encrypted_value_without_iv_dup = encrypted_value_without_iv.dup
encrypted_value_without_iv_dup.decrypt!(key: key, algorithm: algorithm, insecure_mode: true)
assert_equal original_value, encrypted_value_without_iv_dup
end
end
end
encryptor-2.0.0/test/encryptor_test.rb 0000644 0000041 0000041 00000012676 12670216620 020174 0 ustar www-data www-data require 'test_helper'
# Tests for new preferred salted encryption mode
#
class EncryptorTest < Minitest::Test
key = SecureRandom.random_bytes(32)
iv = SecureRandom.random_bytes(16)
salt = SecureRandom.random_bytes(16)
original_value = SecureRandom.random_bytes(64)
auth_data = SecureRandom.random_bytes(64)
wrong_auth_tag = SecureRandom.random_bytes(16)
OpenSSLHelper::ALGORITHMS.each do |algorithm|
encrypted_value_with_iv = Encryptor.encrypt(value: original_value, key: key, iv: iv, salt: salt, algorithm: algorithm)
encrypted_value_without_iv = Encryptor.encrypt(value: original_value, key: key, algorithm: algorithm, insecure_mode: true)
define_method "test_should_crypt_with_the_#{algorithm}_algorithm_with_iv" do
refute_equal original_value, encrypted_value_with_iv
refute_equal encrypted_value_without_iv, encrypted_value_with_iv
assert_equal original_value, Encryptor.decrypt(value: encrypted_value_with_iv, key: key, iv: iv, salt: salt, algorithm: algorithm)
end
define_method "test_should_crypt_with_the_#{algorithm}_algorithm_without_iv" do
refute_equal original_value, encrypted_value_without_iv
assert_equal original_value, Encryptor.decrypt(value: encrypted_value_without_iv, key: key, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_encrypt_with_the_#{algorithm}_algorithm_with_iv_with_the_first_arg_as_the_value" do
assert_equal encrypted_value_with_iv, Encryptor.encrypt(original_value, key: key, iv: iv, salt: salt, algorithm: algorithm)
end
define_method "test_should_encrypt_with_the_#{algorithm}_algorithm_without_iv_with_the_first_arg_as_the_value" do
assert_equal encrypted_value_without_iv, Encryptor.encrypt(original_value, key: key, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_decrypt_with_the_#{algorithm}_algorithm_with_iv_with_the_first_arg_as_the_value" do
assert_equal original_value, Encryptor.decrypt(encrypted_value_with_iv, key: key, iv: iv, salt: salt, algorithm: algorithm)
end
define_method "test_should_decrypt_with_the_#{algorithm}_algorithm_without_iv_with_the_first_arg_as_the_value" do
assert_equal original_value, Encryptor.decrypt(encrypted_value_without_iv, key: key, algorithm: algorithm, insecure_mode: true)
end
end
define_method 'test_should_use_the_default_algorithm_if_one_is_not_specified' do
assert_equal Encryptor.encrypt(value: original_value, key: key, salt: salt, iv: iv, algorithm: Encryptor.default_options[:algorithm]), Encryptor.encrypt(value: original_value, key: key, salt: salt, iv: iv)
end
def test_should_have_a_default_algorithm
assert !Encryptor.default_options[:algorithm].nil?
assert !Encryptor.default_options[:algorithm].empty?
end
def test_should_raise_argument_error_if_key_is_not_specified
assert_raises(ArgumentError, "must specify a key") { Encryptor.encrypt('some value') }
assert_raises(ArgumentError, "must specify a key") { Encryptor.decrypt('some encrypted string') }
end
def test_should_raise_argument_error_if_key_is_too_short
assert_raises(ArgumentError, "key must be 32 bytes or longer") { Encryptor.encrypt('some value', key: '') }
assert_raises(ArgumentError, "key must be 32 bytes or longer") { Encryptor.decrypt('some encrypted string', key: '') }
end
define_method 'test_should_raise_argument_error_if_iv_is_not_specified' do
assert_raises(ArgumentError, "must specify an iv") { Encryptor.encrypt('some value', key: key) }
assert_raises(ArgumentError, "must specify an iv") { Encryptor.decrypt('some encrypted string', key: key) }
end
define_method 'test_should_raise_argument_error_if_iv_is_too_short' do
assert_raises(ArgumentError, "iv must be 16 bytes or longer") { Encryptor.encrypt('some value', key: key, iv: 'a') }
assert_raises(ArgumentError, "iv must be 16 bytes or longer") { Encryptor.decrypt('some encrypted string', key: key, iv: 'a') }
end
define_method 'test_should_yield_block_with_cipher_and_options' do
called = false
Encryptor.encrypt('some value', key: key, iv: iv, salt: salt) { |cipher, options| called = true }
assert called
end
OpenSSLHelper::AUTHENTICATED_ENCRYPTION_ALGORITHMS.each do |algorithm|
define_method 'test_should_use_the_default_authentication_data_if_it_is_not_specified' do
encrypted_value = Encryptor.encrypt(value: original_value, key: key, iv: iv, salt: salt, algorithm: algorithm)
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: key, iv: iv, salt: salt, algorithm: algorithm)
refute_equal original_value, encrypted_value
assert_equal original_value, decrypted_value
assert_raises(OpenSSL::Cipher::CipherError) { Encryptor.decrypt(value: encrypted_value[0..-17] + wrong_auth_tag, key: key, iv: iv, salt: salt, algorithm: algorithm) }
end
define_method 'test_should_use_authentication_data_if_it_is_specified' do
encrypted_value = Encryptor.encrypt(value: original_value, key: key, iv: iv, salt: salt, algorithm: algorithm, auth_data: auth_data)
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: key, iv: iv, salt: salt, algorithm: algorithm, auth_data: auth_data)
refute_equal original_value, encrypted_value
assert_equal original_value, decrypted_value
assert_raises(OpenSSL::Cipher::CipherError) { Encryptor.decrypt(value: encrypted_value[0..-17] + wrong_auth_tag, key: key, iv: iv, salt: salt, algorithm: algorithm) }
end
end
end
encryptor-2.0.0/test/legacy_encryptor_test.rb 0000644 0000041 0000041 00000006525 12670216620 021514 0 ustar www-data www-data require 'test_helper'
# Tests for legacy (non-salted) encryption mode
#
class LegacyEncryptorTest < Minitest::Test
key = SecureRandom.random_bytes(64)
iv = SecureRandom.random_bytes(64)
original_value = SecureRandom.random_bytes(64)
OpenSSLHelper::ALGORITHMS.each do |algorithm|
encrypted_value_with_iv = Encryptor.encrypt(value: original_value, key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
encrypted_value_without_iv = Encryptor.encrypt(value: original_value, key: key, algorithm: algorithm, insecure_mode: true)
define_method "test_should_crypt_with_the_#{algorithm}_algorithm_with_iv" do
refute_equal original_value, encrypted_value_with_iv
refute_equal encrypted_value_without_iv, encrypted_value_with_iv
assert_equal original_value, Encryptor.decrypt(value: encrypted_value_with_iv, key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_crypt_with_the_#{algorithm}_algorithm_without_iv" do
refute_equal original_value, encrypted_value_without_iv
assert_equal original_value, Encryptor.decrypt(value: encrypted_value_without_iv, key: key, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_encrypt_with_the_#{algorithm}_algorithm_with_iv_with_the_first_arg_as_the_value" do
assert_equal encrypted_value_with_iv, Encryptor.encrypt(original_value, key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_encrypt_with_the_#{algorithm}_algorithm_without_iv_with_the_first_arg_as_the_value" do
assert_equal encrypted_value_without_iv, Encryptor.encrypt(original_value, key: key, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_decrypt_with_the_#{algorithm}_algorithm_with_iv_with_the_first_arg_as_the_value" do
assert_equal original_value, Encryptor.decrypt(encrypted_value_with_iv, key: key, iv: iv, algorithm: algorithm, insecure_mode: true)
end
define_method "test_should_decrypt_with_the_#{algorithm}_algorithm_without_iv_with_the_first_arg_as_the_value" do
assert_equal original_value, Encryptor.decrypt(encrypted_value_without_iv, key: key, algorithm: algorithm, insecure_mode: true)
end
end
define_method 'test_should_use_the_default_algorithm_if_one_is_not_specified' do
assert_equal Encryptor.encrypt(value: original_value, key: key, algorithm: Encryptor.default_options[:algorithm], insecure_mode: true), Encryptor.encrypt(value: original_value, key: key, insecure_mode: true)
end
def test_should_have_a_default_algorithm
assert !Encryptor.default_options[:algorithm].nil?
assert !Encryptor.default_options[:algorithm].empty?
end
def test_should_raise_argument_error_if_key_is_not_specified
assert_raises(ArgumentError) { Encryptor.encrypt('some value', insecure_mode: true) }
assert_raises(ArgumentError) { Encryptor.decrypt('some encrypted string', insecure_mode: true) }
assert_raises(ArgumentError) { Encryptor.encrypt('some value', key: '', insecure_mode: true) }
assert_raises(ArgumentError) { Encryptor.decrypt('some encrypted string', key: '', insecure_mode: true) }
end
def test_should_yield_block_with_cipher_and_options
called = false
Encryptor.encrypt('some value', key: 'some key', insecure_mode: true) { |cipher, options| called = true }
assert called
end
end
encryptor-2.0.0/test/compatibility_test.rb 0000644 0000041 0000041 00000005432 12670216620 021010 0 ustar www-data www-data require File.expand_path('../test_helper', __FILE__)
# Test ensures that values stored by previous versions of the gem will
# roundtrip and decrypt correctly in this and future versions. This is important
# for data stored in databases and allows consumers of the gem to upgrade with
# confidence in the future.
#
class CompatibilityTest < Minitest::Test
ALGORITHM = 'aes-256-cbc'
def self.base64_encode(value)
[value].pack('m').strip
end
def self.base64_decode(value)
value.unpack('m').first
end
if OpenSSL::Cipher.ciphers.include?(ALGORITHM)
def test_encrypt_with_iv
key = Digest::SHA256.hexdigest('my-fixed-key')
iv = Digest::SHA256.hexdigest('my-fixed-iv')
result = Encryptor.encrypt(
algorithm: ALGORITHM,
value: 'my-fixed-input',
key: key,
iv: iv,
insecure_mode: true
)
assert_equal 'nGuyGniksFXnMYj/eCxXKQ==', self.class.base64_encode(result)
end
def test_encrypt_without_iv
key = Digest::SHA256.hexdigest('my-fixed-key')
result = Encryptor.encrypt(
algorithm: ALGORITHM,
value: 'my-fixed-input',
key: key,
insecure_mode: true
)
assert_equal 'XbwHRMFWqR5M80kgwRcEEg==', self.class.base64_encode(result)
end
def test_decrypt_with_iv
key = Digest::SHA256.hexdigest('my-fixed-key')
iv = Digest::SHA256.hexdigest('my-fixed-iv')
result = Encryptor.decrypt(
algorithm: ALGORITHM,
value: self.class.base64_decode('nGuyGniksFXnMYj/eCxXKQ=='),
key: key,
iv: iv,
insecure_mode: true
)
assert_equal 'my-fixed-input', result
end
def test_decrypt_without_iv
key = Digest::SHA256.hexdigest('my-fixed-key')
result = Encryptor.decrypt(
algorithm: ALGORITHM,
value: self.class.base64_decode('XbwHRMFWqR5M80kgwRcEEg=='),
key: key,
insecure_mode: true
)
assert_equal 'my-fixed-input', result
end
def test_encrypt_with_iv_and_salt
key = Digest::SHA256.hexdigest('my-fixed-key')
iv = Digest::SHA256.hexdigest('my-fixed-iv')
salt = 'my-fixed-salt'
result = Encryptor.encrypt(
algorithm: ALGORITHM,
value: 'my-fixed-input',
key: key,
iv: iv,
salt: salt
)
assert_equal 'DENuQSh9b0eW8GN3YLzLGw==', self.class.base64_encode(result)
end
def test_decrypt_with_iv_and_salt
key = Digest::SHA256.hexdigest('my-fixed-key')
iv = Digest::SHA256.hexdigest('my-fixed-iv')
salt = 'my-fixed-salt'
result = Encryptor.decrypt(
algorithm: ALGORITHM,
value: self.class.base64_decode('DENuQSh9b0eW8GN3YLzLGw=='),
key: key,
iv: iv,
salt: salt
)
assert_equal 'my-fixed-input', result
end
end
end
encryptor-2.0.0/encryptor.gemspec 0000644 0000041 0000041 00000002671 12670216620 017170 0 ustar www-data www-data # -*- encoding: utf-8 -*-
lib = File.expand_path('../lib/', __FILE__)
$:.unshift lib unless $:.include?(lib)
require 'encryptor/version'
require 'date'
Gem::Specification.new do |s|
s.name = 'encryptor'
s.version = Encryptor::Version
s.date = Date.today
s.platform = Gem::Platform::RUBY
s.summary = 'A simple wrapper for the standard ruby OpenSSL library'
s.description = 'A simple wrapper for the standard ruby OpenSSL library to encrypt and decrypt strings'
s.authors = ['Sean Huber', 'S. Brent Faulkner', 'William Monk', 'Stephen Aghaulor']
s.email = ['sean@shuber.io', 'sbfaulkner@gmail.com', 'billy.monk@gmail.com', 'saghaulor@gmail.com']
s.homepage = 'http://github.com/attr-encrypted/encryptor'
s.license = 'MIT'
s.rdoc_options = %w(--charset=UTF-8 --inline-source --line-numbers --main README.md)
s.require_paths = ['lib']
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- test/*`.split("\n")
s.required_ruby_version = '>= 2.0.0'
s.add_development_dependency('minitest', '>= 0')
s.add_development_dependency('rake', '>= 0')
s.add_development_dependency('simplecov', '>= 0')
s.add_development_dependency('simplecov-rcov', '>= 0')
s.add_development_dependency('codeclimate-test-reporter', '>= 0')
s.requirements << 'openssl, >= v1.0.1'
s.cert_chain = ['certs/saghaulor.pem']
s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
end
encryptor-2.0.0/.gitignore 0000644 0000041 0000041 00000000047 12670216620 015561 0 ustar www-data www-data pkg
rdoc
.bundle
coverage
Gemfile.lock
encryptor-2.0.0/checksums.yaml.gz.sig 0000444 0000041 0000041 00000000400 12670216620 017631 0 ustar www-data www-data ~=>AR2.xl_'E*cfLgƸJv-w'{*kV[qX4ׁ(9&?ɛr<,ƻ6_<Ժp>R 4a\d7oe7¦
F`0[9Y6N)P?NS9CIS.R1R .z'](https://travis-ci.org/attr-encrypted/encryptor) [](https://codeclimate.com/github/attr-encrypted/encryptor) [](https://codeclimate.com/github/attr-encrypted/encryptor) [](http://badge.fury.io/rb/encryptor) [](https://hakiri.io/github/attr-encrypted/encryptor/master)
A simple wrapper for the standard Ruby OpenSSL library
### Installation
```bash
gem install encryptor
```
### Usage
#### Basic
Encryptor uses the AES-256-GCM algorithm by default to encrypt strings securely.
The best example is:
```ruby
cipher = OpenSSL::Cipher.new('aes-256-gcm')
cipher.encrypt # Required before '#random_key' or '#random_iv' can be called. http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-encrypt
secret_key = cipher.random_key # Insures that the key is the correct length respective to the algorithm used.
iv = cipher.random_iv # Insures that the IV is the correct length respective to the algorithm used.
salt = SecureRandom.random_bytes(16)
encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: secret_key, iv: iv, salt: salt)
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: secret_key, iv: iv, salt: salt)
```
A slightly easier example is:
```ruby
require 'securerandom'
secret_key = SecureRandom.random_bytes(32) # The length in bytes must be equal to or greater than the algorithm bit length.
iv = SecureRandom.random_bytes(12) # Recomended length for AES-###-GCM algorithm. https://tools.ietf.org/html/rfc5084#section-3.2
encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: secret_key, iv: iv)
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: secret_key, iv: iv)
```
**NOTE: It is imperative that you use a unique IV per each string and encryption key combo; a nonce as the IV.**
See [RFC 5084](https://tools.ietf.org/html/rfc5084#section-1.5) for more details.
The value to encrypt or decrypt may also be passed as the first option if you'd prefer.
```ruby
encrypted_value = Encryptor.encrypt('some string to encrypt', key: secret_key, iv: iv)
decrypted_value = Encryptor.decrypt(encrypted_value, key: secret_key, iv: iv)
```
#### Options
**Defaults:**
```ruby
{ algorithm: 'aes-256-gcm',
auth_data: '',
insecure_mode: false,
hmac_iterations: 2000 }
```
Older versions of Encryptor allowed you to use it in a less secure way. Namely, you were allowed to run Encryptor without an IV, or with a key of insufficient length. Encryptor now requires a key and IV of the correct length respective to the algorithm that you use. However, to maintain backwards compatibility you can run Encryptor with the `:insecure_mode` option.
You may also pass an `:algorithm`,`:salt`, and `hmac_iterations` option, however none of these options are required. If you pass the `:salt` option, a new unique key will be derived from the key that you passed in using PKCS5 with a default of 2000 iterations. You can change the number of PKCS5 iterations with the `hmac_iterations` option. As PKCS5 is slow, it is optional behavior, but it does provide more security to use a unique IV and key for every encryption operation.
```ruby
Encryptor.default_options.merge!(algorithm: 'aes-256-cbc', key: 'some default secret key', iv: iv, salt: salt)
```
#### Strings
Older versions of Encryptor added `encrypt` and `decrypt` methods to `String` objects for your convenience. However, this behavior has been removed to avoid polluting Ruby's core `String` class. The `Encryptor::String` module remains within this gem to allow users of this feature to implement it themselves. These `encrypt` and `decrypt` methods accept the same arguments as the associated ones in the `Encryptor` module. They're nice when you set the default options in the `Encryptor.default_options attribute.` For example:
```ruby
require 'encryptor/string'
String.include Encryptor::String
Encryptor.default_options.merge!(key: 'some default secret key', iv: iv)
credit_card = 'xxxx xxxx xxxx 1234'
encrypted_credit_card = credit_card.encrypt
```
There's also `encrypt!` and `decrypt!` methods that replace the contents of a string with the encrypted or decrypted version of itself.
#### Algorithms
To view a list of all cipher algorithms that are supported on your platform, run the following code in your favorite Ruby REPL:
```ruby
require 'openssl'
puts OpenSSL::Cipher.ciphers
```
The supported ciphers will vary depending on the version of OpenSSL that was used to compile your version of Ruby. However, the following ciphers are typically supported:
Cipher Name|Key size in bytes|IV size in bytes
---|---|---
aes-128-cbc|16|16
aes-128-cbc-hmac-sha1|16|16
aes-128-cbc-hmac-sha256|16|16
aes-128-ccm|16|12
aes-128-cfb|16|16
aes-128-cfb1|16|16
aes-128-cfb8|16|16
aes-128-ctr|16|16
aes-128-ecb|16|0
aes-128-gcm|16|12
aes-128-ofb|16|16
aes-128-xts|32|16
aes-192-cbc|24|16
aes-192-ccm|24|12
aes-192-cfb|24|16
aes-192-cfb1|24|16
aes-192-cfb8|24|16
aes-192-ctr|24|16
aes-192-ecb|24|0
aes-192-gcm|24|12
aes-192-ofb|24|16
aes-256-cbc|32|16
aes-256-cbc-hmac-sha1|32|16
aes-256-cbc-hmac-sha256|32|16
aes-256-ccm|32|12
aes-256-cfb|32|16
aes-256-cfb1|32|16
aes-256-cfb8|32|16
aes-256-ctr|32|16
aes-256-ecb|32|0
aes-256-gcm|32|12
aes-256-ofb|32|16
aes-256-xts|64|16
aes128|16|16
aes192|24|16
aes256|32|16
bf|16|8
bf-cbc|16|8
bf-cfb|16|8
bf-ecb|16|0
bf-ofb|16|8
blowfish|16|8
camellia-128-cbc|16|16
camellia-128-cfb|16|16
camellia-128-cfb1|16|16
camellia-128-cfb8|16|16
camellia-128-ecb|16|0
camellia-128-ofb|16|16
camellia-192-cbc|24|16
camellia-192-cfb|24|16
camellia-192-cfb1|24|16
camellia-192-cfb8|24|16
camellia-192-ecb|24|0
camellia-192-ofb|24|16
camellia-256-cbc|32|16
camellia-256-cfb|32|16
camellia-256-cfb1|32|16
camellia-256-cfb8|32|16
camellia-256-ecb|32|0
camellia-256-ofb|32|16
camellia128|16|16
camellia192|24|16
camellia256|32|16
cast|16|8
cast-cbc|16|8
cast5-cbc|16|8
cast5-cfb|16|8
cast5-ecb|16|0
cast5-ofb|16|8
des|8|8
des-cbc|8|8
des-cfb|8|8
des-cfb1|8|8
des-cfb8|8|8
des-ecb|8|0
des-ede|16|0
des-ede-cbc|16|8
des-ede-cfb|16|8
des-ede-ofb|16|8
des-ede3|24|0
des-ede3-cbc|24|8
des-ede3-cfb|24|8
des-ede3-cfb1|24|8
des-ede3-cfb8|24|8
des-ede3-ofb|24|8
des-ofb|8|8
des3|24|8
desx|24|8
desx-cbc|24|8
idea|16|8
idea-cbc|16|8
idea-cfb|16|8
idea-ecb|16|0
idea-ofb|16|8
rc2|16|8
rc2-40-cbc|5|8
rc2-64-cbc|8|8
rc2-cbc|16|8
rc2-cfb|16|8
rc2-ecb|16|0
rc2-ofb|16|8
rc4|16|0
rc4-40|5|0
rc4-hmac-md5|16|0
seed|16|16
seed-cbc|16|16
seed-cfb|16|16
seed-ecb|16|0
seed-ofb|16|16
**NOTE: Some ciphers may not be supported by Ruby. Additionally, Ruby compiled with OpenSSL >= v1.0.1 will include AEAD ciphers, ie., aes-256-gcm.**
#### Notes on patches/pull requests
* Fork the project.
* Make your feature addition or bug fix.
* Add tests for it: this is important so I don't break it in a future version unintentionally.
* Commit, do not mess with Rakefile, version, or history: if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull).
* Send me a pull request: bonus points for topic branches.