encryptor 1.3.0 → 2.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.
- 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
|
+
[](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)
|
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
|