【bat】バッチファイルでファイル暗号化・復号を自動化する方法|certutil・OpenSSL・PowerShell完全ガイド

【bat】バッチファイルでファイル暗号化・復号を自動化する方法|certutil・OpenSSL・PowerShell完全ガイド bat

業務ファイルや個人情報を含むデータをバッチ処理で扱う場合、暗号化による保護は欠かせません。しかしWindowsバッチから暗号化を行う方法は複数あり、それぞれ用途や強度が異なります。誤った方法を選ぶと「暗号化しているつもりで実は無防備」という状態になりかねません。

本記事では certutilOpenSSLPowerShell の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 のエンコード/デコードは、バイナリファイルをテキスト形式に変換して転送したい場合や、ファイルをスクリプトに埋め込む際の前処理に使われます。

Base64エンコード(バイナリ→テキスト)
@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
Base64デコード(テキスト→バイナリ)
@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 -encode の主な用途バイナリファイル(画像・EXE等)をメール本文やテキストファイルに埋め込む用途や、スクリプト内にファイルデータを文字列として持たせる際に使います。セキュリティ目的での使用は避けてください。

certutil でファイルのハッシュ値を検証する(改ざん検知)

certutil のもう一つの実用的な使い方がハッシュ値の生成です。ファイルの配布前後でハッシュ値を比較することで、転送中の破損や改ざんを検知できます。

SHA256ハッシュ値の生成と保存
@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 フラグを必ず付けてください。これを省略すると弱い鍵導出関数が使われ、セキュリティが大幅に低下します。

AES-256-CBC暗号化(-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
AES-256-CBC復号
@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:パスファイル を使い、パスワードファイルへのアクセス権を制限してください。

パスワードファイルの作成と管理

pass.key の作成例(コマンドプロンプトで1度だけ実行)
:: ランダムなパスワードを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が提供する暗号化機構で、ログオン中のユーザーとマシンに紐づいた暗号化を行います。パスワードをスクリプトに書かなくて済む点が最大のメリットです。

DPAPIで文字列を暗号化して保存(PowerShell)
# 暗号化したいパスワードをSecureStringに変換して保存
Read-Host -Prompt "暗号化するパスワードを入力" -AsSecureString |
    ConvertFrom-SecureString |
    Out-File "$PSScriptRoot\secure.bin"

Write-Host "パスワードを暗号化して secure.bin に保存しました。"
DPAPIで保存済みパスワードを復元(PowerShell)
# 保存済みの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"
バッチからPowerShellで復号してOpenSSLに渡す
@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
DPAPIの制約DPAPIで暗号化した secure.bin は、暗号化を実行したユーザー・マシン上でのみ復元できます。別PCや別ユーザーでは復元不可能です。同一マシン内の機密情報保護には最適ですが、ファイルを他者に渡す用途にはOpenSSLのパスワードベース暗号化を使ってください。

PowerShellとバッチの連携についてはPowerShellをバッチファイルから呼び出す方法もあわせて参照してください。

実務シナリオ:バックアップファイルを定期暗号化する

タスクスケジューラと組み合わせて、毎日のバックアップファイルを自動暗号化・ログ記録する完全版スクリプトです。

backup_encrypt.bat(完全版)
@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)

certutil -encode で暗号化できると書いてある記事を見たが本当に安全?
安全ではありません。certutil -encode はBase64という「エンコード方式」で変換しているだけです。暗号化とは異なり、デコードコマンドを知っていれば誰でも元のファイルに戻せます。機密性が必要なファイルには必ずOpenSSLやDPAPIなどの本格的な暗号化を使ってください。
-pbkdf2 オプションをつけないとどうなる?
OpenSSL の古いデフォルト鍵導出関数(EVP_BytesToKey)が使われ、ブルートフォース攻撃への耐性が大幅に低下します。OpenSSL 3.x ではこの設定のまま使うと警告が出ます。常に -pbkdf2 -iter 100000(反復回数10万回以上推奨)を指定してください。
暗号化ファイルを別のPCで復号したい
OpenSSLのパスワードベース暗号化(-pass file:)であれば、同じパスワードファイルさえあれば別PCでも復号できます。DPAPIは同一PC・同一ユーザーでのみ復号可能なため、ファイルを他者に渡す場合はOpenSSLを使ってください。
OpenSSLをインストールせずに使える方法はあるか?
はい。PowerShell の DPAPI(ConvertFrom-SecureString)はWindows標準機能で追加インストール不要です。ただし同一PC・ユーザー内の保護に限定されます。他者との暗号化ファイルのやり取りにはOpenSSLが必要です。
暗号化したファイルのパスワードを忘れたら復号できない?
OpenSSLのパスワードベース暗号化は、パスワードを失うと復号は事実上不可能です(それが暗号化の目的です)。パスワードファイルは必ず安全な場所にバックアップしてください。pass.key 自体を別のパスワードで暗号化して保管する多層管理が理想です。
ハッシュ値と暗号化の違いは?
ハッシュ(SHA256等)は一方向変換で、元のデータには戻せません。「ファイルが変わっていないか」の確認(完全性検証)に使います。暗号化は鍵(パスワード)があれば元に戻せる双方向変換で、「内容を見せたくない」場合に使います。用途が異なるため、両方を組み合わせるのが理想的です。

まとめ

バッチファイルからのファイル暗号化・保護には、目的に応じた手段の選択が重要です。

  • certutil -encode:暗号化ではなくBase64変換。難読化・転送フォーマット変換用
  • certutil -hashfile:SHA256でファイルの改ざん検知に使う
  • OpenSSL AES-256-CBC:本格的な暗号化。-pbkdf2 -iter 100000 を必ず付ける
  • PowerShell DPAPI:パスワード不要・同一PC内の機密保護に最適

暗号化処理のエラーハンドリングとログ記録についてはバッチファイルでエラーログを自動収集して保存する方法、エラー時の処理中断パターンについてはエラー時に処理を中断・終了する方法もあわせて参照してください。