• ベストアンサー
  • すぐに回答を!

CRC32の計算方法

ZIPファイルを作るときにCRC32を算出すると思うのですが、 CRC32の計算方法を教えてください。 よろしくお願いします。

共感・応援の気持ちを伝えよう!

質問者が選んだベストアンサー

  • ベストアンサー
  • 回答No.2
  • ore100
  • ベストアンサー率54% (34/62)

CRCとは巡回冗長検査(じゅんかい・じょうちょう・けんさ)という誤りを検出する方法の1つです。 その他ハッシュ・キーを計算するハッシュ関数としても使うことが出来ます。 今回のCRCは32ビット幅で生成多項式に X32 + X26 + X23 + X22 + X16 + X12 + X11 + X10 + X8 + X7 + X5 + X4 + X2 + X1 + 1 を利用します。 この生成多項式は CRC32 で使われているものです。 1.CRCタイプ (1)CRCタイプ(CRC32) (2)生成多項式(0x04C11DB7) (3)初期値(0xFFFFFFFF) (4)出力XOR(0xFFFFFFFF) (5)入力ビット逆転(なし) (6)出力ビット逆転(なし) (7)ビット送り(左送り) // サンプル #include <stdio.h> #include <string.h> #include <limits.h> // CHAR_BIT // CRC32のテーブル情報 static unsigned long CRC32Table[ 256 ] = { 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4, }; // メモリのCRC32コードを計算 extern unsigned long getMemCRC32( unsigned long crc32, unsigned const char buff[], size_t size ) { while ( size != 0 ){ crc32 = CRC32Table[ (crc32 >> (32 - CHAR_BIT)) ^ *buff ] ^ (crc32 << CHAR_BIT); buff++; size--; } return crc32; } // ファイルのCRC32コードを計算 extern unsigned long getFileCRC32( const char file[] ) { unsigned long crc32 = 0xFFFFFFFF; char buff[ 10 * 1024 ]; size_t size; FILE *fp; if ( (fp = fopen(file,"rb")) != NULL ){ do { size = fread( buff, 1, sizeof(buff), fp ); crc32 = getMemCRC32( crc32, (unsigned const char *)buff, size ); } while ( size != 0 ); fclose( fp ); } return crc32 ^ 0xFFFFFFFF; } // メイン関数 int main( void ) { char file[ 256 ]; char *find; while ( fgets(file,sizeof(file),stdin) != NULL ){ if ( (find = strchr(file,'\n')) != NULL ){ *find = '\0'; } printf( "0x%08lX⇒%s\n", getFileCRC32(file), file ); } return 0; } 試し方: ファイル名をフルパスで入力します。 またはパイプやリダイレクションを利用して入力させます。 出力は32ビットの16進8桁とフルパス名が標準出力に表示されます。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

わかりやすい解説ありがとうございました!

その他の回答 (1)

  • 回答No.1
  • php504
  • ベストアンサー率42% (926/2160)

私的ZIPファイル研究所 http://www.tnksoft.com/reading/zipfile/nonarc.php にCのソースがあります

共感・感謝の気持ちを伝えよう!

関連するQ&A

  • CRCについて

    CRCの算出についてなのですが http://www2c.biglobe.ne.jp/~osakana/vc/pc/crc.html こちらのサイトを参考にすると 1. データを一つ(1バイト)とってきます 2. CRC値を左ビットシフトして、桁上がりがあればさらに生成多項式とXORを取ります 3. データを左ビットシフトして、桁上がりがあればCRC値と1のXORを取ります 4. あと7回(1バイト=8ビットなので)2と3を繰り返します 5. 残りのデータがあれば1に戻ります とあります。 例えばアドレス部00000000にデータ01が入っているもの(ファイルサイズ1バイト)を算出しようとした場合 手計算を行うとCRC16は0001、CRC32は00000001になりそうなのですが いくつかのフリーソフトで実際にバイナリエディタを用いて1バイトのファイルを作成し、試して見たところ CRC16が1E0E CRC32がA505DF1B と出ます。 一般的な算出方法では、上記の説明以外に何か別の処理、初期値などがあるのでしょうか? お分かりになる方是非教えてください。 よろしくお願いします。

  • CRC計算方法

    CRCの生成多項式によるmodulo2計算等については一通り調べて理解したつもりですが、実装するとなるとどうしたものかと止まってしまいます。 実装の要求が 「何バイトあるか不明なデータのCRCを計算する」 (CRC-16にて) です。 どなたかお知恵を拝借できないものでしょうか。

  • CRC8 ATMの計算方法

    CRC8 ATMの演算を行うツールの検証を行っているのですが、 CRCの机上計算方法を詳しく解説したサイトが無く生成多項式で 割って余りを求めると言う事しかわかりませんでした。 CRCを求める際はCRCの初期値も重要な筈ですが、CRCの初期値は 余りを求める際にどの様に使うのかを開設した物がなく、私に 検証を依頼してきた人に聞いてもまともな回答をもらえません でした(検証を依頼してきた人もちゃんと理解していない?)。 このサイトの別の質問の回答で 1. 与えられたデータの下位 (ビット送りの反対側) に「初期値」   を付加する 2. 生成多項式で割って余りを求める とあったので、その通りに計算しましたが初期値が0x00の時は ツールと机上計算の結果が一致するのですが、初期値0xFFの時は ツールと机上計算の結果が一致しませんでした。 実際の計算過程と結果は下記です。 生成多項式:x8+x2+x1+1(9'b100000111) 入力データ:0x12345678 CRC初期値:0x00 データ左送り、入出力反転なし 机上計算 初期値:0001001000110100010101100111100000000000(0x1234567800) 100000111 ---------------------------------------- 0001001000100010101100111100000000000 100000111 ---------------------------------------- 0001001010010101100111100000000000 100000111 ---------------------------------------- 0001011100101100111100000000000 100000111 ---------------------------------------- 0011101011100111100000000000 100000111 ---------------------------------------- 01101000000111100000000000 100000111 ---------------------------------------- 0101001110111100000000000 100000111 ---------------------------------------- 001001001111100000000000 100000111 ---------------------------------------- 0001000001100000000000 100000111 ---------------------------------------- 0000000010000000000 100000111 ---------------------------------------- 00000011100 なのでCRC(余り)は0x1C(00011100)でツールの結果0x1Cと一致。 CRC初期値:0xFF 机上計算 初期値:0001001000110100010101100111100011111111(0x12345678FF) 100000111 ---------------------------------------- 0001001000100010101100111100011111111 100000111 ---------------------------------------- 0001001010010101100111100011111111 100000111 ---------------------------------------- 0001011100101100111100011111111 100000111 ---------------------------------------- 0011101011100111100011111111 100000111 ---------------------------------------- 01101000000111100011111111 100000111 ---------------------------------------- 0101001110111100011111111 100000111 ---------------------------------------- 001001001111100011111111 100000111 ---------------------------------------- 0001000001100011111111 100000111 ---------------------------------------- 0000000010011111111 100000111 ---------------------------------------- 00011100011 なのでCRC(余り)は0xE3(11100011)でツールの結果0xCDと不一致 となりました。 これは計算の仕方が間違っているのでしょうか? それともツールの結果が間違っているのでしょうか? 何方かCRCの計算に詳しい人、ご回答をお願いします。

  • CRCの計算方法について

    色々なサイトを参考にして、自分なりにCRC-ITU-TでCRCを計算する関数を作成しました。 いまいち理解が浅く、そのCRCの値が正しいのか判断できずに困っています。 以下にソースを載せます。 アドバイスを、どうかよろしくお願いします。 unsigned short Crc(unsigned char *Data, unsigned long num) {   unsigned short vCrc;    //CRCを計算する変数   unsigned char vData;   unsigned long i;   int j;   vCrc = 0;   vData = 0;   //初期化   for(i = 0; i <= num; i++){     vData = *(Data+i);   //1byte読み込み     for(j = 0; j < 8; j++){       //CRC計算変数がシフトで桁あふれする場合       if((vCrc & 0x8000) != 0){         vCrc = vCrc << 1;   //1bitシフト         vCrc = vCrc ^ 0x1021;  //多項式とXOR       }       else{         vCrc = vCrc << 1;       }       if((vData & 0x80) != 0){         vData = vData << 1;   //データ変数1bitシフト                 vCrc = vCrc ^ 0x0001;  //CRC計算変数に1をXOR       }       else{         vData = vData << 1;       }     }   }   return(vCrc); }

  • CRC16計算について

    CRC16のプログラムを作ったのでデバッグしていて気付いた事なのですが (産業装置で使うMODBUS-RTUのソフト) CRC16 x16+x15+x2+1 生成多項式 0xA001 CRC16でCRCを含めたデータを再CRCするとゼロになると言われておりますが そうならないのですが何故でしょう? もちろん、自分の作ったソフトが信用できないので他ソフトで検証 具体例 ベクターにあるCRC16の計算ソフト - CRC16.exe http://blog.goo.ne.jp/masaki_goo_2006/e/50b20edb79f60964faeaefe6fa064469 これに文字列"ABCD" [0x4142,0x4344]を入れて計算実行 出力結果  初期値:0xFFFF、出力XOR:0xFFFF、出力結果、右送り0x0F85 この出力を最初の文字列に追加する 0x4142,0x4344,0x0F85 結果は0xc7e6 となってゼロになりません やりかたが違うのでしょうか? 尚、私の作ったプログラムと上記ソフトの結果が同じです また、ネット上にある同様な他ソフトでも同じ結果でした (もちろんCRC計算条件が同じ物) 尚、上記ソフトで 初期値:0x0000、出力XOR:0x0000、左送り:9AA8 この場合のみCRC追加しての再CRCはゼロになりました ゼロになる場合とならない場合があるのでしょうか?

  • crcを計算してくれるモジュール

    こんにちは。 perlのモジュールでcrcを計算してくれるモジュールを探しています。 perlで直接計算する方法はわかるのですが、いくらかでも高速化できるかと思い、探しているのですが、みつかりません。 どなたかご存知ないでしょうか? よろしくお願いします。

  • CRC5(X^5+X^3+1)の計算方法

    どなたか、CRC5(X^5+X^3+1)の計算方法を知ってらっしゃる方がおられれば、ご教授下さい。 # サンプルコードつきだと、なお嬉しいのですが CRC5について詳しく解説してくれてるサイトでも結構です。(英文可) どうぞよろしくお願い致します。

  • CRCの計算でエラー

    VisualC++2008でプログラミングしております。簡単なモデムプログラムを作っているのですが、エラー検出で利用するCRCでつまづいています。具体的には、特定のファイルを送信しようとすると常にエラーが発生したと判断され、再送要求をし続けてしまいます。 以前、チェックサムでXORを利用した時も同様なことが発生したので、XORの計算があやしいのかなと感じています。デバッグでは正しく計算されるようなのですが、リリースで実行すると上記のようになります。 どなたかアドバイスを頂ければと思います。よろしくお願いします。

  • CRC

    .rarファイルをダウンロードしたのですがCRCが一致しないらしく解凍できません。どうにかして解凍する方法はありませんか?

  • CRC32

    CRC32について CRC32の数値を変えずにファイルの一部を変更することは可能ですか?