Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/matsu911/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyshields committed Jan 16, 2015
2 parents 744244d + f61b3e9 commit 71225dc
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 29 deletions.
6 changes: 5 additions & 1 deletion lib/zip/crypto/null_encryption.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ def gp_flags
class NullEncrypter < Encrypter
include NullEncryption

def header(crc32)
def header(mtime)
''
end

def encrypt(data)
data
end

def data_descriptor(crc32, compressed_size, uncomprssed_size)
''
end

def reset!
end
end
Expand Down
13 changes: 9 additions & 4 deletions lib/zip/crypto/traditional_encryption.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def header_bytesize
end

def gp_flags
1
0x0001 | 0x0008
end

protected
Expand Down Expand Up @@ -39,19 +39,24 @@ def decrypt_byte
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

def encrypt(data)
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
Expand Down
3 changes: 1 addition & 2 deletions lib/zip/deflater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def initialize(output_stream, level = Zip.default_compression, encrypter = NullE
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('')
Expand All @@ -19,7 +19,6 @@ def << (data)
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
Expand Down
6 changes: 5 additions & 1 deletion lib/zip/entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def cdir_header_size #:nodoc:all
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).
Expand Down Expand Up @@ -648,6 +648,10 @@ def parse_zip64_extra(for_local_header) #:nodoc:all
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
Expand Down
2 changes: 2 additions & 0 deletions lib/zip/output_stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,12 @@ def copy_raw_entry(entry)

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
Expand Down
4 changes: 1 addition & 3 deletions test/crypto/null_encryption_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ def test_gp_flags
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
Expand Down
37 changes: 19 additions & 18 deletions test/crypto/traditional_encryption_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

class TraditionalEncrypterTest < MiniTest::Test
def setup
@mtime = ::Zip::DOSTime.new(2014, 12, 17, 15, 56, 24)
@encrypter = ::Zip::TraditionalEncrypter.new('password')
end

Expand All @@ -10,36 +11,36 @@ def test_header_bytesize
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
Expand All @@ -55,24 +56,24 @@ def test_header_bytesize
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
Expand Down
Binary file added test/data/zipWithEncryption.zip
Binary file not shown.
33 changes: 33 additions & 0 deletions test/encryption_test.rb
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 71225dc

Please sign in to comment.