ねらい: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、秘匿が必要なら暗号と併用。
- 正規化を入口で固定し、クオート・戻り値判定・開始/終了枠を徹底すれば、初心者でも壊れない運用が作れます。
