crypt_keeper 0.16.0.pre → 1.1.1
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 +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +22 -13
- data/Appraisals +6 -16
- data/README.md +43 -21
- data/Rakefile +7 -3
- data/crypt_keeper.gemspec +9 -9
- data/gemfiles/activerecord_4_2.gemfile +8 -0
- data/gemfiles/activerecord_5_1.gemfile +8 -0
- data/lib/crypt_keeper/helper.rb +31 -21
- data/lib/crypt_keeper/log_subscriber/mysql_aes.rb +11 -11
- data/lib/crypt_keeper/log_subscriber/postgres_pgp.rb +29 -10
- data/lib/crypt_keeper/model.rb +64 -17
- data/lib/crypt_keeper/provider/aes_new.rb +1 -1
- data/lib/crypt_keeper/provider/base.rb +21 -0
- data/lib/crypt_keeper/provider/mysql_aes_new.rb +2 -2
- data/lib/crypt_keeper/provider/postgres_base.rb +28 -0
- data/lib/crypt_keeper/provider/postgres_pgp.rb +27 -8
- data/lib/crypt_keeper/provider/postgres_pgp_public_key.rb +4 -20
- data/lib/crypt_keeper/version.rb +1 -1
- data/lib/crypt_keeper.rb +11 -2
- data/spec/crypt_keeper/log_subscriber/mysql_aes_spec.rb +50 -0
- data/spec/crypt_keeper/log_subscriber/postgres_pgp_spec.rb +78 -0
- data/spec/crypt_keeper/model_spec.rb +178 -0
- data/spec/crypt_keeper/provider/aes_new_spec.rb +41 -0
- data/spec/crypt_keeper/provider/mysql_aes_new_spec.rb +50 -0
- data/spec/crypt_keeper/provider/postgres_pgp_public_key_spec.rb +67 -0
- data/spec/crypt_keeper/provider/postgres_pgp_spec.rb +87 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support/active_record.rb +36 -26
- data/spec/support/encryptors.rb +9 -3
- data/spec/support/logging.rb +89 -0
- metadata +84 -92
- data/bin/crypt_keeper +0 -99
- data/gemfiles/activerecord_3_1.gemfile +0 -8
- data/gemfiles/activerecord_3_1.gemfile.lock +0 -109
- data/gemfiles/activerecord_3_2.gemfile +0 -8
- data/gemfiles/activerecord_3_2.gemfile.lock +0 -109
- data/gemfiles/activerecord_4_0.gemfile +0 -8
- data/gemfiles/activerecord_4_0.gemfile.lock +0 -117
- data/gemfiles/activerecord_4_1.gemfile +0 -8
- data/gemfiles/activerecord_4_1.gemfile.lock +0 -117
- data/lib/crypt_keeper/provider/aes.rb +0 -66
- data/lib/crypt_keeper/provider/mysql_aes.rb +0 -47
- data/spec/log_subscriber/postgres_pgp_spec.rb +0 -98
- data/spec/model_spec.rb +0 -95
- data/spec/provider/aes_new_spec.rb +0 -45
- data/spec/provider/aes_spec.rb +0 -67
- data/spec/provider/mysql_aes_new_spec.rb +0 -52
- data/spec/provider/mysql_aes_spec.rb +0 -35
- data/spec/provider/postgres_pgp_public_key_spec.rb +0 -70
- data/spec/provider/postgres_pgp_spec.rb +0 -68
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module CryptKeeper::LogSubscriber
|
|
4
|
-
describe PostgresPgp do
|
|
5
|
-
use_postgres
|
|
6
|
-
|
|
7
|
-
context "Symmetric encryption" do
|
|
8
|
-
# Fire the ActiveSupport.on_load
|
|
9
|
-
before do
|
|
10
|
-
CryptKeeper::Provider::PostgresPgp.new key: 'secret'
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
subject { ::ActiveRecord::LogSubscriber.new }
|
|
14
|
-
|
|
15
|
-
let(:input_query) do
|
|
16
|
-
"SELECT pgp_sym_encrypt('encrypt_value', 'encrypt_key'), pgp_sym_decrypt('decrypt_value', 'decrypt_key') FROM DUAL;"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
let(:output_query) do
|
|
20
|
-
"SELECT encrypt([FILTERED]) FROM DUAL;"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
let(:input_search_query) do
|
|
24
|
-
"SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE ((pgp_sym_decrypt('f'), 'tool') = 'blah')) AND secret = 'testing'"
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
let(:output_search_query) do
|
|
28
|
-
"SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE decrypt([FILTERED]) AND secret = 'testing'"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it "filters pgp functions" do
|
|
32
|
-
subject.should_receive(:sql_without_postgres_pgp) do |event|
|
|
33
|
-
event.payload[:sql].should == output_query
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query }))
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it "filters pgp functions in lowercase" do
|
|
40
|
-
subject.should_receive(:sql_without_postgres_pgp) do |event|
|
|
41
|
-
event.payload[:sql].should == output_query.downcase.gsub(/filtered/, 'FILTERED')
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query.downcase }))
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "filters pgp functions when searching" do
|
|
48
|
-
subject.should_receive(:sql_without_postgres_pgp) do |event|
|
|
49
|
-
event.payload[:sql].should == output_search_query
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_search_query }))
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
context "Public key encryption" do
|
|
57
|
-
let(:public_key) do
|
|
58
|
-
IO.read(File.join(SPEC_ROOT, 'fixtures', 'public.asc'))
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
let(:private_key) do
|
|
62
|
-
IO.read(File.join(SPEC_ROOT, 'fixtures', 'private.asc'))
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# Fire the ActiveSupport.on_load
|
|
66
|
-
before do
|
|
67
|
-
CryptKeeper::Provider::PostgresPgpPublicKey.new key: 'secret', public_key: public_key, private_key: private_key
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
subject { ::ActiveRecord::LogSubscriber.new }
|
|
71
|
-
|
|
72
|
-
let(:input_query) do
|
|
73
|
-
"SELECT pgp_pub_encrypt('test', dearmor('#{public_key}
|
|
74
|
-
'))"
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
let(:output_query) do
|
|
78
|
-
"SELECT encrypt([FILTERED])"
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it "filters pgp functions" do
|
|
82
|
-
subject.should_receive(:sql_without_postgres_pgp) do |event|
|
|
83
|
-
event.payload[:sql].should == output_query
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query }))
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it "filters pgp functions in lowercase" do
|
|
90
|
-
subject.should_receive(:sql_without_postgres_pgp) do |event|
|
|
91
|
-
event.payload[:sql].should == output_query.downcase.gsub(/filtered/, 'FILTERED')
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query.downcase }))
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
data/spec/model_spec.rb
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module CryptKeeper
|
|
4
|
-
describe Model do
|
|
5
|
-
use_sqlite
|
|
6
|
-
|
|
7
|
-
before do
|
|
8
|
-
SensitiveData.instance_variable_set('@encryptor_klass', nil)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
subject { SensitiveData }
|
|
12
|
-
|
|
13
|
-
describe "#crypt_keeper" do
|
|
14
|
-
context "Fields" do
|
|
15
|
-
it "enables encryption for the given fields" do
|
|
16
|
-
subject.crypt_keeper :storage, :secret, encryptor: :fake_encryptor
|
|
17
|
-
subject.crypt_keeper_fields.should == [:storage, :secret]
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it "raises an exception for missing field" do
|
|
21
|
-
msg = "Column :none does not exist"
|
|
22
|
-
subject.crypt_keeper :none, encryptor: :fake_encryptor
|
|
23
|
-
expect { subject.new.save }.to raise_error(ArgumentError, msg)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it "raises an exception for non text fields" do
|
|
27
|
-
msg = "Column :name must be of type 'text' to be used for encryption"
|
|
28
|
-
subject.crypt_keeper :name, encryptor: :fake_encryptor
|
|
29
|
-
expect { subject.new.save }.to raise_error(ArgumentError, msg)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context "Options" do
|
|
34
|
-
it "accepts the class name as a string" do
|
|
35
|
-
subject.crypt_keeper :storage, :secret, key1: 1, key2: 2, encryptor: "FakeEncryptor"
|
|
36
|
-
subject.send(:encryptor_klass).should == CryptKeeper::Provider::FakeEncryptor
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it "raises an error on missing encryptor" do
|
|
40
|
-
expect { subject.crypt_keeper :storage, :secret }.
|
|
41
|
-
to raise_error(RuntimeError, /You must specify a valid encryptor/)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
context "Encryption and Decryption" do
|
|
47
|
-
let(:plain_text) { 'plain_text' }
|
|
48
|
-
let(:cipher_text) { 'tooltxet_nialp' }
|
|
49
|
-
|
|
50
|
-
before do
|
|
51
|
-
SensitiveData.crypt_keeper :storage, passphrase: 'tool', encryptor: :encryptor
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it "encrypts the data" do
|
|
55
|
-
CryptKeeper::Provider::Encryptor.any_instance.should_receive(:encrypt).with('testing')
|
|
56
|
-
SensitiveData.create!(storage: 'testing')
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "decrypts the data" do
|
|
60
|
-
record = SensitiveData.create!(storage: 'testing')
|
|
61
|
-
CryptKeeper::Provider::Encryptor.any_instance.should_receive(:decrypt).at_least(1).times.with('toolgnitset')
|
|
62
|
-
SensitiveData.find(record).storage
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it "returns the plaintext on decrypt" do
|
|
66
|
-
record = SensitiveData.create!(storage: 'testing')
|
|
67
|
-
SensitiveData.find(record).storage.should == 'testing'
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it "does not encrypt or decrypt nil" do
|
|
71
|
-
data = SensitiveData.create!(storage: nil)
|
|
72
|
-
data.storage.should be_nil
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "does not encrypt or decrypt empty strings" do
|
|
76
|
-
data = SensitiveData.create!(storage: "")
|
|
77
|
-
data.storage.should be_empty
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
context "Search" do
|
|
82
|
-
before do
|
|
83
|
-
SensitiveData.crypt_keeper :storage, passphrase: 'tool', encryptor: :search_encryptor
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it "searches if supported" do
|
|
87
|
-
expect { SensitiveData.search_by_plaintext(:storage, 'test1') }.to_not raise_error
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
it "complains about bad columns" do
|
|
91
|
-
expect { SensitiveData.search_by_plaintext(:what, 'test1') }.to raise_error(/what is not a crypt_keeper field/)
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module CryptKeeper
|
|
4
|
-
module Provider
|
|
5
|
-
describe AesNew do
|
|
6
|
-
subject { AesNew.new(key: 'cake', salt: 'salt') }
|
|
7
|
-
|
|
8
|
-
describe "#initialize" do
|
|
9
|
-
let(:digested_key) do
|
|
10
|
-
::Armor.digest('cake', 'salt')
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
its(:key) { should == digested_key }
|
|
14
|
-
specify { expect { AesNew.new }.to raise_error(ArgumentError, "Missing :key") }
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
describe "#encrypt" do
|
|
18
|
-
let(:encrypted) do
|
|
19
|
-
subject.encrypt 'string'
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
specify { encrypted.should_not == 'string' }
|
|
23
|
-
specify { encrypted.should_not be_blank }
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
describe "#decrypt" do
|
|
27
|
-
let(:decrypted) do
|
|
28
|
-
subject.decrypt "V02ebRU2wLk25AizasROVg==$kE+IpRaUNdBfYqR+WjMqvA=="
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
specify { decrypted.should == 'string' }
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
describe "#search" do
|
|
35
|
-
let(:records) do
|
|
36
|
-
[{ name: 'Bob' }, { name: 'Tim' }]
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it "finds the matching record" do
|
|
40
|
-
expect(subject.search(records, :name, 'Bob')).to eql([records.first])
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
data/spec/provider/aes_spec.rb
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module CryptKeeper
|
|
4
|
-
module Provider
|
|
5
|
-
describe Aes do
|
|
6
|
-
subject { Aes.new(key: 'cake') }
|
|
7
|
-
|
|
8
|
-
describe "#initialize" do
|
|
9
|
-
let(:hexed_key) do
|
|
10
|
-
Digest::SHA256.digest('cake')
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
its(:key) { should == hexed_key }
|
|
14
|
-
specify { expect { Aes.new }.to raise_error(ArgumentError, "Missing :key") }
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
describe "#encrypt" do
|
|
18
|
-
let(:encrypted) do
|
|
19
|
-
subject.encrypt 'string'
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
specify { encrypted.should_not == 'string' }
|
|
23
|
-
specify { encrypted.should_not be_blank }
|
|
24
|
-
|
|
25
|
-
context "an empty string" do
|
|
26
|
-
let(:encrypted) do
|
|
27
|
-
subject.encrypt ''
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
specify { encrypted.should == '' }
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context "a nil" do
|
|
34
|
-
let(:encrypted) do
|
|
35
|
-
subject.encrypt nil
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
specify { encrypted.should be_nil }
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
describe "#decrypt" do
|
|
43
|
-
let(:decrypted) do
|
|
44
|
-
subject.decrypt "MC41MDk5MjI2NjgxMDI1MDI2OmNyeXB0X2tlZXBlcjpPI/8dCqWXDMVj7Jqs\nuwf/\n"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
specify { decrypted.should == 'string' }
|
|
48
|
-
|
|
49
|
-
context "an empty string" do
|
|
50
|
-
let(:decrypted) do
|
|
51
|
-
subject.decrypt ''
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
specify { decrypted.should == '' }
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
context "a nil" do
|
|
58
|
-
let(:decrypted) do
|
|
59
|
-
subject.decrypt nil
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
specify { decrypted.should be_nil }
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module CryptKeeper
|
|
4
|
-
module Provider
|
|
5
|
-
describe MysqlAesNew do
|
|
6
|
-
use_mysql
|
|
7
|
-
|
|
8
|
-
let(:plain_text) { 'test' }
|
|
9
|
-
|
|
10
|
-
# MySQL stores AES encrypted strings in binary which you can't paste
|
|
11
|
-
# into a spec :). This is a Base64 encoded string of 'test' AES encrypted
|
|
12
|
-
# by AES_ENCRYPT()
|
|
13
|
-
let(:cipher_text) do
|
|
14
|
-
"fBN8i7bx/DGAA4NJ4EWi0A=="
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
subject { MysqlAesNew.new key: ENCRYPTION_PASSWORD, salt: 'salt' }
|
|
18
|
-
|
|
19
|
-
its(:key) { should == "825e8c5e8ca394818b307b22b8cb7d3df2735e9c1e5838b476e7719135a4f499f2133022c1a0e8597c9ac1507b0f0c44328a40049f9704fab3598c5dec120724" }
|
|
20
|
-
|
|
21
|
-
describe "#initialize" do
|
|
22
|
-
specify { expect { MysqlAesNew.new }.to raise_error(ArgumentError, "Missing :key") }
|
|
23
|
-
specify { expect { MysqlAesNew.new(key: 'blah') }.to raise_error(ArgumentError, "Missing :salt") }
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
describe "#encrypt" do
|
|
27
|
-
specify { subject.encrypt(plain_text).should_not == plain_text }
|
|
28
|
-
specify { subject.encrypt(plain_text).should_not be_blank }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
describe "#decrypt" do
|
|
32
|
-
specify { subject.decrypt(cipher_text).should == plain_text }
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
describe "#search" do
|
|
36
|
-
it "finds the matching record" do
|
|
37
|
-
SensitiveDataMysql.create!(storage: 'blah2')
|
|
38
|
-
match = SensitiveDataMysql.create!(storage: 'blah')
|
|
39
|
-
SensitiveDataMysql.search_by_plaintext(:storage, 'blah').first.should == match
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it "keeps the scope" do
|
|
43
|
-
SensitiveDataMysql.create!(storage: 'blah')
|
|
44
|
-
SensitiveDataMysql.create!(storage: 'blah')
|
|
45
|
-
|
|
46
|
-
scope = SensitiveDataMysql.limit(1)
|
|
47
|
-
expect(scope.search_by_plaintext(:storage, 'blah').count).to eql(1)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module CryptKeeper
|
|
4
|
-
module Provider
|
|
5
|
-
describe MysqlAes do
|
|
6
|
-
use_mysql
|
|
7
|
-
|
|
8
|
-
let(:plain_text) { 'test' }
|
|
9
|
-
|
|
10
|
-
# MySQL stores AES encrypted strings in binary which you can't paste
|
|
11
|
-
# into a spec :). This is a Base64 encoded string of 'test' AES encrypted
|
|
12
|
-
# by AES_ENCRYPT()
|
|
13
|
-
let(:cipher_text) do
|
|
14
|
-
"nbKOoWn8kvAw9k/C2Mex6Q==\n"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
subject { MysqlAes.new key: 'candy' }
|
|
18
|
-
|
|
19
|
-
its(:key) { should == 'candy' }
|
|
20
|
-
|
|
21
|
-
describe "#initialize" do
|
|
22
|
-
specify { expect { MysqlAes.new }.to raise_error(ArgumentError, "Missing :key") }
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
describe "#encrypt" do
|
|
26
|
-
specify { subject.encrypt(plain_text).should_not == plain_text }
|
|
27
|
-
specify { subject.encrypt(plain_text).should_not be_blank }
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
describe "#decrypt" do
|
|
31
|
-
specify { subject.decrypt(cipher_text).should == plain_text }
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module CryptKeeper
|
|
4
|
-
module Provider
|
|
5
|
-
describe PostgresPgpPublicKey do
|
|
6
|
-
use_postgres
|
|
7
|
-
|
|
8
|
-
let(:cipher_text) { '\xc1c04c036c401ad086beb9e3010800987d6c4ccd974322190caa75a3a01aba37bc1970182c4c1d3faec98edf186780520f0586101f286e0626096a1eca91a229ed4d4058a6913a8d13cdf49f29ea44e2b96d10347f9b1b860bb3c959f000a3b1b415a95d2cd07af8c74aa6df8cd10ab06b6a6f7db69cdf3185466d68c5b66b95b813acdfb3ddfb021cac92e0967d67e90df73332f27970c1d2b9a56ac74f602d4107b163ed73ef89fca560d9a0a0d2bc7a74005f29fa27babfbaf950ac07b1c809049db4ab126be4824cf76416c278571f7064f638edf830a1ae5ee1ab544d35fce0f974f21b9dcbbea3986077d27b0de34144dc23f369f471090b57e067a056901e680493ddf2a6b29e4af3462387d235010259556079d07daa249b6703e2bc79345da556cfb46f228cad40a8a5b569ac46f08865f9176acf89129a3e0ceb2a7b1991012f65' }
|
|
9
|
-
|
|
10
|
-
let(:integer_cipher_text) { '\xc1c04c036c401ad086beb9e30107ff59e674ba05958eb053c2427b44355e0f333f1726e18a0b851130130510c648f580b13b3f6a223eb26e397008596867c5a511a4f5bfbf2ecc852d8929814480d63166e525fa2b259b6a8d4474b5b1373b4e1a4fe70a491d25442e1c0046fd3d69466ad30153c8d8d920e9b4260d4e4e421ef3ead162b3aba5d85408c4ef9f9d342b5655c7568d1bdc61c27ddb419133bf091f22f42e7bc91ec6d279b7b25b87ea65119568b85ae81079dd0a6a7258b58fb219c6cc4580f33cb46de97770a1eb0880bdf87426fd0529576a1e791e521d9b3c426e393e63d83321f319b00f9dc4027ea5a81dd57c0f5ba868fb86d73179c34f2287c437266e8becc072b45a929562d2320194be54464e03854635d0f7d7fb10813adbc6efe51efa9095a9bacc2a03fb5c41d1c1896384e4f36b100c0f00e81d4cff7d' }
|
|
11
|
-
|
|
12
|
-
let(:integer_plain_text) { 1 }
|
|
13
|
-
let(:plain_text) { 'test' }
|
|
14
|
-
|
|
15
|
-
let(:public_key) do
|
|
16
|
-
IO.read(File.join(SPEC_ROOT, 'fixtures', 'public.asc'))
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
let(:private_key) do
|
|
20
|
-
IO.read(File.join(SPEC_ROOT, 'fixtures', 'private.asc'))
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
subject { PostgresPgpPublicKey.new key: ENCRYPTION_PASSWORD, public_key: public_key, private_key: private_key }
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
its(:key) { should == ENCRYPTION_PASSWORD }
|
|
27
|
-
|
|
28
|
-
describe "#initialize" do
|
|
29
|
-
specify { expect { PostgresPgpPublicKey.new }.to raise_error(ArgumentError, "Missing :key") }
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
describe "#encrypt" do
|
|
33
|
-
context "Strings" do
|
|
34
|
-
specify { subject.encrypt(plain_text).should_not == plain_text }
|
|
35
|
-
specify { subject.encrypt(plain_text).should_not be_empty }
|
|
36
|
-
|
|
37
|
-
it "does not double encrypt" do
|
|
38
|
-
pgp = PostgresPgpPublicKey.new key: ENCRYPTION_PASSWORD, public_key: public_key
|
|
39
|
-
pgp.encrypt(cipher_text).should == cipher_text
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
context "Integers" do
|
|
44
|
-
specify { subject.encrypt(integer_plain_text).should_not == integer_plain_text }
|
|
45
|
-
specify { subject.encrypt(integer_plain_text).should_not be_empty }
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
describe "#decrypt" do
|
|
50
|
-
specify { subject.decrypt(cipher_text).should == plain_text }
|
|
51
|
-
specify { subject.decrypt(integer_cipher_text).should == integer_plain_text.to_s }
|
|
52
|
-
|
|
53
|
-
it "does not decrypt w/o private key" do
|
|
54
|
-
pgp = PostgresPgpPublicKey.new key: ENCRYPTION_PASSWORD, public_key: public_key
|
|
55
|
-
pgp.decrypt(cipher_text).should eql(cipher_text)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
describe "#encrypted?" do
|
|
60
|
-
it "returns true for encrypted strings" do
|
|
61
|
-
subject.encrypted?(cipher_text).should be_true
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it "returns false for non-encrypted strings" do
|
|
65
|
-
subject.encrypted?(plain_text).should be_false
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module CryptKeeper
|
|
4
|
-
module Provider
|
|
5
|
-
describe PostgresPgp do
|
|
6
|
-
use_postgres
|
|
7
|
-
|
|
8
|
-
let(:cipher_text) { '\xc30d04070302f1a092093988b26873d235017203ce086a53fce1925dc39b4e972e534f192d10b94af3dcf8589abc1f828456f5d3e20b225d56006ffd1e312e3b8a492a6010e9' }
|
|
9
|
-
let(:plain_text) { 'test' }
|
|
10
|
-
|
|
11
|
-
let(:integer_cipher_text) { '\xc30d04070302c8d266353bcf2fc07dd23201153f9d9c32fbb3c36b9b0db137bf8b6c609172210d89ded63f11dff23d1ddbf5111c0266549dde26175c4425e06bb4bd6f' }
|
|
12
|
-
|
|
13
|
-
let(:integer_plain_text) { 1 }
|
|
14
|
-
|
|
15
|
-
subject { PostgresPgp.new key: ENCRYPTION_PASSWORD }
|
|
16
|
-
|
|
17
|
-
its(:key) { should == ENCRYPTION_PASSWORD }
|
|
18
|
-
|
|
19
|
-
describe "#initialize" do
|
|
20
|
-
specify { expect { PostgresPgp.new }.to raise_error(ArgumentError, "Missing :key") }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe "#encrypt" do
|
|
24
|
-
context "Strings" do
|
|
25
|
-
specify { subject.encrypt(plain_text).should_not == plain_text }
|
|
26
|
-
specify { subject.encrypt(plain_text).should_not be_empty }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
context "Integers" do
|
|
30
|
-
specify { subject.encrypt(integer_plain_text).should_not == integer_plain_text }
|
|
31
|
-
specify { subject.encrypt(integer_plain_text).should_not be_empty }
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
describe "#decrypt" do
|
|
36
|
-
specify { subject.decrypt(cipher_text).should == plain_text }
|
|
37
|
-
specify { subject.decrypt(integer_cipher_text).should == integer_plain_text.to_s }
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
describe "#search" do
|
|
41
|
-
it "finds the matching record" do
|
|
42
|
-
SensitiveDataPg.create!(storage: 'blah2')
|
|
43
|
-
match = SensitiveDataPg.create!(storage: 'blah')
|
|
44
|
-
SensitiveDataPg.search_by_plaintext(:storage, 'blah').first.should == match
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
describe "Custom pgcrypto options" do
|
|
49
|
-
let(:pgcrypto_options) { 'compress-level=0' }
|
|
50
|
-
|
|
51
|
-
subject { PostgresPgp.new key: 'candy', pgcrypto_options: pgcrypto_options }
|
|
52
|
-
|
|
53
|
-
it "reads and writes" do
|
|
54
|
-
queries = logged_queries do
|
|
55
|
-
encrypted = subject.encrypt(plain_text)
|
|
56
|
-
subject.decrypt(encrypted).should == plain_text
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
queries.should_not be_empty
|
|
60
|
-
|
|
61
|
-
queries.select { |query| query.include?("pgp_sym_encrypt") }.each do |q|
|
|
62
|
-
q.should include(pgcrypto_options)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|