easy-crypto 0.1.5 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5efd19b2abcdb117cb3d09a29a78b67d250d05510040d24f60e316c9141dad95
4
- data.tar.gz: 9f32de6d1fa839450fc2d20e662303344d03a91bf5d7a851d2cdc35bc6eb19c2
3
+ metadata.gz: 31671eab7f89fa8fc412441808f40e9d9e4ccbe1a969070b5249d56a5cef5bcc
4
+ data.tar.gz: 36d78c9ef113c69143b7588a3bf9a9884e0c9b2c0179efd6936622b9b41da401
5
5
  SHA512:
6
- metadata.gz: 32984a7de2a56bd8e01bd269543e769c4ada0c32e11afd002bef92f1f4dd219b6fe783e85b6053079b32ca82bae7bca295d366acb30faac5b13eb738bd648c65
7
- data.tar.gz: 87f80569ad96f5cc6efbec5719861a48ef83313e18ea08fff67095ebbd4accbfd8088b100bc18d5969a5e1d9120960d850bcaab761c753654fa77ae87947ee0a
6
+ metadata.gz: c5ce234ec34ea19d1701f6c2810539013bb64c7af5ea9b19692995012f1db6398b199bbd9b7c830eb9de80513f58c724a4b4a336cfa552742251b0f4c1bc0e26
7
+ data.tar.gz: 48282d3f7edef07f465e33e5adad4cfe8e597cfd8c4e5c497032eecc23fb23a82dc744efafc4745eab566e8470519b454e70fe9e2487d9994d1d5ead89b04d98
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ .bundle/
3
+ vendor/
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.16.1
6
+ deploy:
7
+ provider: rubygems
8
+ api_key: ${RUBYGEMS_API_KEY}
9
+ gem: easy-crypto
10
+ gemspec: easy-crypto.gemspec
11
+ skip_cleanup: true
12
+ on:
13
+ tags: true
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ easy-crypto (0.1.7)
5
+ openssl (~> 2.1.1, >= 2.1.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.3)
11
+ ipaddr (1.2.2)
12
+ openssl (2.1.2)
13
+ ipaddr
14
+ rake (12.3.2)
15
+ rspec (3.8.0)
16
+ rspec-core (~> 3.8.0)
17
+ rspec-expectations (~> 3.8.0)
18
+ rspec-mocks (~> 3.8.0)
19
+ rspec-core (3.8.0)
20
+ rspec-support (~> 3.8.0)
21
+ rspec-expectations (3.8.2)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.8.0)
24
+ rspec-mocks (3.8.0)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.8.0)
27
+ rspec-support (3.8.0)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ bundler (~> 1.16)
34
+ easy-crypto!
35
+ rake (~> 12.3)
36
+ rspec (~> 3.0)
37
+
38
+ BUNDLED WITH
39
+ 1.17.3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Emarsys Technologies
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # EasyCrypto [![Build Status](https://travis-ci.org/emartech/ruby-easy-crypto.svg?branch=master)](https://travis-ci.org/emartech/ruby-easy-crypto) [![Gem Version](https://badge.fury.io/rb/easy-crypto.svg)](https://badge.fury.io/rb/easy-crypto)
2
+
3
+ Provides simple wrappers around the openssl crypto implementation. The library provides two interfaces: simple and advanced. Simple mode is designed for ease-of-use and advanced mode provides some performance benefits in certain use-cases. See below for more details.
4
+
5
+ All the underlying crypto operations are the same.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'easy-crypto'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install easy-crypto
22
+
23
+ ## Simple usage (Recommended)
24
+
25
+ ```ruby
26
+ require 'easycrypto'
27
+
28
+ password = 'secret password'
29
+ plaintext = 'some data'
30
+
31
+ ecrypto = EasyCrypto::Crypto.new
32
+
33
+ encrypted = ecrypto.encrypt(password, plaintext)
34
+ decrypted = ecrypto.encrypt(password, encrypted)
35
+
36
+ decrypted == plaintext
37
+ ```
38
+
39
+ ## Advanced usage (Use for performance)
40
+
41
+ [Key derivation](https://en.wikipedia.org/wiki/Key_derivation_function) is a resource heavy process. The simple interface abstracts this away and forces you to recompute the key before each encryption/decryption process.
42
+
43
+ This interface allows you to cache the result of the key derivation. This is required if you need to encrypt/decrypt multiple times with the same derived key. Caching the key saves you the time to have to recompute it before every encryption/decryption.
44
+
45
+ ```ruby
46
+ require 'easycrypto'
47
+
48
+ password = 'secret password'
49
+ plaintext = 'data to encrypt ...'
50
+
51
+ ecrypto = EasyCrypto::Crypto.new
52
+
53
+ key = EasyCrypto::Key.generate(key_password)
54
+
55
+ encrypted = ecrypto.encrypt_with_key(key, plaintext)
56
+ decrypted = ecrypto.decrypt_with_key(key, encrypted)
57
+
58
+ decrypted == plaintext
59
+ ```
60
+
61
+ ## License
62
+
63
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,23 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'easycrypto/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'easy-crypto'
7
+ spec.version = EasyCrypto::VERSION
8
+ spec.authors = ['Emarsys Security']
9
+ spec.email = ['security@emarsys.com']
10
+
11
+ spec.summary = 'Provides simple wrappers around openssl crypto implementation.'
12
+ spec.homepage = 'https://github.com/emartech/ruby-easy-crypto'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.require_paths = ['lib']
17
+
18
+ spec.add_development_dependency 'bundler', '~> 1.16'
19
+ spec.add_development_dependency 'rake', '~> 12.3'
20
+ spec.add_development_dependency 'rspec', '~> 3.0'
21
+
22
+ spec.add_runtime_dependency 'openssl', '~> 2.1.1', '>= 2.1.1'
23
+ end
@@ -0,0 +1,86 @@
1
+ require 'base64'
2
+ require 'openssl'
3
+ require_relative 'key'
4
+
5
+ module EasyCrypto
6
+ class Crypto
7
+ KEY_BITS = 256
8
+ AES_MODE = :GCM
9
+ IV_LEN = 12
10
+ AUTH_TAG_LEN = 16
11
+
12
+ def initialize(salt_length = DEFAULT_SALT_LENGTH)
13
+ @salt_length = salt_length
14
+ end
15
+
16
+ def encrypt(password, plaintext)
17
+ key = EasyCrypto::Key.generate(password, @salt_length)
18
+
19
+ encrypt_with_key(key, plaintext)
20
+ end
21
+
22
+ def encrypt_with_key(key, plaintext)
23
+ validate_key_type(key)
24
+ validate_plaintext(plaintext)
25
+
26
+ iv = OpenSSL::Random.random_bytes(Crypto::IV_LEN)
27
+ cipher = create_cipher(key, iv)
28
+
29
+ encrypted = cipher.update(plaintext) + cipher.final
30
+
31
+ Base64.strict_encode64(key.salt + iv + encrypted + cipher.auth_tag)
32
+ end
33
+
34
+ def decrypt(password, ciphertext)
35
+ salt = get_salt_from_ciphertext(ciphertext)
36
+ key = EasyCrypto::Key.generate_with_salt(password, salt)
37
+
38
+ decrypt_with_key(key, ciphertext)
39
+ end
40
+
41
+ def decrypt_with_key(key, ciphertext)
42
+ validate_key_type(key)
43
+
44
+ raw_ciphertext = Base64.strict_decode64(ciphertext)
45
+
46
+ iv = raw_ciphertext[key.salt.length, IV_LEN]
47
+ encrypted = raw_ciphertext[(key.salt.length + IV_LEN)..-(AUTH_TAG_LEN + 1)]
48
+ auth_tag = raw_ciphertext[-AUTH_TAG_LEN..-1]
49
+
50
+ decipher = create_decipher(key, iv, auth_tag)
51
+
52
+ decipher.update(encrypted) + decipher.final
53
+ end
54
+
55
+ private
56
+
57
+ def validate_key_type(key)
58
+ raise TypeError, 'key must have Key type' unless key.is_a?(EasyCrypto::Key)
59
+ end
60
+
61
+ def validate_plaintext(plaintext)
62
+ raise TypeError, 'Encryptable data must be a string' unless plaintext.is_a?(String)
63
+ raise ArgumentError, 'Encryptable data must not be empty' if plaintext.empty?
64
+ end
65
+
66
+ def create_cipher(key, iv)
67
+ cipher = OpenSSL::Cipher::AES.new(Crypto::KEY_BITS, Crypto::AES_MODE).encrypt
68
+ cipher.key = key.key
69
+ cipher.iv = iv
70
+ cipher
71
+ end
72
+
73
+ def create_decipher(key, iv, auth_tag)
74
+ decipher = OpenSSL::Cipher::AES.new(Crypto::KEY_BITS, Crypto::AES_MODE).decrypt
75
+ decipher.key = key.key
76
+ decipher.iv = iv
77
+ decipher.auth_tag = auth_tag
78
+ decipher
79
+ end
80
+
81
+ def get_salt_from_ciphertext(ciphertext)
82
+ raw_ciphertext = Base64.strict_decode64(ciphertext)
83
+ raw_ciphertext[0, @salt_length]
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ module EasyCrypto
6
+ class Key
7
+ ITERATION_COUNT = 10_000
8
+ KEY_LENGTH = 32
9
+ HASH_ALGO = 'sha256'
10
+
11
+ attr_reader :key, :salt
12
+
13
+ def initialize(key, salt)
14
+ @key = key
15
+ @salt = salt
16
+ end
17
+
18
+ def self.generate(password, salt_length = DEFAULT_SALT_LENGTH)
19
+ salt = OpenSSL::Random.random_bytes(salt_length)
20
+
21
+ generate_with_salt(password, salt)
22
+ end
23
+
24
+ def self.generate_with_salt(password, salt)
25
+ key = OpenSSL::KDF.pbkdf2_hmac(
26
+ password,
27
+ salt: salt,
28
+ iterations: Key::ITERATION_COUNT,
29
+ length: Key::KEY_LENGTH,
30
+ hash: Key::HASH_ALGO
31
+ )
32
+
33
+ new(key, salt)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasyCrypto
4
+ VERSION = '0.1.7'
5
+ end
data/lib/easycrypto.rb ADDED
@@ -0,0 +1,7 @@
1
+ module EasyCrypto
2
+ DEFAULT_SALT_LENGTH = 12
3
+
4
+ require 'easycrypto/version'
5
+ require 'easycrypto/key'
6
+ require 'easycrypto/crypto'
7
+ end
@@ -0,0 +1,89 @@
1
+ require 'easycrypto'
2
+
3
+ RSpec.describe EasyCrypto::Crypto do
4
+ let(:salt) { 'aaaaaaaaaaaa' }
5
+ let(:iv) { 'bbbbbbbbbbbb' }
6
+ let(:password) { 'some password' }
7
+ let(:data) { 'some data' }
8
+ let(:key) { EasyCrypto::Key.generate_with_salt(password, salt) }
9
+
10
+ it 'has a version number' do
11
+ expect(EasyCrypto::VERSION).not_to be nil
12
+ end
13
+
14
+ it 'can encrypt and decrypt data' do
15
+ ciphertext = subject.encrypt(password, data)
16
+ plaintext = subject.decrypt(password, ciphertext)
17
+
18
+ expect(plaintext).to eq data
19
+ end
20
+
21
+ it 'can encrypt and decrypt data with given key' do
22
+ key = EasyCrypto::Key.generate(password)
23
+
24
+ ciphertext = subject.encrypt_with_key(key, data)
25
+ plaintext = subject.decrypt_with_key(key, ciphertext)
26
+
27
+ expect(plaintext).to eq data
28
+ end
29
+
30
+ describe '#encrypt' do
31
+ before do
32
+ allow(OpenSSL::Random).to receive(:random_bytes).and_return(iv)
33
+ allow(EasyCrypto::Key).to receive(:generate).and_return(key)
34
+ end
35
+
36
+ it 'can encrypt data' do
37
+ result = subject.encrypt(password, data)
38
+ raw_result = Base64.strict_decode64(result)
39
+
40
+ expect(raw_result[0,12]).to eq salt
41
+ expect(raw_result[12,12]).to eq iv
42
+ end
43
+ end
44
+
45
+ describe '#encrypt_with_key' do
46
+ before do
47
+ allow(OpenSSL::Random).to receive(:random_bytes).and_return(iv)
48
+ end
49
+
50
+ it 'returns encrypted text as a single line' do
51
+ ciphertext = subject.encrypt_with_key(key, data)
52
+
53
+ expect(ciphertext).not_to include("\n")
54
+ end
55
+
56
+ it 'raise error if the encryptable data is not a string' do
57
+ expect{
58
+ subject.encrypt_with_key(key, 1234)
59
+ }.to raise_error(TypeError, 'Encryptable data must be a string')
60
+ end
61
+
62
+ it 'raise error if the encryptable data is empty' do
63
+ expect{
64
+ subject.encrypt_with_key(key, '')
65
+ }.to raise_error(ArgumentError, 'Encryptable data must not be empty')
66
+ end
67
+
68
+ it 'can encrypt data with given key' do
69
+ expected_ciphertext = 'YWFhYWFhYWFhYWFhYmJiYmJiYmJiYmJifAUY9TEdvoOQ79sxKd3zv1dT67K1GM36mQ=='
70
+ expect(subject.encrypt_with_key(key, data)).to eq expected_ciphertext
71
+ end
72
+ end
73
+
74
+ describe '#decrypt' do
75
+ it 'can decrypt encrypted data' do
76
+ ciphertext = 'FPXj2e2DZrFYRVUhqoBWXhVVVGUO2ZJgayU2F1f6duLtBjYOINvAZPWIXjIVHHslgg=='
77
+
78
+ expect(subject.decrypt(password, ciphertext)).to eq data
79
+ end
80
+ end
81
+
82
+ describe '#decrypt_with_key' do
83
+ it 'can decrypt encrypted data' do
84
+ ciphertext = 'YWFhYWFhYWFhYWFhzs8I/ks+nAy2V+Q7xIrJAnOHefyfO4zYwwmz1F2y1mf1wfXDqA=='
85
+
86
+ expect(subject.decrypt_with_key(key, ciphertext)).to eq data
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,34 @@
1
+ require 'easycrypto'
2
+
3
+ RSpec.describe EasyCrypto::Key do
4
+ describe '#generate' do
5
+ it 'returns key with a salt of the specified length' do
6
+ key = EasyCrypto::Key.generate('key password', 24)
7
+
8
+ expect(key.salt.length).to be 24
9
+ end
10
+
11
+ it 'returns key with a 12 byte length salt' do
12
+ key = EasyCrypto::Key.generate('key password')
13
+
14
+ expect(key.salt.length).to be 12
15
+ end
16
+ end
17
+
18
+ describe '#generate_with_salt' do
19
+ let(:salt) { 'aaaaaaaaaaaa' }
20
+
21
+ it 'generates key with the given salt' do
22
+ key = EasyCrypto::Key.generate_with_salt('key password', salt)
23
+
24
+ expect(key.salt).to eq salt
25
+ end
26
+
27
+ it 'generates the same key with the same password and salt' do
28
+ key_1 = EasyCrypto::Key.generate_with_salt('key password', salt)
29
+ key_2 = EasyCrypto::Key.generate_with_salt('key password', salt)
30
+
31
+ expect(key_1.key).to eq key_2.key
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ lib = File.expand_path('../../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ RSpec.configure do |config|
5
+ config.disable_monkey_patching!
6
+
7
+ config.expect_with :rspec do |c|
8
+ c.syntax = :expect
9
+ end
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy-crypto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emarsys Security
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-07 00:00:00.000000000 Z
11
+ date: 2019-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -78,7 +78,22 @@ email:
78
78
  executables: []
79
79
  extensions: []
80
80
  extra_rdoc_files: []
81
- files: []
81
+ files:
82
+ - ".gitignore"
83
+ - ".travis.yml"
84
+ - Gemfile
85
+ - Gemfile.lock
86
+ - LICENSE.txt
87
+ - README.md
88
+ - Rakefile
89
+ - easy-crypto.gemspec
90
+ - lib/easycrypto.rb
91
+ - lib/easycrypto/crypto.rb
92
+ - lib/easycrypto/key.rb
93
+ - lib/easycrypto/version.rb
94
+ - spec/easycrypto/crypto_spec.rb
95
+ - spec/easycrypto/key_spec.rb
96
+ - spec/spec_helper.rb
82
97
  homepage: https://github.com/emartech/ruby-easy-crypto
83
98
  licenses:
84
99
  - MIT
@@ -98,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
113
  - !ruby/object:Gem::Version
99
114
  version: '0'
100
115
  requirements: []
101
- rubygems_version: 3.0.1
116
+ rubygems_version: 3.0.2
102
117
  signing_key:
103
118
  specification_version: 4
104
119
  summary: Provides simple wrappers around openssl crypto implementation.