Home > Windows にまつわる e.t.c.

PowerShell でファイルの AES256 暗号/復号


このサイトで暗号系のサンプル実装をいろいろ書いていますが、サンプルなのでテキストにして結果を見る感じの実装になっています。

でも、実際の運用で暗号系の実装する場合は、byte 配列でデーターをハンドリングするのがセオリーなんですね。

AES256 暗号が必要だったので、byte 配列ハンドリングの AES256 暗号/復号の PowerShell スクリプトを書いたので公開します。

以下 ReadMe より

■ これは何?

AES 256 共通鍵暗号を使ってファイルを暗号/復号します

 

■ 動作環境は?

PowerShell 3.0 以降環境で動作します

動作確認したバージョンは以下の通り

3.0 Windows 7
5.1 Windows 10
6.0 beta 9 Windows 10
CentOS 7

■ 使用方法

・暗号化

以下スクリプトに、暗号化するファイルのパス(又は Get-ChildItem で得られる fileinfo)と共通鍵のフルパス又は Base64 文字列(-KeyBase64)を与えると、AES256 で暗号化したファイルを作成します(拡張子 .enc)

暗号化するファイルは複数指定できます。

AES256.ps1 -Encrypto -KeyPath 共通鍵のフルパス -Path 暗号化するファイル
AES256.ps1 -Encrypto -KeyBase64 Base64共通鍵 -Path 暗号化するファイル

 

・復号化

以下スクリプトに、復号化するファイルのパス(又は Get-ChildItem で得られる fileinfo)と共通鍵のフルパス又は Base64 文字列(-KeyBase64)を与えると、復号ファイルを作成します(注意:既存ファイルがあれば上書き)

復号化するファイルは複数指定できます。

AES256.ps1 -Decrypto -KeyPath 共通鍵のフルパス -Path 復号化するファイル
AES256.ps1 -Decrypto -KeyBase64 Base64共通鍵 -Path 復号化するファイル

 

・共通鍵の作成

以下スクリプトに共通鍵のフルパスを与えると、ランダムな 256 bit の共通鍵を生成します(Base64 でエンコード)

Make256Key.ps1 共通鍵のフルパス

 

■ 実行例

・鍵ファイルを指定して暗号化

PS C:\Script\aes256> .\AES256.ps1 -Encrypto -KeyPath "C:\Key\Shared.key" -Path "C:\Data\TestData.txt"

 

・複数ファイルを暗号化

PS C:\Script\aes256> $EncFiles = dir C:\Data
PS C:\Script\aes256> .\AES256.ps1 -Encrypto -KeyPath "C:\Key\Shared.key" -Path $EncFiles

 

・Base64鍵を指定して復号化

PS C:\Script\aes256> .\AES256.ps1 -Decrypto -KeyBase64 "X6iFs1i1wB1nFJaRxAM3PuzduvRS/Kyh8+cfcE+7FxA=" -Path "C:\Data\TestData.txt"

 

・共通鍵を作成

PS C:\Script\aes256> .\Make256Key.ps1 "C:\Key\Shared.key"

 

■ 注意事項

AES256 のストリーミングを使わず、オンメモリーで暗号/復号しています。
このため、でかいファイルを暗号/復号する場合は、メモリーに余裕のある環境での実行をお勧めします。

 

リポジトリ公開場所

GitHub でリポジトリ公開しています。

https://github.com/MuraAtVwnet/AES256

 

ダウンロード

リポジトリを Clone して下さい。

git@github.com:MuraAtVwnet/AES256.git

 

Clone が面倒な場合は、以下スクリプトでのダウンロードでもイケます。
(PowerShell 4.0 以降)

$Terget = "C:\Script\aes256"
$DowunLoadFile = Join-Path $Terget "AES256.zip"
if( -not(Test-Path $Terget) ){ md $Terget }
Invoke-WebRequest https://github.com/MuraAtVwnet/AES256/archive/master.zip -OutFile $DowunLoadFile
ii $Terget

 

コード

以下公開時点のソースコードです
(コピペして .ps1 を作っても動きますが、最新版をリポジトリから Clone してもらえると嬉しいです)

[AES256.ps1]

##################################################
# AES256 暗号/復号
##################################################
Param(
    [switch]$Encrypto,  # 暗号化
    [switch]$Decrypto,  # 復号化
    $KeyPath,           # 共通鍵ファイルの Path
    $KeyBase64,         # 共通鍵(Base64)
    [array]$Path        # 処理対象ファイル
)

# 暗号ファイルの拡張子
$ExtName = "enc"

# AES 定数
$AES_KeySize = 256
$AES_BlockSize = 128
$AES_IVSize = $AES_BlockSize / 8
$AES_Mode = "CBC"
$AES_Padding = "PKCS7"

##################################################
# Base64 をバイト配列にする
##################################################
function Base642Byte( $Base64 ){
    $Byte = [System.Convert]::FromBase64String($Base64)
    return $Byte
}

##################################################
# AES 暗号化
##################################################
function AESEncrypto($ByteKey, $BytePlain){

    if( $ByteKey.Length * 8 -ne $AES_KeySize ){
        echo "[FAIL] Key size error"
        return $null
    }

    # アセンブリロード
    Add-Type -AssemblyName System.Security

    # AES オブジェクトの生成
    $AES = New-Object System.Security.Cryptography.AesCryptoServiceProvider

    # 各値セット
    $AES.KeySize = $AES_KeySize
    $AES.BlockSize = $AES_BlockSize
    $AES.Mode = $AES_Mode
    $AES.Padding = $AES_Padding

    # IV 生成
    $AES.GenerateIV()

    # 生成した IV
    $IV = $AES.IV

    # 鍵セット
    $AES.Key = $ByteKey

    # 暗号化オブジェクト生成
    $Encryptor = $AES.CreateEncryptor()

    # 暗号化
    $EncryptoByte = $Encryptor.TransformFinalBlock($BytePlain, 0, $BytePlain.Length)

    # IV と暗号化した文字列を結合
    $DataByte = $IV + $EncryptoByte

    # オブジェクト削除
    $Encryptor.Dispose()
    $AES.Dispose()

    return $DataByte
}

##################################################
# AES 復号化
##################################################
function AESDecrypto($ByteKey, $ByteEncrypto){

    if( $ByteKey.Length * 8 -ne $AES_KeySize ){
        echo "[FAIL] Key size error"
        return $null
    }

    # IV を取り出す
    $IV = @()
    for( $i = 0; $i -lt $AES_IVSize; $i++){
        $IV += $ByteEncrypto[$i]
    }

    # アセンブリロード
    Add-Type -AssemblyName System.Security

    # オブジェクトの生成
    $AES = New-Object System.Security.Cryptography.AesCryptoServiceProvider

    # 各値セット
    $AES.KeySize = $AES_KeySize
    $AES.BlockSize = $AES_BlockSize
    $AES.Mode = $AES_Mode
    $AES.Padding = $AES_Padding

    # IV セット
    $AES.IV = $IV

    # 鍵セット
    $AES.Key = $ByteKey

    # 復号化オブジェクト生成
    $Decryptor = $AES.CreateDecryptor()

    try{
        # 復号化
        $DecryptoByte = $Decryptor.TransformFinalBlock($ByteEncrypto, $AES_IVSize, $ByteEncrypto.Length - $AES_IVSize)
    }
    catch{
        $DecryptoByte = $null
    }

    # オブジェクト削除
    $Decryptor.Dispose()
    $AES.Dispose()

    return $DecryptoByte
}

##################################################
# main
##################################################
$PsMajorVertion = $PSVersionTable.PSVersion.Major
if( $PsMajorVertion -le 2 ){
    echo "[FAIL] PowerSehll 2.0 以下はサポートしていません"
    exit
}

if( $Path -eq $null ){
    echo "Usage..."
    echo " .\aes256.ps1 [-Encrypto|-Decrypto] [-KeyPath KeyFilePath|-KeyBase64 KeyText] -Path InputFilePath(s)"
    exit
}

# 鍵指定
if( ($KeyPath -eq $null) -and `
    ($KeyBase64 -eq $null)){
    echo "[FAIL] Set -KeyPath or KeyBase64"
    exit
}

# 暗号/復号オプション
if( (($Encrypto -eq $fals) -and ( $Decrypto -eq $false)) -or `
    (($Encrypto -eq $true) -and ( $Decrypto -eq $true))){
    echo "[FAIL] select -Encrypto or -Decrypto"
    exit
}

### 鍵読み込み
# ファイルを読む
if( $KeyPath -ne $null ){

    if( -not (Test-Path $KeyPath )){
        echo "[FAIL] $KeyPath not found."
        exit
    }

    $Base64Key = Get-Content $KeyPath
}
# 引数に指定された値を使う
else{
    $Base64Key = $KeyBase64
}

$ByteKey = Base642Byte $Base64Key
if( $ByteKey -eq $null ){
    echo "[FAIL] 鍵エラー"
    exit
}


foreach($TergetFile in $Path){
    # 文字列の場合
    if( $TergetFile.GetType().Name -eq "String" ){
        # フルパスにする
        $TergetFileName = Convert-Path $TergetFile -ErrorAction SilentlyContinue
    }
    # fileinfo
    elseif( $TergetFile.GetType().Name -eq "FileInfo" ){
        $TergetFileName = $TergetFile.FullName
    }
    # 意図しないデータ
    else{
        echo "[ERROR] $TergetFile is bad data."
        continue
    }

    # 正常にフルパスが取れなかった
    if( $TergetFileName -eq $null ){
        echo "[ERROR] $TergetFile is not file name."
        continue
    }

    # Data
    if( -not (Test-Path $TergetFileName )){
        echo "[ERROR] $TergetFileName not found."
        continue
    }

    # 暗号化
    if( $Encrypto ){

        echo "[INFO] Encrypto : $TergetFileName"

        # 暗号化ファイル名
        $EncryptoFileName = $TergetFileName + "." + $ExtName

        # データファイル読み込み
        $BytePlainData = [System.IO.File]::ReadAllBytes($TergetFileName)

        # 暗号
        $ByteEncryptoData = AESEncrypto $ByteKey $BytePlainData
        if( $ByteEncryptoData -eq $null ){
            echo "[FAIL] 暗号失敗"
            exit
        }

        # ファイル出力
        [System.IO.File]::WriteAllBytes($EncryptoFileName, $ByteEncryptoData)
    }
    # 復号化
    else{
        # 拡張子確認
        if( $TergetFileName -notmatch "$ExtName$" ){
            echo "[ERROR] $TergetFileName は暗号化ファイルではない"
            continue
        }

        echo "[INFO] Decrypto : $TergetFileName"

        # 復号ファイル名
        $ChangeString = "."+ $ExtName
        $DecryptoFileName = $TergetFileName.Replace($ChangeString,"")

        # 暗号化ファイル読み込み
        $ByteEncryptoData = [System.IO.File]::ReadAllBytes($TergetFileName)

        # 復号
        $BytePlainData = AESDecrypto $ByteKey $ByteEncryptoData
        if( $BytePlainData -eq $null ){
            echo "[ERROR] 復号失敗"
            continue
        }

        # 平文ファイル出力
        [System.IO.File]::WriteAllBytes($DecryptoFileName, $BytePlainData)
    }
}

 

[Make256Key.ps1]

#####################################################################
# 256 bit の共通鍵を生成する
#####################################################################
Param($Path)

#####################################################################
# バイト配列を Base64 にする
#####################################################################
function Byte2Base64( $Byte ){
    $Base64 = [System.Convert]::ToBase64String($Byte)
    return $Base64
}

##################################################
# セッション鍵生成
##################################################
function CreateRandomKey( $BitSize ){
    if( ($BitSize % 8) -ne 0 ){
        echo "Key size Error"
        return $null
    }
    # アセンブリロード
    Add-Type -AssemblyName System.Security

    # バイト数にする
    $ByteSize = $BitSize / 8

    # 入れ物作成
    $KeyBytes = New-Object byte[] $ByteSize

    # オブジェクト 作成
    $RNG = New-Object System.Security.Cryptography.RNGCryptoServiceProvider

    # 鍵サイズ分の乱数を生成
    $RNG.GetNonZeroBytes($KeyBytes)

    # オブジェクト削除
    $RNG.Dispose()

    return $KeyBytes
}


##################################################
# main
##################################################
if( $PSVersionTable.PSVersion.Major -le 2 ){
    echo "[FAIL] PowerSehll 2.0 以下はサポートしていません"
    exit
}

if( $Path -eq $null ){
    echo "Usage..."
    echo " .\make256key.ps1 -Path KeyFile"
    exit
}


# 256 Bitの共通鍵生成
$ByteKey = CreateRandomKey 256


# Base 64 にする
$Base64Key = Byte2Base64 $ByteKey

# ファイル出力
Set-Content -Path $Path -Value $Base64Key -Encoding UTF8

 

関連情報

SHA-2(SHA256) の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/SHA256.htm

RSA 公開鍵暗号の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/RSACrypto.htm

RSA 電子署名(SHA256)の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/RSASignature.htm

HMAC(SHA256) の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/HMAC-SHA256.htm

スケジュールジョブ(PowerShell)でパスワードをセキュアに使う(証明書編)
http://www.vwnet.jp/Windows/WS12R2/Password/CertPassword.htm

PowerShell で指定サイズのランダムな文字列/バイナリ列を生成する
http://www.vwnet.jp/Windows/PowerShell/CreateRandomData.htm

PowerShell で公開鍵方式暗号ファイルを交換をする
http://www.vwnet.jp/Windows/PowerShell/PublicKeyCrypto.htm

文字列/Base64/Byte配列を PowerShell で相互変換する
http://www.vwnet.jp/Windows/PowerShell/2017110301/ConvertStringBase64Byte.htm

 

 

back.gif (1980 バイト)

home.gif (1907 バイト)

Copyright © MURA All rights reserved.