Windows暗号化の基礎と安全な実装
はじめに
データの暗号化は、現代のセキュリティにおいて不可欠です。この記事では、Windows環境での暗号化の基本概念と、安全な実装方法について解説します。
暗号化の基本概念
対称暗号と非対称暗号
| 特性 | 対称暗号 | 非対称暗号 |
|---|---|---|
| キー数 | 1つ(共有キー) | 2つ(公開鍵・秘密鍵) |
| 速度 | 高速 | 低速 |
| 用途 | 大量データの暗号化 | キー交換、署名 |
| 例 | AES, ChaCha20 | RSA, ECC |
Windows暗号化API
Windowsには以下の暗号化APIが提供されています:
- BCrypt: カーネルモード対応のCNG(Cryptography Next Generation)
- NCrypt: キーストレージ機能付きCNG
- CryptoAPI: 従来のAPI(非推奨)
AES暗号化の安全な実装
推奨されるパラメータ
- アルゴリズム: AES-256-GCM(認証付き暗号化)
- IV(初期化ベクトル): 毎回ランダムに生成(96ビット)
- 認証タグ: 128ビット
実装例(BCrypt)
HLJSC
// セキュアなキー生成
NTSTATUS generate_key(BCRYPT_ALG_HANDLE hAesAlg, PBYTE pbKey, DWORD cbKey) {
NTSTATUS status;
BCRYPT_GEN_RANDOM pBcryptGenRandom = NULL;
// CryptGenRandomは非推奨、BCryptGenRandomを使用
status = BCryptGenRandom(NULL, pbKey, cbKey, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
return status;
}
// AES-256-GCM暗号化
NTSTATUS encrypt_aes_gcm(
const BYTE* pbPlainText, DWORD cbPlainText,
const BYTE* pbKey, const BYTE* pbIV,
BYTE* pbCipherText, DWORD cbCipherText,
BYTE* pbTag, DWORD cbTag
) {
NTSTATUS status;
BCRYPT_ALG_HANDLE hAesAlg = NULL;
BCRYPT_KEY_HANDLE hKey = NULL;
DWORD cbResult;
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
// AES-GCMプロバイダーのオープン
status = BCryptOpenAlgorithmProvider(&hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0);
if (!NT_SUCCESS(status)) goto cleanup;
// GCMモードの設定
status = BCryptSetProperty(hAesAlg, BCRYPT_CHAINING_MODE,
(PBYTE)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
if (!NT_SUCCESS(status)) goto cleanup;
// キーのインポート
status = BCryptGenerateSymmetricKey(hAesAlg, &hKey, NULL, 0,
(PBYTE)pbKey, AES_KEY_SIZE, 0);
if (!NT_SUCCESS(status)) goto cleanup;
// 認証情報の初期化
BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
authInfo.pbNonce = (PUCHAR)pbIV;
authInfo.cbNonce = AES_IV_SIZE;
authInfo.pbTag = pbTag;
authInfo.cbTag = cbTag;
// 暗号化
status = BCryptEncrypt(hKey, (PUCHAR)pbPlainText, cbPlainText,
&authInfo, NULL, 0, pbCipherText, cbCipherText, &cbResult, 0);
cleanup:
if (hKey) BCryptDestroyKey(hKey);
if (hAesAlg) BCryptCloseAlgorithmProvider(hAesAlg, 0);
return status;
}
ハッシュ化とパスワード管理
安全なパスワードハッシュ
HLJSC
// Argon2は現在BCryptでは未サポートのため、PBKDF2を使用
// より安全な実装にはOpenSSLまたはlibsodiumの使用を推奨
NTSTATUS hash_password(
const wchar_t* password,
const BYTE* salt, DWORD cbSalt,
BYTE* pbHash, DWORD cbHash
) {
NTSTATUS status;
BCRYPT_ALG_HANDLE hAlg = NULL;
// PBKDF2の使用
status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, NULL,
BCRYPT_ALG_HANDLE_HMAC_FLAG);
if (!NT_SUCCESS(status)) return status;
// パスワードをUTF-16としてエンコード
int passwordLen = lstrlenW(password) * sizeof(wchar_t);
// キー導出
status = BCryptDeriveKeyPBKDF2(hAlg,
(PUCHAR)password, passwordLen,
(PUCHAR)salt, cbSalt,
100000, // 繰り返し回数(高いほど安全だが遅い)
pbHash, cbHash);
BCryptCloseAlgorithmProvider(hAlg, 0);
return status;
}
Windowsデータ保護API(DPAPI)
ユーザー固有の暗号化
HLJSC
// データの暗号化(現在のユーザーに紐付け)
BOOL encrypt_data(const BYTE* plaintext, DWORD plaintextLen,
DATA_BLOB* encryptedBlob) {
DATA_BLOB dataIn;
dataIn.cbData = plaintextLen;
dataIn.pbData = (BYTE*)plaintext;
// CRYPTPROTECT_LOCAL_MACHINEを使用しない(ユーザー固有)
return CryptProtectData(
&dataIn,
L"My Application Data",
NULL, // 追加エントロピーなし
NULL, // 予約済み
NULL, // プロンプトなし
CRYPTPROTECT_UI_FORBIDDEN,
encryptedBlob
);
}
// データの復号
BOOL decrypt_data(const DATA_BLOB* encryptedBlob, BYTE** plaintext, DWORD* len) {
DATA_BLOB dataOut;
if (!CryptUnprotectData(
encryptedBlob,
NULL, // 説明不要
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN,
&dataOut)) {
return FALSE;
}
*plaintext = dataOut.pbData;
*len = dataOut.cbData;
return TRUE;
}
暗号化のベストプラクティス
絶対に避けるべき実装
HLJSC
// 悪い例:ECBモードの使用(パターンが残る)
// 悪い例:固定IVの使用
// 悪い例:独自の暗号アルゴリズムの実装
// 悪い例:短いキー(128ビット以下)の使用
// 良い例:ランダムIVの生成
void generate_secure_iv(BYTE* iv, DWORD len) {
BCryptGenRandom(NULL, iv, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
}
// 良い例:セキュアなキー導出
void derive_key_securely(const wchar_t* password, BYTE* key, DWORD keyLen) {
BYTE salt[32];
BCryptGenRandom(NULL, salt, sizeof(salt), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
// 高い反復回数を使用
// PBKDF2、scrypt、Argon2idのいずれかを使用
}
監査と監視
暗号化操作のログ記録
HLJSPOWERSHELL
# 暗号化関連のイベントを監査
Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4673, # 特権サービスが呼び出された
4688, # 新しいプロセスが作成された
4692 # バックアップデータ復元の試行
}
まとめ
安全な暗号化の実装には以下が必要です:
- 推奨されるアルゴリズムの使用: AES-256-GCM、ChaCha20-Poly1305
- 適切なパラメータ: 十分な長さのキーとIV、十分な繰り返し回数
- 安全なランダム生成: 暗号論的セキュア乱数生成器(CSPRNG)
- 定期的な更新: 暗号化ライブラリとアルゴリズムの更新
- 監査: 暗号化操作のログ記録と監視
これらのプラクティスを守ることで、データの機密性と完全性を保護できます。