チェックサム
データの誤り検出のために計算される値。データ転送やファイル保存時の整合性確認に使われる。
チェックサムとは、データの整合性を検証するために計算される固定長の値です。送信元と受信先でチェックサムを比較することで、データが転送中に破損していないかを確認できます。原理はシンプルで、データ全体を特定のアルゴリズムで処理し、短い「指紋」のような値を生成するものです。
代表的な方式には CRC (巡回冗長検査)、Adler-32、MD5、SHA-256 などがあります。CRC-32 は 32 ビットの検査値を生成し、Ethernet フレームの検査列や ZIP アーカイブで使われています。Adler-32 は zlib の仕様 (RFC 1950) で定義された方式で、バイトごとの 2 つの和を 65521 (65536 より小さい最大の素数) で割った余りとして計算します。同 RFC は、この方式が CRC-32 より大幅に高速でありながら誤りを見逃す確率は極めて低いと述べています。MD5 は 128 ビット (16 進数 32 文字) のダイジェストを生成しますが、IETF の RFC 6151 (2011 年) は、電子署名のように衝突耐性が必要な用途で MD5 はもはや受け入れられないとし、当時の 2.6 GHz デスクトップ CPU では 10 秒程度、1.6 GHz のノート PC でも 1 分以内で衝突を見つけられる報告を挙げています。改ざん検出を目的とするなら SHA-256 を選びます。
実務でもっとも身近な使い方は、配布ファイルの検証です。コマンドラインでは sha256sum (Linux)、shasum -a 256 (macOS)、certutil -hashfile ファイル名 SHA256 または Get-FileHash (Windows) で計算できます。ここで落とし穴になるのが、チェックサムの入手経路です。配布ファイルと同じページに並べて置かれた値を照合しても、そのページごと差し替えられていれば両方が一致してしまい、改ざんは検出できません。電子署名付きのチェックサムファイルを使うか、値だけは別の経路で確認する、というのが検証の前提条件です。照合は目視で先頭数文字を見るのではなく、sha256sum -c ファイル名.sha256 のように機械的に突き合わせます。
チェックサムとハッシュ値は混同されがちですが、厳密には目的が異なります。チェックサムは偶発的なデータ破損の検出を主目的とし、ハッシュ値は意図的な改ざんの検出やデータの一意識別を目的とします。この違いは方式選定に直結します。CRC-32 は計算が単純なため、検査値を狙った値に合わせたままデータを書き換えるのが容易で、改ざん検出には使えません。転送中のビット化けを見つけたいのか、第三者による書き換えを見つけたいのかで、CRC 系と暗号学的ハッシュ関数を使い分けます。実務では SHA-256 をチェックサムと呼ぶ場面も多く、呼び方の上では両者の境界は曖昧です。
テキストデータのチェックサムを計算するときは、見た目が同じでもバイト列が違えば値が変わる、という点に注意が必要です。同じ文字列でも UTF-8 と Shift_JIS ではバイト列が異なり、改行コードが LF か CRLF かでも、行頭の BOM の有無でも、末尾に改行が 1 つあるかどうかでも別の値になります。Git がチェックアウト時に改行コードを変換する設定になっていると、同じコミットから取り出したファイルでも環境間でチェックサムが一致しません。文字列としての同一性を比べたいのであれば、符号化方式・改行コード・BOM をそろえた形に正規化してから計算します。
文字数の観点では、チェックサムの文字列長はアルゴリズムごとに固定です。16 進数で表したとき CRC-32 は 8 文字、MD5 は 32 文字、SHA-256 は 64 文字になります。入力が 1 バイトでも 10 ギガバイトでも出力長が変わらないため、データベースの列は CHAR(64) のような固定長で設計できます。ただし CRC-32 を数値として出力するツールは先頭のゼロを省くことがあり、文字列比較の前に桁をそろえる必要があります。16 進数の大文字と小文字は同じ値を指すため、比較時はどちらかに寄せてから突き合わせます。