encryptor 1.3.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/.gitignore +5 -0
- data/.travis.yml +19 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +3 -0
- data/README.md +168 -73
- data/Rakefile +5 -14
- data/certs/saghaulor.pem +21 -0
- data/encryptor.gemspec +41 -0
- data/lib/encryptor.rb +54 -19
- data/lib/encryptor/string.rb +3 -3
- data/lib/encryptor/version.rb +2 -2
- data/test/compatibility_test.rb +29 -25
- data/test/encryptor_string_test.rb +60 -0
- data/test/encryptor_test.rb +57 -65
- data/test/legacy_encryptor_string_test.rb +56 -0
- data/test/legacy_encryptor_test.rb +22 -63
- data/test/openssl_helper.rb +24 -4
- data/test/test_helper.rb +21 -12
- metadata +94 -39
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dc166257be860dc17bd32f793762a69aa8d0bb17
|
4
|
+
data.tar.gz: 0229093567b3307695cb5cf2bdd12de1005cc32d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 48dea5301f97036ce8198865090fb7ae13e8385ec1376332043a06ec25d9ae17dfb49d629fc962a193faa763f3cf9624252609b59149a3fba4fe6ead7230b7f1
|
7
|
+
data.tar.gz: 554b9fd4f471a8ef2131b0bce5c2fa843f0abe277f54bbe1a9d6c28e156aa56d0d23077be08c8f003a2d396f9c14347419bc41fc7026d6c2d9a46d8408977058
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
��A�\D|��<�2bU��PK���Ot#g'n7�������$Qu��zʎ%���W&�9ƶ�Ե�ϝv�0�m�0�HL(��PW�~sC�6e@
|
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
sudo: false
|
2
|
+
language: ruby
|
3
|
+
cache: bundler
|
4
|
+
matrix:
|
5
|
+
fast_finish: true
|
6
|
+
include:
|
7
|
+
- rvm: 2.0.0
|
8
|
+
- rvm: 2.1
|
9
|
+
- rvm: 2.2
|
10
|
+
- rvm: 2.3.0
|
11
|
+
- rvm: jruby
|
12
|
+
- rvm: rbx
|
13
|
+
allow_failures:
|
14
|
+
- rvm: jruby
|
15
|
+
exclude:
|
16
|
+
- rvm: 1.9.3
|
17
|
+
addons:
|
18
|
+
code_climate:
|
19
|
+
repo_token: 5dcb75d5b6c58e2a5f6dc850eb2c1d4e0dbf262e69981db00b765a66bfc9ef10
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Encryptor #
|
2
|
+
|
3
|
+
## Unreleased ##
|
4
|
+
|
5
|
+
* Added support for MRI 2.1, 2.2, 2.3, and Rubinius. (@saghaulor)
|
6
|
+
* Added support for Authenticated Encryption Authentiation Data (AEAD) via aes-###-gcm. (@saghaulor)
|
7
|
+
* Changed the defaults to improve security, aes-256-gcm, IV is required. (@saghaulor)
|
8
|
+
* Added key and IV minimum length validations. (@saghaulor)
|
9
|
+
* Added insecure_mode option to allow for backwards compatibility for users who didn't use unique IV. (@saghaulor)
|
10
|
+
* Deprecated using Encryptor without an IV.
|
11
|
+
* Added hmac_iterations option to allow for adjusting the number of PKCS5 iterations when deriving a unique key. (@saghaulor)
|
12
|
+
* Removed support for MRI 1.9.3 and JRuby (until JRuby supports `auth_data=`, https://github.com/jruby/jruby/issues/3376). (@saghaulor)
|
13
|
+
* Changed tests to use Minitest. (@saghaulor)
|
14
|
+
* Changed syntax to use Ruby 1.9+ hash syntax. (@saghaulor)
|
15
|
+
* Salt may be deprecated in a future release, it remains for backwards compatibility. It's better security to have a unique key per record, however, the cost of PKCS5 is too high to force on to users by default. If users want a unique key per record they can implement it in their own way.
|
16
|
+
|
17
|
+
## 1.3.0 ##
|
18
|
+
|
19
|
+
* Added support for unique key (via salt) and IV. (@danpal & @rcook)
|
20
|
+
|
21
|
+
## 1.2.3 ##
|
22
|
+
|
23
|
+
* Added support for passing blocks to `encrypt` and `decrypt`. (@shuber)
|
24
|
+
* Changed raising an exception if key is missing or empty. (@shuber)
|
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
1
|
+
# Encryptor
|
2
2
|
|
3
|
-
|
3
|
+
[![Build Status](https://secure.travis-ci.org/attr-encrypted/encryptor.svg)](https://travis-ci.org/attr-encrypted/encryptor) [![Code Climate](https://codeclimate.com/github/attr-encrypted/encryptor/badges/gpa.svg)](https://codeclimate.com/github/attr-encrypted/encryptor) [![Coverage](https://codeclimate.com/github/attr-encrypted/encryptor/badges/coverage.svg)](https://codeclimate.com/github/attr-encrypted/encryptor) [![Gem Version](https://badge.fury.io/rb/encryptor.svg)](http://badge.fury.io/rb/encryptor) [![security](https://hakiri.io/github/attr-encrypted/encryptor/master.svg)](https://hakiri.io/github/attr-encrypted/encryptor/master)
|
4
4
|
|
5
|
-
|
5
|
+
A simple wrapper for the standard Ruby OpenSSL library
|
6
6
|
|
7
7
|
### Installation
|
8
8
|
|
@@ -14,104 +14,199 @@ gem install encryptor
|
|
14
14
|
|
15
15
|
#### Basic
|
16
16
|
|
17
|
-
Encryptor uses the AES-256-
|
17
|
+
Encryptor uses the AES-256-GCM algorithm by default to encrypt strings securely.
|
18
18
|
|
19
19
|
The best example is:
|
20
20
|
|
21
21
|
```ruby
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
cipher = OpenSSL::Cipher.new('aes-256-gcm')
|
23
|
+
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
|
24
|
+
secret_key = cipher.random_key # Insures that the key is the correct length respective to the algorithm used.
|
25
|
+
iv = cipher.random_iv # Insures that the IV is the correct length respective to the algorithm used.
|
26
|
+
salt = SecureRandom.random_bytes(16)
|
27
|
+
encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: secret_key, iv: iv, salt: salt)
|
28
|
+
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: secret_key, iv: iv, salt: salt)
|
27
29
|
```
|
28
30
|
|
29
|
-
|
31
|
+
A slightly easier example is:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
require 'securerandom'
|
35
|
+
secret_key = SecureRandom.random_bytes(32) # The length in bytes must be equal to or greater than the algorithm bit length.
|
36
|
+
iv = SecureRandom.random_bytes(12) # Recomended length for AES-###-GCM algorithm. https://tools.ietf.org/html/rfc5084#section-3.2
|
37
|
+
encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: secret_key, iv: iv)
|
38
|
+
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: secret_key, iv: iv)
|
39
|
+
```
|
40
|
+
|
41
|
+
**NOTE: It is imperative that you use a unique IV per each string and encryption key combo; a nonce as the IV.**
|
42
|
+
See [RFC 5084](https://tools.ietf.org/html/rfc5084#section-1.5) for more details.
|
43
|
+
|
44
|
+
The value to encrypt or decrypt may also be passed as the first option if you'd prefer.
|
30
45
|
|
31
46
|
```ruby
|
32
|
-
encrypted_value = Encryptor.encrypt(
|
33
|
-
decrypted_value = Encryptor.decrypt(
|
47
|
+
encrypted_value = Encryptor.encrypt('some string to encrypt', key: secret_key, iv: iv)
|
48
|
+
decrypted_value = Encryptor.decrypt(encrypted_value, key: secret_key, iv: iv)
|
34
49
|
```
|
35
50
|
|
36
|
-
|
51
|
+
#### Options
|
52
|
+
|
53
|
+
**Defaults:**
|
37
54
|
|
38
55
|
```ruby
|
39
|
-
|
40
|
-
|
56
|
+
{ algorithm: 'aes-256-gcm',
|
57
|
+
auth_data: '',
|
58
|
+
insecure_mode: false,
|
59
|
+
hmac_iterations: 2000 }
|
41
60
|
```
|
42
61
|
|
43
|
-
|
62
|
+
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.
|
63
|
+
|
64
|
+
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.
|
44
65
|
|
45
66
|
```ruby
|
46
|
-
Encryptor.default_options.merge!(:
|
67
|
+
Encryptor.default_options.merge!(algorithm: 'aes-256-cbc', key: 'some default secret key', iv: iv, salt: salt)
|
47
68
|
```
|
48
69
|
|
49
70
|
#### Strings
|
50
71
|
|
51
|
-
Encryptor
|
72
|
+
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:
|
52
73
|
|
53
74
|
```ruby
|
54
|
-
|
75
|
+
require 'encryptor/string'
|
76
|
+
String.include Encryptor::String
|
77
|
+
Encryptor.default_options.merge!(key: 'some default secret key', iv: iv)
|
55
78
|
credit_card = 'xxxx xxxx xxxx 1234'
|
56
79
|
encrypted_credit_card = credit_card.encrypt
|
57
80
|
```
|
58
81
|
|
59
82
|
There's also `encrypt!` and `decrypt!` methods that replace the contents of a string with the encrypted or decrypted version of itself.
|
60
83
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
84
|
+
#### Algorithms
|
85
|
+
|
86
|
+
To view a list of all cipher algorithms that are supported on your platform, run the following code in your favorite Ruby REPL:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
require 'openssl'
|
90
|
+
puts OpenSSL::Cipher.ciphers
|
91
|
+
```
|
92
|
+
|
93
|
+
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:
|
94
|
+
|
95
|
+
Cipher Name|Key size in bytes|IV size in bytes
|
96
|
+
---|---|---
|
97
|
+
aes-128-cbc|16|16
|
98
|
+
aes-128-cbc-hmac-sha1|16|16
|
99
|
+
aes-128-cbc-hmac-sha256|16|16
|
100
|
+
aes-128-ccm|16|12
|
101
|
+
aes-128-cfb|16|16
|
102
|
+
aes-128-cfb1|16|16
|
103
|
+
aes-128-cfb8|16|16
|
104
|
+
aes-128-ctr|16|16
|
105
|
+
aes-128-ecb|16|0
|
106
|
+
aes-128-gcm|16|12
|
107
|
+
aes-128-ofb|16|16
|
108
|
+
aes-128-xts|32|16
|
109
|
+
aes-192-cbc|24|16
|
110
|
+
aes-192-ccm|24|12
|
111
|
+
aes-192-cfb|24|16
|
112
|
+
aes-192-cfb1|24|16
|
113
|
+
aes-192-cfb8|24|16
|
114
|
+
aes-192-ctr|24|16
|
115
|
+
aes-192-ecb|24|0
|
116
|
+
aes-192-gcm|24|12
|
117
|
+
aes-192-ofb|24|16
|
118
|
+
aes-256-cbc|32|16
|
119
|
+
aes-256-cbc-hmac-sha1|32|16
|
120
|
+
aes-256-cbc-hmac-sha256|32|16
|
121
|
+
aes-256-ccm|32|12
|
122
|
+
aes-256-cfb|32|16
|
123
|
+
aes-256-cfb1|32|16
|
124
|
+
aes-256-cfb8|32|16
|
125
|
+
aes-256-ctr|32|16
|
126
|
+
aes-256-ecb|32|0
|
127
|
+
aes-256-gcm|32|12
|
128
|
+
aes-256-ofb|32|16
|
129
|
+
aes-256-xts|64|16
|
130
|
+
aes128|16|16
|
131
|
+
aes192|24|16
|
132
|
+
aes256|32|16
|
133
|
+
bf|16|8
|
134
|
+
bf-cbc|16|8
|
135
|
+
bf-cfb|16|8
|
136
|
+
bf-ecb|16|0
|
137
|
+
bf-ofb|16|8
|
138
|
+
blowfish|16|8
|
139
|
+
camellia-128-cbc|16|16
|
140
|
+
camellia-128-cfb|16|16
|
141
|
+
camellia-128-cfb1|16|16
|
142
|
+
camellia-128-cfb8|16|16
|
143
|
+
camellia-128-ecb|16|0
|
144
|
+
camellia-128-ofb|16|16
|
145
|
+
camellia-192-cbc|24|16
|
146
|
+
camellia-192-cfb|24|16
|
147
|
+
camellia-192-cfb1|24|16
|
148
|
+
camellia-192-cfb8|24|16
|
149
|
+
camellia-192-ecb|24|0
|
150
|
+
camellia-192-ofb|24|16
|
151
|
+
camellia-256-cbc|32|16
|
152
|
+
camellia-256-cfb|32|16
|
153
|
+
camellia-256-cfb1|32|16
|
154
|
+
camellia-256-cfb8|32|16
|
155
|
+
camellia-256-ecb|32|0
|
156
|
+
camellia-256-ofb|32|16
|
157
|
+
camellia128|16|16
|
158
|
+
camellia192|24|16
|
159
|
+
camellia256|32|16
|
160
|
+
cast|16|8
|
161
|
+
cast-cbc|16|8
|
162
|
+
cast5-cbc|16|8
|
163
|
+
cast5-cfb|16|8
|
164
|
+
cast5-ecb|16|0
|
165
|
+
cast5-ofb|16|8
|
166
|
+
des|8|8
|
167
|
+
des-cbc|8|8
|
168
|
+
des-cfb|8|8
|
169
|
+
des-cfb1|8|8
|
170
|
+
des-cfb8|8|8
|
171
|
+
des-ecb|8|0
|
172
|
+
des-ede|16|0
|
173
|
+
des-ede-cbc|16|8
|
174
|
+
des-ede-cfb|16|8
|
175
|
+
des-ede-ofb|16|8
|
176
|
+
des-ede3|24|0
|
177
|
+
des-ede3-cbc|24|8
|
178
|
+
des-ede3-cfb|24|8
|
179
|
+
des-ede3-cfb1|24|8
|
180
|
+
des-ede3-cfb8|24|8
|
181
|
+
des-ede3-ofb|24|8
|
182
|
+
des-ofb|8|8
|
183
|
+
des3|24|8
|
184
|
+
desx|24|8
|
185
|
+
desx-cbc|24|8
|
186
|
+
idea|16|8
|
187
|
+
idea-cbc|16|8
|
188
|
+
idea-cfb|16|8
|
189
|
+
idea-ecb|16|0
|
190
|
+
idea-ofb|16|8
|
191
|
+
rc2|16|8
|
192
|
+
rc2-40-cbc|5|8
|
193
|
+
rc2-64-cbc|8|8
|
194
|
+
rc2-cbc|16|8
|
195
|
+
rc2-cfb|16|8
|
196
|
+
rc2-ecb|16|0
|
197
|
+
rc2-ofb|16|8
|
198
|
+
rc4|16|0
|
199
|
+
rc4-40|5|0
|
200
|
+
rc4-hmac-md5|16|0
|
201
|
+
seed|16|16
|
202
|
+
seed-cbc|16|16
|
203
|
+
seed-cfb|16|16
|
204
|
+
seed-ecb|16|0
|
205
|
+
seed-ofb|16|16
|
206
|
+
|
207
|
+
**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.**
|
208
|
+
|
209
|
+
#### Notes on patches/pull requests
|
115
210
|
|
116
211
|
* Fork the project.
|
117
212
|
* Make your feature addition or bug fix.
|
data/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
|
-
require '
|
3
|
+
require 'rdoc/task'
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
|
4
6
|
|
5
7
|
desc 'Test the encryptor gem'
|
6
8
|
Rake::TestTask.new(:test) do |t|
|
@@ -18,16 +20,5 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
18
20
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
19
21
|
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
task :rcov do
|
25
|
-
system "rcov -o coverage/rcov --exclude '^(?!lib)' " + FileList[ 'test/**/*_test.rb' ].join(' ')
|
26
|
-
end
|
27
|
-
|
28
|
-
desc 'Default: run unit tests under rcov.'
|
29
|
-
task :default => :rcov
|
30
|
-
else
|
31
|
-
desc 'Default: run unit tests.'
|
32
|
-
task :default => :test
|
33
|
-
end
|
23
|
+
desc 'Default: run unit tests.'
|
24
|
+
task default: :test
|
data/certs/saghaulor.pem
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDdDCCAlygAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMRIwEAYDVQQDDAlzYWdo
|
3
|
+
YXVsb3IxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
|
4
|
+
bTAeFw0xNjAxMTEyMjQyMDFaFw0xNzAxMTAyMjQyMDFaMEAxEjAQBgNVBAMMCXNh
|
5
|
+
Z2hhdWxvcjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD
|
6
|
+
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx0xdQYk2GwCpQ1n/
|
7
|
+
n2mPVYHLYqU5TAn/82t5kbqBUWjbcj8tHAi41tJ19+fT/hH0dog8JHvho1zmOr71
|
8
|
+
ZIqreJQo60TqP6oE9a5HncUpjqbRp7tOmHo9E+mOW1yT4NiXqFf1YINExQKy2XND
|
9
|
+
WPQ+T50ZNUsGMfHFWB4NAymejRWXlOEY3bvKW0UHFeNmouP5he51TjoP8uCc9536
|
10
|
+
4AIWVP/zzzjwrFtC7av7nRw4Y+gX2bQjrkK2k2JS0ejiGzKBIEMJejcI2B+t79zT
|
11
|
+
kUQq9SFwp2BrKSIy+4kh4CiF20RT/Hfc1MbvTxSIl/bbIxCYEOhmtHExHi0CoCWs
|
12
|
+
YCGCXQIDAQABo3kwdzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU
|
13
|
+
SCpVzSBvYbO6B3oT3n3RCZmurG8wHgYDVR0RBBcwFYETc2FnaGF1bG9yQGdtYWls
|
14
|
+
LmNvbTAeBgNVHRIEFzAVgRNzYWdoYXVsb3JAZ21haWwuY29tMA0GCSqGSIb3DQEB
|
15
|
+
BQUAA4IBAQAeiGdC3e0WiZpm0cF/b7JC6hJYXC9Yv9VsRAWD9ROsLjFKwOhmonnc
|
16
|
+
+l/QrmoTjMakYXBCai/Ca3L+k5eRrKilgyITILsmmFxK8sqPJXUw2Jmwk/dAky6x
|
17
|
+
hHKVZAofT1OrOOPJ2USoZyhR/VI8epLaD5wUmkVDNqtZWviW+dtRa55aPYjRw5Pj
|
18
|
+
wuj9nybhZr+BbEbmZE//2nbfkM4hCuMtxxxilPrJ22aYNmeWU0wsPpDyhPYxOUgU
|
19
|
+
ZjeLmnSDiwL6doiP5IiwALH/dcHU67ck3NGf6XyqNwQrrmtPY0mv1WVVL4Uh+vYE
|
20
|
+
kHoFzE2no0BfBg78Re8fY69P5yES5ncC
|
21
|
+
-----END CERTIFICATE-----
|
data/encryptor.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib/', __FILE__)
|
4
|
+
$:.unshift lib unless $:.include?(lib)
|
5
|
+
|
6
|
+
require 'encryptor/version'
|
7
|
+
require 'date'
|
8
|
+
|
9
|
+
Gem::Specification.new do |s|
|
10
|
+
s.name = 'encryptor'
|
11
|
+
s.version = Encryptor::Version
|
12
|
+
s.date = Date.today
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
|
15
|
+
s.summary = 'A simple wrapper for the standard ruby OpenSSL library'
|
16
|
+
s.description = 'A simple wrapper for the standard ruby OpenSSL library to encrypt and decrypt strings'
|
17
|
+
|
18
|
+
s.authors = ['Sean Huber', 'S. Brent Faulkner', 'William Monk', 'Stephen Aghaulor']
|
19
|
+
s.email = ['sean@shuber.io', 'sbfaulkner@gmail.com', 'billy.monk@gmail.com', 'saghaulor@gmail.com']
|
20
|
+
s.homepage = 'http://github.com/attr-encrypted/encryptor'
|
21
|
+
s.license = 'MIT'
|
22
|
+
s.rdoc_options = %w(--charset=UTF-8 --inline-source --line-numbers --main README.md)
|
23
|
+
|
24
|
+
s.require_paths = ['lib']
|
25
|
+
|
26
|
+
s.files = `git ls-files`.split("\n")
|
27
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
28
|
+
|
29
|
+
s.required_ruby_version = '>= 2.0.0'
|
30
|
+
|
31
|
+
s.add_development_dependency('minitest', '>= 0')
|
32
|
+
s.add_development_dependency('rake', '>= 0')
|
33
|
+
s.add_development_dependency('simplecov', '>= 0')
|
34
|
+
s.add_development_dependency('simplecov-rcov', '>= 0')
|
35
|
+
s.add_development_dependency('codeclimate-test-reporter', '>= 0')
|
36
|
+
|
37
|
+
s.requirements << 'openssl, >= v1.0.1'
|
38
|
+
|
39
|
+
s.cert_chain = ['certs/saghaulor.pem']
|
40
|
+
s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
|
41
|
+
end
|
data/lib/encryptor.rb
CHANGED
@@ -1,45 +1,48 @@
|
|
1
1
|
require 'openssl'
|
2
|
-
require 'encryptor/
|
3
|
-
|
4
|
-
String.send(:include, Encryptor::String)
|
2
|
+
require 'encryptor/version'
|
5
3
|
|
6
4
|
# A simple wrapper for the standard OpenSSL library
|
7
5
|
module Encryptor
|
8
|
-
autoload :Version, 'encryptor/version'
|
9
6
|
|
10
7
|
extend self
|
11
8
|
|
12
9
|
# The default options to use when calling the <tt>encrypt</tt> and <tt>decrypt</tt> methods
|
13
10
|
#
|
14
|
-
# Defaults to { :
|
11
|
+
# Defaults to { algorithm: 'aes-256-gcm',
|
12
|
+
# auth_data: '',
|
13
|
+
# insecure_mode: false,
|
14
|
+
# hmac_iterations: 2000 }
|
15
15
|
#
|
16
16
|
# Run 'openssl list-cipher-commands' in your terminal to view a list all cipher algorithms that are supported on your platform
|
17
17
|
def default_options
|
18
|
-
@default_options ||= { :
|
18
|
+
@default_options ||= { algorithm: 'aes-256-gcm',
|
19
|
+
auth_data: '',
|
20
|
+
insecure_mode: false,
|
21
|
+
hmac_iterations: 2000 }
|
19
22
|
end
|
20
23
|
|
21
|
-
# Encrypts a <tt>:value</tt> with a specified <tt>:key</tt>
|
24
|
+
# Encrypts a <tt>:value</tt> with a specified <tt>:key</tt> and <tt>:iv</tt>.
|
22
25
|
#
|
23
|
-
# Optionally accepts <tt>:
|
26
|
+
# Optionally accepts <tt>:salt</tt>, <tt>:auth_data</tt>, <tt>:algorithm</tt>, <tt>:hmac_iterations</tt>, and <tt>:insecure_mode</tt> options.
|
24
27
|
#
|
25
28
|
# Example
|
26
29
|
#
|
27
|
-
# encrypted_value = Encryptor.encrypt(:
|
30
|
+
# encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
|
28
31
|
# # or
|
29
|
-
# encrypted_value = Encryptor.encrypt('some string to encrypt', :
|
32
|
+
# encrypted_value = Encryptor.encrypt('some string to encrypt', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
|
30
33
|
def encrypt(*args, &block)
|
31
34
|
crypt :encrypt, *args, &block
|
32
35
|
end
|
33
36
|
|
34
|
-
# Decrypts a <tt>:value</tt> with a specified <tt>:key</tt>
|
37
|
+
# Decrypts a <tt>:value</tt> with a specified <tt>:key</tt> and <tt>:iv</tt>.
|
35
38
|
#
|
36
|
-
# Optionally accepts <tt>:
|
39
|
+
# Optionally accepts <tt>:salt</tt>, <tt>:auth_data</tt>, <tt>:algorithm</tt>, <tt>:hmac_iterations</tt>, and <tt>:insecure_mode</tt> options.
|
37
40
|
#
|
38
41
|
# Example
|
39
42
|
#
|
40
|
-
# decrypted_value = Encryptor.decrypt(:
|
43
|
+
# decrypted_value = Encryptor.decrypt(value: 'some encrypted string', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
|
41
44
|
# # or
|
42
|
-
# decrypted_value = Encryptor.decrypt('some encrypted string', :
|
45
|
+
# decrypted_value = Encryptor.decrypt('some encrypted string', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
|
43
46
|
def decrypt(*args, &block)
|
44
47
|
crypt :decrypt, *args, &block
|
45
48
|
end
|
@@ -47,10 +50,15 @@ module Encryptor
|
|
47
50
|
protected
|
48
51
|
|
49
52
|
def crypt(cipher_method, *args) #:nodoc:
|
50
|
-
options = default_options.merge(:
|
51
|
-
raise ArgumentError.new('must specify a
|
52
|
-
cipher = OpenSSL::Cipher
|
53
|
+
options = default_options.merge(value: args.first).merge(args.last.is_a?(Hash) ? args.last : {})
|
54
|
+
raise ArgumentError.new('must specify a key') if options[:key].to_s.empty?
|
55
|
+
cipher = OpenSSL::Cipher.new(options[:algorithm])
|
53
56
|
cipher.send(cipher_method)
|
57
|
+
unless options[:insecure_mode]
|
58
|
+
raise ArgumentError.new("key must be #{cipher.key_len} bytes or longer") if options[:key].bytesize < cipher.key_len
|
59
|
+
raise ArgumentError.new('must specify an iv') if options[:iv].to_s.empty?
|
60
|
+
raise ArgumentError.new("iv must be #{cipher.iv_len} bytes or longer") if options[:iv].bytesize < cipher.iv_len
|
61
|
+
end
|
54
62
|
if options[:iv]
|
55
63
|
cipher.iv = options[:iv]
|
56
64
|
if options[:salt].nil?
|
@@ -63,13 +71,40 @@ module Encryptor
|
|
63
71
|
# Use an explicit salt (which can be persisted into a database on a
|
64
72
|
# per-column basis, for example). This is the preferred (and more
|
65
73
|
# secure) mode of operation.
|
66
|
-
cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(options[:key], options[:salt],
|
74
|
+
cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(options[:key], options[:salt], options[:hmac_iterations], cipher.key_len)
|
67
75
|
end
|
68
76
|
else
|
77
|
+
# This is deprecated and needs to be changed.
|
69
78
|
cipher.pkcs5_keyivgen(options[:key])
|
70
79
|
end
|
71
80
|
yield cipher, options if block_given?
|
72
|
-
|
81
|
+
value = options[:value]
|
82
|
+
if cipher.authenticated?
|
83
|
+
if encryption?(cipher_method)
|
84
|
+
cipher.auth_data = options[:auth_data]
|
85
|
+
else
|
86
|
+
value = extract_cipher_text(options[:value])
|
87
|
+
cipher.auth_tag = extract_auth_tag(options[:value])
|
88
|
+
# auth_data must be set after auth_tag has been set when decrypting
|
89
|
+
# See http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-auth_data-3D
|
90
|
+
cipher.auth_data = options[:auth_data]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
result = cipher.update(value)
|
73
94
|
result << cipher.final
|
95
|
+
result << cipher.auth_tag if cipher.authenticated? && encryption?(cipher_method)
|
96
|
+
result
|
97
|
+
end
|
98
|
+
|
99
|
+
def encryption?(cipher_method)
|
100
|
+
cipher_method == :encrypt
|
101
|
+
end
|
102
|
+
|
103
|
+
def extract_cipher_text(value)
|
104
|
+
value[0..-17]
|
105
|
+
end
|
106
|
+
|
107
|
+
def extract_auth_tag(value)
|
108
|
+
value[-16..-1]
|
74
109
|
end
|
75
110
|
end
|