ブラウザ暗号の実践:Web Crypto API と国密 SM2/SM3/SM4
前端安全(更新: 2026年5月18日)
なぜブラウザで暗号処理するのか
従来のフローではデータをサーバーに送って暗号化するため、プライバシーリスクがあります。
従来:平文 → ネットワーク → サーバーで暗号化 → 暗号文を返却
リスク:平文の傍受、サーバー側のログ
ブラウザ:平文 → ローカルで暗号化 → 暗号文
利点:平文が端末外に出ない
ToolsKu の 30 以上の暗号ツールはすべてブラウザ内で完結し、アップロードはゼロです。
Web Crypto API:ブラウザ標準の暗号
主な機能
Web Crypto API は W3C 標準で、モダンブラウザはすべて対応しています。
// 機能検出
if (window.crypto?.subtle) {
// Web Crypto API 利用可能
}
| カテゴリ | アルゴリズム | 鍵長 |
|---|---|---|
| 対称 | AES-GCM, AES-CBC, AES-CTR | 128/192/256 |
| 非対称 | RSA-OAEP, RSA-PSS, ECDSA | 2048/4096 |
| 鍵導出 | PBKDF2, HKDF, ECDH | - |
| ハッシュ | SHA-1, SHA-256, SHA-384, SHA-512 | - |
| HMAC | HMAC(上記ハッシュと組み合わせ) | - |
AES-256-GCM の実装例
async function aesGcmEncrypt(plaintext: string, password: string) {
const enc = new TextEncoder();
// 1. パスワードから鍵を導出(PBKDF2)
const salt = crypto.getRandomValues(new Uint8Array(16));
const keyMaterial = await crypto.subtle.importKey(
'raw', enc.encode(password), 'PBKDF2', false, ['deriveKey']
);
const key = await crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 600000, hash: 'SHA-256' },
keyMaterial,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt']
);
// 2. ランダム IV
const iv = crypto.getRandomValues(new Uint8Array(12));
// 3. 暗号化
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
enc.encode(plaintext)
);
// 4. 連結:salt + iv + ciphertext
return concatBuffers(salt, iv, ciphertext);
}
セキュリティ上の選択
| 項目 | 選択 | 理由 |
|---|---|---|
| 対称モード | AES-GCM(CBC ではない) | 認証付き暗号で改ざん検知 |
| 鍵導出 | PBKDF2 + SHA-256 | 標準で広くサポート |
| 反復回数 | 600,000 | OWASP 2023 の推奨下限 |
| IV 長 | 12 バイト(96 ビット) | GCM の推奨 |
| Salt | 16 バイト乱数 | レインボーテーブル対策 |
国密アルゴリズム:JS 実装の課題
アルゴリズム体系
| アルゴリズム | 種別 | 国際標準との対応 | ToolsKu |
|---|---|---|---|
| SM2 | 公開鍵暗号・署名 | ECDSA (P-256) | sm-crypto |
| SM3 | ハッシュ | SHA-256 | sm-crypto |
| SM4 | 対称暗号 | AES-128 | sm-crypto |
sm-crypto の利用
import { sm2, sm3, sm4 } from 'sm-crypto';
// SM2 鍵ペア生成
const keyPair = sm2.generateKeyPairHex();
// publicKey: keyPair.publicKey (130 hex chars, uncompressed)
// privateKey: keyPair.privateKey (64 hex chars)
// SM2 暗号化(C1C3C4 モード、国密標準)
const cipherMode = 1; // 1 = C1C3C4, 0 = C1C2C3
const ciphertext = sm2.doEncrypt(msg, keyPair.publicKey, cipherMode);
// SM2 復号
const plaintext = sm2.doDecrypt(ciphertext, keyPair.privateKey, cipherMode);
// SM3 ハッシュ
const hash = sm3('message');
// SM4 暗号化(ECB モード)
const key = '0123456789abcdeffedcba9876543210'; // 128-bit hex
const encrypted = sm4.encrypt(msg, key);
性能比較
| 操作 | Web Crypto (AES-256-GCM) | sm-crypto (SM4) | 倍率 |
|---|---|---|---|
| 1MB 暗号化 | 2ms | 45ms | 22x |
| 1MB 復号 | 2ms | 42ms | 21x |
| 鍵生成 | 0.5ms | 3ms | 6x |
Web Crypto は 20 倍以上高速です。ブラウザネイティブ(C/Rust や HW 加速)に対し、sm-crypto は純 JS の大整数演算のためです。
最適化の方針
- Web Worker:SM2/SM4 を Worker に逃がして UI をブロックしない
- Wasm 加速:sm-crypto のホットパスを Wasm に(コミュニティ実験あり)
- チャンク分割:大ファイルはブロック単位で暗号化し進捗表示
暗号ツールのアーキテクチャ
ToolsKu のレイヤ構成
UI 層(React コンポーネント)
↓
暗号サービス層(統一 API)
↓
┌──────────────┬──────────────┐
│ Web Crypto │ sm-crypto │
│(標準) │(国密) │
│ ネイティブ │ 純 JS │
└──────────────┴──────────────┘
統一インターフェース
interface CryptoService {
encrypt(data: Uint8Array, key: CryptoKeyInput): Promise<Uint8Array>;
decrypt(data: Uint8Array, key: CryptoKeyInput): Promise<Uint8Array>;
generateKey(): Promise<CryptoKeyOutput>;
}
標準・国密とも同一インターフェースを実装し、UI は実装を意識しません。
ファイル暗号のメモリ管理
async function encryptFile(file: File, password: string) {
// 1. ファイルをメモリに読み込み
const buffer = await file.arrayBuffer();
// 2. 大ファイルはチャンク処理(一括暗号化の OOM 回避)
const CHUNK_SIZE = 64 * 1024 * 1024; // 64MB
if (buffer.byteLength > CHUNK_SIZE) {
return encryptFileInChunks(buffer, password, CHUNK_SIZE);
}
// 3. 暗号化
const result = await aesGcmEncrypt(new Uint8Array(buffer), password);
// 4. 機密データのクリア
buffer = null; // GC に任せる
return result;
}
よくある誤解
誤解 1:Base64 = 暗号化
Base64("password123") = "5a+G56CBMTIz" ← すぐ復元できる
AES-256("password123") = "U2FsdGVkX1..." ← 鍵なしでは復元不可
Base64 はエンコードであり暗号ではありません。誰でもデコードできます。
誤解 2:MD5/SHA-1 は「暗号化」
ハッシュは一方向で「復号」できません。完全性検証用であり、機密性のためではありません。
- MD5:破られている—セキュリティ用途に使わない
- SHA-1:衝突攻撃—非推奨
- SHA-256/SM3:現時点では安全とみなされる
誤解 3:ECB モードは安全
ECB:同じ平文ブロック → 同じ暗号文(パターンが漏れる)
CBC/GCM:同じ平文ブロック → 異なる暗号文(安全)
ToolsKu の AES ツールは GCM のみ—不安全な ECB は提供しません。
まとめ
ブラウザ暗号はすでに実用段階です。
- Web Crypto API:標準アルゴリズム(AES/RSA/SHA)をネイティブに近い速度で
- sm-crypto:国密を純 JS で、コンプライアンス要件に対応
- ゼロアップロード:鍵もデータも端末外に出ない
ToolsKu では AES暗号、RSA暗号、SM2暗号、SM3ハッシュ、SM4暗号 など 30 以上のツールを、すべてブラウザ内で処理しています。
ブラウザローカルツールを無料で試す →
#加密#WebCrypto#国密#SM2#AES#安全