Excel VBA 逆引き集 | ハッシュ生成

Excel VBA
スポンサーリンク

ねらい:VBAで「ハッシュ生成」を道具化し、改ざん検知・差分・キー作成を一気に楽にする

ハッシュは、内容を固定長の指紋(ダイジェスト)に変換する技術です。ファイルやテキストが「同じか・変わったか」を一瞬で判定でき、差分レポート、改ざん検知、重複判定、結合キー作成に直結します。VBAではOS標準(PowerShellのGet-FileHash)、.NETのハッシュライブラリ、簡易文字列ハッシュ(CRC/自前)を使い分けます。初心者でも貼って動くテンプレを、用途別にかみ砕いて示します。


基本の考え方と選び方

ハッシュの種類と用途

  • MD5/ SHA-1: 速度重視の場面向け。衝突耐性は十分ではないため、改ざん検知はSHA-256以上を推奨。
  • SHA-256: 実務標準。配布ファイルの整合性、監査ログ、差分の確証に適します。
  • HMAC(SHA-256など): 鍵付きハッシュ。改ざん検知+正当性証明(鍵を持つ人だけが生成)に使います。
  • 軽量擬似ハッシュ(連結文字列やCRC32): 表の「変更判定」や、突合の高速キーとして便利。セキュリティ目的には不適。

重要ポイントの深掘り

  • ハッシュは「同じ入力→必ず同じ値、違う入力→高確率で違う値」。セキュリティ(改ざん対策)ではSHA-256以上、性能目的(差分)では軽量化も検討。
  • 文字列は正規化(Trim、大小統一、改行統一)してからハッシュを取ると“意味のない差”を除去できます。
  • ファイルハッシュは読み取りストリーム方式が堅牢。巨大ファイルでも安定して処理できます。

ファイルのSHA-256を最速で取る(PowerShell標準)

Get-FileHashで取得してVBAへ取り込む

' ModHash_File_PS.bas
Option Explicit

Public Function FileSha256(ByVal path As String) As String
    Dim cmd As String
    cmd = "powershell -NoProfile -Command ""(Get-FileHash -Algorithm SHA256 -Path '" & Replace(path, "'", "''") & "').Hash"""
    FileSha256 = ExecReadAll(cmd)
End Function

Private Function ExecReadAll(ByVal cmd As String) As String
    Dim sh As Object: Set sh = CreateObject("WScript.Shell")
    Dim p As Object: Set p = sh.Exec(cmd)
    ExecReadAll = Trim$(p.StdOut.ReadAll)
End Function

Public Sub Demo_FileSha256()
    Dim h As String
    h = FileSha256(ThisWorkbook.FullName)
    MsgBox "SHA-256: " & h, vbInformation
End Sub
VB

重要ポイントの深掘り

  • PowerShell標準は戻り値と例外が明確で、実務の信頼性が高いです。日本語パス・スペースを安全に通すため、シングルクォートとエスケープ(Replace)を徹底します。
  • 監査用は「ファイル名、サイズ、更新日時、SHA-256」を一緒に記録すると、長期運用で意味のある台帳になります。

テキストのMD5/SHA-256をVBAから生成(.NET委譲)

.NETのハッシュ関数をPowerShell経由で呼び出す

' ModHash_Text_NET.bas
Option Explicit

Public Function TextSha256(ByVal s As String) As String
    Dim ps As String
    ps = "powershell -NoProfile -Command " & _
         """$t='" & EscapePS(s) & "'; " & _
         "$bytes=[Text.Encoding]::UTF8.GetBytes($t); " & _
         "$sha=[System.Security.Cryptography.SHA256]::Create(); " & _
         "$hash=$sha.ComputeHash($bytes); " & _
         "[BitConverter]::ToString($hash).Replace('-', '')"""
    TextSha256 = ExecReadAll(ps)
End Function

Public Function TextMd5(ByVal s As String) As String
    Dim ps As String
    ps = "powershell -NoProfile -Command " & _
         """$t='" & EscapePS(s) & "'; " & _
         "$bytes=[Text.Encoding]::UTF8.GetBytes($t); " & _
         "$md5=[System.Security.Cryptography.MD5]::Create(); " & _
         "$hash=$md5.ComputeHash($bytes); " & _
         "[BitConverter]::ToString($hash).Replace('-', '')"""
    TextMd5 = ExecReadAll(ps)
End Function

Private Function ExecReadAll(ByVal cmd As String) As String
    Dim sh As Object: Set sh = CreateObject("WScript.Shell")
    Dim p As Object: Set p = sh.Exec(cmd)
    ExecReadAll = Trim$(p.StdOut.ReadAll)
End Function

Private Function EscapePS(ByVal s As String) As String
    EscapePS = Replace(Replace(s, "'", "''"), """", "`" & """")
End Function

Public Sub Demo_TextHash()
    Dim t As String: t = "こんにちは、Excel。"
    MsgBox "MD5: " & TextMd5(t) & vbCrLf & "SHA-256: " & TextSha256(t), vbInformation
End Sub
VB

重要ポイントの深掘り

  • 文字列はUTF-8でバイト列化してからハッシュ化します。改行や空白の揺らぎを消すには、事前正規化(Trim、改行統一)を挟みます。
  • MD5は速度重視で差分用に便利ですが、改ざん検知やセキュア用途はSHA-256を使ってください。

表の「行ハッシュ」を作るテンプレ(差分・変更判定用)

複数列を正規化して連結→SHA-256(実務定番)

' ModHash_Row_SHA.bas
Option Explicit

Private Const SEP As String = Chr$(30)

Public Sub ComputeRowHashSha256(ByVal wsName As String, ByVal colsCsv As String)
    Dim ws As Worksheet: Set ws = Worksheets(wsName)
    Dim a As Variant: a = ws.Range("A1").CurrentRegion.Value

    Dim cols() As Long: cols = ColsToIndex(colsCsv)
    Dim out() As Variant: ReDim out(1 To UBound(a, 1), 1 To 1)
    out(1, 1) = "RowHash(SHA-256)"

    Dim r As Long
    For r = 2 To UBound(a, 1)
        out(r, 1) = TextSha256(RowConcat(a, r, cols))
    Next

    ws.Range("Z1").Resize(UBound(out, 1), 1).Value = out
    ws.Columns.AutoFit
End Sub

Private Function ColsToIndex(ByVal colsCsv As String) As Long()
    Dim parts() As String: parts = Split(colsCsv, ",")
    Dim idx() As Long: ReDim idx(0 To UBound(parts))
    Dim i As Long
    For i = 0 To UBound(parts)
        idx(i) = Range(Trim$(parts(i)) & "1").Column
    Next
    ColsToIndex = idx
End Function

Private Function RowConcat(ByVal a As Variant, ByVal r As Long, ByVal idx() As Long) As String
    Dim i As Long, s As String
    For i = LBound(idx) To UBound(idx)
        s = s & LCase$(Trim$(CStr(a(r, idx(i))))) & SEP
    Next
    RowConcat = s
End Function
VB

重要ポイントの深掘り

  • 実務の差分判定は「キー列で一致→値列のハッシュが違うか」で見ます。ここでは行の固定列集合を正規化連結→SHA-256化。
  • 区切りはありえない文字(Chr(30))にして、列値が連結しても誤結合しないようにします。日本語・空白の揺らぎは入口で統一。

共有検証や認証向け:HMAC-SHA256(鍵付きハッシュ)

送受双方が同じ鍵で「正当な発信か」を確認できる

' ModHmac_SHA256.bas
Option Explicit

Public Function HmacSha256(ByVal text As String, ByVal keyHex As String) As String
    Dim ps As String
    ps = "powershell -NoProfile -Command " & _
         """$t='" & EscapePS(text) & "'; $k='" & keyHex & "'; " & _
         "$key=[byte[]]($k -split '([A-Fa-f0-9]{2})' | ? { $_ -match '^[A-Fa-f0-9]{2}$' } | % {[Convert]::ToByte($_,16)}); " & _
         "$mac=new-object System.Security.Cryptography.HMACSHA256($key); " & _
         "$bytes=[Text.Encoding]::UTF8.GetBytes($t); " & _
         "[BitConverter]::ToString($mac.ComputeHash($bytes)).Replace('-', '')"""
    HmacSha256 = ExecReadAll(ps)
End Function
VB

重要ポイントの深掘り

  • HMACは“改ざん検知+正当性証明”。鍵管理がすべてなので、キーの保管(資格情報・環境変数)とローテーション方針を決めておきます。
  • 暗号化は行わず「タグ付け」だけ。内容秘匿が必要なら、AES暗号と併用します。

軽量擬似ハッシュ:CRC32や簡易FNVで速度重視のキー生成

CSVやログの高速キー用(セキュリティ目的では使わない)

' ModHash_Light.bas
Option Explicit

Public Function Crc32(ByVal s As String) As Long
    Static table(255) As Long
    Static inited As Boolean
    Dim i As Long, j As Long, c As Long

    If Not inited Then
        For i = 0 To 255
            c = i
            For j = 1 To 8
                If (c And 1) <> 0 Then
                    c = &HEDB88320 Xor (c \ 2)
                Else
                    c = (c \ 2)
                End If
            Next
            table(i) = c
        Next
        inited = True
    End If

    Dim bytes() As Byte: bytes = StrConv(s, vbFromUnicode)
    Dim crc As Long: crc = &HFFFFFFFF
    For i = LBound(bytes) To UBound(bytes)
        crc = table((crc Xor bytes(i)) And &HFF) Xor (crc \ 256)
    Next
    Crc32 = Not crc
End Function
VB

重要ポイントの深掘り

  • CRC32は高速で、差分・重複検出の一次キーに便利。ただし衝突耐性は弱いので、最終判定はSHA-256などで補完する設計が安全です。
  • 文字列の正規化(Trim/LCase/改行統一)を必ず挟み、実質同一の行が別扱いになるのを防ぎます。

実務テンプレ:ハッシュ台帳の自動生成

フォルダ内の全ファイルをSHA-256で記録

' ModHashLedger.bas
Option Explicit

Public Sub BuildHashLedger(ByVal root As String)
    Dim ws As Worksheet: Set ws = PrepareOutputSheet("HashLedger")
    ws.Range("A1:D1").Value = Array("Path", "Size", "LastWriteTime", "SHA256")

    Dim rowOut As Long: rowOut = 2
    Dim f As String: f = Dir(root & "\*.*", vbNormal)
    Do While Len(f) > 0
        Dim full As String: full = root & "\" & f
        ws.Cells(rowOut, "A").Value = full
        ws.Cells(rowOut, "B").Value = FileLen(full)
        ws.Cells(rowOut, "C").Value = FileDateTime(full)
        ws.Cells(rowOut, "D").Value = FileSha256(full)
        rowOut = rowOut + 1
        f = Dir
    Loop
    ws.Columns.AutoFit
    MsgBox "ハッシュ台帳を作成しました。", vbInformation
End Sub

Private Function PrepareOutputSheet(ByVal name As String) As Worksheet
    Dim ws As Worksheet
    On Error Resume Next: Set ws = ThisWorkbook.Worksheets(name): On Error GoTo 0
    If ws Is Nothing Then Set ws = ThisWorkbook.Worksheets.Add: ws.Name = name
    ws.Cells.Clear
    Set PrepareOutputSheet = ws
End Function
VB

重要ポイントの深掘り

  • 台帳は「いつ・何を・どのハッシュで記録したか」を残すのが目的。サイズ・時刻・パスとセットで記録し、配布前後で一致確認します。
  • ネットワークドライブは遅延や権限で失敗しやすいので、まずローカルで生成→移動の運用が安定します。

落とし穴と対策

MD5/ SHA-1を改ざん検知に使う誤用

速度は魅力ですが、セキュリティ目的はSHA-256以上。監査や配布はSHA-256で統一。

正規化不足による擬似差分

空白・改行・大小の差で別ハッシュになりがち。仕様に合わせた正規化関数を入口で固定。

ハッシュだけで「認証」をやろうとする

ハッシュは改ざん検知。送信者の正当性はHMACや署名(公開鍵)領域。用途を混同しない。

文字コードのズレ

日本語はUTF-8化してからハッシュ化。Windows-31J/UTF-16のまま混在させると一致判定が崩れます。


まとめ:目的別に「SHA-256・HMAC・軽量擬似」を使い分け、正規化と配列I/Oで実務を高速化

  • ファイル整合性はSHA-256の台帳化、テキストはUTF-8でハッシュ化。
  • 差分・変更判定は行連結→SHA-256(または軽量擬似+最終確認)。
  • 送受の正当性はHMAC、秘匿が必要なら暗号と併用。
  • 正規化を入口で固定し、クオート・戻り値判定・開始/終了枠を徹底すれば、初心者でも壊れない運用が作れます。

タイトルとURLをコピーしました