secret 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a56b7cd7533a64c852d89901ba1460a2b487d498
4
- data.tar.gz: 2993017272c967c3b9e7249f6be3eff1a9bc3e22
3
+ metadata.gz: 41f92b03a262766c7d234c19c6a960de5a842c19
4
+ data.tar.gz: 6e32e9c816c5fc79e8a37409438e8874a66d79d9
5
5
  SHA512:
6
- metadata.gz: f263a042a3fb1373b73a7548143b36fc1eb6147cbdbd5ce58e7f6aa34c22bfa40cb014d6934186b220ee08c305976b3b87df8ffb1721091c120243b363297fdd
7
- data.tar.gz: a80eb4b104b6fde26085b253e9d6065aa145d9a6cf65d8a54041e98310f4dd69e7b29abd4a88b3f1b2fd9f0faab5ee5f7bc126d2d23b2a0cc9b850a3778e3b76
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
 
@@ -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 = ".sfile"
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
@@ -1,45 +1,90 @@
1
- require 'openssl'
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
- def encrypt_basic(passphrase)
9
- cipher = OpenSSL::Cipher.new('aes-256-cbc')
10
- cipher.encrypt
11
- key = passphrase
12
- iv = cipher.random_iv
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
- out = StringIO.new("", "wb") do |outf|
15
- StringIO.new(contents, "rb") do |inf|
16
- while inf.read(4096, buf)
17
- outf << cipher.update(buf)
18
- end
19
- outf << cipher.final
20
- end
21
- end
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
- return out.string
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 stash(content); raise "Not Implemented"; end
33
-
34
- def contents; raise "Not Implemented"; end
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
- raise NotImplementedError, "Must implement dis!"
84
+ file_path + '.enc'
42
85
  end
86
+
87
+
43
88
 
44
89
  end
45
90
  end
@@ -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
- # include Secret::Encryption
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
 
@@ -1,3 +1,3 @@
1
1
  module Secret
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -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"
@@ -7,9 +7,24 @@ require 'secret'
7
7
  Secret.configure_default 'secrets'
8
8
  container = Secret.default
9
9
 
10
- container.stash "key.crt", "The contents of this key!"
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.2
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