in reply to Re: Forge CRCs
in thread Forge CRCs

Many interesting properties indeed, due to the simple mathematical structure of linear feedback shift registers. Basically, you take the bits of the input string to be the coefficients of a polynomial mod 2, and calculate the remainder modulus the CRC polynomial.

You don't have to append to the end to get whatever CRC you want, either. By changing any 4 consecutive bytes, you can set the internal state of the CRC register however you like, as the code below shows. In certain conditions, you can do it with non-consecutive bytes, but it usually takes a little bit of a brute force search.

Once again, you could optimize the "for (1..8)" loops with a lookup table (that's the ordinary way of calculating CRCs). It's easier to see what's happening this way, though.

# the usual crc32 polynomial my $crc_poly = 0xedb88320; my $crc_size = 32; my $initial_str = "foo bar"; my $final_str = "baz blat"; my $desired_crc = 0x12345678; my $magic = forward_crc($initial_str, 0xffffffff) ^ reverse_crc("\0\0\0\0".$final_str, $desired_crc^0xffffffff); my $forged_str = $initial_str . pack("V",$magic) . $final_str; use String::CRC32; printf "%x\n", crc32($forged_str); # calculate an ordinary crc of $string, # given the initial register contents sub forward_crc { my ($str, $reg) = @_; foreach (split //, $str) { $reg ^= ord; for (1..8) { $reg = ($reg & 1) ? ($reg >> 1) ^ $crc_poly : $reg >> 1; } } return $reg; } # forward_crc # given the final register contents, calculate # what the register state was before $str sub reverse_crc { my ($str, $reg) = @_; my $poly = ($crc_poly << 1) ^ 1; my $highbit = 1 << ($crc_size - 1); foreach (reverse split //, $str) { for (1..8) { $reg = ($reg & $highbit) ? ($reg << 1) ^ $poly : $reg << 1; } $reg ^= ord; } return $reg; } # reverse_crc