閉じる

はじめてでもわかるCRC32・MD5・SHA-256の違いと使い分け

ハッシュ関数は、データから短い指紋のような値を作る道具です。

本記事ではCRC32、MD5、SHA-256の違いを、初心者の方にも伝わるように一歩ずつ説明します。

どれを選ぶべきか、どんな場面に向いているかを具体例とコードで示し、実装時の注意点までまとめます。

安全性と速度のバランスを理解し、正しく使い分けることが大切です

ハッシュ関数の基本

ハッシュ関数とは

ハッシュ関数は、長さの異なる入力(文字列やファイル)から、決まった長さの出力(ハッシュ値)を計算する関数です。

同じ入力からは必ず同じハッシュ値が得られ、ほんの少しでも入力が違えば大きく違うハッシュ値になります。

ハッシュは暗号化ではなく、元のデータに戻すことはできません

また、理論上は異なる入力が同じハッシュになる衝突が起こり得ます。

主な用途

ハッシュは日常の多くの場面で使われています。

データの誤り検出、ファイルの整合性確認、重複データの判定、キャッシュのキー生成、署名やメッセージ認証(HMAC)などが代表例です。

誤り検出改ざん検出は似ていますが目的が異なり、前者は偶発的なエラー、後者は攻撃者の意図的な改ざんを対象にします。

CRCは誤り検出向け、暗号学的ハッシュ(MD5やSHA-256)は改ざん対策向けという違いがあります。

比較の軸

CRC32・MD5・SHA-256を選ぶときは、以下の軸で考えると混乱しにくくなります。

ハッシュ長(ビット数)、計算速度、衝突耐性(安全性)、用途との適合性です。

実装の容易さやライブラリの有無も現実的な判断材料になります。

CRC32・MD5・SHA-256の違い

CRC32とは

CRC32(Cyclic Redundancy Check)は、通信や保存時の偶発的なビット誤りを検出するために設計されたハッシュです。

ネットワークパケットやZIP、PNGなどで広く使われます。

非常に高速で、ランダムエラーの検出性能が高い一方、攻撃者による意図的な改ざんを防ぐ設計ではありません。

CRC32には多くの“流派”(多項式・初期値・反転・最終XOR)があり、実装差で結果が変わることがあります(一般的にはCRC-32(IEEE)が標準的です)。

MD5とは

MD5はかつて広く使われた暗号学的ハッシュですが、現在は衝突が現実的に作られてしまうほど弱点が見つかっています。

セキュリティ目的(改ざん対策や署名)ではMD5を使ってはいけません

一方で、攻撃者を想定しない用途(重複検出、キャッシュキーなど)では、速度の面から今でも使われることがあります。

SHA-256とは

SHA-256はSHA-2ファミリの一つで、現在も推奨される強力な暗号学的ハッシュです。

TLS(HTTPS)やソフトウェア配布の整合性確認などで広く採用されています。

衝突耐性と広範な実装の両立が特徴で、用途に迷ったらSHA-256が基本の選択肢になります

ハッシュ長の違い

ハッシュ長は安全性や衝突確率に直結します。

長いほど偶然の衝突は起きにくくなります。

アルゴリズムハッシュ長(ビット)バイト数16進文字数(小文字)
CRC323248
MD51281632
SHA-2562563264

見た目が短いほど扱いやすい反面、衝突のリスクは上がります

速度と計算コストの違い

おおまかな相対速度は、CRC32が最速、次いでMD5、SHA-256はやや遅いという順です。

とはいえ現代のCPUではSHA-256も十分高速で、多くのアプリケーションでボトルネックにはなりません。

大量のデータをストリーミング処理する場合は差が出やすく、誤り検出ならCRC32、非セキュアな高速用途ならMD5、安全性が必要ならSHA-256を選ぶのが基本です。

衝突耐性と安全性の違い

  • CRC32: 偶発的なエラー検出向けで、攻撃への耐性は考慮外です。意図的に同じCRC32を作ることは容易です。
  • MD5: 実用的な衝突攻撃が可能で、改ざん対策としては不適切です。
  • SHA-256: 現時点で広く安全と見なされ、改ざん検出やHMACに適します。

「改ざん対策」や「認証」が目的なら、素のハッシュではなくHMACや電子署名を使うべき場面が多いことも覚えておくと安全です。

使い分けのガイドライン

通信や保存の誤り検出はCRC32

ネットワークやストレージでは、ランダムなビット反転が主な脅威です。

CRC32はこの種の誤りを効率よく見つけられます。

ZIPやPNGのCRCはまさにその例で、攻撃者を想定しない誤り検出ならCRC32が最適です。

複数のCRC32バリアントがあるため、同じバリアントを使うよう仕様を揃えることが重要です。

配布ファイルの改ざん対策はSHA-256

ソフトウェアやドキュメントを配布する際には、ダウンロード後にSHA-256を計算して公開値と一致するか確認します。

MD5では悪意ある衝突の可能性があり、SHA-256を使うのが安全です。

より強固にするなら、公開サイトはHTTPSで配布し、可能であれば署名(PGPなど)も併用します。

高速な非セキュア用途はMD5

ファイルの重複検出やキャッシュキー生成など、攻撃者がいない前提ならMD5は手軽で高速です。

ただし「改ざん検知」や「本人確認」には使わないでください。

速度をさらに求めるなら、用途に応じてxxHashやBLAKE3などの非暗号学的ハッシュも検討できます(本記事では詳細割愛)。

パスワード保存には使わない

CRC32・MD5・SHA-256をそのままパスワード保存に使ってはいけません

代わりにbcrypt、scrypt、Argon2などのパスワードハッシュを使用します。

これらはソルトと計算コストを組み合わせ、総当たり攻撃に強くなっています。

SHA-256単体にソルトを足すだけでは十分とは言えません。

使い分けの目安

目的おすすめ理由注意
通信/保存の誤り検出CRC32高速で偶発エラーに強いバリアントを統一
ダウンロード整合性SHA-256安全性と広い実装可能なら署名も併用
重複検出/キャッシュMD5(非セキュア用途)高速・実装容易改ざん対策には不可
メッセージ認証HMAC-SHA-256共有鍵で改ざん検知素のSHA-256は不可
パスワード保存bcrypt/Argon2等総当たりに強いソルトとコスト設定

迷ったら「誤り検出=CRC32」「安全な整合性=SHA-256」を基本軸にすると判断しやすくなります

実装の基本

PythonでのCRC32/MD5/SHA-256

Python標準ライブラリだけで実装できます。

文字列からハッシュを取るときは、まずUTF-8などでバイト列に変換します。

基本の関数

Python
import zlib
import hashlib

def crc32_hex(data: bytes) -> str:
    # & 0xffffffff で符号なし32ビットに正規化
    return f"{zlib.crc32(data) & 0xffffffff:08x}"

def md5_hex(data: bytes) -> str:
    return hashlib.md5(data).hexdigest()

def sha256_hex(data: bytes) -> str:
    return hashlib.sha256(data).hexdigest()

text = "hello"
b = text.encode("utf-8")
print("CRC32:", crc32_hex(b))     # 8桁16進
print("MD5:", md5_hex(b))         # 32桁16進
print("SHA-256:", sha256_hex(b))  # 64桁16進

大きなファイルを分割してハッシュ

大きなファイルは少しずつ読み込む方がメモリに優しいです。

SHA-256の例を示します。

Python
import hashlib

def sha256_file_hex(path: str, chunk_size: int = 1024 * 1024) -> str:
    h = hashlib.sha256()
    with open(path, "rb") as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            h.update(chunk)
    return h.hexdigest()

print(sha256_file_hex("example.bin"))

テキストモードでは改行コードが変換される可能性があるため、ファイルは必ずバイナリモード(rb)で読みます

JavaScriptでのMD5/SHA-256

JavaScriptは環境(ブラウザ/Node.js)で手段が少し異なります。

ブラウザでのSHA-256(Web Crypto API)

HTML
<script>
async function sha256Hex(text) {
  const enc = new TextEncoder();
  const data = enc.encode(text);
  const buf = await crypto.subtle.digest("SHA-256", data);
  const bytes = new Uint8Array(buf);
  return Array.from(bytes).map(b => b.toString(16).padStart(2, "0")).join("");
}

sha256Hex("hello").then(console.log);
</script>

WebブラウザにはMD5の標準実装はありません

どうしてもMD5が必要なら、blueimp-md5などの実績ある外部ライブラリを読み込んで使用します。

HTML
<script src="https://cdn.jsdelivr.net/npm/blueimp-md5/js/md5.min.js"></script>
<script>
  console.log(md5("hello")); // 32桁16進
</script>

Node.jsでのMD5/SHA-256

JavaScript
const crypto = require("crypto");

function hashHex(alg, input) {
  return crypto.createHash(alg).update(input).digest("hex");
}

console.log("MD5:", hashHex("md5", "hello"));
console.log("SHA-256:", hashHex("sha256", "hello"));

GoでのCRC32/MD5/SHA-256

Goは標準パッケージで完結します。

go
package main

import (
	"crypto/md5"
	"crypto/sha256"
	"fmt"
	"hash/crc32"
)

func main() {
	data := []byte("hello")

	// CRC32(IEEE)
	crc := crc32.ChecksumIEEE(data)
	fmt.Printf("CRC32: %08x\n", crc)

	// MD5
	md5Sum := md5.Sum(data)
	fmt.Printf("MD5: %x\n", md5Sum)

	// SHA-256
	shaSum := sha256.Sum256(data)
	fmt.Printf("SHA-256: %x\n", shaSum)
}

fmt.Printf(“%x”, …)はバイト列を16進の小文字で出力し、CRC32はゼロ埋め8桁(%08x)でそろえます

ハッシュの表現形式

ハッシュ値は内部的にはバイト列ですが、人が扱いやすいように文字列表現に変換することが多いです。

  • 16進表記(hex): 最も一般的。小文字(例: a1b2…)か大文字(例: A1B2…)を統一します。
  • Base64: 文字数を短くでき、URLセーフ版(Base64URL)もあります。
  • 生のバイト列: 通信やバイナリ保存に向きます。
表現長所注意
16進(小文字)e3b0c442…視認性・比較が容易大小文字の混在を避ける
Base6447DEQpj8…短くできるパディング(=)やURLエスケープ
バイト列0x…高速・省メモリ表示には不向き

同じハッシュでも表現形式が違うと見た目が一致しないため、比較時は形式と大文字/小文字を合わせます

よくある落とし穴

  • 文字コードの違い: “こんにちは”をUTF-8でエンコードするかShift_JISでエンコードするかでバイト列が変わります。常にUTF-8など統一したエンコーディングを使います
  • テキスト/バイナリ読み込み: テキストモードは改行変換が入ることがあるため、ファイルはバイナリモードで読みます。
  • CRC32のバリアント: 多項式や初期値が異なると結果が一致しません。仕様で「CRC-32(IEEE)」などバリアントを明記します。
  • 先頭ゼロの欠落: CRC32は8桁16進でゼロ埋めします(例: 0000ab12)。言語によってはゼロが落ちるので注意します。
  • MD5の誤用: MD5で改ざん対策や署名をしてはいけません
  • 素のハッシュでの認証: 共有鍵があるならHMAC-SHA-256を使用します。素のSHA-256を「署名」として使うのは誤りです。
  • パスワード保存: CRC32/MD5/SHA-256単体は不可。bcrypt/Argon2などを使う。ソルトとコストを設定します。
  • シリアライズの不一致: JSONのキー順や空白が違うとハッシュも変わります。同じカノニカル形式でシリアライズしてからハッシュ化します。
  • 大きなファイルの一括読み込み: メモリを圧迫します。チャンク分割のストリーミングで計算します。

まとめ

CRC32・MD5・SHA-256は、目的と前提が異なるハッシュです。

誤り検出にはCRC32、攻撃者を想定しない高速な用途にはMD5、安全性が必要ならSHA-256という使い分けを押さえれば、初学者の方でも迷いにくくなります。

ハッシュ長は衝突リスクと直結し、実装時はエンコーディングや表現形式、バリアントの統一が重要です。

改ざん検知や認証ではHMAC、パスワード保存ではbcrypt/Argon2など、ハッシュ以外の正しい部品を組み合わせることも欠かせません。

最後に、コード例はあくまで基本形です。

実際のプロダクトではエラー処理や入力の正規化、ストリーミング処理を取り入れ、安全で再現性の高い実装を目指してください。

正しく理解し正しく使えば、ハッシュは強力で信頼できる基盤になります

この記事を書いた人
エーテリア編集部
エーテリア編集部

このサイトでは、プログラミングをこれから学びたい初心者の方に向けて記事を書いています。 基本的な用語や環境構築の手順から、実際に手を動かして学べるサンプルコードまで、わかりやすく整理することを心がけています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!