trustworthy 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,80 +2,75 @@ require 'spec_helper'
2
2
 
3
3
  describe Trustworthy::Settings do
4
4
  before(:each) do
5
- SCrypt::Engine.stub(:generate_salt).and_return('400$8$1b$3e31f076a3226825')
6
- Trustworthy::Random.stub(:bytes).and_return(Trustworthy::TestValues::InitializationVector)
7
-
8
- key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
9
- @settings = Trustworthy::Settings.new
5
+ SCrypt::Engine.stub(:generate_salt).and_return(TestValues::Salt)
6
+ AEAD::Cipher::AES_256_CBC_HMAC_SHA_256.stub(:generate_nonce).and_return(TestValues::InitializationVector)
10
7
  end
11
8
 
12
- describe 'add_key' do
13
- it 'encrypts and signs the key with the password' do
14
- key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
15
- settings = Trustworthy::Settings.new
16
- settings.add_key(key, 'user', 'password1')
17
- settings.keys['user']['salt'].should == '400$8$1b$3e31f076a3226825'
18
- settings.keys['user']['authentication'].should == ['20c274efc68a460568853cc4be586183012769a312549d1aa57e29a36ec1503d'].pack('H*')
19
- settings.keys['user']['ciphertext'].should == ['39164ec082fb8b7336d3c5500af99dcb17d2e60496ed553dfab4b05c568aa926'].pack('H*')
9
+ around(:each) do |example|
10
+ within_construct do |construct|
11
+ construct.file(TestValues::SettingsFile)
12
+ example.run
20
13
  end
21
14
  end
22
15
 
23
- describe 'add_secret' do
24
- it 'adds a secret file name with an environment' do
25
- settings = Trustworthy::Settings.new
26
- settings.add_secret('foo', 'foo.enc')
27
- settings.secrets['foo'].should == 'foo.enc'
28
- end
29
- end
16
+ describe 'self.open' do
17
+ it 'should read and write the key information to a file' do
18
+ Trustworthy::Settings.open(TestValues::SettingsFile) do |settings|
19
+ key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
20
+ settings.add_key(key, 'user', 'password1')
21
+ end
30
22
 
31
- describe 'unlock_key' do
32
- it 'verifies and decrypts the key with the password' do
33
- key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
34
- settings = Trustworthy::Settings.new
35
- settings.add_key(key, 'user', 'password1')
36
- unlocked_key = settings.unlock_key('user', 'password1')
37
- unlocked_key.x.should == BigDecimal.new('2')
38
- unlocked_key.y.should == BigDecimal.new('3')
23
+ Trustworthy::Settings.open(TestValues::SettingsFile) do |settings|
24
+ found_key = settings.find_key('user')
25
+ found_key['salt'].should == TestValues::Salt
26
+ found_key['encrypted_point'].should == TestValues::EncryptedPoint
27
+ end
39
28
  end
40
- end
41
29
 
30
+ it 'should preserve the contents if an exception is raised' do
31
+ Trustworthy::Settings.open(TestValues::SettingsFile) do |settings|
32
+ key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
33
+ settings.add_key(key, 'user', 'password1')
34
+ end
42
35
 
43
- describe 'write' do
44
- it 'writes key information to the given file' do
45
- key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
46
- settings = Trustworthy::Settings.new
47
- settings.add_key(key, 'user', 'password1')
48
- FakeFS do
49
- settings.write('settings.yml')
36
+ expect do
37
+ Trustworthy::Settings.open(TestValues::SettingsFile) do |settings|
38
+ key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
39
+ settings.add_key(key, 'user', 'password2')
40
+ settings.add_key(key, 'missing', 'password')
41
+ raise 'boom'
42
+ end
43
+ end.to raise_error
50
44
 
51
- data = File.read('settings.yml')
52
- yaml = YAML.load(data)
53
- yaml['keys']['user']['salt'].should == '400$8$1b$3e31f076a3226825'
54
- yaml['keys']['user']['authentication'].should == ['20c274efc68a460568853cc4be586183012769a312549d1aa57e29a36ec1503d'].pack('H*')
55
- yaml['keys']['user']['ciphertext'].should == ['39164ec082fb8b7336d3c5500af99dcb17d2e60496ed553dfab4b05c568aa926'].pack('H*')
45
+ Trustworthy::Settings.open(TestValues::SettingsFile) do |settings|
46
+ settings.find_key('missing').should be_nil
47
+ found_key = settings.find_key('user')
48
+ found_key['salt'].should == TestValues::Salt
49
+ found_key['encrypted_point'].should == TestValues::EncryptedPoint
56
50
  end
57
51
  end
58
52
  end
59
53
 
60
- describe 'self.load' do
61
- it 'loads the key information from the given file' do
62
- FakeFS do
63
- File.open('settings.yml', 'w') do |file|
64
- file.write(<<-EOF)
65
- keys:
66
- user:
67
- salt: 400$8$1b$3e31f076a3226825
68
- ciphertext: !binary |-
69
- ORZOwIL7i3M208VQCvmdyxfS5gSW7VU9+rSwXFaKqSY=
70
- authentication: !binary |-
71
- IMJ078aKRgVohTzEvlhhgwEnaaMSVJ0apX4po27BUD0=
72
- EOF
73
- end
54
+ describe 'add_key' do
55
+ it 'should encrypt the key with the password' do |settings|
56
+ Trustworthy::Settings.open(TestValues::SettingsFile) do |settings|
57
+ key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
58
+ settings.add_key(key, 'user', 'password1')
59
+ found_key = settings.find_key('user')
60
+ found_key['salt'].should == TestValues::Salt
61
+ found_key['encrypted_point'].should == TestValues::EncryptedPoint
62
+ end
63
+ end
64
+ end
74
65
 
75
- settings = Trustworthy::Settings.load('settings.yml')
76
- settings.keys['user']['salt'].should == '400$8$1b$3e31f076a3226825'
77
- settings.keys['user']['authentication'].should == ['20c274efc68a460568853cc4be586183012769a312549d1aa57e29a36ec1503d'].pack('H*')
78
- settings.keys['user']['ciphertext'].should == ['39164ec082fb8b7336d3c5500af99dcb17d2e60496ed553dfab4b05c568aa926'].pack('H*')
66
+ describe 'unlock_key' do
67
+ it 'should decrypt the key with the password' do
68
+ Trustworthy::Settings.open(TestValues::SettingsFile) do |settings|
69
+ key = Trustworthy::Key.new(BigDecimal.new('2'), BigDecimal.new('3'))
70
+ settings.add_key(key, 'user', 'password1')
71
+ unlocked_key = settings.unlock_key('user', 'password1')
72
+ unlocked_key.x.should == BigDecimal.new('2')
73
+ unlocked_key.y.should == BigDecimal.new('3')
79
74
  end
80
75
  end
81
76
  end
metadata CHANGED
@@ -1,68 +1,60 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trustworthy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - John Downey
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-08-17 00:00:00.000000000 Z
11
+ date: 2013-03-26 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: commander
14
+ name: aead
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
21
- version: '4.1'
19
+ version: '1.6'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
29
- version: '4.1'
26
+ version: '1.6'
30
27
  - !ruby/object:Gem::Dependency
31
- name: hkdf
28
+ name: highline
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
37
- version: 0.1.0
33
+ version: '1.6'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
45
- version: 0.1.0
40
+ version: '1.6'
46
41
  - !ruby/object:Gem::Dependency
47
- name: posix-spawn
42
+ name: hkdf
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ~>
52
46
  - !ruby/object:Gem::Version
53
- version: 0.3.6
47
+ version: 0.2.0
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ~>
60
53
  - !ruby/object:Gem::Version
61
- version: 0.3.6
54
+ version: 0.2.0
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: scrypt
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ~>
68
60
  - !ruby/object:Gem::Version
@@ -70,62 +62,55 @@ dependencies:
70
62
  type: :runtime
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ~>
76
67
  - !ruby/object:Gem::Version
77
68
  version: '1.1'
78
69
  - !ruby/object:Gem::Dependency
79
- name: fakefs
70
+ name: test-construct
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ~>
73
+ - - '='
84
74
  - !ruby/object:Gem::Version
85
- version: 0.4.0
75
+ version: 1.2.0
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ~>
80
+ - - '='
92
81
  - !ruby/object:Gem::Version
93
- version: 0.4.0
82
+ version: 1.2.0
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rspec
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ~>
87
+ - - '='
100
88
  - !ruby/object:Gem::Version
101
- version: '2.11'
89
+ version: '2.13'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ~>
94
+ - - '='
108
95
  - !ruby/object:Gem::Version
109
- version: '2.11'
96
+ version: '2.13'
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: rake
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ! '>='
101
+ - - '='
116
102
  - !ruby/object:Gem::Version
117
- version: '0'
103
+ version: 10.0.3
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
- - - ! '>='
108
+ - - '='
124
109
  - !ruby/object:Gem::Version
125
- version: '0'
110
+ version: 10.0.3
126
111
  description: Implements a special case (k = 2) of Adi Shamir's secret sharing algorithm.
127
- This allows secret files to be encrypted on disk but loaded into a process on start
128
- if two keys are available.
112
+ This allows secret files to be encrypted on disk and require two secret holders
113
+ to decrypt it.
129
114
  email:
130
115
  - jdowney@gmail.com
131
116
  executables:
@@ -133,7 +118,13 @@ executables:
133
118
  extensions: []
134
119
  extra_rdoc_files: []
135
120
  files:
136
- - lib/trustworthy/crypto.rb
121
+ - lib/trustworthy/cli/add_key.rb
122
+ - lib/trustworthy/cli/command.rb
123
+ - lib/trustworthy/cli/decrypt.rb
124
+ - lib/trustworthy/cli/encrypt.rb
125
+ - lib/trustworthy/cli/helpers.rb
126
+ - lib/trustworthy/cli/init.rb
127
+ - lib/trustworthy/cli.rb
137
128
  - lib/trustworthy/key.rb
138
129
  - lib/trustworthy/master_key.rb
139
130
  - lib/trustworthy/random.rb
@@ -141,7 +132,11 @@ files:
141
132
  - lib/trustworthy/version.rb
142
133
  - lib/trustworthy.rb
143
134
  - spec/spec_helper.rb
144
- - spec/trustworthy/crypto_spec.rb
135
+ - spec/trustworthy/cli/add_key_spec.rb
136
+ - spec/trustworthy/cli/command_spec.rb
137
+ - spec/trustworthy/cli/decrypt_spec.rb
138
+ - spec/trustworthy/cli/encrypt_spec.rb
139
+ - spec/trustworthy/cli/init_spec.rb
145
140
  - spec/trustworthy/key_spec.rb
146
141
  - spec/trustworthy/master_key_spec.rb
147
142
  - spec/trustworthy/random_spec.rb
@@ -149,32 +144,36 @@ files:
149
144
  - bin/trustworthy
150
145
  - README.md
151
146
  homepage: http://github.com/jtdowney/trustworthy
152
- licenses: []
147
+ licenses:
148
+ - MIT
149
+ metadata: {}
153
150
  post_install_message:
154
151
  rdoc_options: []
155
152
  require_paths:
156
153
  - lib
157
154
  required_ruby_version: !ruby/object:Gem::Requirement
158
- none: false
159
155
  requirements:
160
- - - ! '>='
156
+ - - '>='
161
157
  - !ruby/object:Gem::Version
162
158
  version: '0'
163
159
  required_rubygems_version: !ruby/object:Gem::Requirement
164
- none: false
165
160
  requirements:
166
- - - ! '>='
161
+ - - '>='
167
162
  - !ruby/object:Gem::Version
168
163
  version: '0'
169
164
  requirements: []
170
165
  rubyforge_project:
171
- rubygems_version: 1.8.24
166
+ rubygems_version: 2.0.1
172
167
  signing_key:
173
- specification_version: 3
174
- summary: Launch processes while keeping secrets encrypted on disk
168
+ specification_version: 4
169
+ summary: Encrypt and decrypt files with multiple key holders
175
170
  test_files:
176
171
  - spec/spec_helper.rb
177
- - spec/trustworthy/crypto_spec.rb
172
+ - spec/trustworthy/cli/add_key_spec.rb
173
+ - spec/trustworthy/cli/command_spec.rb
174
+ - spec/trustworthy/cli/decrypt_spec.rb
175
+ - spec/trustworthy/cli/encrypt_spec.rb
176
+ - spec/trustworthy/cli/init_spec.rb
178
177
  - spec/trustworthy/key_spec.rb
179
178
  - spec/trustworthy/master_key_spec.rb
180
179
  - spec/trustworthy/random_spec.rb
@@ -1,50 +0,0 @@
1
- module Trustworthy
2
- class Crypto
3
- def initialize(encryption_key, authentication_key)
4
- @encryption_key = encryption_key
5
- @authentication_key = authentication_key
6
- @digest = OpenSSL::Digest.new('SHA256')
7
- @cipher = OpenSSL::Cipher.new('AES-256-CBC')
8
- end
9
-
10
- def decrypt(ciphertext)
11
- ciphertext.force_encoding('BINARY') if ciphertext.respond_to?(:force_encoding)
12
- iv = ciphertext.slice(0..15)
13
- ciphertext = ciphertext.slice(16..-1)
14
- @cipher.decrypt
15
- @cipher.key = @encryption_key
16
- @cipher.iv = iv
17
- @cipher.update(ciphertext) + @cipher.final
18
- end
19
-
20
- def encrypt(plaintext)
21
- iv = Trustworthy::Random.bytes(16)
22
- @cipher.encrypt
23
- @cipher.key = @encryption_key
24
- @cipher.iv = iv
25
- ciphertext = @cipher.update(plaintext) + @cipher.final
26
- iv + ciphertext
27
- end
28
-
29
- def sign(data)
30
- OpenSSL::HMAC.digest(@digest, @authentication_key, data)
31
- end
32
-
33
- def valid_signature?(given_signature, data)
34
- computed_signature = sign(data)
35
- _secure_compare(given_signature, computed_signature)
36
- end
37
-
38
- def _secure_compare(a, b)
39
- return false unless a.bytesize == b.bytesize
40
-
41
- bytes = a.unpack("C#{a.bytesize}")
42
-
43
- result = 0
44
- b.each_byte do |byte|
45
- result |= byte ^ bytes.shift
46
- end
47
- result == 0
48
- end
49
- end
50
- end
@@ -1,42 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Trustworthy::Crypto do
4
- before(:each) do
5
- @crypto = Trustworthy::Crypto.new(Trustworthy::TestValues::EncryptionKey, Trustworthy::TestValues::AuthenticationKey)
6
- end
7
-
8
- describe 'sign' do
9
- it 'should sign the input using the authentication key' do
10
- signature = @crypto.sign('foobar')
11
- signature.should == ['f9e948d9259d35e729b14e370a7456ec4b22d2a0a1d5daa1accbeb54f414865e'].pack('H*')
12
- end
13
- end
14
-
15
- describe 'valid_signature?' do
16
- it 'should return true when the signature matches the data' do
17
- given_signature = ['f9e948d9259d35e729b14e370a7456ec4b22d2a0a1d5daa1accbeb54f414865e'].pack('H*')
18
- @crypto.should be_valid_signature(given_signature, 'foobar')
19
- end
20
-
21
- it 'should return false when the signature matches the data' do
22
- given_signature = ['4d15a6427d6b56e07b819ff0a147dd8ff77b1b5fafd33f9071b0359755edde42'].pack('H*')
23
- @crypto.should_not be_valid_signature(given_signature, 'foobar')
24
- end
25
- end
26
-
27
- describe 'encrypt' do
28
- it 'should encrypt the input using the encryption key' do
29
- Trustworthy::Random.stub(:bytes).and_return(Trustworthy::TestValues::InitializationVector)
30
- ciphertext = @crypto.encrypt('foobar')
31
- ciphertext.should == ['39164ec082fb8b7336d3c5500af99dcbf3af2b0abd6f2ac79f1a76cb4e092a7c'].pack('H*')
32
- end
33
- end
34
-
35
- describe 'decrypt' do
36
- it 'should decrypt the input using the encryption key' do
37
- ciphertext = ['39164ec082fb8b7336d3c5500af99dcbf3af2b0abd6f2ac79f1a76cb4e092a7c'].pack('H*')
38
- plaintext = @crypto.decrypt(ciphertext)
39
- plaintext.should == 'foobar'
40
- end
41
- end
42
- end