fuka’s diary

A blog that shares my knowledge.

本気でVBAからAES-256 CBCを扱う方法を考える

VBAからAES-256 CBCを扱う方法を理解したので共有します。

本題の前に・・・

時折AESのKeyの値として、MD5で取得した16進数文字列をByte列にしたものを・・・
と言うコードサンプルを見る事があります。
16進数の文字種は0-9a-fの16種類ですから、AES-256のパスワード長は32byteなので、強度が著しく低下してしまう事が分かると思います。
SHA-256で生成したバイト列を使うと良いでしょう。

強度の差は下表のとおりです。

16進数文字列→Byte列 32^16 = 1.20892581961463E24
SHA-256のByte列 32^256 = 2.08158643893288E385

あと、IVはAESを提供するオブジェクトのデフォルト値を使うのが適切です。
万が一、そのサービスが生成するIVに十分な強度が無い場合は、ランダムに0~255の値が格納された16Byte列を利用すると良いでしょう。
IVは決して使い回さず、暗号化する時に生成し、復号時に使用したら、新たなIVを生成するようにします。

本題のソースです、Classにしてあります。
ライセンスはMITライセンスね。

Option Explicit

Private privateAes As Object
Private Const BLOCK_SIZE As Byte = 128

Enum AesKeySize
    AesKeySize_128 = 128
    AesKeySize_192 = 192
    AesKeySize_256 = 256
End Enum

Enum AesMode
    AesMode_CBC = 1
    AesMode_ECB = 2
    AesMode_OFB = 3
    AesMode_CFB = 4
    AesMode_CTS = 5
End Enum

Enum AesPaddingMode
    AesPaddingMode_None = 1
    AesPaddingMode_PKCS7 = 2
    AesPaddingMode_Zeros = 3
    AesPaddingMode_ANSIX923 = 4
    AesPaddingMode_ISO10126 = 5
End Enum

Public Property Get GetKeySize() As AesKeySize
     GetKeySize = privateAes.KeySize
End Property

Public Property Let SetKeySize(key_size As AesKeySize)
    privateAes.KeySize = key_size
End Property

Public Property Get GetMode() As AesMode
    GetMode = privateAes.Mode
End Property

Public Property Let SetMode(field_mode As AesMode)
    privateAes.Mode = field_mode
End Property

Public Property Get GetPadding() As AesPaddingMode
    GetPadding = privateAes.Padding
End Property

Public Property Let SetPadding(padding_mode As AesPaddingMode)
    privateAes.Padding = padding_mode
End Property

Public Property Get GetIV()
    GetIV = privateAes.iv
End Property

Public Property Let SetIV(iv_bytes)
    Dim bytes() As Byte: bytes = iv_bytes
    
    privateAes.iv = bytes
End Property

Public Property Get GetKey()
    GetKey = privateAes.Key
End Property

Public Property Let SetKey(key_bytes)
    Dim bytes() As Byte: bytes = key_bytes
    
    privateAes.Key = bytes
End Property

Public Sub CreateKey()
    Call privateAes.GenerateKey
End Sub

Public Sub CreateIV()
    Call privateAes.GenerateIV
End Sub

Public Function Encryptor(target_bytes)
    Dim encrypto As Object
    Set encrypto = privateAes.CreateEncryptor
    
    Dim bytes() As Byte: bytes = target_bytes
    
    Dim result() As Byte
    result = encrypto.TransformFinalBlock(bytes, 0, UBound(bytes) + 1)

    Encryptor = result
End Function

Public Function Decryptor(encrypto_bytes)
    Dim decrypto As Object
    Set decrypto = privateAes.CreateDecryptor
    
    Dim bytes() As Byte: bytes = encrypto_bytes
    
    Dim result() As Byte
    result = decrypto.TransformFinalBlock(bytes, 0, UBound(bytes) + 1)

    Decryptor = result
End Function

Private Sub Class_Initialize()
    Set privateAes = CreateObject("System.Security.Cryptography.RijndaelManaged")
    
    With privateAes
        .KeySize = 256
        .Mode = 1
        .Padding = 2
        .BlockSize = BLOCK_SIZE
        
        Call .GenerateKey
        Call .GenerateIV
    End With
End Sub

Private Sub Class_Terminate()
    Set privateAes = Nothing
End Sub

簡単な使い方はこんな感じ。

Sub Sample()
    Dim aes As CryptoAes:   Set aes = New CryptoAes
    Dim target As String:   target = "暗号化する文字列"
    
    Dim encrypto() As Byte
    encrypto = aes.Encryptor(target)
    
    Dim decrypto() As Byte
    decrypto = aes.Decryptor(encrypto)
    
    Debug.Print decrypto
End Sub

今度、実用に耐えられるサンプルコードを用意します。