2015-11-24 11:28:25 +00:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
|
|
|
# Copyright 2013 StalkR <github-misc@stalkr.net>
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# 2015-01-28, Thomas Kindler <mail@t-kindler.de>:
|
|
|
|
#
|
|
|
|
# * Taken from github, added copyright header. See:
|
|
|
|
# https://github.com/StalkR/misc/blob/master/crypto/crc32.py
|
|
|
|
# http://blog.stalkr.net/2011/03/crc-32-forging.html
|
|
|
|
#
|
|
|
|
# * Changed forge() semantics to /change/ the bytes at pos instead of
|
|
|
|
# inserting there. Also return the forged CRC instead of changed data.
|
|
|
|
#
|
|
|
|
#
|
|
|
|
|
2016-01-07 23:28:59 +00:00
|
|
|
|
|
|
|
#https://code.google.com/p/tweakcrc/
|
|
|
|
#http://blog.stalkr.net/2011/03/crc-32-forging.html
|
|
|
|
|
|
|
|
|
2015-11-24 11:28:25 +00:00
|
|
|
"""Calculate and manipulate CRC32.
|
|
|
|
http://en.wikipedia.org/wiki/Cyclic_redundancy_check
|
|
|
|
-- StalkR
|
|
|
|
"""
|
|
|
|
import struct
|
|
|
|
import sys
|
|
|
|
|
|
|
|
# Polynoms in reversed notation
|
|
|
|
POLYNOMS = {
|
2016-01-07 23:28:59 +00:00
|
|
|
'CRC-32-IEEE': 0x04C11DB7, # 802.3
|
2015-11-24 11:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class Error(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class CRC32(object):
|
|
|
|
"""A class to calculate and manipulate CRC32.
|
2016-01-07 23:28:59 +00:00
|
|
|
|
2015-11-24 11:28:25 +00:00
|
|
|
Use one instance per type of polynom you want to use.
|
|
|
|
Use calc() to calculate a crc32.
|
|
|
|
Use forge() to forge crc32 by adding 4 bytes anywhere.
|
|
|
|
"""
|
|
|
|
def __init__(self, type="CRC-32-IEEE"):
|
|
|
|
if type not in POLYNOMS:
|
|
|
|
raise Error("Unknown polynom. %s" % type)
|
|
|
|
self.polynom = POLYNOMS[type]
|
2016-01-07 23:28:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
def calc_next(self, crc, data):
|
|
|
|
crc = crc ^ data
|
|
|
|
for i in range(32):
|
|
|
|
if (crc & 0x80000000):
|
|
|
|
crc = (crc << 1) ^ self.polynom
|
|
|
|
else:
|
|
|
|
crc = (crc << 1)
|
|
|
|
return crc & 0xffffffff
|
|
|
|
|
|
|
|
def calc_rev(self, crc, data):
|
|
|
|
for i in range(32):
|
|
|
|
if (crc & 1):
|
|
|
|
crc = ((crc ^ self.polynom) >> 1) | 0x80000000
|
|
|
|
else:
|
|
|
|
crc = crc >> 1
|
|
|
|
crc = crc ^ data
|
|
|
|
return crc
|
2015-11-24 11:28:25 +00:00
|
|
|
|
|
|
|
def calc(self, s):
|
2016-01-07 23:28:59 +00:00
|
|
|
"""Calculate crc32 of a string."""
|
|
|
|
|
2015-11-24 11:28:25 +00:00
|
|
|
crc = 0xffffffff
|
2016-01-07 23:28:59 +00:00
|
|
|
for i in range(0, len(s), 4):
|
|
|
|
c = struct.unpack('<L', s[i:i + 4])[0]
|
|
|
|
crc = self.calc_next(crc, c)
|
|
|
|
|
|
|
|
return crc
|
|
|
|
|
|
|
|
def rcalc(self, s, wanna_crc):
|
|
|
|
crc = wanna_crc
|
|
|
|
for i in range(len(s) - 4, -4, -4): # go from last byte to 0
|
|
|
|
c = struct.unpack('<L', s[i:i + 4])[0]
|
|
|
|
crc = self.calc_rev(crc, c)
|
|
|
|
return crc
|
2015-11-24 11:28:25 +00:00
|
|
|
|
|
|
|
def forge(self, wanted_crc, s, pos):
|
|
|
|
"""Forge crc32 of a string by changing 4 bytes at position pos."""
|
2016-01-07 23:28:59 +00:00
|
|
|
|
2015-11-24 11:28:25 +00:00
|
|
|
# forward calculation of CRC up to pos, sets current forward CRC state
|
2016-01-07 23:28:59 +00:00
|
|
|
fwd_crc = self.calc(s[:pos])
|
|
|
|
|
2015-11-24 11:28:25 +00:00
|
|
|
# backward calculation of CRC up to pos, sets wanted backward CRC state
|
2016-01-07 23:28:59 +00:00
|
|
|
bkd_crc = wanted_crc
|
|
|
|
for i in range(len(s) - 4, pos, -4): # go from last byte to pos + 4
|
|
|
|
c = struct.unpack('<L', s[i:i + 4])[0]
|
|
|
|
bkd_crc = self.calc_rev(bkd_crc, c)
|
|
|
|
|
2015-11-24 11:28:25 +00:00
|
|
|
# deduce the 4 bytes we need to insert
|
2016-01-07 23:28:59 +00:00
|
|
|
bkd_crc = self.calc_rev(bkd_crc, 0) # xor 0 to ignore data
|
|
|
|
bkd_crc = bkd_crc ^ fwd_crc
|
|
|
|
|
|
|
|
|
|
|
|
# test result
|
2015-11-24 11:28:25 +00:00
|
|
|
assert(self.calc(s[:pos] + struct.pack('<L', bkd_crc) + s[pos+4:]) == wanted_crc)
|
2016-01-07 23:28:59 +00:00
|
|
|
|
2015-11-24 11:28:25 +00:00
|
|
|
return bkd_crc
|
|
|
|
|
|
|
|
|
|
|
|
if __name__=='__main__':
|
|
|
|
if len(sys.argv) > 1:
|
|
|
|
arg = sys.argv[1]
|
|
|
|
else:
|
2016-01-07 23:28:59 +00:00
|
|
|
arg = "\x12\x34\x56\x78"
|
|
|
|
check = "\xdf\x8a\x8a\x2b"
|
|
|
|
|
2015-11-24 11:28:25 +00:00
|
|
|
# CRC32 with default polynom
|
2016-01-07 23:28:59 +00:00
|
|
|
crc = CRC32().calc(arg[::-1])
|
|
|
|
print "CRC32(%s) = 0x%08x" % (repr(arg), crc)
|
|
|
|
assert(struct.pack('<L', crc) == check[::-1])
|
|
|
|
|
|
|
|
rcrc = CRC32().rcalc(arg[::-1], crc)
|
|
|
|
print "RCRC32(%s, 0x%08x) = 0x%08x" % (repr(arg), crc, rcrc)
|
|
|
|
assert(rcrc == 0xffffffff)
|
|
|
|
|
|
|
|
|