Module: MPQ::Hashing
- Defined in:
- lib/mpq.rb
Overview
Various hashes are used throughout MPQ archives.
Class Method Summary collapse
-
.decrypt(data, seed1) ⇒ Object
Data in the hash and block tables can be decrypted using this algorithm.
-
.hash_for(hash_type, s) ⇒ Object
The algorithm is unchanged across hash types, but the first step in the hashing differs depending on what we’re hashing.
Class Method Details
.decrypt(data, seed1) ⇒ Object
Data in the hash and block tables can be decrypted using this algorithm.
135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/mpq.rb', line 135 def self.decrypt data, seed1 seed2 = 0xEEEEEEEE data.unpack('V*').map do |value| # Again, the `AND`s here forces 32-bit precision. seed2 = (seed2 + @encryption_table[0x400 + (seed1 & 0xFF)]) & 0xFFFFFFFF value = (value ^ (seed1 + seed2)) & 0xFFFFFFFF seed1 = (((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B)) & 0xFFFFFFFF seed2 = (value + seed2 + (seed2 << 5) + 3) & 0xFFFFFFFF value end.pack('V*') end |
.hash_for(hash_type, s) ⇒ Object
The algorithm is unchanged across hash types, but the first step in the hashing differs depending on what we’re hashing.
Both this hashing and the decryption below make use of a precalculated table of values.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/mpq.rb', line 119 def self.hash_for hash_type, s hash_type = [:table_offset, :hash_a, :hash_b, :table].index hash_type seed1, seed2 = 0x7FED7FED, 0xEEEEEEEE s.upcase.each_byte do |c| value = @encryption_table[(hash_type << 8) + c] # The seemingly pointless `AND`ing by 32 ones is because Ruby's numbers # are arbitrary precision. Normally that's great, but right now that's # actually unhelpful. seed1 = (value ^ (seed1 + seed2)) & 0xFFFFFFFF seed2 = (c + seed1 + seed2 + (seed2 << 5) + 3) & 0xFFFFFFFF end seed1 end |