File: traditional_encryption.rb

package info (click to toggle)
ruby-zip 3.2.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 11,120 kB
  • sloc: ruby: 9,958; makefile: 23
file content (103 lines) | stat: -rw-r--r-- 2,115 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# frozen_string_literal: true

module Zip
  module TraditionalEncryption # :nodoc:
    def initialize(password)
      @password = password
      reset_keys!
    end

    def header_bytesize
      12
    end

    def gp_flags
      0x0001 | 0x0008
    end

    protected

    def reset_keys!
      @key0 = 0x12345678
      @key1 = 0x23456789
      @key2 = 0x34567890
      @password.each_byte do |byte|
        update_keys(byte.chr)
      end
    end

    def update_keys(num)
      @key0 = ~Zlib.crc32(num, ~@key0)
      @key1 = (((@key1 + (@key0 & 0xff)) * 134_775_813) + 1) & 0xffffffff
      @key2 = ~Zlib.crc32((@key1 >> 24).chr, ~@key2)
    end

    def decrypt_byte
      temp = (@key2 & 0xffff) | 2
      ((temp * (temp ^ 1)) >> 8) & 0xff
    end
  end

  class TraditionalEncrypter < Encrypter # :nodoc:
    include TraditionalEncryption

    def header(mtime)
      [].tap do |header|
        (header_bytesize - 2).times do
          header << Random.rand(0..255)
        end
        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, uncompressed_size)
      [0x08074b50, crc32, compressed_size, uncompressed_size].pack('VVVV')
    end

    def reset!
      reset_keys!
    end

    private

    def encode(num)
      t = decrypt_byte
      update_keys(num.chr)
      t ^ num
    end
  end

  class TraditionalDecrypter < Decrypter # :nodoc:
    include TraditionalEncryption

    def decrypt(data)
      data.unpack('C*').map { |x| decode x }.pack('C*')
    end

    def reset!(header)
      reset_keys!
      header.each_byte do |x|
        decode x
      end
    end

    def check_integrity!(_io); end

    private

    def decode(num)
      num ^= decrypt_byte
      update_keys(num.chr)
      num
    end
  end
end

# Copyright (C) 2002, 2003 Thomas Sondergaard
# rubyzip is free software; you can redistribute it and/or
# modify it under the terms of the ruby license.