trustworthy 0.1.0 → 0.2.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.
@@ -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