attr_cipher 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 00b32ff728220c366f964a0305a33a5b1c8216e1
4
+ data.tar.gz: fcf407ad3d80e9533649b0910147d7d5ea8c5d1d
5
+ SHA512:
6
+ metadata.gz: 516fc8a442a58f34795447dd56f3f01cc8eed3d4bd7cf5cec96331de37f3b63eaeeac34bd6851fc1a51e20c34700478628a94538660d64e834fc36e6617c8ed9
7
+ data.tar.gz: 1a6437ac77c47f4a991d7c237cf04c86faaa9b61b726426dcf9728b47839c633ddf6edcfa5a9f9f77feac60c8c8f267e3e2e08196d1dde642172f825258761e3
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ # Change Log
2
+
3
+ ##v1.0.0
4
+ - Initial release.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Brightcommerce, Inc. All rights reserved.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ [![Gem Version](https://badge.fury.io/rb/attr_cipher.svg)](https://badge.fury.io/rb/attr_cipher)
2
+ [![Build Status](https://travis-ci.org/brightcommerce/attr_cipher.svg?branch=master)](https://travis-ci.org/brightcommerce/attr_cipher)
3
+ [![codecov.io](https://codecov.io/github/brightcommerce/attr_cipher/coverage.svg?branch=master)](https://codecov.io/github/brightcommerce/attr_cipher?branch=master)
4
+ [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/brightcommerce/attr_cipher/pulls)
5
+
6
+ # AttrCipher
7
+
8
+ [**AttrCipher**](https://github.com/brightcommerce/attr_cipher) provides functionality to store encrypted attributes in ActiveRecord models. Values are encrypted and decrypted transparently.
9
+
10
+ Using the same secret for both encryption of plaintext and decryption of ciphertext, **AttrCipher** uses a method that is known as a symmetric-key algorithm, specifically the Advanced Encryption Standard Cipher-Block Chaining algorithm with a 256bit key (AES-256-CBC). However, you can provide your own cipher algorithm to **AttrCipher**, if you prefer. As a side note, 256bit AES is what the United States government uses to encrypt information at the Top Secret level.
11
+
12
+ ## Installation
13
+
14
+ To install add the following line to your `Gemfile`:
15
+
16
+ ``` ruby
17
+ gem 'attr_cipher'
18
+ ```
19
+
20
+ And run `bundle install`.
21
+
22
+ ## Dependencies
23
+
24
+ Runtime:
25
+ - activerecord (>= 4.2.6, < 5.2.0)
26
+ - activesupport (>= 4.2.6, < 5.2.0)
27
+
28
+ Development/Test:
29
+ - rake (~> 10.5)
30
+ - rspec (~> 3.4)
31
+ - sqlite3 (~> 1.3)
32
+ - simplecov (~> 0.11.2)
33
+ - factory_girl (~> 4.5)
34
+
35
+ ## Compatibility
36
+
37
+ Tested with Ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15] against ActiveRecord 5.0.0 on macOS Sierra 10.12.4 (16E195).
38
+
39
+ **AttrCipher** uses OpenSSL to perform the cipher.
40
+
41
+ ## Usage
42
+
43
+ **AttrCipher** uses a global secret by default and it must be at least 100 characters or more. You can set the secret by setting `AttrCipher.secret`; (e.g. `$ openssl rand -hex 50`).
44
+
45
+ ```ruby
46
+ AttrCipher.secret = ENV['SECRET_KEY']
47
+ ```
48
+
49
+ You can also set the secret on a per attribute basis.
50
+
51
+ ```ruby
52
+ class User
53
+ attr_cipher :api_key, secret: ENV['USER_API_KEY_SECRET']
54
+ end
55
+ ```
56
+
57
+ Attributes to be encrypted are declared using the `attr_cipher` class method in your model:
58
+
59
+ ```ruby
60
+ ActiveRecord::Schema.define do
61
+ create_table :users do |t|
62
+ t.text :security_question
63
+ t.text :security_answer_cipher
64
+ end
65
+ end
66
+
67
+ class User < ActiveRecord::Base
68
+ attr_cipher :security_answer
69
+ end
70
+ ```
71
+
72
+ **AttrCipher** automatically creates the `#security_answer` getter and `#security_answer=` setter. The getter authomatically decrypts the return value. The setter encrypts the value provided and stores it in the `security_answer_cipher` column.
73
+ CustomCipher
74
+ If you don't want to use the AES-256-CBC cipher, you can provide your own cipher module. Define an object that responds to `encrypt(secret, value)` and `decrypt(secret, value)`:
75
+
76
+ ```ruby
77
+ module CustomCipher
78
+ def self.encrypt(secret, value)
79
+ value.to_s.reverse
80
+ end
81
+ def self.decrypt(secret, value)
82
+ value.to_s.reverse
83
+ end
84
+ end
85
+ ```
86
+
87
+ Then pass the custom cipher module to the `cipher` option of the `attr_cipher` class method:
88
+
89
+ ```ruby
90
+ class User < ActiveRecord::Base
91
+ attr_cipher :api_key, cipher: CustomCipher
92
+ end
93
+ ```
94
+
95
+ ## Tests
96
+
97
+ Tests are written using Rspec, FactoryGirl and Sqlite3. There are 13 examples with 100% code coverage.
98
+
99
+ To run the tests, execute the default rake task:
100
+
101
+ ``` bash
102
+ bundle exec rake
103
+ ```
104
+
105
+ ## Contributing
106
+
107
+ 1. Fork it
108
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
109
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
110
+ 4. Push to the branch (`git push origin my-new-feature`)
111
+ 5. Create new Pull Request
112
+
113
+ ## Credit
114
+
115
+ I would like to thank [Nando Vieira](http://nandovieira.com/) for his [encrypt_attr](https://github.com/fnando/encrypt_attr) gem which provided a lot of the inspiration and framework for **AttrCipher**.
116
+
117
+ This gem was written and is maintained by [Jurgen Jocubeit](https://github.com/JurgenJocubeit), CEO and President Brightcommerce, Inc.
118
+
119
+ ## License
120
+
121
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
122
+
123
+ ## Copyright
124
+
125
+ Copyright 2017 Brightcommerce, Inc.
@@ -0,0 +1,56 @@
1
+ require 'active_record'
2
+ require 'active_support/all'
3
+
4
+ module AttrCipher
5
+ extend ActiveSupport::Concern
6
+
7
+ class << self
8
+ attr_accessor :cipher
9
+ attr_reader :secret
10
+ end
11
+
12
+ def self.secret=(value)
13
+ validate_secret(value.to_s)
14
+ @secret = value.to_s
15
+ end
16
+
17
+ def self.validate_secret(value)
18
+ if value.size < 100
19
+ offending_line = caller.reject { |entry|
20
+ entry.include?(__dir__) || entry.include?("forwardable.rb")
21
+ }.first[/^(.*?:\d+)/, 1]
22
+ warn "[attr_cipher] secret must have at least 100 characters (called from #{offending_line})"
23
+ end
24
+ end
25
+
26
+ self.cipher = Cipher
27
+ self.secret = ''
28
+
29
+ module ClassMethods
30
+ def attr_cipher(*args, secret: AttrCipher.secret, cipher: AttrCipher.cipher)
31
+ AttrCipher.validate_secret(secret)
32
+ args.each do |attribute|
33
+ define_cipher_attribute(attribute, secret, cipher)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def define_cipher_attribute(attribute, secret, cipher)
40
+ define_method attribute do
41
+ value = instance_variable_get("@#{attribute}")
42
+ cipher_value = send("#{attribute}_cipher") unless value
43
+ value = cipher.decrypt(secret, cipher_value) if cipher_value
44
+ instance_variable_set("@#{attribute}", value)
45
+ end
46
+
47
+ define_method "#{attribute}=" do |value|
48
+ instance_variable_set("@#{attribute}", value)
49
+ send("#{attribute}_cipher=", nil)
50
+ send("#{attribute}_cipher=", cipher.encrypt(secret, value)) if value && value != ""
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ ActiveRecord::Base.send :include, AttrCipher
@@ -0,0 +1,47 @@
1
+ require 'base64'
2
+ require 'digest/sha2'
3
+ require 'openssl'
4
+
5
+ module AttrCipher
6
+ class Cipher
7
+ ALGORITHM = "AES-256-CBC".freeze
8
+
9
+ attr_reader :secret
10
+
11
+ def initialize(secret)
12
+ @secret = secret
13
+ end
14
+
15
+ def cipher(mode, value)
16
+ cipher = OpenSSL::Cipher.new(ALGORITHM).public_send(mode)
17
+ digest = Digest::SHA256.digest(@secret)
18
+ cipher.key = digest
19
+ cipher.iv = digest[0...cipher.iv_len]
20
+ cipher.update(value) + cipher.final
21
+ end
22
+
23
+ def decode(value)
24
+ Base64.decode64(value)
25
+ end
26
+
27
+ def decrypt(value)
28
+ cipher(:decrypt, decode(value))
29
+ end
30
+
31
+ def encode(value)
32
+ Base64.encode64(value).chomp
33
+ end
34
+
35
+ def encrypt(value)
36
+ encode(cipher(:encrypt, value))
37
+ end
38
+
39
+ def self.decrypt(secret, value)
40
+ new(secret).decrypt(value)
41
+ end
42
+
43
+ def self.encrypt(secret, value)
44
+ new(secret).encrypt(value)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ module AttrCipher
2
+ module VERSION
3
+ MAJOR = 1
4
+ MINOR = 1
5
+ TINY = 0
6
+ PRE = nil
7
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
8
+ SUMMARY = "AttrCipher v#{STRING}"
9
+ DESCRIPTION = "Provides functionality to store encrypted attributes using AES-256-CBC."
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ require 'attr_cipher/version'
2
+ require 'attr_cipher/cipher'
3
+ require 'attr_cipher/attr_cipher'
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attr_cipher
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jurgen Jocubeit
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.2.6
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 5.2.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 4.2.6
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 5.2.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: activerecord
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 4.2.6
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: 5.2.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 4.2.6
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: 5.2.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: rake
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '10.5'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '10.5'
67
+ - !ruby/object:Gem::Dependency
68
+ name: rspec
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '3.4'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '3.4'
81
+ - !ruby/object:Gem::Dependency
82
+ name: sqlite3
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.3'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '1.3'
95
+ - !ruby/object:Gem::Dependency
96
+ name: factory_girl
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '4.5'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '4.5'
109
+ - !ruby/object:Gem::Dependency
110
+ name: simplecov
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: 0.11.2
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: 0.11.2
123
+ description: Provides functionality to store encrypted attributes using AES-256-CBC.
124
+ email:
125
+ - support@brightcommerce.com
126
+ executables: []
127
+ extensions: []
128
+ extra_rdoc_files: []
129
+ files:
130
+ - CHANGELOG.md
131
+ - MIT-LICENSE
132
+ - README.md
133
+ - lib/attr_cipher.rb
134
+ - lib/attr_cipher/attr_cipher.rb
135
+ - lib/attr_cipher/cipher.rb
136
+ - lib/attr_cipher/version.rb
137
+ homepage: https://github.com/brightcommerce/attr_cipher
138
+ licenses:
139
+ - MIT
140
+ metadata:
141
+ copyright: Copyright 2017 Brightcommerce, Inc.
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '2.2'
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubyforge_project:
158
+ rubygems_version: 2.5.1
159
+ signing_key:
160
+ specification_version: 4
161
+ summary: AttrCipher v1.1.0
162
+ test_files: []