symmetric-encryption 0.5.2 → 0.6.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.
@@ -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