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
include NullEncryption
def header(crc32)
def header(mtime)
''
end
@ -20,6 +20,10 @@ module Zip
data
end
def data_descriptor(crc32, compressed_size, uncomprssed_size)
''
end
def reset!
end
end

View File

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

View File

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

View File

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

View File

@ -123,10 +123,12 @@ module Zip
def finalize_current_entry
return unless @current_entry
@output_stream << @encrypter.header(@current_entry.mtime)
finish
@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.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 = nil
@compressor = ::Zip::NullCompressor.instance

View File

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

View File

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