Merge remote-tracking branch 'remotes/matsu911/master'

This commit is contained in:
johnnyshields 2015-01-16 13:17:43 +09:00
commit 71225dc628
9 changed files with 75 additions and 29 deletions

View File

@ -12,7 +12,7 @@ module Zip
class NullEncrypter < Encrypter class NullEncrypter < Encrypter
include NullEncryption include NullEncryption
def header(crc32) def header(mtime)
'' ''
end end
@ -20,6 +20,10 @@ module Zip
data data
end end
def data_descriptor(crc32, compressed_size, uncomprssed_size)
''
end
def reset! def reset!
end end
end end

View File

@ -10,7 +10,7 @@ module Zip
end end
def gp_flags def gp_flags
1 0x0001 | 0x0008
end end
protected protected
@ -39,12 +39,13 @@ module Zip
class TraditionalEncrypter < Encrypter class TraditionalEncrypter < Encrypter
include TraditionalEncryption include TraditionalEncryption
def header(crc32) def header(mtime)
[].tap do |header| [].tap do |header|
(header_bytesize - 1).times do (header_bytesize - 2).times do
header << Random.rand(0..255) header << Random.rand(0..255)
end end
header << (crc32 >> 24) header << (mtime.to_binary_dos_time & 0xff)
header << (mtime.to_binary_dos_time >> 8)
end.map{|x| encode x}.pack("C*") end.map{|x| encode x}.pack("C*")
end end
@ -52,6 +53,10 @@ module Zip
data.unpack("C*").map{|x| encode x}.pack("C*") data.unpack("C*").map{|x| encode x}.pack("C*")
end end
def data_descriptor(crc32, compressed_size, uncomprssed_size)
[0x08074b50, crc32, compressed_size, uncomprssed_size].pack("VVVV")
end
def reset! def reset!
reset_keys! reset_keys!
end end

View File

@ -5,7 +5,7 @@ module Zip
super() super()
@output_stream = output_stream @output_stream = output_stream
@zlib_deflater = ::Zlib::Deflate.new(level, -::Zlib::MAX_WBITS) @zlib_deflater = ::Zlib::Deflate.new(level, -::Zlib::MAX_WBITS)
@size = encrypter.header_bytesize @size = 0
@crc = ::Zlib.crc32 @crc = ::Zlib.crc32
@encrypter = encrypter @encrypter = encrypter
@buffer_stream = ::StringIO.new('') @buffer_stream = ::StringIO.new('')
@ -19,7 +19,6 @@ module Zip
end end
def finish def finish
@output_stream << @encrypter.header(@crc)
@output_stream << @encrypter.encrypt(@buffer_stream.string) @output_stream << @encrypter.encrypt(@buffer_stream.string)
@output_stream << @encrypter.encrypt(@zlib_deflater.finish) until @zlib_deflater.finished? @output_stream << @encrypter.encrypt(@zlib_deflater.finish) until @zlib_deflater.finished?
end end

View File

@ -143,7 +143,7 @@ module Zip
end end
def next_header_offset #:nodoc:all def next_header_offset #:nodoc:all
local_entry_offset + self.compressed_size local_entry_offset + self.compressed_size + data_descriptor_size
end end
# Extracts entry to file dest_path (defaults to @name). # Extracts entry to file dest_path (defaults to @name).
@ -648,6 +648,10 @@ module Zip
end end
end end
def data_descriptor_size
(@gp_flags & 0x0008) > 0 ? 16 : 0
end
# create a zip64 extra information field if we need one # create a zip64 extra information field if we need one
def prep_zip64_extra(for_local_header) #:nodoc:all def prep_zip64_extra(for_local_header) #:nodoc:all
return unless ::Zip.write_zip64_support return unless ::Zip.write_zip64_support

View File

@ -123,10 +123,12 @@ module Zip
def finalize_current_entry def finalize_current_entry
return unless @current_entry return unless @current_entry
@output_stream << @encrypter.header(@current_entry.mtime)
finish finish
@current_entry.compressed_size = @output_stream.tell - @current_entry.local_header_offset - @current_entry.calculate_local_header_size @current_entry.compressed_size = @output_stream.tell - @current_entry.local_header_offset - @current_entry.calculate_local_header_size
@current_entry.size = @compressor.size @current_entry.size = @compressor.size
@current_entry.crc = @compressor.crc @current_entry.crc = @compressor.crc
@output_stream << @encrypter.data_descriptor(@current_entry.crc, @current_entry.compressed_size, @current_entry.size)
@current_entry.gp_flags |= @encrypter.gp_flags @current_entry.gp_flags |= @encrypter.gp_flags
@current_entry = nil @current_entry = nil
@compressor = ::Zip::NullCompressor.instance @compressor = ::Zip::NullCompressor.instance

View File

@ -14,9 +14,7 @@ class NullEncrypterTest < MiniTest::Test
end end
def test_header def test_header
[nil, '', 'a' * 10, 0xffffffff].each do |arg| assert_empty @encrypter.header(nil)
assert_empty @encrypter.header(arg)
end
end end
def test_encrypt def test_encrypt

View File

@ -2,6 +2,7 @@ require 'test_helper'
class TraditionalEncrypterTest < MiniTest::Test class TraditionalEncrypterTest < MiniTest::Test
def setup def setup
@mtime = ::Zip::DOSTime.new(2014, 12, 17, 15, 56, 24)
@encrypter = ::Zip::TraditionalEncrypter.new('password') @encrypter = ::Zip::TraditionalEncrypter.new('password')
end end
@ -10,36 +11,36 @@ class TraditionalEncrypterTest < MiniTest::Test
end end
def test_gp_flags def test_gp_flags
assert_equal 1, @encrypter.gp_flags assert_equal 9, @encrypter.gp_flags
end end
def test_header def test_header
@encrypter.reset! @encrypter.reset!
exepected = [239, 57, 234, 154, 246, 80, 83, 221, 74, 200, 116, 154].pack("C*") exepected = [239, 57, 234, 154, 246, 80, 83, 221, 74, 200, 121, 91].pack("C*")
Random.stub(:rand, 1) do Random.stub(:rand, 1) do
assert_equal exepected, @encrypter.header(0xffffffff) assert_equal exepected, @encrypter.header(@mtime)
end end
end end
def test_encrypt def test_encrypt
@encrypter.reset! @encrypter.reset!
Random.stub(:rand, 1) { @encrypter.header(0xffffffff) } Random.stub(:rand, 1) { @encrypter.header(@mtime) }
assert_raises(NoMethodError) { @encrypter.encrypt(nil) } assert_raises(NoMethodError) { @encrypter.encrypt(nil) }
assert_raises(NoMethodError) { @encrypter.encrypt(1) } assert_raises(NoMethodError) { @encrypter.encrypt(1) }
assert_equal '', @encrypter.encrypt('') assert_equal '', @encrypter.encrypt('')
assert_equal [2, 25, 13, 222, 17, 190, 250, 133, 133, 166].pack("C*"), @encrypter.encrypt('a' * 10) assert_equal [100, 218, 7, 114, 226, 82, 62, 93, 224, 62].pack("C*"), @encrypter.encrypt('a' * 10)
end end
def test_reset! def test_reset!
@encrypter.reset! @encrypter.reset!
Random.stub(:rand, 1) { @encrypter.header(0xffffffff) } Random.stub(:rand, 1) { @encrypter.header(@mtime) }
[2, 25, 13, 222, 17, 190, 250, 133, 133, 166].map(&:chr).each do |c| [100, 218, 7, 114, 226, 82, 62, 93, 224, 62].map(&:chr).each do |c|
assert_equal c, @encrypter.encrypt('a') assert_equal c, @encrypter.encrypt('a')
end end
assert_equal 134.chr, @encrypter.encrypt('a') assert_equal 56.chr, @encrypter.encrypt('a')
@encrypter.reset! @encrypter.reset!
Random.stub(:rand, 1) { @encrypter.header(0xffffffff) } Random.stub(:rand, 1) { @encrypter.header(@mtime) }
[2, 25, 13, 222, 17, 190, 250, 133, 133, 166].map(&:chr).each do |c| [100, 218, 7, 114, 226, 82, 62, 93, 224, 62].map(&:chr).each do |c|
assert_equal c, @encrypter.encrypt('a') assert_equal c, @encrypter.encrypt('a')
end end
end end
@ -55,24 +56,24 @@ class TraditionalDecrypterTest < MiniTest::Test
end end
def test_gp_flags def test_gp_flags
assert_equal 1, @decrypter.gp_flags assert_equal 9, @decrypter.gp_flags
end end
def test_decrypt def test_decrypt
@decrypter.reset!([239, 57, 234, 154, 246, 80, 83, 221, 74, 200, 116, 154].pack("C*")) @decrypter.reset!([239, 57, 234, 154, 246, 80, 83, 221, 74, 200, 121, 91].pack("C*"))
[2, 25, 13, 222, 17, 190, 250, 133, 133, 166].map(&:chr).each do |c| [100, 218, 7, 114, 226, 82, 62, 93, 224, 62].map(&:chr).each do |c|
assert_equal 'a', @decrypter.decrypt(c) assert_equal 'a', @decrypter.decrypt(c)
end end
end end
def test_reset! def test_reset!
@decrypter.reset!([239, 57, 234, 154, 246, 80, 83, 221, 74, 200, 116, 154].pack("C*")) @decrypter.reset!([239, 57, 234, 154, 246, 80, 83, 221, 74, 200, 121, 91].pack("C*"))
[2, 25, 13, 222, 17, 190, 250, 133, 133, 166].map(&:chr).each do |c| [100, 218, 7, 114, 226, 82, 62, 93, 224, 62].map(&:chr).each do |c|
assert_equal 'a', @decrypter.decrypt(c) assert_equal 'a', @decrypter.decrypt(c)
end end
assert_equal 229.chr, @decrypter.decrypt(2.chr) assert_equal 91.chr, @decrypter.decrypt(2.chr)
@decrypter.reset!([239, 57, 234, 154, 246, 80, 83, 221, 74, 200, 116, 154].pack("C*")) @decrypter.reset!([239, 57, 234, 154, 246, 80, 83, 221, 74, 200, 121, 91].pack("C*"))
[2, 25, 13, 222, 17, 190, 250, 133, 133, 166].map(&:chr).each do |c| [100, 218, 7, 114, 226, 82, 62, 93, 224, 62].map(&:chr).each do |c|
assert_equal 'a', @decrypter.decrypt(c) assert_equal 'a', @decrypter.decrypt(c)
end end
end end

Binary file not shown.

33
test/encryption_test.rb Normal file
View File

@ -0,0 +1,33 @@
require 'test_helper'
class EncryptionTest < MiniTest::Test
ENCRYPT_ZIP_TEST_FILE = 'test/data/zipWithEncryption.zip'
INPUT_FILE1 = 'test/data/file1.txt'
def test_encrypt
test_file = open(ENCRYPT_ZIP_TEST_FILE, 'rb').read
@rand = [250, 143, 107, 13, 143, 22, 155, 75, 228, 150, 12]
@output = ::Zip::DOSTime.stub(:now, ::Zip::DOSTime.new(2014, 12, 17, 15, 56, 24)) do
Random.stub(:rand, lambda { |range| @rand.shift }) do
Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |zos|
zos.put_next_entry('file1.txt')
zos.write open(INPUT_FILE1).read
end.string
end
end
@output.unpack("C*").each_with_index do |c, i|
assert_equal test_file[i].ord, c
end
end
def test_decrypt
Zip::InputStream.open(ENCRYPT_ZIP_TEST_FILE, 0, Zip::TraditionalDecrypter.new('password')) do |zis|
entry = zis.get_next_entry
assert_equal 'file1.txt', entry.name
assert_equal 1327, entry.size
assert_equal open(INPUT_FILE1, 'r').read, zis.read
end
end
end