業務ファイルや個人情報を含むデータをバッチ処理で扱う場合、暗号化による保護は欠かせません。しかしWindowsバッチから暗号化を行う方法は複数あり、それぞれ用途や強度が異なります。誤った方法を選ぶと「暗号化しているつもりで実は無防備」という状態になりかねません。
本記事では certutil・OpenSSL・PowerShell の3つのアプローチを整理し、それぞれの用途・強度・実装方法を実践コードとともに解説します。
この記事で学べること
- certutil によるBase64エンコード/デコードの使い方と限界
- certutil のハッシュ生成(SHA256)でファイル改ざんを検知する方法
- OpenSSL によるAES-256-CBC暗号化・復号の実装
- パスワードを外部ファイルから安全に読み込む方法
- PowerShell の DPAPI でパスワード不要の機密保護を行う方法
- 実務で使えるバックアップ自動暗号化スクリプト
手段の選び方:certutil・OpenSSL・PowerShell 比較
まず3つの手段の特徴を把握してから実装を選びましょう。
| 手段 | 暗号強度 | 外部ツール | 主な用途 |
|---|---|---|---|
| certutil -encode | なし(エンコードのみ) | 不要(Windows標準) | 難読化・転送準備・ログ整形 |
| certutil -hashfile | ハッシュ(改ざん検知) | 不要(Windows標準) | ファイル完全性確認 |
| OpenSSL | 強(AES-256-CBC等) | 必要(要インストール) | 本格的な暗号化・復号 |
| PowerShell DPAPI | 強(OS連携) | 不要(Windows標準) | 同一PC・ユーザー内での機密保護 |
重要:certutil -encode は暗号化ではありません
certutil の -encode は Base64 変換(エンコード)であり、暗号化ではありません。デコードコマンドを知っていれば誰でも元に戻せます。「暗号化している」と誤解して機密ファイルに使うのは危険です。難読化・転送フォーマット変換・バイナリのテキスト化の目的には使えますが、セキュリティ目的には使わないでください。
certutil でBase64エンコード・デコードを行う
certutil のエンコード/デコードは、バイナリファイルをテキスト形式に変換して転送したい場合や、ファイルをスクリプトに埋め込む際の前処理に使われます。
@echo off
setlocal
set "INPUT=%~1"
set "OUTPUT=%~dpn1.b64"
if not exist "%INPUT%" (
echo [ERROR] ファイルが見つかりません: %INPUT%
exit /b 1
)
certutil -encode "%INPUT%" "%OUTPUT%"
if errorlevel 1 (
echo [ERROR] エンコードに失敗しました。
exit /b 1
)
echo [OK] エンコード完了: %OUTPUT%
endlocal
@echo off
setlocal
set "INPUT=%~1"
set "OUTPUT=%~dpn1.bin"
if not exist "%INPUT%" (
echo [ERROR] ファイルが見つかりません: %INPUT%
exit /b 1
)
certutil -decode "%INPUT%" "%OUTPUT%"
if errorlevel 1 (
echo [ERROR] デコードに失敗しました。
exit /b 1
)
echo [OK] デコード完了: %OUTPUT%
endlocal
certutil でファイルのハッシュ値を検証する(改ざん検知)
certutil のもう一つの実用的な使い方がハッシュ値の生成です。ファイルの配布前後でハッシュ値を比較することで、転送中の破損や改ざんを検知できます。
@echo off
setlocal
set "TARGET=%~1"
set "HASHFILE=%~dpn1.sha256"
if not exist "%TARGET%" (
echo [ERROR] ファイルが見つかりません: %TARGET%
exit /b 1
)
:: SHA256ハッシュを生成してファイルに保存
certutil -hashfile "%TARGET%" SHA256 > "%HASHFILE%"
if errorlevel 1 (
echo [ERROR] ハッシュ生成に失敗しました。
exit /b 1
)
echo [OK] ハッシュ値を保存しました: %HASHFILE%
type "%HASHFILE%"
endlocal
@echo off
setlocal enabledelayedexpansion
set "TARGET=%~1"
set "EXPECTED_HASH=%~2"
:: 現在のハッシュを取得(2行目がハッシュ値)
set "TMPFILE=%TEMP%\hash_check.tmp"
certutil -hashfile "%TARGET%" SHA256 > "%TMPFILE%"
set "LINE=0"
set "ACTUAL_HASH="
for /f "usebackq skip=1 delims=" %%A in ("%TMPFILE%") do (
set /a LINE+=1
if !LINE! == 1 set "ACTUAL_HASH=%%A"
)
del "%TMPFILE%"
:: 空白を除去して比較
set "ACTUAL_HASH=!ACTUAL_HASH: =!"
set "EXPECTED_HASH=!EXPECTED_HASH: =!"
if /i "!ACTUAL_HASH!" == "!EXPECTED_HASH!" (
echo [OK] ハッシュ一致:ファイルは改ざんされていません。
exit /b 0
) else (
echo [ERROR] ハッシュ不一致:ファイルが変更されている可能性があります。
echo 期待値: !EXPECTED_HASH!
echo 実際値: !ACTUAL_HASH!
exit /b 1
)
endlocal
OpenSSL でAES-256-CBC暗号化・復号を行う
OpenSSL のインストール
WindowsでOpenSSLを使うにはインストールが必要です。インストール後、openssl コマンドが使えるようにPATHを通してください。パスが通っているか確認するには openssl version を実行します。
インストール確認
コマンドプロンプトで openssl version を実行し、OpenSSL 3.x.x ... のようにバージョンが表示されれば使用できます。インストールされていない場合は https://slproweb.com/products/Win32OpenSSL.html から入手してください。
AES-256-CBC で暗号化する
AES-256-CBCはOpenSSLで最もよく使われる対称暗号方式です。-pbkdf2 フラグを必ず付けてください。これを省略すると弱い鍵導出関数が使われ、セキュリティが大幅に低下します。
@echo off
setlocal
set "INPUT=%~1"
set "OUTPUT=%~1.enc"
set "PASSFILE=%~dp0pass.key"
if not exist "%INPUT%" (
echo [ERROR] ファイルが見つかりません: %INPUT%
exit /b 1
)
if not exist "%PASSFILE%" (
echo [ERROR] パスワードファイルが見つかりません: %PASSFILE%
exit /b 1
)
:: -pbkdf2 で安全な鍵導出、-iter で反復回数を指定
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 ^
-in "%INPUT%" ^
-out "%OUTPUT%" ^
-pass file:"%PASSFILE%"
if errorlevel 1 (
echo [ERROR] 暗号化に失敗しました。
exit /b 1
)
echo [OK] 暗号化完了: %OUTPUT%
endlocal
@echo off
setlocal
set "INPUT=%~1"
set "OUTPUT=%~dpn1.dec"
set "PASSFILE=%~dp0pass.key"
if not exist "%INPUT%" (
echo [ERROR] ファイルが見つかりません: %INPUT%
exit /b 1
)
if not exist "%PASSFILE%" (
echo [ERROR] パスワードファイルが見つかりません: %PASSFILE%
exit /b 1
)
openssl enc -aes-256-cbc -d -pbkdf2 -iter 100000 ^
-in "%INPUT%" ^
-out "%OUTPUT%" ^
-pass file:"%PASSFILE%"
if errorlevel 1 (
echo [ERROR] 復号に失敗しました。パスワードが間違っている可能性があります。
exit /b 1
)
echo [OK] 復号完了: %OUTPUT%
endlocal
パスワードの直書きは厳禁
-k mypassword のようにスクリプト内にパスワードを直書きすると、ファイルを見た人なら誰でも復号できてしまいます。-pass file:パスファイル を使い、パスワードファイルへのアクセス権を制限してください。
パスワードファイルの作成と管理
:: ランダムなパスワードをOpenSSLで生成してファイルに保存 openssl rand -base64 32 > pass.key :: ファイルのアクセス権を現在のユーザーのみに制限 icacls pass.key /inheritance:r /grant:r "%USERNAME%:R"
PowerShell の DPAPI で機密文字列を保護する
OpenSSLが使えない環境では、PowerShellの DPAPI(Data Protection API)を使う方法があります。DPAPIはWindowsが提供する暗号化機構で、ログオン中のユーザーとマシンに紐づいた暗号化を行います。パスワードをスクリプトに書かなくて済む点が最大のメリットです。
# 暗号化したいパスワードをSecureStringに変換して保存
Read-Host -Prompt "暗号化するパスワードを入力" -AsSecureString |
ConvertFrom-SecureString |
Out-File "$PSScriptRoot\secure.bin"
Write-Host "パスワードを暗号化して secure.bin に保存しました。"
# 保存済みのSecureStringを復元してプレーンテキストに変換
$securePath = "$PSScriptRoot\secure.bin"
if (-not (Test-Path $securePath)) {
Write-Error "secure.bin が見つかりません。先に暗号化スクリプトを実行してください。"
exit 1
}
$secure = Get-Content $securePath | ConvertTo-SecureString
$plain = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
)
Write-Host "復元されたパスワード: $plain"
@echo off
setlocal
:: PowerShellでDPAPI復元→パスワードを一時ファイルに書き出し
powershell -ExecutionPolicy Bypass -Command ^
"$s=Get-Content '%~dp0secure.bin'|ConvertTo-SecureString;" ^
"$p=[System.Runtime.InteropServices.Marshal]::PtrToStringAuto(" ^
"[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($s));" ^
"$p|Out-File -Encoding ASCII '%TEMP%\tmppass.key' -NoNewline"
:: OpenSSLで復号
openssl enc -aes-256-cbc -d -pbkdf2 -iter 100000 ^
-in "%~1" -out "%~dpn1.dec" ^
-pass file:"%TEMP%\tmppass.key"
:: 一時パスワードファイルを即削除
del "%TEMP%\tmppass.key"
endlocal
secure.bin は、暗号化を実行したユーザー・マシン上でのみ復元できます。別PCや別ユーザーでは復元不可能です。同一マシン内の機密情報保護には最適ですが、ファイルを他者に渡す用途にはOpenSSLのパスワードベース暗号化を使ってください。PowerShellとバッチの連携についてはPowerShellをバッチファイルから呼び出す方法もあわせて参照してください。
実務シナリオ:バックアップファイルを定期暗号化する
タスクスケジューラと組み合わせて、毎日のバックアップファイルを自動暗号化・ログ記録する完全版スクリプトです。
@echo off
setlocal enabledelayedexpansion
:: ===== 設定 =====
set "BACKUP_DIR=C:\backup\daily"
set "ENCRYPT_DIR=C:\backup\encrypted"
set "PASSFILE=C:\scripts\pass.key"
set "LOG=C:\scripts\encrypt_log.txt"
set "DATE_STR=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"
echo ==== 暗号化バックアップ開始 %DATE% %TIME% ==== >> "%LOG%"
:: 暗号化先フォルダの確認
if not exist "%ENCRYPT_DIR%" mkdir "%ENCRYPT_DIR%"
:: バックアップフォルダ内の .zip を暗号化
set "FOUND=0"
for %%F in ("%BACKUP_DIR%\*.zip") do (
set "FOUND=1"
set "OUTFILE=%ENCRYPT_DIR%\%%~nF_%DATE_STR%.enc"
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 ^
-in "%%F" ^
-out "!OUTFILE!" ^
-pass file:"%PASSFILE%" >> "%LOG%" 2>&1
if errorlevel 1 (
echo [ERROR] 暗号化失敗: %%F >> "%LOG%"
) else (
echo [OK] 暗号化完了: !OUTFILE! >> "%LOG%"
:: 暗号化後の元ファイルを削除(任意)
:: del "%%F"
)
)
if "%FOUND%"=="0" (
echo [INFO] 暗号化対象ファイルなし。 >> "%LOG%"
)
echo ==== 暗号化バックアップ終了 %DATE% %TIME% ==== >> "%LOG%"
endlocal
タスクスケジューラへの登録方法はバッチでタスクスケジューラを登録・削除する方法を参照してください。
注意:管理者権限について
システム領域のフォルダへの書き込みやicaclsによるアクセス権変更には管理者権限が必要です。バッチファイルで管理者権限を自動取得する方法も参考にしてください。
よくある質問(FAQ)
-pbkdf2 -iter 100000(反復回数10万回以上推奨)を指定してください。まとめ
バッチファイルからのファイル暗号化・保護には、目的に応じた手段の選択が重要です。
- certutil -encode:暗号化ではなくBase64変換。難読化・転送フォーマット変換用
- certutil -hashfile:SHA256でファイルの改ざん検知に使う
- OpenSSL AES-256-CBC:本格的な暗号化。
-pbkdf2 -iter 100000を必ず付ける - PowerShell DPAPI:パスワード不要・同一PC内の機密保護に最適
暗号化処理のエラーハンドリングとログ記録についてはバッチファイルでエラーログを自動収集して保存する方法、エラー時の処理中断パターンについてはエラー時に処理を中断・終了する方法もあわせて参照してください。

