Crc32.c
Jump to navigation
Jump to search
#include <stdio.h> #define CRCPOLY 0xEDB88320 #define CRCINV 0x5B358FD3 // inverse poly of (x^N) mod CRCPOLY #define INITXOR 0xFFFFFFFF #define FINALXOR 0xFFFFFFFF typedef unsigned int uint32; /** * Creates the CRC table with 256 32-bit entries. CAUTION: Assumes that * enough space for the resulting table has already been allocated. */ void make_crc_table(uint32 *table) { uint32 c; int n, k; for (n = 0; n < 256; n++) { c = n; for (k = 0; k < 8; k++) { if ((c & 1) != 0) { c = CRCPOLY ^ (c >> 1); } else { c = c >> 1; } } table[n] = c; } } /** * Creates the reverse CRC table with 256 32-bit entries. CAUTION: Assumes * that enough space for the resulting table has already been allocated. */ void make_crc_revtable(uint32 *table) { uint32 c; int n, k; for (n = 0; n < 256; n++) { c = n << 3*8; for (k = 0; k < 8; k++) { if ((c & 0x80000000) != 0) { c = ((c ^ CRCPOLY) << 1) | 1; } else { c <<= 1; } } table[n] = c; } } /** * Computes the CRC32 of the buffer of the given length using the * (slow) bit-oriented approach */ int crc32_bitoriented(unsigned char *buffer, int length) { int i, j; uint32 crcreg = INITXOR; for (j = 0; j < length; ++j) { unsigned char b = buffer[j]; for (i = 0; i < 8; ++i) { if ((crcreg ^ b) & 1) { crcreg = (crcreg >> 1) ^ CRCPOLY; } else { crcreg >>= 1; } b >>= 1; } } return crcreg ^ FINALXOR; } /** * Computes the CRC32 of the buffer of the given length * using the supplied crc_table */ int crc32_tabledriven(unsigned char *buffer, int length, uint32 *crc_table) { int i; uint32 crcreg = INITXOR; for (i = 0; i < length; ++i) { crcreg = (crcreg >> 8) ^ crc_table[((crcreg ^ buffer[i]) & 0xFF)]; } return crcreg ^ FINALXOR; } /** * Changes the last 4 bytes of the given buffer so that it afterwards will * compute to the "magic sequence" (usually 0x2144DF1C for CRC32) */ void fix_crc_magic(unsigned char *buffer, int length, uint32 *crc_table) { int i; // calculate CRC32 except for the last 4 bytes uint32 crcreg = crc32_tabledriven(buffer, length-4, crc_table); // inject crcreg as content - nothing easier than that! for (i = 0; i < 4; ++i) buffer[length - 4 + i] = (crcreg >> i*8) & 0xFF; } /** * Changes the last 4 bytes of the given buffer so that it afterwards will * compute to the given tcrcreg using the given crc_table * * This function uses the method of the multiplication with (x^N)^-1. */ void fix_crc_end(unsigned char *buffer, int length, uint32 tcrcreg, uint32 *crc_table) { int i; tcrcreg ^= FINALXOR; // calculate crc except for the last 4 bytes; this is essentially crc32() uint32 crcreg = INITXOR; for (i = 0; i < length - 4; ++i) { crcreg = (crcreg >> 8) ^ crc_table[((crcreg ^ buffer[i]) & 0xFF)]; } // calculate new content bits // new_content = tcrcreg * CRCINV mod CRCPOLY uint32 new_content = 0; for (i = 0; i < 32; ++i) { // reduce modulo CRCPOLY if (new_content & 1) { new_content = (new_content >> 1) ^ CRCPOLY; } else { new_content >>= 1; } // add CRCINV if corresponding bit of operand is set if (tcrcreg & 1) { new_content ^= CRCINV; } tcrcreg >>= 1; } // finally add old crc new_content ^= crcreg; // inject new content for (i = 0; i < 4; ++i) buffer[length - 4 + i] = (new_content >> i*8) & 0xFF; } /** * Changes the 4 bytes of the given buffer at position fix_pos so that * it afterwards will compute to the given tcrcreg using the given crc_table. * A reversed crc table (crc_revtable) must be provided. */ void fix_crc_pos(unsigned char *buffer, int length, uint32 tcrcreg, int fix_pos, uint32 *crc_table, uint32 *crc_revtable) { int i; // make sure fix_pos is within 0..(length-1) fix_pos = ((fix_pos%length)+length)%length; // calculate crc register at position fix_pos; this is essentially crc32() uint32 crcreg = INITXOR; for (i = 0; i < fix_pos; ++i) { crcreg = (crcreg >> 8) ^ crc_table[((crcreg ^ buffer[i]) & 0xFF)]; } // inject crcreg as content for (i = 0; i < 4; ++i) buffer[fix_pos + i] = (crcreg >> i*8) & 0xFF; // calculate crc backwards to fix_pos, beginning at the end tcrcreg ^= FINALXOR; for (i = length - 1; i >= fix_pos; --i) { tcrcreg = (tcrcreg << 8) ^ crc_revtable[tcrcreg >> 3*8] ^ buffer[i]; } // inject new content for (i = 0; i < 4; ++i) buffer[fix_pos + i] = (tcrcreg >> i*8) & 0xFF; } /** * this function is obsolete as i used it as a testbed */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 void fix_crc_old(unsigned char *buffer, int length, uint32 target_crc, int fix_pos, uint32 *crc_table) { int i, j; fix_pos = ((fix_pos%length)+length)%length; // calculate target crc register on position fix_pos+4 uint32 tcrcreg = (target_crc & 0xFFFFFFFF) ^ FINALXOR; // uint32 tcrcreg = (target_crc & 0xFFFFFFFF) ^ 0x2144DF1C; for (j = length - 1; j > fix_pos + 3; --j) { // printf("fix_crc_old: \ttcrcreg[%d] = %08X\n", j, tcrcreg); unsigned char cbyte = buffer[j]; for (i = 0; i<=7; ++i) { uint32 xor = (tcrcreg >> 31) & 1 ; tcrcreg = ((tcrcreg ^ (xor*CRCPOLY)) << 1) & 0xFFFFFFFF | (xor ^ (cbyte >> 7) & 1); cbyte <<= 1; } } // printf("fix_crc_old: \ttcrcreg[%d] = %08X\n", j, tcrcreg); // calculate positions for XORing the CRCPOLY uint32 xorreg = 0; for (i=0; i<=31; ++i) { xorreg <<= 1; if ((tcrcreg & 0x80000000) != 0) { tcrcreg ^= CRCPOLY; xorreg |= 1; } tcrcreg = (tcrcreg << 1) & 0xFFFFFFFF; } // calculate crc register on position fix_pos uint32 crcreg = crc32_tabledriven(buffer, fix_pos, crc_table); crcreg ^= 0xFFFFFFFFL; printf("fix_crc_old: \tcrcreg = %08X\n", crcreg); // printf("fix_crc: \t*** crcreg = %08X", crcreg); // calculate new content bits uint32 new_content = 0; for (i=0; i<=31; ++i) { new_content >>= 1; new_content |= ((crcreg ^ xorreg) & 1) << 31; crcreg = (crcreg >> 1) ^ ((xorreg & 1) * CRCPOLY); xorreg >>= 1; } // printf(", b = %08X\n", new_content); printf("fix_crc_old: \tnew_content = %08X\n", new_content); // inject new content for (i=0; i<=3; ++i) buffer[fix_pos + i] = (new_content >> i*8) & 0xFF; } #if 0 int main() { int i; uint32 crc_table[256*8]; uint32 crc_revtable[256*8]; unsigned char foostr1[] = "foobar1234"; unsigned char foostr2[] = "foobar1234"; unsigned char foostr3[] = "foobar1234"; unsigned char foostr4[] = "foobar1234"; make_crc_table(crc_table); make_crc_revtable(crc_revtable); unsigned char foostr[] = "bla 1234"; fix_crc_pos(foostr, 8, 0xcafebabe, -4, crc_table, crc_revtable); printf("crc of foostr: %08X\n", crc32_tabledriven(foostr, 8, crc_table)); uint32 targetcrc = 0xdeadbeef; printf("crc of foobar1: %08X\n", crc32_bitoriented(foostr1, 6)); printf("crc of foobar2: %08X\n", crc32_tabledriven(foostr2, 6, crc_table)); printf("crc of foobar3: %08X\n", crc32_tabledriven(foostr3, 6, crc_table)); printf("crc of foobar4: %08X\n", crc32_tabledriven(foostr4, 6, crc_table)); fix_crc_old(foostr1, 10, targetcrc, 3, crc_table); fix_crc_pos(foostr2, 10, targetcrc, 3, crc_table, crc_revtable); fix_crc_end(foostr3, 10, targetcrc, crc_table); fix_crc_magic(foostr4, 10, crc_table); printf("crc after fix old: %08X\n", crc32_tabledriven(foostr1, 10, crc_table)); for (i=0; i<10; ++i) printf("%02X ", foostr1[i]);printf("\n"); printf("crc after fix new: %08X\n", crc32_tabledriven(foostr2, 10, crc_table)); for (i=0; i<10; ++i) printf("%02X ", foostr2[i]);printf("\n"); printf("crc after fix end: %08X\n", crc32_tabledriven(foostr3, 10, crc_table)); for (i=0; i<10; ++i) printf("%02X ", foostr3[i]);printf("\n"); printf("crc after fix magic: %08X\n", crc32_tabledriven(foostr4, 10, crc_table)); for (i=0; i<10; ++i) printf("%02X ", foostr4[i]);printf("\n"); } #endif