archive-zip 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,176 @@
1
+ require 'archive/support/io-like'
2
+ require 'archive/zip/codec'
3
+
4
+ module Archive; class Zip; module Codec
5
+ # Archive::Zip::Codec::NullEncryption is a handle for an encryption codec
6
+ # which passes data through itself unchanged.
7
+ class NullEncryption
8
+ # Archive::Zip::Codec::NullEncryption::Encrypt is a writable, IO-like object
9
+ # which writes all data written to it directly to a delegate IO object. A
10
+ # _close_ method is also provided which can optionally closed the delegate
11
+ # object.
12
+ class Encrypt
13
+ include IO::Like
14
+
15
+ # Creates a new instance of this class with the given argument using #new
16
+ # and then passes the instance to the given block. The #close method is
17
+ # guaranteed to be called after the block completes.
18
+ #
19
+ # Equivalent to #new if no block is given.
20
+ def self.open(io)
21
+ encrypt_io = new(io)
22
+ return encrypt_io unless block_given?
23
+
24
+ begin
25
+ yield(encrypt_io)
26
+ ensure
27
+ encrypt_io.close unless encrypt_io.closed?
28
+ end
29
+ end
30
+
31
+ # Creates a new instance of this class using _io_ as a data sink. _io_
32
+ # must be writable and must provide a write method as IO does or errors
33
+ # will be raised when performing write operations.
34
+ #
35
+ # The _flush_size_ attribute is set to <tt>0</tt> by default under the
36
+ # assumption that _io_ is already buffered.
37
+ def initialize(io)
38
+ @io = io
39
+ # Assume that the delegate IO object is already buffered.
40
+ self.flush_size = 0
41
+ end
42
+
43
+ # Closes this object so that further write operations will fail. If
44
+ # _close_delegate_ is +true+, the delegate object used as a data sink will
45
+ # also be closed using its close method.
46
+ def close(close_delegate = true)
47
+ super()
48
+ @io.close if close_delegate
49
+ end
50
+
51
+ private
52
+
53
+ # Writes _string_ to the delegate IO object and returns the result.
54
+ def unbuffered_write(string)
55
+ @io.write(string)
56
+ end
57
+ end
58
+
59
+ # Archive::Zip::Codec::NullEncryption::Decrypt is a readable, IO-like object
60
+ # which reads data directly from a delegate IO object, making no changes. A
61
+ # _close_ method is also provided which can optionally closed the delegate
62
+ # object.
63
+ class Decrypt
64
+ include IO::Like
65
+
66
+ # Creates a new instance of this class with the given argument using #new
67
+ # and then passes the instance to the given block. The #close method is
68
+ # guaranteed to be called after the block completes.
69
+ #
70
+ # Equivalent to #new if no block is given.
71
+ def self.open(io)
72
+ decrypt_io = new(io)
73
+ return decrypt_io unless block_given?
74
+
75
+ begin
76
+ yield(decrypt_io)
77
+ ensure
78
+ decrypt_io.close unless decrypt_io.closed?
79
+ end
80
+ end
81
+
82
+ # Creates a new instance of this class using _io_ as a data source. _io_
83
+ # must be readable and provide a read method as IO does or errors will be
84
+ # raised when performing read operations. If _io_ provides a rewind
85
+ # method, this class' rewind method will be enabled.
86
+ #
87
+ # The _fill_size_ attribute is set to <tt>0</tt> by default under the
88
+ # assumption that _io_ is already buffered.
89
+ def initialize(io)
90
+ @io = io
91
+ # Assume that the delegate IO object is already buffered.
92
+ self.fill_size = 0
93
+ end
94
+
95
+ # Closes this object so that further write operations will fail. If
96
+ # _close_delegate_ is +true+, the delegate object used as a data sink will
97
+ # also be closed using its close method.
98
+ def close(close_delegate = true)
99
+ super()
100
+ @io.close if close_delegate
101
+ end
102
+
103
+ private
104
+
105
+ # Reads and returns at most _length_ bytes from the delegate IO object.
106
+ #
107
+ # Raises EOFError if there is no data to read.
108
+ def unbuffered_read(length)
109
+ buffer = @io.read(length)
110
+ raise EOFError, 'end of file reached' if buffer.nil?
111
+
112
+ buffer
113
+ end
114
+
115
+ # Allows resetting this object and the delegate object back to the
116
+ # beginning of the stream. _offset_ must be <tt>0</tt> and _whence_ must
117
+ # be IO::SEEK_SET or an error will be raised. The delegate object must
118
+ # respond to the _rewind_ method or an error will be raised.
119
+ def unbuffered_seek(offset, whence = IO::SEEK_SET)
120
+ unless offset == 0 && whence == IO::SEEK_SET then
121
+ raise Errno::EINVAL, 'Invalid argument'
122
+ end
123
+ unless @io.respond_to?(:rewind) then
124
+ raise Errno::ESPIPE, 'Illegal seek'
125
+ end
126
+ @io.rewind
127
+ end
128
+ end
129
+
130
+ # This method signature is part of the interface contract expected by
131
+ # Archive::Zip::Entry for encryption codec objects.
132
+ #
133
+ # A convenience method for creating an
134
+ # Archive::Zip::Codec::NullEncryption::Encrypt object using that class' open
135
+ # method.
136
+ def encryptor(io, password, &b)
137
+ Encrypt.open(io, &b)
138
+ end
139
+
140
+ # This method signature is part of the interface contract expected by
141
+ # Archive::Zip::Entry for encryption codec objects.
142
+ #
143
+ # A convenience method for creating an
144
+ # Archive::Zip::Codec::NullEncryption::Decrypt object using that class' open
145
+ # method.
146
+ def decryptor(io, password, &b)
147
+ Decrypt.open(io, &b)
148
+ end
149
+
150
+ # This method signature is part of the interface contract expected by
151
+ # Archive::Zip::Entry for encryption codec objects.
152
+ #
153
+ # Returns an integer which indicates the version of the official ZIP
154
+ # specification which introduced support for this encryption codec.
155
+ def version_needed_to_extract
156
+ 0x0014
157
+ end
158
+
159
+ # This method signature is part of the interface contract expected by
160
+ # Archive::Zip::Entry for encryption codec objects.
161
+ #
162
+ # Returns an integer representing the general purpose flags of a ZIP archive
163
+ # entry using this encryption codec.
164
+ def general_purpose_flags
165
+ 0b0000000000000000
166
+ end
167
+
168
+ # This method signature is part of the interface contract expected by
169
+ # Archive::Zip::Entry for encryption codec objects.
170
+ #
171
+ # Returns the size of the encryption header in bytes.
172
+ def header_size
173
+ 0
174
+ end
175
+ end
176
+ end; end; end
@@ -1,19 +1,22 @@
1
1
  require 'archive/support/io-like'
2
2
  require 'archive/zip/codec'
3
- require 'archive/zip/datadescriptor'
3
+ require 'archive/zip/data_descriptor'
4
4
 
5
5
  module Archive; class Zip; module Codec
6
6
  # Archive::Zip::Codec::Store is a handle for the store-unstore (no
7
7
  # compression) codec.
8
8
  class Store
9
- # Archive::Zip::Codec::Store::Store is simply a writable, IO-like wrapper
9
+ # Archive::Zip::Codec::Store::Compress is simply a writable, IO-like wrapper
10
10
  # around a writable, IO-like object which provides a CRC32 checksum of the
11
11
  # data written through it as well as the count of the total amount of data.
12
- # A #close method is also provided which can optionally close the delegate
12
+ # A _close_ method is also provided which can optionally close the delegate
13
13
  # object. In addition a convenience method is provided for generating
14
14
  # DataDescriptor objects based on the data which is passed through this
15
15
  # object.
16
- class Store
16
+ #
17
+ # Instances of this class should only be accessed via the
18
+ # Archive::Zip::Codec::Store#compressor method.
19
+ class Compress
17
20
  include IO::Like
18
21
 
19
22
  # Creates a new instance of this class with the given argument using #new
@@ -36,8 +39,8 @@ module Archive; class Zip; module Codec
36
39
  # must be writable and must provide a write method as IO does or errors
37
40
  # will be raised when performing write operations.
38
41
  #
39
- # The _flush_size_ attribute is set to +0+ by default under the assumption
40
- # that _io_ is already buffered.
42
+ # The _flush_size_ attribute is set to <tt>0</tt> by default under the
43
+ # assumption that _io_ is already buffered.
41
44
  def initialize(io)
42
45
  @io = io
43
46
  @crc32 = 0
@@ -82,14 +85,17 @@ module Archive; class Zip; module Codec
82
85
  end
83
86
  end
84
87
 
85
- # Archive::Zip::Codec::Store::Unstore is a readable, IO-like wrapper around
86
- # a readable, IO-like object which provides a CRC32 checksum of the data
87
- # read through it as well as the count of the total amount of data. A
88
- # #close method is also provided which can optionally close the delegate
88
+ # Archive::Zip::Codec::Store::Decompress is a readable, IO-like wrapper
89
+ # around a readable, IO-like object which provides a CRC32 checksum of the
90
+ # data read through it as well as the count of the total amount of data. A
91
+ # _close_ method is also provided which can optionally close the delegate
89
92
  # object. In addition a convenience method is provided for generating
90
93
  # DataDescriptor objects based on the data which is passed through this
91
94
  # object.
92
- class Unstore
95
+ #
96
+ # Instances of this class should only be accessed via the
97
+ # Archive::Zip::Codec::Store#decompressor method.
98
+ class Decompress
93
99
  include IO::Like
94
100
 
95
101
  # Creates a new instance of this class with the given arguments using #new
@@ -113,8 +119,8 @@ module Archive; class Zip; module Codec
113
119
  # raised when performing read operations. If _io_ provides a rewind
114
120
  # method, this class' rewind method will be enabled.
115
121
  #
116
- # The _fill_size_ attribute is set to +0+ by default under the assumption
117
- # that _io_ is already buffered.
122
+ # The _fill_size_ attribute is set to <tt>0</tt> by default under the
123
+ # assumption that _io_ is already buffered.
118
124
  def initialize(io)
119
125
  @io = io
120
126
  @crc32 = 0
@@ -151,18 +157,16 @@ module Archive; class Zip; module Codec
151
157
  # uncompressed_size and crc32 attributes as a side effect.
152
158
  def unbuffered_read(length)
153
159
  buffer = @io.read(length)
154
- if buffer.nil? then
155
- raise EOFError, 'end of file reached'
156
- else
157
- @uncompressed_size += buffer.length
158
- @crc32 = Zlib.crc32(buffer, @crc32)
159
- end
160
+ raise EOFError, 'end of file reached' if buffer.nil?
161
+
162
+ @uncompressed_size += buffer.length
163
+ @crc32 = Zlib.crc32(buffer, @crc32)
160
164
  buffer
161
165
  end
162
166
 
163
167
  # Allows resetting this object and the delegate object back to the
164
- # beginning of the stream. _offset_ must be +0+ and _whence_ must be
165
- # IO::SEEK_SET or an error will be raised. The delegate object must
168
+ # beginning of the stream. _offset_ must be <tt>0</tt> and _whence_ must
169
+ # be IO::SEEK_SET or an error will be raised. The delegate object must
166
170
  # respond to the _rewind_ method or an error will be raised. The
167
171
  # uncompressed_size and crc32 attributes are reinitialized as a side
168
172
  # effect.
@@ -179,14 +183,15 @@ module Archive; class Zip; module Codec
179
183
  end
180
184
  end
181
185
 
182
- # The numeric identifier assigned to this codec by the ZIP specification.
186
+ # The numeric identifier assigned to this compresion codec by the ZIP
187
+ # specification.
183
188
  ID = 0
184
189
 
185
- # Register this codec.
186
- CODECS[ID] = self
190
+ # Register this compression codec.
191
+ COMPRESSION_CODECS[ID] = self
187
192
 
188
193
  # This method signature is part of the interface contract expected by
189
- # Archive::Zip::Entry for codec objects.
194
+ # Archive::Zip::Entry for compression codec objects.
190
195
  #
191
196
  # Creates a new instance of this class. _general_purpose_flags_ is not
192
197
  # used.
@@ -194,46 +199,47 @@ module Archive; class Zip; module Codec
194
199
  end
195
200
 
196
201
  # This method signature is part of the interface contract expected by
197
- # Archive::Zip::Entry for codec objects.
202
+ # Archive::Zip::Entry for compression codec objects.
198
203
  #
199
- # A convenience method for creating an Archive::Zip::Codec::Store::Store
204
+ # A convenience method for creating an Archive::Zip::Codec::Store::Compress
200
205
  # object using that class' open method.
201
206
  def compressor(io, &b)
202
- Store.open(io, &b)
207
+ Compress.open(io, &b)
203
208
  end
204
209
 
205
210
  # This method signature is part of the interface contract expected by
206
- # Archive::Zip::Entry for codec objects.
211
+ # Archive::Zip::Entry for compression codec objects.
207
212
  #
208
- # A convenience method for creating an Archive::Zip::Codec::Store::Unstore
209
- # object using that class' open method.
213
+ # A convenience method for creating an
214
+ # Archive::Zip::Codec::Store::Decompress object using that class' open
215
+ # method.
210
216
  def decompressor(io, &b)
211
- Unstore.open(io, &b)
217
+ Decompress.open(io, &b)
212
218
  end
213
219
 
214
220
  # This method signature is part of the interface contract expected by
215
- # Archive::Zip::Entry for codec objects.
221
+ # Archive::Zip::Entry for compression codec objects.
216
222
  #
217
223
  # Returns an integer which indicates the version of the official ZIP
218
- # specification which introduced support for this codec.
224
+ # specification which introduced support for this compression codec.
219
225
  def version_needed_to_extract
220
226
  0x000a
221
227
  end
222
228
 
223
229
  # This method signature is part of the interface contract expected by
224
- # Archive::Zip::Entry for codec objects.
230
+ # Archive::Zip::Entry for compression codec objects.
225
231
  #
226
- # Returns an integer used to flag that this codec is used for a particular
227
- # ZIP archive entry.
232
+ # Returns an integer used to flag that this compression codec is used for a
233
+ # particular ZIP archive entry.
228
234
  def compression_method
229
235
  ID
230
236
  end
231
237
 
232
238
  # This method signature is part of the interface contract expected by
233
- # Archive::Zip::Entry for codec objects.
239
+ # Archive::Zip::Entry for compression codec objects.
234
240
  #
235
- # Returns +0+ since this codec does not make use of general purpose flags of
236
- # ZIP archive entries.
241
+ # Returns <tt>0</tt> since this compression codec does not make use of
242
+ # general purpose flags of ZIP archive entries.
237
243
  def general_purpose_flags
238
244
  0
239
245
  end
@@ -0,0 +1,308 @@
1
+ require 'archive/support/io-like'
2
+ require 'archive/support/time'
3
+ require 'archive/support/zlib'
4
+ require 'archive/zip/codec'
5
+
6
+ module Archive; class Zip; module Codec
7
+ # Archive::Zip::Codec::TraditionalEncryption is a handle for the traditional
8
+ # encryption codec.
9
+ class TraditionalEncryption
10
+ # Archive::Zip::Codec::TraditionalEncryption::Base provides some basic
11
+ # methods which are shared between
12
+ # Archive::Zip::Codec::TraditionalEncryption::Encrypt and
13
+ # Archive::Zip::Codec::TraditionalEncryption::Decrypt.
14
+ #
15
+ # Do not use this class directly.
16
+ class Base
17
+ # Creates a new instance of this class. _io_ must be an IO-like object to
18
+ # be used as a delegate for IO operations. _password_ should be the
19
+ # encryption key. _mtime_ must be the last modified time of the entry to
20
+ # be encrypted/decrypted.
21
+ def initialize(io, password, mtime)
22
+ @io = io
23
+ @password = password.nil? ? '' : password
24
+ @mtime = mtime
25
+ initialize_keys
26
+ end
27
+
28
+ protected
29
+
30
+ # The delegate IO-like object.
31
+ attr_reader :io
32
+ # The encryption key.
33
+ attr_reader :password
34
+ # The last modified time of the entry being encrypted. This is used in
35
+ # the entryption header as a way to check the password.
36
+ attr_reader :mtime
37
+
38
+ private
39
+
40
+ # Initializes the keys used for encrypting/decrypting data by setting the
41
+ # keys to well known values and then processing them with the password.
42
+ def initialize_keys
43
+ @key0 = 0x12345678
44
+ @key1 = 0x23456789
45
+ @key2 = 0x34567890
46
+ @password.each_byte { |byte| update_keys(byte.chr) }
47
+ nil
48
+ end
49
+
50
+ # Updates the keys following the ZIP specification using _char_, which
51
+ # must be a single byte String.
52
+ def update_keys(char)
53
+ # For some reason not explained in the ZIP specification but discovered
54
+ # in the source for InfoZIP, the old CRC value must first have its bits
55
+ # flipped before processing. The new CRC value must have its bits
56
+ # flipped as well for storage and later use. This applies to the
57
+ # handling of @key0 and @key2.
58
+ #
59
+ # NOTE: XOR'ing with 0xffffffff is used instead of simple bit negation
60
+ # in case this is run on a platform with a native integer size of
61
+ # something other than 32 bits.
62
+ @key0 = Zlib.crc32(char, @key0 ^ 0xffffffff) ^ 0xffffffff
63
+ @key1 = ((@key1 + (@key0 & 0xff)) * 134775813 + 1) & 0xffffffff
64
+ @key2 = Zlib.crc32((@key1 >> 24).chr, @key2 ^ 0xffffffff) ^ 0xffffffff
65
+ nil
66
+ end
67
+
68
+ # Returns the next decryption byte based on the current keys.
69
+ def decrypt_byte
70
+ temp = (@key2 | 2) & 0x0000ffff
71
+ ((temp * (temp ^ 1)) >> 8) & 0x000000ff
72
+ end
73
+ end
74
+
75
+ # Archive::Zip::Codec::TraditionalEncryption::Encrypt is a writable, IO-like
76
+ # object which encrypts data written to it using the traditional encryption
77
+ # algorithm as documented in the ZIP specification and writes the result to
78
+ # a delegate IO object. A _close_ method is also provided which can
79
+ # optionally close the delegate object.
80
+ #
81
+ # Instances of this class should only be accessed via the
82
+ # Archive::Zip::Codec::TraditionalEncryption#compressor method.
83
+ class Encrypt < Base
84
+ include IO::Like
85
+
86
+ # Creates a new instance of this class with the given argument using #new
87
+ # and then passes the instance to the given block. The #close method is
88
+ # guaranteed to be called after the block completes.
89
+ #
90
+ # Equivalent to #new if no block is given.
91
+ def self.open(io, password, mtime)
92
+ encrypt_io = new(io, password, mtime)
93
+ return encrypt_io unless block_given?
94
+
95
+ begin
96
+ yield(encrypt_io)
97
+ ensure
98
+ encrypt_io.close unless encrypt_io.closed?
99
+ end
100
+ end
101
+
102
+ # Creates a new instance of this class using _io_ as a data sink. _io_
103
+ # must be writable and must provide a write method as IO does or errors
104
+ # will be raised when performing write operations. _password_ should be
105
+ # the encryption key. _mtime_ must be the last modified time of the entry
106
+ # to be encrypted/decrypted.
107
+ #
108
+ # The _flush_size_ attribute is set to <tt>0</tt> by default under the
109
+ # assumption that _io_ is already buffered.
110
+ def initialize(io, password, mtime)
111
+ super(io, password, mtime)
112
+
113
+ # Assume that the delegate IO object is already buffered.
114
+ self.flush_size = 0
115
+ end
116
+
117
+ # Closes this object so that further write operations will fail. If
118
+ # _close_delegate_ is +true+, the delegate object used as a data sink will
119
+ # also be closed using its close method.
120
+ def close(close_delegate = true)
121
+ super()
122
+ io.close if close_delegate
123
+ end
124
+
125
+ private
126
+
127
+ # Extend the inherited initialize_keys method to further initialize the
128
+ # keys by encrypting and writing a 12 byte header to the delegate IO
129
+ # object.
130
+ def initialize_keys
131
+ super
132
+
133
+ # Create and encrypt a 12 byte header to protect the encrypted file data
134
+ # from attack. The first 10 bytes are random, and the lat 2 bytes are
135
+ # the low order word of the last modified time of the entry in DOS
136
+ # format.
137
+ 10.times do
138
+ unbuffered_write(rand(256).chr)
139
+ end
140
+ time = mtime.to_dos_time.to_i
141
+ unbuffered_write((time & 0xff).chr)
142
+ unbuffered_write(((time >> 8) & 0xff).chr)
143
+ nil
144
+ end
145
+
146
+ # Encrypts and writes _string_ to the delegate IO object. Returns the
147
+ # number of bytes of _string_ written. If _string_ is not a String, it is
148
+ # converted into one using its _to_s_ method.
149
+ def unbuffered_write(string)
150
+ string = string.to_s
151
+ bytes_written = 0
152
+ string.each_byte do |byte|
153
+ temp = decrypt_byte
154
+ break unless io.write((byte ^ temp).chr) > 0
155
+ bytes_written += 1
156
+ update_keys(byte.chr)
157
+ end
158
+ bytes_written
159
+ end
160
+ end
161
+
162
+ # Archive::Zip::Codec::TraditionalEncryption::Decrypt is a readable, IO-like
163
+ # object which decrypts data data it reads from a delegate IO object using
164
+ # the traditional encryption algorithm as documented in the ZIP
165
+ # specification. A _close_ method is also provided which can optionally
166
+ # close the delegate object.
167
+ #
168
+ # Instances of this class should only be accessed via the
169
+ # Archive::Zip::Codec::TraditionalEncryption#decompressor method.
170
+ class Decrypt < Base
171
+ include IO::Like
172
+
173
+ # Creates a new instance of this class with the given argument using #new
174
+ # and then passes the instance to the given block. The #close method is
175
+ # guaranteed to be called after the block completes.
176
+ #
177
+ # Equivalent to #new if no block is given.
178
+ def self.open(io, password, mtime)
179
+ decrypt_io = new(io, password, mtime)
180
+ return decrypt_io unless block_given?
181
+
182
+ begin
183
+ yield(decrypt_io)
184
+ ensure
185
+ decrypt_io.close unless decrypt_io.closed?
186
+ end
187
+ end
188
+
189
+ # Creates a new instance of this class using _io_ as a data source. _io_
190
+ # must be readable and provide a read method as IO does or errors will be
191
+ # raised when performing read operations. If _io_ provides a rewind
192
+ # method, this class' rewind method will be enabled. _password_ should be
193
+ # the encryption key. _mtime_ must be the last modified time of the entry
194
+ # to be encrypted/decrypted.
195
+ #
196
+ # The _fill_size_ attribute is set to <tt>0</tt> by default under the
197
+ # assumption that _io_ is already buffered.
198
+ def initialize(io, password, mtime)
199
+ super(io, password, mtime)
200
+
201
+ # Assume that the delegate IO object is already buffered.
202
+ self.fill_size = 0
203
+ end
204
+
205
+ # Closes this object so that further write operations will fail. If
206
+ # _close_delegate_ is +true+, the delegate object used as a data sink will
207
+ # also be closed using its close method.
208
+ def close(close_delegate = true)
209
+ super()
210
+ io.close if close_delegate
211
+ end
212
+
213
+ private
214
+
215
+ # Extend the inherited initialize_keys method to further initialize the
216
+ # keys by encrypting and writing a 12 byte header to the delegate IO
217
+ # object.
218
+ def initialize_keys
219
+ super
220
+
221
+ # Decrypt the 12 byte header.
222
+ unbuffered_read(12)
223
+ nil
224
+ end
225
+
226
+ # Reads, decrypts, and returns at most _length_ bytes from the delegate IO
227
+ # object.
228
+ #
229
+ # Raises EOFError if there is no data to read.
230
+ def unbuffered_read(length)
231
+ buffer = io.read(length)
232
+ raise EOFError, 'end of file reached' if buffer.nil?
233
+
234
+ (0 ... buffer.size).each do |i|
235
+ buffer[i] = (buffer[i] ^ decrypt_byte)
236
+ update_keys(buffer[i].chr)
237
+ end
238
+ buffer
239
+ end
240
+
241
+ # Allows resetting this object and the delegate object back to the
242
+ # beginning of the stream. _offset_ must be <tt>0</tt> and _whence_ must
243
+ # be IO::SEEK_SET or an error will be raised. The delegate object must
244
+ # respond to the _rewind_ method or an error will be raised.
245
+ def unbuffered_seek(offset, whence = IO::SEEK_SET)
246
+ unless offset == 0 && whence == IO::SEEK_SET then
247
+ raise Errno::EINVAL, 'Invalid argument'
248
+ end
249
+ unless io.respond_to?(:rewind) then
250
+ raise Errno::ESPIPE, 'Illegal seek'
251
+ end
252
+ io.rewind
253
+ initialize_keys
254
+ 0
255
+ end
256
+ end
257
+
258
+ # The last modified time of the entry to be processed. Set this before
259
+ # calling #encryptor or #decryptor.
260
+ attr_accessor :mtime
261
+
262
+ # This method signature is part of the interface contract expected by
263
+ # Archive::Zip::Entry for encryption codec objects.
264
+ #
265
+ # A convenience method for creating an
266
+ # Archive::Zip::Codec::TraditionalEncryption::Encrypt object using that
267
+ # class' open method.
268
+ def encryptor(io, password, &b)
269
+ Encrypt.open(io, password, mtime, &b)
270
+ end
271
+
272
+ # This method signature is part of the interface contract expected by
273
+ # Archive::Zip::Entry for encryption codec objects.
274
+ #
275
+ # A convenience method for creating an
276
+ # Archive::Zip::Codec::TraditionalEncryption::Decrypt object using that
277
+ # class' open method.
278
+ def decryptor(io, password, &b)
279
+ Decrypt.open(io, password, mtime, &b)
280
+ end
281
+
282
+ # This method signature is part of the interface contract expected by
283
+ # Archive::Zip::Entry for encryption codec objects.
284
+ #
285
+ # Returns an integer which indicates the version of the official ZIP
286
+ # specification which introduced support for this encryption codec.
287
+ def version_needed_to_extract
288
+ 0x0014
289
+ end
290
+
291
+ # This method signature is part of the interface contract expected by
292
+ # Archive::Zip::Entry for encryption codec objects.
293
+ #
294
+ # Returns an integer representing the general purpose flags of a ZIP archive
295
+ # entry using this encryption codec.
296
+ def general_purpose_flags
297
+ 0b0000000000000001
298
+ end
299
+
300
+ # This method signature is part of the interface contract expected by
301
+ # Archive::Zip::Entry for encryption codec objects.
302
+ #
303
+ # Returns the size of the encryption header in bytes.
304
+ def header_size
305
+ 12
306
+ end
307
+ end
308
+ end; end; end