symmetric-encryption 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,34 +4,6 @@ module SymmetricEncryption
4
4
  # Features:
5
5
  # * Decryption on the fly whilst reading files
6
6
  # * Large file support by only buffering small amounts of data in memory
7
- #
8
- # # Example: Read and decrypt a line at a time from a file
9
- # SymmetricEncryption::Reader.open('test_file') do |file|
10
- # file.each_line {|line| p line }
11
- # end
12
- #
13
- # # Example: Read and decrypt entire file in memory
14
- # # Not recommended for large files
15
- # SymmetricEncryption::Reader.open('test_file') {|f| f.read }
16
- #
17
- # # Example: Reading a limited number of bytes at a time from the file
18
- # SymmetricEncryption::Reader.open('test_file') do |file|
19
- # file.read(1)
20
- # file.read(5)
21
- # file.read
22
- # end
23
- #
24
- # # Example: Read and decrypt 5 bytes at a time until the end of file is reached
25
- # SymmetricEncryption::Reader.open('test_file') do |file|
26
- # while !file.eof? do
27
- # file.read(5)
28
- # end
29
- # end
30
- #
31
- # # Example: Read, Unencrypt and decompress data in a file
32
- # SymmetricEncryption::Reader.open('encrypted_compressed.zip', :compress => true) do |file|
33
- # file.each_line {|line| p line }
34
- # end
35
7
  class Reader
36
8
  # Open a file for reading, or use the supplied IO Stream
37
9
  #
@@ -62,6 +34,45 @@ module SymmetricEncryption
62
34
  # Default: 4096
63
35
  #
64
36
  # Note: Decryption occurs before decompression
37
+ #
38
+ # # Example: Read and decrypt a line at a time from a file
39
+ # SymmetricEncryption::Reader.open('test_file') do |file|
40
+ # file.each_line {|line| p line }
41
+ # end
42
+ #
43
+ # # Example: Read and decrypt entire file in memory
44
+ # # Not recommended for large files
45
+ # SymmetricEncryption::Reader.open('test_file') {|f| f.read }
46
+ #
47
+ # # Example: Reading a limited number of bytes at a time from the file
48
+ # SymmetricEncryption::Reader.open('test_file') do |file|
49
+ # file.read(1)
50
+ # file.read(5)
51
+ # file.read
52
+ # end
53
+ #
54
+ # # Example: Read and decrypt 5 bytes at a time until the end of file is reached
55
+ # SymmetricEncryption::Reader.open('test_file') do |file|
56
+ # while !file.eof? do
57
+ # file.read(5)
58
+ # end
59
+ # end
60
+ #
61
+ # # Example: Read, Unencrypt and decompress data in a file
62
+ # SymmetricEncryption::Reader.open('encrypted_compressed.zip', :compress => true) do |file|
63
+ # file.each_line {|line| p line }
64
+ # end
65
+ #
66
+ # # Example: Reading from a CSV file
67
+ #
68
+ # require 'fastercsv'
69
+ # begin
70
+ # # Must supply :row_sep for FasterCSV otherwise it will attempt to rewind the file etc.
71
+ # csv = FasterCSV.new(SymmetricEncryption::Reader.open('csv_encrypted'), :row_sep => "\n")
72
+ # csv.each {|row| p row}
73
+ # ensure
74
+ # csv.close if csv
75
+ # end
65
76
  def self.open(filename_or_stream, options={}, &block)
66
77
  raise "options must be a hash" unless options.respond_to?(:each_pair)
67
78
  mode = options.fetch(:mode, 'r')
@@ -71,9 +82,9 @@ module SymmetricEncryption
71
82
  begin
72
83
  file = self.new(ios, options)
73
84
  file = Zlib::GzipReader.new(file) if file.compressed? || compress
74
- block.call(file)
85
+ block ? block.call(file) : file
75
86
  ensure
76
- file.close if file
87
+ file.close if block && file
77
88
  end
78
89
  end
79
90
 
@@ -89,8 +100,8 @@ module SymmetricEncryption
89
100
  if buf.start_with?(SymmetricEncryption::MAGIC_HEADER)
90
101
  # Header includes magic header and version byte
91
102
  # Remove header and extract flags
92
- header, flags = buf.slice!(0..MAGIC_HEADER_SIZE).unpack(MAGIC_HEADER_UNPACK)
93
- @compressed = flags & 0b1000_0000_0000_0000
103
+ header, flags = buf.slice!(0..MAGIC_HEADER_SIZE+1).unpack(MAGIC_HEADER_UNPACK)
104
+ @compressed = (flags & 0b1000_0000_0000_0000) != 0
94
105
  @version = @compressed ? flags - 0b1000_0000_0000_0000 : flags
95
106
  else
96
107
  @version = options[:version]
@@ -179,15 +190,27 @@ module SymmetricEncryption
179
190
  end
180
191
 
181
192
  # Reads a single decrypted line from the file up to and including the optional sep_string.
182
- # Returns nil on eof
193
+ # Raises EOFError on eof
183
194
  # The stream must be opened for reading or an IOError will be raised.
184
195
  def readline(sep_string = "\n")
196
+ gets(sep_string) || raise(EOFError.new("End of file reached when trying to read a line"))
197
+ end
198
+
199
+ # Reads a single decrypted line from the file up to and including the optional sep_string.
200
+ # A sep_string of nil reads the entire contents of the file
201
+ # Returns nil on eof
202
+ # The stream must be opened for reading or an IOError will be raised.
203
+ def gets(sep_string)
204
+ return read if sep_string.nil?
205
+
185
206
  # Read more data until we get the sep_string
186
207
  while (index = @read_buffer.index(sep_string)).nil? && !@ios.eof?
187
208
  read_block
188
209
  end
189
210
  index ||= -1
190
- @read_buffer.slice!(0..index)
211
+ data = @read_buffer.slice!(0..index)
212
+ return nil if data.length == 0 && eof?
213
+ data
191
214
  end
192
215
 
193
216
  # ios.each(sep_string="\n") {|line| block } => ios
@@ -196,7 +219,7 @@ module SymmetricEncryption
196
219
  # ios must be opened for reading or an IOError will be raised.
197
220
  def each_line(sep_string = "\n")
198
221
  while !eof?
199
- yield readline(sep_string)
222
+ yield gets(sep_string)
200
223
  end
201
224
  self
202
225
  end
@@ -208,6 +231,19 @@ module SymmetricEncryption
208
231
  (@read_buffer.size == 0) && @ios.eof?
209
232
  end
210
233
 
234
+ # Return the approximate offset in bytes of the current input stream
235
+ # Since the encrypted data size does not match the unencrypted size
236
+ # this value cannot be guaranteed. Especially if compression is turned on
237
+ def pos
238
+ @ios.pos - @read_buffer.size
239
+ end
240
+
241
+ # Rewind back to the beginning of the file
242
+ def rewind
243
+ @read_buffer = ''
244
+ @ios.rewind
245
+ end
246
+
211
247
  private
212
248
 
213
249
  # Read a block of data and append the decrypted data in the read buffer
@@ -21,8 +21,8 @@ module SymmetricEncryption
21
21
  # Returns the Primary Symmetric Cipher being used
22
22
  # If a version is supplied, then the cipher matching that version will be
23
23
  # returned or nil if no match was found
24
- def self.cipher(version = nil)
25
- return @@cipher if version.nil? || (@@cipher.version == version)
24
+ def self.cipher(version = 0)
25
+ return @@cipher if version.nil? || (version == 0) || (@@cipher.version == version)
26
26
  secondary_ciphers.find {|c| c.version == version}
27
27
  end
28
28
 
@@ -190,7 +190,7 @@ module SymmetricEncryption
190
190
  unless defined? MAGIC_HEADER
191
191
  MAGIC_HEADER = '@EnC'
192
192
  MAGIC_HEADER_SIZE = MAGIC_HEADER.size
193
- MAGIC_HEADER_UNPACK = "A#{MAGIC_HEADER_SIZE}v"
193
+ MAGIC_HEADER_UNPACK = "a#{MAGIC_HEADER_SIZE}v"
194
194
  end
195
195
 
196
196
  protected
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module SymmetricEncryption #:nodoc
3
- VERSION = "0.5.2"
3
+ VERSION = "0.6.0"
4
4
  end
@@ -1,29 +1,13 @@
1
1
  module SymmetricEncryption
2
+ # Write to encrypted files and other IO streams
3
+ #
4
+ # Features:
5
+ # * Encryption on the fly whilst writing files.
6
+ # * Large file support by only buffering small amounts of data in memory
7
+ # * Underlying buffering to ensure that encrypted data fits
8
+ # into the Symmetric Encryption Cipher block size
9
+ # Only the last block in the file will be padded if it is less than the block size
2
10
  class Writer
3
- # Write to encrypted files and other IO streams
4
- #
5
- # Features:
6
- # * Encryption on the fly whilst writing files.
7
- # * Large file support by only buffering small amounts of data in memory
8
- # * Underlying buffering to ensure that encrypted data fits
9
- # into the Symmetric Encryption Cipher block size
10
- # Only the last block in the file will be padded if it is less than the block size
11
- #
12
- # # Example: Encrypt and write data to a file
13
- # SymmetricEncryption::Writer.open('test_file') do |file|
14
- # file.write "Hello World\n"
15
- # file.write "Keep this secret"
16
- # end
17
- #
18
- # # Example: Compress, Encrypt and write data to a file
19
- # SymmetricEncryption::Writer.open('encrypted_compressed.zip', :compress => true) do |file|
20
- # file.write "Hello World\n"
21
- # file.write "Compress this\n"
22
- # file.write "Keep this safe and secure\n"
23
- # end
24
- #
25
-
26
-
27
11
  # Open a file for writing, or use the supplied IO Stream
28
12
  #
29
13
  # Parameters:
@@ -57,6 +41,29 @@ module SymmetricEncryption
57
41
  #
58
42
  # Note: Compression occurs before encryption
59
43
  #
44
+ #
45
+ # # Example: Encrypt and write data to a file
46
+ # SymmetricEncryption::Writer.open('test_file') do |file|
47
+ # file.write "Hello World\n"
48
+ # file.write "Keep this secret"
49
+ # end
50
+ #
51
+ # # Example: Compress, Encrypt and write data to a file
52
+ # SymmetricEncryption::Writer.open('encrypted_compressed.zip', :compress => true) do |file|
53
+ # file.write "Hello World\n"
54
+ # file.write "Compress this\n"
55
+ # file.write "Keep this safe and secure\n"
56
+ # end
57
+ #
58
+ # # Example: Writing to a CSV file
59
+ # require 'fastercsv'
60
+ # begin
61
+ # # Must supply :row_sep for FasterCSV otherwise it will attempt to read from and then rewind the file
62
+ # csv = FasterCSV.new(SymmetricEncryption::Writer.open('csv_encrypted'), :row_sep => "\n")
63
+ # csv << [1,2,3,4,5]
64
+ # ensure
65
+ # csv.close if csv
66
+ # end
60
67
  def self.open(filename_or_stream, options={}, &block)
61
68
  raise "options must be a hash" unless options.respond_to?(:each_pair)
62
69
  mode = options.fetch(:mode, 'w')
@@ -66,9 +73,9 @@ module SymmetricEncryption
66
73
  begin
67
74
  file = self.new(ios, options)
68
75
  file = Zlib::GzipWriter.new(file) if compress
69
- block.call(file)
76
+ block ? block.call(file) : file
70
77
  ensure
71
- file.close if file
78
+ file.close if block && file
72
79
  end
73
80
  end
74
81
 
@@ -114,6 +121,16 @@ module SymmetricEncryption
114
121
  data.length
115
122
  end
116
123
 
124
+ # Write to the IO Stream as encrypted data
125
+ # Returns self
126
+ #
127
+ # Example:
128
+ # file << "Hello.\n" << "This is Jack"
129
+ def <<(data)
130
+ write(data)
131
+ self
132
+ end
133
+
117
134
  private
118
135
 
119
136
  # Write the Encryption header if this is the first write
@@ -6,11 +6,11 @@
6
6
  <line>62</line>
7
7
  </file>
8
8
  <file>
9
- <url>lib/symmetric_encryption/encryption.rb</url>
9
+ <url>lib/symmetric_encryption/symmetric_encryption.rb</url>
10
10
  <line>60</line>
11
11
  </file>
12
12
  <file>
13
- <url>lib/symmetric_encryption/symmetric_encryption.rb</url>
13
+ <url>lib/symmetric_encryption/encryption.rb</url>
14
14
  <line>60</line>
15
15
  </file>
16
16
  </editor-bookmarks>
@@ -22,7 +22,6 @@ class ReaderTest < Test::Unit::TestCase
22
22
  @data_str = @data.inject('') {|sum,str| sum << str}
23
23
  @data_len = @data_str.length
24
24
  @data_encrypted = SymmetricEncryption.cipher.encrypt(@data_str)
25
- @filename = '._test'
26
25
  end
27
26
 
28
27
  should "decrypt from string stream as a single read" do
@@ -68,9 +67,40 @@ class ReaderTest < Test::Unit::TestCase
68
67
  end
69
68
  end
70
69
 
71
- should "decrypt from file" do
70
+ context "reading from file" do
71
+ # With and without header
72
+ [false, true].each do |header|
73
+ context "with#{'out' unless header} header" do
74
+ setup do
75
+ @filename = '._test'
76
+ @options = { :header => header }
77
+ # Create encrypted file
78
+ SymmetricEncryption::Writer.open(@filename, @options) do |file|
79
+ @data.inject(0) {|sum,str| sum + file.write(str)}
80
+ end
81
+ end
82
+
83
+ teardown do
84
+ File.delete(@filename) if File.exist?(@filename)
85
+ end
86
+
87
+ should "decrypt from file in a single read" do
88
+ decrypted = SymmetricEncryption::Reader.open(@filename) {|file| file.read}
89
+ assert_equal @data_str, decrypted
90
+ end
91
+
92
+ should "decrypt from file a line at a time" do
93
+ decrypted = SymmetricEncryption::Reader.open(@filename) do |file|
94
+ i = 0
95
+ file.each_line do |line|
96
+ assert_equal @data[i], line
97
+ i += 1
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
72
103
 
73
104
  end
74
105
  end
75
-
76
- end
106
+ end
@@ -25,6 +25,10 @@ class EncryptionWriterTest < Test::Unit::TestCase
25
25
  @filename = '._test'
26
26
  end
27
27
 
28
+ teardown do
29
+ File.delete(@filename) if File.exist?(@filename)
30
+ end
31
+
28
32
  should "encrypt to string stream" do
29
33
  stream = StringIO.new
30
34
  file = SymmetricEncryption::Writer.new(stream)
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 5
8
- - 2
9
- version: 0.5.2
7
+ - 6
8
+ - 0
9
+ version: 0.6.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Reid Morrison
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-04-17 00:00:00 -04:00
17
+ date: 2012-04-30 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -49,10 +49,6 @@ files:
49
49
  - nbproject/project.xml
50
50
  - Rakefile
51
51
  - README.md
52
- - symmetric-encryption-0.2.0.gem
53
- - symmetric-encryption-0.4.0.gem
54
- - symmetric-encryption-0.5.0.gem
55
- - symmetric-encryption-0.5.1.gem
56
52
  - test/attr_encrypted_test.rb
57
53
  - test/cipher_test.rb
58
54
  - test/config/database.yml