secret 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -1
- data/lib/secret.rb +4 -1
- data/lib/secret/encryption.rb +65 -20
- data/lib/secret/file.rb +9 -1
- data/lib/secret/version.rb +1 -1
- data/secret.gemspec +2 -0
- data/test/tester.rb +17 -2
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41f92b03a262766c7d234c19c6a960de5a842c19
|
4
|
+
data.tar.gz: 6e32e9c816c5fc79e8a37409438e8874a66d79d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 675d910898db33b3b877c5b18d0a6a510e41cef439c4ad9c2133e1965c112e02fad125c04537d784da9a944cc002596f85838c52a83ff50cdaa8a696a994d13c
|
7
|
+
data.tar.gz: 29a50491731fc543171b33a47296f3c49275469f8fce3ab3abc4a5847bbf8754e43b1e7eef996e6ea17fd97c1f3f6dbfdd0fba780298ffbc7987a30a1763944c
|
data/README.md
CHANGED
@@ -30,7 +30,7 @@ secret.some_key.stash "ThisIsSomeKey"
|
|
30
30
|
puts secret.some_key.contents
|
31
31
|
|
32
32
|
# Manually seek through the file
|
33
|
-
secret.some_key.stream do |f|
|
33
|
+
secret.some_key.stream 'r' do |f|
|
34
34
|
f.seek 1, IO::SEEK_CUR
|
35
35
|
end
|
36
36
|
|
@@ -44,6 +44,44 @@ secret.stash "certs/file.key", "Contents of this key file!"
|
|
44
44
|
puts secret.contents "certs/file.key"
|
45
45
|
```
|
46
46
|
|
47
|
+
## Encryption
|
48
|
+
The secret gem supports basic AES encryption with a random [IV](http://en.wikipedia.org/wiki/Initialization_vector).
|
49
|
+
Note that encryption / decryption is somewhat slow and is intended only for small strings and files.
|
50
|
+
|
51
|
+
You should implement your own encryption mechanism for anything that is more comprehensive than basic passphrase encryption.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
secret = Secret.default
|
55
|
+
file = secret.file "my_file.txt"
|
56
|
+
|
57
|
+
# Note here that unencrypted content touches the hard drive
|
58
|
+
file.stash "This is some secret contents"
|
59
|
+
|
60
|
+
if file.encrypted?
|
61
|
+
puts "Encrypting file contents..."
|
62
|
+
file.encrypt! "password"
|
63
|
+
puts file.contents
|
64
|
+
|
65
|
+
puts "Changing file passphrase..."
|
66
|
+
file.change_encryption_passphrase! "password", "password2"
|
67
|
+
else
|
68
|
+
puts "Decrypted file contents..."
|
69
|
+
puts file.decrypted "password2"
|
70
|
+
|
71
|
+
# Will still be an encrypted string
|
72
|
+
puts file.contents
|
73
|
+
|
74
|
+
# Decrypt the file
|
75
|
+
puts "Decrypting file..."
|
76
|
+
file.decrypt!
|
77
|
+
puts file.contents
|
78
|
+
end
|
79
|
+
|
80
|
+
# If we immediately wish to stash some encrypted data
|
81
|
+
file = secret.file "file2.txt"
|
82
|
+
file.stash_encrypted "This is encrypted", "password"
|
83
|
+
```
|
84
|
+
|
47
85
|
## How Secure is It?
|
48
86
|
Ths is only *somewhat* secure and will provide protection against:
|
49
87
|
|
data/lib/secret.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "secret/version"
|
2
|
+
require "secret/encryption"
|
2
3
|
require "secret/file"
|
3
4
|
require "secret/container"
|
4
5
|
|
@@ -8,7 +9,7 @@ module Secret
|
|
8
9
|
CHMOD_MODE = 0700
|
9
10
|
|
10
11
|
# The file extension for secret files
|
11
|
-
FILE_EXT = ".
|
12
|
+
FILE_EXT = ".sf"
|
12
13
|
|
13
14
|
# Gets the default container
|
14
15
|
# @return [Secret::Container] the default container
|
@@ -29,6 +30,8 @@ module Secret
|
|
29
30
|
end
|
30
31
|
|
31
32
|
class FileUnreadableError < Exception; end
|
33
|
+
|
34
|
+
class FileEncryptedError < Exception; end
|
32
35
|
|
33
36
|
|
34
37
|
end
|
data/lib/secret/encryption.rb
CHANGED
@@ -1,45 +1,90 @@
|
|
1
|
-
require '
|
1
|
+
require 'aes'
|
2
2
|
|
3
3
|
module Secret
|
4
|
+
|
5
|
+
# Enables basic encryption support with AES.
|
6
|
+
#
|
7
|
+
# Note that encryption and decription are rather slow processes and are intended to be
|
8
|
+
# used with small strings / file sizes. Please use sparingly!
|
4
9
|
module Encryption
|
5
10
|
|
6
11
|
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
# Gets the contents of the file in an encrypted format. This may quite possibly
|
14
|
+
# result in doubly-encrypted text if you're not careful. This process will take
|
15
|
+
# a few moments.
|
16
|
+
def encrypted(passphrase)
|
17
|
+
return contents if encrypted?
|
18
|
+
encrypt_string passphrase, contents
|
19
|
+
end
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
|
22
|
+
# Gets the decrypted version of this.
|
23
|
+
# @raise [OpenSSL::Cipher::CipherError] if the password was incorrect
|
24
|
+
def decrypted(passphrase)
|
25
|
+
return contents unless encrypted?
|
26
|
+
AES.decrypt contents, passphrase
|
27
|
+
end
|
28
|
+
|
29
|
+
# Immediately decrypt the contents of this file.
|
30
|
+
# @raise [OpenSSL::Cipher::CipherError] if the password was incorrect
|
31
|
+
def decrypt!(passphrase)
|
32
|
+
raise ArgumentError, "The contents of this file are not encrypted" unless encrypted?
|
33
|
+
str = decrypted(passphrase)
|
34
|
+
remove_encrypted_indicator
|
35
|
+
stash str
|
36
|
+
end
|
22
37
|
|
23
|
-
|
38
|
+
# Encrypt the contents of this file immediately
|
39
|
+
def encrypt!(passphrase)
|
40
|
+
stash_encrypted passphrase, contents
|
24
41
|
end
|
42
|
+
|
43
|
+
# Change the passphrase.
|
44
|
+
def change_encryption_passphrase!(old_passphrase, new_passphrase)
|
45
|
+
raise ArgumentError, "The contents of this file are not encrypted" unless encrypted?
|
46
|
+
original = decrypted old_passphrase
|
47
|
+
remove_encrypted_indicator
|
48
|
+
stash_encrypted original, new_passphrase
|
49
|
+
end
|
50
|
+
|
51
|
+
# Stash the contents of this file with an encrypted password
|
52
|
+
def stash_encrypted(data, passphrase)
|
53
|
+
raise ArgumentError, "The contents of this file is already encrypted" if encrypted?
|
54
|
+
::File.open(encrypted_meta_filename, 'w', container.chmod_mode) {|f| f.write "aes-default" }
|
55
|
+
str = encrypt_string passphrase, data
|
56
|
+
stash str
|
57
|
+
::File.open(encrypted_meta_filename, 'w', container.chmod_mode) {|f| f.write "aes-default" }
|
58
|
+
end
|
59
|
+
|
25
60
|
|
26
61
|
# Checks to see if the file is encrypted
|
27
62
|
def encrypted?
|
28
63
|
::File.exist?(encrypted_meta_filename)
|
29
64
|
end
|
30
65
|
|
31
|
-
|
32
|
-
def
|
33
|
-
|
34
|
-
|
66
|
+
# Ensure that the contents of this file are unencrypted
|
67
|
+
def ensure_unencrypted!
|
68
|
+
raise FileEncryptedError, "Contents of the file are encrypted" if encrypted?
|
69
|
+
end
|
35
70
|
|
36
71
|
|
72
|
+
def remove_encrypted_indicator
|
73
|
+
::File.delete encrypted_meta_filename if encrypted?
|
74
|
+
end
|
37
75
|
|
38
76
|
protected
|
77
|
+
|
78
|
+
def encrypt_string(passphrase, string)
|
79
|
+
iv = AES.iv :base_64
|
80
|
+
return AES.encrypt string, passphrase, :iv => iv
|
81
|
+
end
|
39
82
|
|
40
83
|
def encrypted_meta_filename
|
41
|
-
|
84
|
+
file_path + '.enc'
|
42
85
|
end
|
86
|
+
|
87
|
+
|
43
88
|
|
44
89
|
end
|
45
90
|
end
|
data/lib/secret/file.rb
CHANGED
@@ -2,7 +2,7 @@ module Secret
|
|
2
2
|
|
3
3
|
# Handles file operations. Uses Ruby's internal file locking mechanisms.
|
4
4
|
class File
|
5
|
-
|
5
|
+
include Secret::Encryption
|
6
6
|
|
7
7
|
attr_reader :container, :identifier
|
8
8
|
|
@@ -108,6 +108,9 @@ module Secret
|
|
108
108
|
# Rename tmp file to backup file now we know contents are sane
|
109
109
|
::File.rename(tmp_file_path, backup_file_path)
|
110
110
|
|
111
|
+
# Remove encryption indicator
|
112
|
+
remove_encrypted_indicator
|
113
|
+
|
111
114
|
# Truncate file contents to zero bytes
|
112
115
|
f.truncate 0
|
113
116
|
|
@@ -153,6 +156,11 @@ module Secret
|
|
153
156
|
|
154
157
|
end
|
155
158
|
|
159
|
+
# Delete the contents of this file, along with any other associated files.
|
160
|
+
def delete!
|
161
|
+
::File.delete(file_path) if exist?
|
162
|
+
Dir[file_path + "*"].each {|f| ::File.delete f }
|
163
|
+
end
|
156
164
|
|
157
165
|
private
|
158
166
|
|
data/lib/secret/version.rb
CHANGED
data/secret.gemspec
CHANGED
@@ -17,6 +17,8 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'aes'
|
20
22
|
|
21
23
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
24
|
spec.add_development_dependency "rake"
|
data/test/tester.rb
CHANGED
@@ -7,9 +7,24 @@ require 'secret'
|
|
7
7
|
Secret.configure_default 'secrets'
|
8
8
|
container = Secret.default
|
9
9
|
|
10
|
-
container.
|
10
|
+
file = container.file "key.crt"
|
11
|
+
#file.delete!
|
12
|
+
unless file.encrypted?
|
13
|
+
puts "Encrypting contents of file..."
|
14
|
+
file.stash_encrypted "This is some secret text!", "password"
|
15
|
+
puts "File contents: #{file.contents}"
|
16
|
+
|
17
|
+
puts "Changing passphrase..."
|
18
|
+
file.change_encryption_passphrase! "password", "password2"
|
19
|
+
|
20
|
+
# puts "This should result in an error..."
|
21
|
+
puts file.contents
|
22
|
+
else
|
23
|
+
puts "Decrypting file contents..."
|
24
|
+
file.decrypt! "password2"
|
25
|
+
puts "Decrypted contents: " + file.contents
|
26
|
+
end
|
11
27
|
|
12
|
-
puts "Contents of key: '#{container.contents 'key.crt'}'"
|
13
28
|
|
14
29
|
|
15
30
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: secret
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Thornton
|
@@ -10,6 +10,20 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2013-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aes
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|