sym-crypt 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ language: ruby
2
+ cache: bundler
3
+ env:
4
+ CODECLIMATE_REPO_TOKEN=40b229d2d4857d67d832b6e0d5110537accb4e954961a8ce59beebf41e7d79b7
5
+ rvm:
6
+ - 2.2.7
7
+ - 2.3.4
8
+ - 2.4.1
9
+ - jruby-9.1.9.0
10
+ notifications:
11
+ email:
12
+ recipients:
13
+ on_success: change
14
+ on_failure: always
15
+ slack:
16
+ rooms:
17
+ secure: GcACCHmcmo99lYE5dgt2TmY4YIPMWr75q0Bkm4Lddegq/1eMXgcZDz00j8iHWtnveyJSjEUpZFQ9uyx+P7dvxT7D5gl43arKZEylS4vMRg9QRgZu7/ROrXbJtrUyKulFRUTdFrmOiK9nDKpAzlvLvMKC4kaQnn88Xtu9pYMU8y4n5fCtl29gZM9ZjVbrBBvV/SumnTDLla2oQ7oFgUZdZhQZ1qsevYknxNq4eIcvPDjbon+bovfsIISEVRSNo2C3yjO+mqWKed3jfuCA4taAZ8/aVVFEKURMH10HFms1CiC3lE/gF4YfBXsqKpjnB+bKjBcWox2FQrp96FulMEIfkKQrnuncO96o7MGHX9oNqKSMoycf3+SZFwNa+5Mfq7SBepbHYCoU7/ow31UTyStrc5idG19XzYgI85yjQHdzQN299Xf0O8cGf9q9qAu7rS7JlM3ekR+3rZYO+OxNYTF8rcW1fYIj6GKcbsV8BvuhAVQRFOsk/ibcIb2N7rGVd/ZbU4HAk3RE1ywt+XowinpIHktu2PQUPDNpgRQwM6xqZHO/7s9r7oW0ULmZCMLZ9CMKNjKzrQ9wfh90+v+FiEiUKsaVj4cCwF3PvhVYvxU2AKbCeHtSEb7K6to86+DYNoIKnGH1ryKoyCtyOTZpNMLGFt34Msv7WfEylhG+DpVMvkM=
18
+ addons:
19
+ code_climate:
20
+ repo_token:
21
+ # regular test configuration
22
+ after_success:
23
+ - bundle exec codeclimate-test-reporter
@@ -0,0 +1,4 @@
1
+ --protected
2
+ --no-private
3
+ --embed-mixin ClassMethods
4
+ --embed-mixin Sym::Crypt::Extensions::InstanceMethods
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright © 2016 Konstantin Gredeskoul, all rights reserved.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,121 @@
1
+ # SymCrypt
2
+
3
+ ## Simple Symmetric Encryption Using OpenSSL
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/sym-crypt.svg)](https://badge.fury.io/rb/sym-crypt)
6
+ [![Downloads](http://ruby-gem-downloads-badge.herokuapp.com/sym-crypt?type=total)](https://rubygems.org/gems/sym-crypt)
7
+
8
+ [![Build Status](https://travis-ci.org/kigster/sym-crypt.svg?branch=master)](https://travis-ci.org/kigster/sym-crypt)
9
+ [![Code Climate](https://codeclimate.com/github/kigster/sym-crypt/badges/gpa.svg)](https://codeclimate.com/github/kigster/sym-crypt)
10
+ [![Test Coverage](https://codeclimate.com/github/kigster/sym-crypt/badges/coverage.svg)](https://codeclimate.com/github/kigster/sym-crypt/coverage)
11
+ [![Issue Count](https://codeclimate.com/github/kigster/sym-crypt/badges/issue_count.svg)](https://codeclimate.com/github/kigster/sym-crypt)
12
+
13
+ [![Gitter](https://img.shields.io/gitter/room/gitterHQ/gitter.svg)](https://gitter.im/kigster/sym)
14
+
15
+ ---
16
+
17
+ ### Summary
18
+
19
+ The `sym-crypt` core library offers simple wrappers around OpenSSL with the following features:
20
+
21
+ * Symmetric data encryption with either:
22
+ 1. A generated or supplied/known 256-bit key, and using the Cipher `AES-256-cBC`, which is the standard Cipher used by the US Government
23
+ 2. A user-provided password is used to construct a 128-bit key, and then encrypt/decrypt with the `AES-128-CBC` Cipher.
24
+ * Automatic compression of the data upon encryption
25
+ * Automatic base64 encryption to make all encrypted strings fit onto a single line.
26
+ * This makes the format suitable for YAML or JSON configuration files, where only the values are encrypted.
27
+ * Note: the generated key is a *base64-encoded* string of about 45 characters long. The *decoded* key is always 32 characters (or 256 bytes) long.
28
+
29
+ ### Usage
30
+
31
+ This library is a "wrapper" that allows you to take advantage of the
32
+ symmetric encryption functionality provided by the {OpenSSL} gem (and the
33
+ underlying C library). In order to use the library in your ruby classes, you
34
+ should _include_ the module `Sym::Crypt`.
35
+
36
+ Any class that includes `Sym::Crypt` is decorated with four instance methods `[:encr, :decr, :encr_password, :decr_password]`, and three class methods `[:create_private_key, :private_key, :private_key=]`.
37
+
38
+ #### Symmetric Encryption with a 256-bit Private Key
39
+
40
+ In the example below, we read a previously generated key from the environment variable. The key must be stored away from the data for obvious reasons.
41
+
42
+ ```ruby
43
+ require 'sym/crypt'
44
+
45
+ class TopSecret
46
+ include Sym::Crypt
47
+ # read the key from environmant variable and assign to this class.
48
+ private_key ENV['PRIVATE_KEY']
49
+
50
+ def sensitive_value=(value)
51
+ @sensitive_value = encr(value, self.class.private_key)
52
+ end
53
+
54
+ def sensitive_value
55
+ decr(@sensitive_value, self.class.private_key)
56
+ end
57
+ end
58
+ ```
59
+
60
+ #### Symmetric Encryption with a Password
61
+
62
+ In this example we encrypt sensitive value with a provided password. Password must not be nil or blank.
63
+
64
+ ```ruby
65
+ require 'sym/crypt'
66
+
67
+ class SensitiveStuff < Struct.new(:password)
68
+ include Sym::Crypt
69
+
70
+ def sensitive_value=(value)
71
+ @sensitive_value = encr_password(value, password)
72
+ end
73
+
74
+ def sensitive_value
75
+ decr_password(@sensitive_value, password)
76
+ end
77
+ end
78
+ ```
79
+
80
+ #### Generating an Encryption Key
81
+
82
+ You can create a new key within any class that includes `Sym::Crypt` by calling the `#create_private_key` class method, which returns a new key every time it's called.
83
+
84
+ Classes that include `Sym::Crypt` are also decorated with a class instance variable `@private_key` and corresponding accessors `#private_key` and `#private_key=`. The writer assigns the key passed via the argument, while the reader returns a previously assigned key, or creates a new one, and assigns it. Subsequent calls will, thus, return the same key as the first call.
85
+
86
+ ## Development
87
+
88
+ 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.
89
+
90
+ To install this gem onto your local machine, run `bundle exec rake install`.
91
+
92
+ 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).
93
+
94
+ #### Contributing
95
+
96
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/kigster/sym-crypt](https://github.com/kigster/sym-crypt)
97
+
98
+ ### License
99
+
100
+ **sym** and **sym-crypt** library is &copy; 2016-2017 Konstantin Gredeskoul.
101
+
102
+ 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).
103
+
104
+ ### Acknowledgements
105
+
106
+ * The blog post [(Symmetric) Encryption With Ruby (and Rails)](http://stuff-things.net/2015/02/12/symmetric-encryption-with-ruby-and-rails/) provided the inspiration for this gem.
107
+ * We'd like to thank [Spike Ilacqua](http://stuff-things.net/spike/), the author of the [strongbox](https://github.com/spikex/strongbox) gem, for providing very easy-to-read code examples of symmetric encryption.
108
+
109
+ #### Contributors:
110
+
111
+ Contributions of any kind are very much welcome from anyone.
112
+
113
+ Any pull requests will be reviewed promptly.
114
+
115
+ Please submit feature requests, bugs, or donations :)
116
+
117
+ * [Konstantin Gredeskoul](http:/kig.re) (primary developer)
118
+ * [Barry Anderson](https://twitter.com/z3ndrag0n) (sanity checking, review)
119
+
120
+
121
+
@@ -0,0 +1,28 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'yard'
4
+
5
+ def shell(*args)
6
+ puts "running: #{args.join(' ')}"
7
+ system(args.join(' '))
8
+ end
9
+
10
+ task :permissions do
11
+ shell('rm -rf pkg/')
12
+ shell("chmod -v o+r,g+r * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/*")
13
+ shell("find . -type d -exec chmod o+x,g+x {} \\;")
14
+ end
15
+
16
+ task :build => :permissions
17
+
18
+ YARD::Rake::YardocTask.new(:doc) do |t|
19
+ t.files = %w(lib/**/*.rb exe/*.rb - README.md LICENSE)
20
+ t.options.unshift('--title','"Sym – Symmetric Key Encryption for Your Data"')
21
+ t.after = ->() { exec('open doc/index.html') }
22
+ end
23
+
24
+ RSpec::Core::RakeTask.new(:spec)
25
+
26
+ task :default => :spec
27
+
28
+
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'sym-crypt'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,119 @@
1
+ require 'zlib'
2
+ require 'logger'
3
+
4
+ require 'sym/crypt/configuration'
5
+ require 'sym/crypt/version'
6
+ require 'sym/crypt/errors'
7
+
8
+ Sym::Crypt::Configuration.configure do |config|
9
+ config.password_cipher = 'AES-128-CBC'
10
+ config.data_cipher = 'AES-256-CBC'
11
+ config.private_key_cipher = config.data_cipher
12
+ config.compression_enabled = true
13
+ config.compression_level = Zlib::BEST_COMPRESSION
14
+ end
15
+
16
+ require 'sym/crypt/extensions/class_methods'
17
+ require 'sym/crypt/extensions/instance_methods'
18
+
19
+ #
20
+ # == Using Sym Library
21
+ #
22
+ # This library is a "wrapper" that allows you to take advantage of the
23
+ # symmetric encryption functionality provided by the {OpenSSL} gem (and the
24
+ # underlying C library). In order to use the library in your ruby classes, you
25
+ # should _include_ the module {Sym}.
26
+ #
27
+ # The including class is decorated with four instance methods from the
28
+ # module {Sym::Crypt::Extensions::InstanceMethods} and two class methods from
29
+ # {Sym::Crypt::Extensions::ClassMethods} – for specifics, please refer there.
30
+ #
31
+ # The two main instance methods are +#encr+ and +#decr+, which as the name
32
+ # implies, perform two-way symmetric encryption and decryption of any Ruby object
33
+ # that can be +marshaled+.
34
+ #
35
+ # Two additional instance methods +#encr_password+ and +#decr_password+ turn on
36
+ # password-based encryption, which actually uses a password to construct a 128-bit
37
+ # long private key, and then uses that in the encryption of the data.
38
+ # You could use them to encrypt data with a password instead of a randomly
39
+ # generated private key.
40
+ #
41
+ # Create a new key with +#create_private_key+ class method, which returns a new
42
+ # key every time it's called, or with +#private_key+ class method, which either
43
+ # assigns, or creates and caches the private key at a class level.
44
+ #
45
+ # == Example
46
+ #
47
+ # require 'sym/crypt'
48
+ #
49
+ # class TestClass
50
+ # include Sym::Crypt
51
+ # # read the key from environmant variable and assign to this class.
52
+ # private_key ENV['PRIVATE_KEY']
53
+ #
54
+ # def sensitive_value=(value)
55
+ # @sensitive_value = encr(value, self.class.private_key)
56
+ # end
57
+ #
58
+ # def sensitive_value
59
+ # decr(@sensitive_value, self.class.private_key)
60
+ # end
61
+ # end
62
+ #
63
+ # == Private Key
64
+ #
65
+ # They private key can be generated by +TestClass.create_private_key+
66
+ # which returns but does not store a new random 256-bit key.
67
+ #
68
+ # The key can be assigned and saved, or auto-generated and saved using the
69
+ # +#private_key+ method on the class that includes the +Sym+ module.
70
+ #
71
+ # Each class including the +Sym+ module would get their own +#private_key#
72
+ # class-instance variable accessor, and a possible value.
73
+ #
74
+
75
+ module Sym
76
+ module Crypt
77
+ NEW_CIPHER_PROC = ->(name) { ::OpenSSL::Cipher.new(name) }
78
+
79
+ def self.included(klass)
80
+ klass.instance_eval do
81
+ include ::Sym::Crypt::Extensions::InstanceMethods
82
+ extend ::Sym::Crypt::Extensions::ClassMethods
83
+ class << self
84
+ def private_key(value = nil)
85
+ if value
86
+ @private_key= value
87
+ elsif @private_key
88
+ @private_key
89
+ else
90
+ @private_key= self.create_private_key
91
+ end
92
+ @private_key
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ class << self
99
+ def config
100
+ Sym::Crypt::Configuration.config
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+
107
+
108
+ class Object
109
+ unless self.methods.include?(:present?)
110
+ def present?
111
+ return false if self.nil?
112
+ if self.is_a?(String)
113
+ return false if self == ''
114
+ end
115
+ true
116
+ end
117
+ end
118
+ end
119
+
@@ -0,0 +1,37 @@
1
+ require 'base64'
2
+ require 'sym/crypt'
3
+
4
+ module Sym
5
+ module Crypt
6
+
7
+ # {Sym::Crypt::CipherHandler} contains cipher-related utilities necessary to create
8
+ # ciphers, and seed them with the salt or iV vector. It also defines the
9
+ # internal structure {Sym::Crypt::CipherHandler::CipherStruct} which is a key
10
+ # struct used in constructing cipher and saving it with the data packet.
11
+ module CipherHandler
12
+
13
+ CipherStruct = Struct.new(:cipher,
14
+ :iv,
15
+ :salt)
16
+
17
+ def create_cipher(direction:,
18
+ cipher_name:,
19
+ iv: nil,
20
+ salt: nil)
21
+
22
+ cipher = NEW_CIPHER_PROC.call(cipher_name)
23
+ cipher.send(direction)
24
+ iv ||= cipher.random_iv
25
+ cipher.iv = iv
26
+ CipherStruct.new(cipher, iv, salt)
27
+ end
28
+
29
+ def update_cipher(cipher, value)
30
+ data = cipher.update(value)
31
+ data << cipher.final
32
+ data
33
+ end
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,44 @@
1
+ module Sym
2
+ module Crypt
3
+ # This class encapsulates application configuration, and exports
4
+ # a familiar method +#configure+ for defining configuration in a
5
+ # block.
6
+ #
7
+ # It's values are requested by the library upon encryption or
8
+ # decryption, or any other operation.
9
+ #
10
+ # == Example
11
+ #
12
+ # The following is an actual initialization from the code of this
13
+ # library. You may override any of the value defined below in your
14
+ # code, but _before_ you _use_ library's encryption methods.
15
+ #
16
+ # Sym::Crypt::Configuration.configure do |config|
17
+ # config.password_cipher = 'AES-128-CBC'
18
+ # config.data_cipher = 'AES-256-CBC'
19
+ # config.private_key_cipher = config.data_cipher
20
+ # config.compression_enabled = true
21
+ # config.compression_level = Zlib::BEST_COMPRESSION
22
+ # end
23
+
24
+ class Configuration
25
+ class << self
26
+ attr_accessor :config
27
+
28
+ def configure
29
+ self.config ||= Configuration.new
30
+ yield config if block_given?
31
+ end
32
+
33
+ def property(name)
34
+ self.config.send(name)
35
+ end
36
+ end
37
+
38
+ # See file +lib/sym/crypt.rb+ where these values are defined.
39
+
40
+ attr_accessor :data_cipher, :password_cipher, :private_key_cipher
41
+ attr_accessor :compression_enabled, :compression_level
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
1
+ require 'base64'
2
+ require 'zlib'
3
+
4
+ require 'sym/crypt/data/encoder'
5
+ require 'sym/crypt/data/decoder'
6
+ require 'sym/crypt/data/wrapper_struct'
7
+
8
+ module Sym
9
+ module Crypt
10
+ # This module is responsible for taking arbitrary data of any format, and safely compressing
11
+ # the result of `Marshal.dump(data)` using Zlib, and then doing `#urlsafe_encode64` encoding
12
+ # to convert it to a string,
13
+ module Data
14
+ def encode(data, compress = true)
15
+ Encoder.new(data, compress).data_encoded
16
+ end
17
+
18
+ def decode(data_encoded, compress = nil)
19
+ Decoder.new(data_encoded, compress).data
20
+ end
21
+ end
22
+ end
23
+ end
24
+