Untangle encryption and decompression

This commit is contained in:
Jan-Joost Spanjers 2019-12-21 11:02:01 +01:00
parent 8f7c5caf29
commit 4e28f7286c
5 changed files with 45 additions and 5 deletions

View File

@ -21,6 +21,7 @@ require 'zip/null_compressor'
require 'zip/null_input_stream'
require 'zip/pass_thru_compressor'
require 'zip/pass_thru_decompressor'
require 'zip/crypto/decrypted_io'
require 'zip/crypto/encryption'
require 'zip/crypto/null_encryption'
require 'zip/crypto/traditional_encryption'

View File

@ -0,0 +1,39 @@
module Zip
class DecryptedIo #:nodoc:all
CHUNK_SIZE = 32_768
def initialize(io, decrypter)
@io = io
@decrypter = decrypter
end
def read(length = nil, outbuf = '')
return ((length.nil? || length.zero?) ? "" : nil) if eof
while length.nil? || (buffer.bytesize < length)
break if input_finished?
buffer << produce_input
end
outbuf.replace(buffer.slice!(0...(length || output_buffer.bytesize)))
end
private
def eof
buffer.empty? && input_finished?
end
def buffer
@buffer ||= ''.dup
end
def input_finished?
@io.eof
end
def produce_input
@decrypter.decrypt(@io.read(CHUNK_SIZE))
end
end
end

View File

@ -49,7 +49,7 @@ module Zip
MAX_SEGMENT_SIZE = 3_221_225_472
MIN_SEGMENT_SIZE = 65_536
DATA_BUFFER_SIZE = 8192
IO_METHODS = [:tell, :seek, :read, :close]
IO_METHODS = [:tell, :seek, :read, :eof, :close]
DEFAULT_OPTIONS = {
restore_ownership: false,

View File

@ -1,11 +1,10 @@
module Zip
class Inflater < Decompressor #:nodoc:all
def initialize(input_stream, decrypter = NullDecrypter.new)
def initialize(input_stream)
super(input_stream)
@zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
@output_buffer = ''.dup
@has_returned_empty_string = false
@decrypter = decrypter
end
def sysread(number_of_bytes = nil, buf = '')
@ -30,7 +29,7 @@ module Zip
def internal_produce_input(buf = '')
retried = 0
begin
@zlib_inflater.inflate(@decrypter.decrypt(@input_stream.read(Decompressor::CHUNK_SIZE, buf)))
@zlib_inflater.inflate(@input_stream.read(Decompressor::CHUNK_SIZE, buf))
rescue Zlib::BufError
raise if retried >= 5 # how many times should we retry?
retried += 1

View File

@ -147,7 +147,8 @@ module Zip
elsif @current_entry.compression_method == ::Zip::Entry::DEFLATED
header = @archive_io.read(@decrypter.header_bytesize)
@decrypter.reset!(header)
::Zip::Inflater.new(@archive_io, @decrypter)
decrypted_io = ::Zip::DecryptedIo.new(@archive_io, @decrypter)
::Zip::Inflater.new(decrypted_io)
else
raise ::Zip::CompressionMethodError,
"Unsupported compression method #{@current_entry.compression_method}"