← レッスン一覧に戻る レッスン 7 / 8
中級 security
暗号学的ハッシュ
はじめに
暗号学的ハッシュはWebAssemblyにとって最適なユースケースです:
- CPU集約的 — Rustのパフォーマンスの恩恵を受ける(JSより2〜5倍高速)
- クライアントサイド — 機密データがブラウザの外に出ることがない
- 純Rust — Web Crypto APIに依存せず、すべてのプラットフォームで同一動作
セットアップ
Cargo.toml に sha2 クレートを追加します:
[dependencies]
wasm-bindgen = "0.2"
sha2 = "0.10"sha2 クレートは純Rust実装です — Cバインディングもシステム依存もありません。設定なしでWasmにコンパイルできます。
SHA-256の仕組み(簡略版)
- 入力データが512ビットの倍数にパディングされる
- データは512ビットブロックごとに64ラウンドの圧縮処理を受ける
- 出力は固定256ビット(32バイト)のハッシュ — 入力サイズに関わらず常に同じ長さ
特性:
- 決定的 — 同じ入力は常に同じハッシュを生成
- 一方向性 — ハッシュから元の入力を復元することはできない
- 衝突耐性 — 同じハッシュを持つ2つの入力を見つけることは実質的に不可能
- 雪崩効果 — 入力の1ビットを変更すると出力ビットの約50%が変化
文字列のハッシュ
use sha2::{Sha256, Digest};
pub fn sha256_hash(input: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(input.as_bytes());
let result = hasher.finalize();
result.iter()
.map(|byte| format!("{:02x}", byte))
.collect()
}ファイルのハッシュ(生バイト)
ファイルハッシュには、JavaScriptの Uint8Array に対応する &[u8] を受け取ります:
#[wasm_bindgen]
pub fn hash_file(data: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize()
.iter()
.map(|byte| format!("{:02x}", byte))
.collect()
}JavaScriptでの使用:
// ユーザーが選択したファイルをハッシュ
const file = document.getElementById('file-input').files[0];
const buffer = await file.arrayBuffer();
const hash = hash_file(new Uint8Array(buffer));
console.log("ファイルSHA-256:", hash);JavaScriptからの呼び出し
import init, { sha256_hash, verify_integrity, sha256_bytes } from './pkg/crypto.js';
await init();
// 文字列をハッシュ
const hash = sha256_hash("Hello, WebAssembly!");
console.log(hash);
// → "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
// 整合性を検証
const valid = verify_integrity("Hello, WebAssembly!", hash);
console.log(valid); // → true
// バイナリデータをハッシュ
const bytes = new TextEncoder().encode("binary data");
const byteHash = sha256_bytes(bytes);パフォーマンス:Rust/Wasm vs JavaScript
| 実装 | 1MBハッシュ | 10MBハッシュ | 100MBハッシュ |
|---|---|---|---|
| 純JavaScript | 約15ms | 約150ms | 約1500ms |
| Rust/Wasm | 約3ms | 約30ms | 約300ms |
| Web Crypto API | 約2ms | 約20ms | 約200ms |
Rust/Wasmは純JSより約5倍高速です。Web Crypto APIはやや高速(ハードウェアアクセラレーション対応)ですが、非同期専用で柔軟性が低くなります。
セキュリティ上の注意事項
- パスワードを直接ハッシュしない — 代わりに鍵導出関数(bcrypt、argon2など)を使用
- SHA-256は暗号化ではない — ハッシュは一方向であり、誰でも同じ入力をハッシュできる
- ハッシュにソルトを付ける — レインボーテーブル攻撃を防ぐためにランダムな値を先頭に付加
- クライアントサイドハッシュはサーバーサイド検証の代替にならない — 悪意のあるクライアントはスキップできる
試してみよう
ファイルの内容(&[u8])をハッシュする関数を追加してみましょう。メッセージ認証用のHMACの実装にも挑戦してみてください。
試してみる
チャプタークイズ
すべての問題に正解してレッスンを完了しましょう