ToolPal
A hand opening a smart home door with digital access panel, conveying security and technology.

暗号学的ハッシュ関数の完全ガイド - SHA-256、SHA-512など

📷 Joppe Beurskens / Pexels

暗号学的ハッシュ関数の完全ガイド - SHA-256、SHA-512など

SHA-256、SHA-512、MD5などの暗号学的ハッシュ関数を徹底解説。ハッシュの特性、チェックサム、パスワードハッシュ、ブロックチェーン、デジタル署名などの用途を紹介。

D著者: Daniel Park2026年3月6日7分で読了

はじめに:ハッシュ関数とは?

ハッシュ関数は、任意のサイズの入力を受け取り、固定サイズの出力(ハッシュ、ダイジェスト、チェックサムとも呼ばれる)を生成する数学関数です。暗号学的ハッシュ関数には、ソフトウェア開発、サイバーセキュリティ、ブロックチェーン技術、データ整合性の検証に不可欠なセキュリティ特性が備わっています。

ハッシュ関数は現代のコンピューティングの至るところで使われています。ウェブサイトへのログイン、ファイルダウンロードの検証、Gitへのコードコミット、ブロックチェーンとのやり取り——そのすべての背後でハッシュ関数が動いています。ハッシュアルゴリズムの仕組みと使い分けを理解することは、すべての開発者にとって必須の知識です。

手軽にハッシュを生成したいですか?MD5、SHA-1、SHA-256、SHA-384、SHA-512に対応したハッシュジェネレーターをぜひお試しください。

暗号学的ハッシュ関数の基本特性

優れた暗号学的ハッシュ関数には、単純なチェックサムや通常のハッシュ関数と区別するいくつかの重要な特性が必要です。

1. 決定性

同じ入力は常に同じ出力を生成します。SHA-256で文字列「Hello, World!」をハッシュすると、どのマシン、どのプログラミング言語でも、毎回同じハッシュが得られます。

Input:  "Hello, World!"
SHA-256: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

2. 固定長の出力

入力サイズに関係なく、出力は常に同じ長さです:

アルゴリズム出力サイズ(ビット)出力サイズ(16進数文字)
MD512832
SHA-116040
SHA-22422456
SHA-25625664
SHA-38438496
SHA-512512128
SHA-3-25625664
BLAKE3256(デフォルト)64
Input: "a"
SHA-256: ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb

Input: "The quick brown fox jumps over the lazy dog"
SHA-256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592

Input: [1GBファイルの全内容]
SHA-256: [それでも正確に64文字の16進数]

3. 原像耐性

ハッシュ値から、そのハッシュを生成する入力を見つけることが計算上不可能であるべきです。つまり、ハッシュ関数は一方向関数であり、逆算できません。

Hash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

入力を見つけられますか?総当たりでしかできません。
(ちなみに答えは空文字列です)

4. 第二原像耐性

ある入力とそのハッシュが与えられた場合、同じハッシュを生成する別の入力を見つけることが計算上不可能であるべきです。

5. 衝突耐性

同じハッシュ出力を生成する2つの異なる入力を見つけることが計算上不可能であるべきです。

6. アバランシェ効果

入力のわずかな変更が出力に劇的な変化をもたらすべきです。1ビットの変更でも、出力ビットのおよそ半分が変わるべきです。

Input: "Hello, World!"
SHA-256: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

Input: "Hello, World?" (!を?に変更)
SHA-256: 4a6e2ef4e4fa0e534f1d1989f453daa87f36e5e4e35b3dcb3d82f22d12654083

入力が1文字しか違わないのに、2つのハッシュは全く異なって見えます。ハッシュジェネレーターで実際に確認できます。

SHAファミリーのハッシュ関数

Secure Hash Algorithm(SHA)ファミリーは、最も広く使われている暗号学的ハッシュ関数群です。NSA(米国国家安全保障局)が開発し、NISTが公開しました。

SHA-1(非推奨)

SHA-1は160ビット(20バイト)のハッシュを生成します。長年標準でしたが、現在は破られたと見なされており、セキュリティ目的での使用は推奨されません。

  • 状態:非推奨——新規アプリケーションには使用しないこと
  • 衝突発見:2017年にGoogleとCWI Amsterdamが実用的な衝突を実証(SHAttered攻撃)
  • まだ使用中:GitはオブジェクトIDにSHA-1を使用(SHA-256への移行中)
  • 出力:40文字の16進数

SHA-256

SHA-256は現在最も広く使われているハッシュ関数です。SHA-2ファミリーの一部で、256ビット(32バイト)のハッシュを生成します。

  • 状態:安全で広く推奨されている
  • 用途:Bitcoin、TLS証明書、コード署名、ファイル整合性チェック
  • 性能:中程度——ほとんどのアプリケーションに十分な速度
  • 出力:64文字の16進数
// JavaScript: SHA-256ハッシュの生成
async function sha256(message) {
  const encoder = new TextEncoder();
  const data = encoder.encode(message);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

const hash = await sha256('Hello, World!');
console.log(hash);
// dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

SHA-384

SHA-384はSHA-512の切り詰めバージョンで、384ビットのハッシュを生成します。SHA-256よりもわずかに高いセキュリティマージンを提供します。

  • 状態:安全
  • 用途:TLS、高セキュリティアプリケーション
  • 出力:96文字の16進数

SHA-512

SHA-512は512ビット(64バイト)のハッシュを生成します。64ビットシステムでは、より大きなブロックでデータを処理するため、実はSHA-256よりも高速です。

  • 状態:安全
  • 性能:64ビットシステムではSHA-256よりも高速なことが多い
  • 用途:パスワードハッシュ、デジタル署名、高セキュリティアプリケーション
  • 出力:128文字の16進数
import hashlib

# PythonでのSHA-512
message = "Hello, World!"
hash_object = hashlib.sha512(message.encode('utf-8'))
hex_digest = hash_object.hexdigest()
print(hex_digest)
# 374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6cc69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387

SHA-2ファミリーの比較

アルゴリズム出力ビットブロックサイズ内部状態セキュリティレベル
SHA-224224512256112ビット
SHA-256256512256128ビット
SHA-3843841024512192ビット
SHA-5125121024512256ビット
SHA-512/2242241024512112ビット
SHA-512/2562561024512128ビット

SHA-3(Keccak)

SHA-3はSHAファミリーの最新メンバーで、Keccakアルゴリズムに基づいています。SHA-2とは根本的に異なる構造(スポンジ構造)を使用し、アルゴリズムの多様性を提供します。

  • 状態:安全、2015年に標準化
  • 構造:スポンジ構造(SHA-2のMerkle-Damgardとは異なる)
  • バリアント:SHA-3-224、SHA-3-256、SHA-3-384、SHA-3-512、SHAKE128、SHAKE256
  • 用途:SHA-2が万が一危殆化した場合のバックアップ

MD5:まだ使われている理由

MD5は128ビットのハッシュを生成し、かつて最も人気のあるハッシュ関数でした。現在は暗号学的に破られていますが、セキュリティ以外の目的ではまだ使われています。

MD5を使ってはいけない用途:

  • パスワードハッシュ
  • デジタル署名
  • 証明書の検証
  • セキュリティに関わるあらゆるアプリケーション

MD5が許容される用途:

  • 非暗号化チェックサム(偶発的な破損に対するファイル整合性の確認)
  • コンテンツアドレス可能ストレージ(セキュリティが不要な場合)
  • 重複排除
  • レガシーシステムとの互換性
import hashlib

# MD5はファイルチェックサムでよく見かける
md5_hash = hashlib.md5(b"Hello, World!").hexdigest()
print(md5_hash)  # 65a8e27d8879283831b664bd8b7f0ad4

BLAKE3:モダンな代替手段

BLAKE3は、SHA-2やSHA-3に比べて大幅なパフォーマンス向上を実現しつつ、強力なセキュリティ特性を維持する新しいハッシュ関数です。

BLAKE3の利点:

  • 極めて高速:現代のCPUでSHA-256の4〜8倍高速
  • 並列化可能:SIMD命令と複数コアを活用可能
  • 安全:十分に分析されたBLAKE2とChaChaストリーム暗号に基づく
  • 多用途:ハッシュ、MAC、KDF、XOFとして機能可能
use blake3;

fn main() {
    let hash = blake3::hash(b"Hello, World!");
    println!("{}", hash.to_hex());
    // 288a26b2bfb0602c0c7c9e4bf714f53f46c090da7e7ab8a30af9bf6c8e3bf0f8
}

ハッシュ関数の用途

1. ファイル整合性とチェックサム

ハッシュ関数は、ファイルが転送中に破損や改ざんされていないことを検証します。

# チェックサムの生成
sha256sum ubuntu-24.04.iso > checksum.txt

# チェックサムの検証
sha256sum -c checksum.txt
# ubuntu-24.04.iso: OK
// JavaScriptでのファイル整合性検証
async function verifyFileIntegrity(file, expectedHash) {
  const buffer = await file.arrayBuffer();
  const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  const actualHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');

  return actualHash === expectedHash;
}

ハッシュジェネレーターを使えば、ファイルや文字列のチェックサムを簡単に計算できます。

2. パスワードハッシュ

パスワードを平文で保存することは重大なセキュリティ脆弱性です。ハッシュ関数を使えば、パスワードを保存せずに検証できます。

**重要:**パスワードハッシュに素のSHA-256を使わないでください。ソルティングを含み、意図的に低速な専用のパスワードハッシュ関数を使用してください。

推奨されるパスワードハッシュアルゴリズム:

アルゴリズム状態主な特徴
Argon2id最良の選択メモリハード、GPU耐性
bcrypt実績あり広くサポート、実戦テスト済み
scrypt良好メモリハード
PBKDF2許容範囲NIST承認、広く利用可能
// Node.jsでbcryptを使ったパスワードハッシュ
import bcrypt from 'bcrypt';

// パスワードのハッシュ化
const saltRounds = 12;
const passwordHash = await bcrypt.hash('user_password', saltRounds);
// 結果: $2b$12$LJ3m6gEwO/fSFqCVXWLwOeR/dYtTVkRDCwoGLBE0Fg6voFEOB5viy

// パスワードの検証
const isValid = await bcrypt.compare('user_password', passwordHash);
// true

// Argon2id(新規アプリケーション推奨)
import argon2 from 'argon2';

const hash = await argon2.hash('user_password', {
  type: argon2.argon2id,
  memoryCost: 65536,  // 64MB
  timeCost: 3,
  parallelism: 4,
});

const valid = await argon2.verify(hash, 'user_password');

素のハッシュだけでは不十分な理由:

// ダメな例: "password123"のSHA-256ハッシュ
ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f

// レインボーテーブルを持つ攻撃者はこれを即座に逆引きできます。
// 解決策: ソルト付きの適切なパスワードハッシュ関数を使用すること。

パスワードセキュリティについて詳しくはパスワードセキュリティガイドをご覧ください。強力なパスワードはパスワードジェネレーターで生成できます。

3. ブロックチェーンと暗号通貨

ハッシュ関数はブロックチェーン技術の基盤です。BitcoinはProof-of-Work合意メカニズムでSHA-256を使用しています。

import hashlib
import time

def mine_block(data, difficulty):
    """シンプルなProof-of-Workマイニングシミュレーション"""
    prefix = '0' * difficulty
    nonce = 0

    while True:
        text = f'{data}{nonce}'
        hash_result = hashlib.sha256(text.encode()).hexdigest()

        if hash_result.startswith(prefix):
            return nonce, hash_result

        nonce += 1

# 難易度4でブロックをマイニング(ハッシュが0000で始まる必要あり)
nonce, hash_value = mine_block("Block data here", 4)
print(f"Nonce: {nonce}")
print(f"Hash: {hash_value}")
# ハッシュは"0000..."で始まる

ブロックチェーンにおけるハッシュ関数:

  • ブロックハッシュ:各ブロックは前のブロックのハッシュを含み、不変のチェーンを形成
  • マークルツリー:トランザクションはツリー構造で整理され、各ノードは子のハッシュ
  • マイニング:Proof-of-Workはターゲット値以下のハッシュを生成するnonceを見つける必要あり
  • アドレス:暗号通貨のアドレスは公開鍵のハッシュから導出

4. デジタル署名

デジタル署名はハッシュ関数を使ってメッセージを効率的に署名します。メッセージ全体(非常に大きい可能性がある)に署名する代わりに、メッセージをハッシュし、そのハッシュに署名します。

// デジタル署名の簡略フロー
// 1. メッセージをハッシュ
const messageHash = await sha256(message);

// 2. 秘密鍵でハッシュに署名
const signature = await crypto.subtle.sign(
  { name: 'RSASSA-PKCS1-v1_5' },
  privateKey,
  encoder.encode(messageHash)
);

// 3. 検証:メッセージをハッシュし署名を確認
const verifyHash = await sha256(message);
const isValid = await crypto.subtle.verify(
  { name: 'RSASSA-PKCS1-v1_5' },
  publicKey,
  signature,
  encoder.encode(verifyHash)
);

5. コンテンツアドレス可能ストレージ

Git、IPFS、Dockerなどのシステムは、ハッシュによってコンテンツをアドレス指定します。これにより、重複排除、整合性検証、不変性が実現されます。

# GitはオブジェクトIDにSHA-1を使用(SHA-256への移行中)
$ echo "Hello, World!" | git hash-object --stdin
8ab686eafeb1f44702738c8b0f24f2567c36da6d

# Dockerレイヤーのコンテンツアドレス指定
$ docker inspect --format='{{.Id}}' my-image
sha256:abc123...

6. HMAC(ハッシュベースメッセージ認証コード)

HMACはハッシュ関数と秘密鍵を組み合わせて、データの整合性と認証の両方を提供します。

// Node.jsでのHMAC
import { createHmac } from 'crypto';

function generateHmac(message, secretKey) {
  return createHmac('sha256', secretKey)
    .update(message)
    .digest('hex');
}

// Webhook署名の検証
function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = generateHmac(payload, secret);
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// APIリクエストの署名
const timestamp = Date.now().toString();
const body = JSON.stringify({ action: 'transfer', amount: 100 });
const signaturePayload = `${timestamp}.${body}`;
const signature = generateHmac(signaturePayload, API_SECRET);

fetch('https://api.example.com/transactions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Timestamp': timestamp,
    'X-Signature': signature,
  },
  body: body,
});

7. サブリソース完全性(SRI)

ブラウザはSRIハッシュを使って、取得したリソース(スクリプト、スタイルシート)が改ざんされていないことを検証できます。

{/*  SRI: ブラウザはスクリプト実行前にハッシュを検証 */}
<script
  src="https://cdn.example.com/library.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
></script>

<link
  rel="stylesheet"
  href="https://cdn.example.com/styles.css"
  integrity="sha256-5IxE/yBJ7PB5TbXxYqBCj9n5xM4mECft3p7/+Gkh1I="
  crossorigin="anonymous"
/>
# SRIハッシュの生成
echo -n "file contents" | openssl dgst -sha384 -binary | openssl base64 -A
# または: shasum -b -a 384 file.js | xxd -r -p | base64

8. データ重複排除

ハッシュ関数はストレージシステムで重複データブロックを識別します:

// コンテンツハッシュによるシンプルな重複排除
class DeduplicatedStorage {
  constructor() {
    this.store = new Map(); // hash -> data
    this.references = new Map(); // hash -> reference count
  }

  async put(data) {
    const hash = await sha256(data);

    if (!this.store.has(hash)) {
      this.store.set(hash, data);
      this.references.set(hash, 1);
    } else {
      this.references.set(hash, this.references.get(hash) + 1);
    }

    return hash;
  }

  get(hash) {
    return this.store.get(hash);
  }
}

ハッシュ関数のセキュリティに関する考慮事項

既知の脆弱性

アルゴリズム状態既知の攻撃
MD5破られている衝突攻撃、実用的な偽造
SHA-1破られているSHAttered衝突攻撃(2017年)
SHA-256安全実用的な攻撃は知られていない
SHA-512安全実用的な攻撃は知られていない
SHA-3安全実用的な攻撃は知られていない
BLAKE3安全実用的な攻撃は知られていない

適切なハッシュ関数の選び方

汎用ハッシュ(チェックサム、データ整合性):

  • セキュリティが重要な場面にはSHA-256
  • パフォーマンスが重要な場面にはBLAKE3
  • セキュリティに関係のないチェックサムにはMD5も許容

パスワードハッシュ:

  • Argon2id(最良)
  • bcrypt(実績あり)
  • 素のSHA-256/SHA-512は使わないこと

デジタル署名:

  • SHA-256またはSHA-384
  • 長期セキュリティにはSHA-512

ブロックチェーン:

  • SHA-256(Bitcoin、大半のチェーン)
  • Keccak-256(Ethereum)

HMAC:

  • HMAC-SHA-256(標準)
  • HMAC-SHA-512(より高いセキュリティマージン)

長さ拡張攻撃

SHA-256とSHA-512(SHA-3やBLAKE3ではない)は長さ拡張攻撃に対して脆弱です。これは、hash(message)が与えられると、攻撃者が元のメッセージを知らなくてもhash(message || padding || extension)を計算できることを意味します。

**対策:**認証にはハッシュ関数の直接使用ではなくHMACを使用しましょう。HMACは長さ拡張攻撃に対して脆弱ではありません。

// 長さ拡張攻撃に脆弱
const token = sha256(secret + message);

// 安全: HMACを使用
const token = hmacSha256(secret, message);

ハッシュ関数の実装

JavaScript(ブラウザとNode.js)

// ブラウザ Web Crypto API
async function hash(algorithm, data) {
  const encoder = new TextEncoder();
  const encoded = encoder.encode(data);
  const hashBuffer = await crypto.subtle.digest(algorithm, encoded);
  return Array.from(new Uint8Array(hashBuffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

// 使用例
await hash('SHA-256', 'Hello, World!');
await hash('SHA-384', 'Hello, World!');
await hash('SHA-512', 'Hello, World!');

// Node.js cryptoモジュール
import { createHash } from 'crypto';

function hashNode(algorithm, data) {
  return createHash(algorithm).update(data).digest('hex');
}

hashNode('sha256', 'Hello, World!');
hashNode('sha512', 'Hello, World!');
hashNode('md5', 'Hello, World!');

Python

import hashlib

# 主要なアルゴリズムすべて
data = b"Hello, World!"

print("MD5:    ", hashlib.md5(data).hexdigest())
print("SHA-1:  ", hashlib.sha1(data).hexdigest())
print("SHA-256:", hashlib.sha256(data).hexdigest())
print("SHA-384:", hashlib.sha384(data).hexdigest())
print("SHA-512:", hashlib.sha512(data).hexdigest())
print("SHA3-256:", hashlib.sha3_256(data).hexdigest())

# ファイルのハッシュ
def hash_file(filepath, algorithm='sha256'):
    h = hashlib.new(algorithm)
    with open(filepath, 'rb') as f:
        while chunk := f.read(8192):
            h.update(chunk)
    return h.hexdigest()

Go

package main

import (
    "crypto/sha256"
    "crypto/sha512"
    "fmt"
)

func main() {
    data := []byte("Hello, World!")

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

    // SHA-512
    sha512Hash := sha512.Sum512(data)
    fmt.Printf("SHA-512: %x\n", sha512Hash)
}

パフォーマンス比較

ハッシュアルゴリズム間でパフォーマンスは大きく異なります。以下は現代のハードウェアでの概算ベンチマークです:

アルゴリズム速度(MB/s)相対速度
MD5約7001.4倍
SHA-1約5501.1倍
SHA-256約5001.0倍(基準)
SHA-512約6001.2倍(64ビット環境)
SHA-3-256約4000.8倍
BLAKE3約3000以上6.0倍以上

注意:BLAKE3のパフォーマンスの優位性は、SIMD命令と並列処理を活用できることに由来します。実際のパフォーマンスはハードウェアと実装に依存します。

まとめ

暗号学的ハッシュ関数は、現代のコンピューティングとセキュリティの基本的な構成要素です。異なるハッシュアルゴリズムの特性、強み、適切な使用場面を理解することは、セキュリティ、データ整合性、分散システムに携わるすべての開発者にとって不可欠です。

重要なポイント:

  1. SHA-256が安全なデフォルト——ほとんどの暗号ハッシュのニーズに
  2. MD5やSHA-1をセキュリティ目的に使わない
  3. 専用のパスワードハッシュを使う(Argon2id、bcrypt)——素のハッシュ関数ではなく
  4. HMACは長さ拡張攻撃を防ぐ——認証にはこれを使用
  5. BLAKE3はパフォーマンスの王者——速度が必要なとき
  6. アバランシェ効果は味方——わずかな入力変更がまったく異なるハッシュを生成
  7. 衝突耐性が重要——実用的な衝突が知られていないアルゴリズムを選択

手軽にハッシュを生成・比較するなら、ハッシュジェネレーターをブックマークしてください。MD5、SHA-1、SHA-256、SHA-384、SHA-512に対応し、ブラウザで直接ハッシュの計算と検証ができます。

関連リソース

よくある質問

D

著者について

Daniel Park

Senior frontend engineer based in Seoul. Seven years of experience building web applications at Korean SaaS companies, with a focus on developer tooling, web performance, and privacy-first architecture. Open-source contributor to the JavaScript ecosystem and founder of ToolPal.

詳細はこちら

この記事を共有

XLinkedIn

関連記事