Visual Basic 6.0, Visual Basic for Application(VBA)での実装
「VBA SHA256」をキーワードにこのサイトへ訪ねて来られる方が結構いらっしゃるので、VB6.0やVBA(Visual Basic for Application)で動作するSHA-256のソースを書いてみました。
処理手順は同じです。 ただ、ビットシフトと符号無し32bit整数型がないので、ビット演算や乗算・除算を使ってゴリゴリやってます。 配列のコピーにCopyMemory、エンディアン変換にWinSockのhtonlという2つのAPI関数を使っています。
プロジェクトにクラスを追加して「SHA256」とでも名付けてください。 呼び出しサンプルはページ下部にあります。
' SHA-256ハッシュアルゴリズムを用いてバイト配列のハッシュ(メッセージダイジェスト)を取得するクラスです。 ' ' コード作成 : StudioAREA.WIZ ( http://wiz-code.net/ ) ' ' 参照文書 : FIPS 180-2 ' 文書URL : http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf Option Explicit ' バイト配列と整数型の相互変換に使います Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" _ (ByVal dest As Long, ByVal src As Long, ByVal length As Long) ' エンディアン変換の変わりにネットワークバイトオーダー変換関数を使います Private Declare Function htonl Lib "wsock32.dll" (ByVal hostlong As Long) As Long Private k(63) As Long Private Bit32(31) As Long Private Const w As Integer = 32 Private Sub Class_Initialize() ' 定数Kの設定 k(0) = &H428A2F98: k(1) = &H71374491: k(2) = &HB5C0FBCF: k(3) = &HE9B5DBA5 k(4) = &H3956C25B: k(5) = &H59F111F1: k(6) = &H923F82A4: k(7) = &HAB1C5ED5 k(8) = &HD807AA98: k(9) = &H12835B01: k(10) = &H243185BE: k(11) = &H550C7DC3 k(12) = &H72BE5D74: k(13) = &H80DEB1FE: k(14) = &H9BDC06A7: k(15) = &HC19BF174 k(16) = &HE49B69C1: k(17) = &HEFBE4786: k(18) = &HFC19DC6: k(19) = &H240CA1CC k(20) = &H2DE92C6F: k(21) = &H4A7484AA: k(22) = &H5CB0A9DC: k(23) = &H76F988DA k(24) = &H983E5152: k(25) = &HA831C66D: k(26) = &HB00327C8: k(27) = &HBF597FC7 k(28) = &HC6E00BF3: k(29) = &HD5A79147: k(30) = &H6CA6351: k(31) = &H14292967 k(32) = &H27B70A85: k(33) = &H2E1B2138: k(34) = &H4D2C6DFC: k(35) = &H53380D13 k(36) = &H650A7354: k(37) = &H766A0ABB: k(38) = &H81C2C92E: k(39) = &H92722C85 k(40) = &HA2BFE8A1: k(41) = &HA81A664B: k(42) = &HC24B8B70: k(43) = &HC76C51A3 k(44) = &HD192E819: k(45) = &HD6990624: k(46) = &HF40E3585: k(47) = &H106AA070 k(48) = &H19A4C116: k(49) = &H1E376C08: k(50) = &H2748774C: k(51) = &H34B0BCB5 k(52) = &H391C0CB3: k(53) = &H4ED8AA4A: k(54) = &H5B9CCA4F: k(55) = &H682E6FF3 k(56) = &H748F82EE: k(57) = &H78A5636F: k(58) = &H84C87814: k(59) = &H8CC70208 k(60) = &H90BEFFFA: k(61) = &HA4506CEB: k(62) = &HBEF9A3F7: k(63) = &HC67178F2 ' ビット演算を高速化するためのビット配列 Dim i As Integer Bit32(0) = 1: Bit32(31) = &H80000000 For i = 1 To 30: Bit32(i) = Bit32(i - 1) * 2: Next End Sub ' 右ビットシフト(SHift Right) Private Function SHR(ByVal v As Long, ByVal n As Integer) As Long Dim r As Long, s As Long If n <= 0 Then SHR = v: Exit Function If n >= 32 Then SHR = 0: Exit Function s = v And &H80000000 v = (v And &H7FFFFFFF) \ Bit32(n) If s Then v = v Or Bit32(31 - n) SHR = v End Function ' 左ビットシフト(Shift Left) Private Function SHL(ByVal v As Long, ByVal n As Integer) As Long Dim r As Long, s As Long If n <= 0 Then SHL = v: Exit Function If n >= 32 Then SHL = 0: Exit Function If n = 31 Then SHL = &H80000000 * (v And &H1&): Exit Function s = v And Bit32(31 - n) v = (v And (Bit32(31 - n) - 1)) * Bit32(n) If s Then v = v Or &H80000000 SHL = v End Function ' 右ビット回転(ROTate Right) Private Function ROTR(ByVal v As Long, ByVal n As Integer) As Long ROTR = SHR(v, n) Or SHL(v, w - n) End Function ' 左ビット回転(ROTate Left) Private Function ROTL(ByVal v As Long, ByVal n As Integer) As Long ROTL = SHL(v, n) Or SHR(v, w - n) End Function ' オーバーフローを回避して複数の値を加算 Private Function SafeAdd(ParamArray Values() As Variant) As Long Dim r As Long, tmp As Long, i As Integer r = Values(0) For i = 1 To UBound(Values) ' 下位30bit同士を加算(31bit→32bitの桁上がりはしない) tmp = ((r And &H3FFFFFFF) + (Values(i) And &H3FFFFFFF)) ' 32bitへ桁上がりする場合は32bitを付加 If ((r And Values(i)) Or ((r Or Values(i)) And tmp)) And &H40000000 Then tmp = tmp Or &H80000000 End If ' 31-32bitを桁上がりなしで加算 r = tmp Xor (r And &HC0000000) Xor (Values(i) And &HC0000000) Next SafeAdd = r End Function ' Ch Private Function Ch(ByVal x As Long, ByVal y As Long, _ ByVal z As Long) As Long Ch = (x And y) Xor ((Not x) And z) End Function ' Maj Private Function Maj(ByVal x As Long, ByVal y As Long, _ ByVal z As Long) As Long Maj = (x And y) Xor (x And z) Xor (y And z) End Function ' シグマA0(Σ0) Private Function SigmaA0(ByVal x As Long) As Long SigmaA0 = ROTR(x, 2) Xor ROTR(x, 13) Xor ROTR(x, 22) End Function ' シグマA1(Σ1) Private Function SigmaA1(ByVal x As Long) As Long SigmaA1 = ROTR(x, 6) Xor ROTR(x, 11) Xor ROTR(x, 25) End Function ' シグマB0(σ0) Private Function SigmaB0(ByVal x As Long) As Long SigmaB0 = ROTR(x, 7) Xor ROTR(x, 18) Xor SHR(x, 3) End Function ' シグマB1(σ1) Private Function SigmaB1(ByVal x As Long) As Long SigmaB1 = ROTR(x, 17) Xor ROTR(x, 19) Xor SHR(x, 10) End Function ' ハッシュ計算処理 Private Sub Computation(buff() As Long, block() As Byte) Dim i As Integer ' ハッシュ計算用変数 Dim t1 As Long Dim t2 As Long Dim w(63) As Long ' 現在のハッシュ値を記憶 Dim a As Long, b As Long, c As Long, d As Long Dim e As Long, f As Long, g As Long, h As Long a = buff(0): b = buff(1): c = buff(2): d = buff(3) e = buff(4): f = buff(5): g = buff(6): h = buff(7) For i = 0 To 63 If i < 16 Then CopyMemory VarPtr(w(i)), VarPtr(block(i * 4)), 4 w(i) = htonl(w(i)) Else w(i) = SafeAdd(SigmaB1(w(i - 2)), w(i - 7), _ SigmaB0(w(i - 15)), w(i - 16)) End If t1 = SafeAdd(h, SigmaA1(e), Ch(e, f, g), k(i), w(i)) t2 = SafeAdd(SigmaA0(a), Maj(a, b, c)) h = g g = f f = e e = SafeAdd(d, t1) d = c c = b b = a a = SafeAdd(t1, t2) Next buff(0) = SafeAdd(a, buff(0)) buff(1) = SafeAdd(b, buff(1)) buff(2) = SafeAdd(c, buff(2)) buff(3) = SafeAdd(d, buff(3)) buff(4) = SafeAdd(e, buff(4)) buff(5) = SafeAdd(f, buff(5)) buff(6) = SafeAdd(g, buff(6)) buff(7) = SafeAdd(h, buff(7)) End Sub ' SHA-256アルゴリズムによりメッセージダイジェストを取得します。 Public Function Hash(bytes() As Byte) As Byte() Dim bytesLen As Long Dim length(3) As Byte bytesLen = UBound(bytes) + 1 CopyMemory VarPtr(length(0)), VarPtr(htonl(bytesLen * 8)), 4 ReDim Preserve bytes(bytesLen) bytes(bytesLen) = &H80 bytesLen = bytesLen + 1 Dim blocks As Long blocks = (bytesLen \ 64) + 1 If (bytesLen And &H3F) > 56 Then blocks = blocks + 1 ReDim Preserve bytes(blocks * 64 - 1) CopyMemory VarPtr(bytes(UBound(bytes) - 3)), VarPtr(length(0)), 4 Dim h(7) As Long h(0) = &H6A09E667: h(1) = &HBB67AE85: h(2) = &H3C6EF372: h(3) = &HA54FF53A h(4) = &H510E527F: h(5) = &H9B05688C: h(6) = &H1F83D9AB: h(7) = &H5BE0CD19 Dim block(63) As Byte Dim i As Long For i = 0 To UBound(bytes) Step 64 CopyMemory VarPtr(block(0)), VarPtr(bytes(i)), 64 Computation h, block Next Dim result(31) As Byte For i = 0 To 7: h(i) = htonl(h(i)): Next CopyMemory VarPtr(result(0)), VarPtr(h(0)), 32 Hash = result End Function
SHA256クラスを利用するサンプルコード
Sub Main() Dim sha As New SHA256 ' SHA256クラスのインスタンスを作成 Dim bytes() As Byte Dim shaHash() As Byte ' ハッシュを得る文字列をバイト配列化(ASCII) bytes = StrConv("abc", vbFromUnicode) ' ハッシュ値を算出 shaHash = sha.Hash(bytes) ' バイナリダンプ Dim i As Integer For i = 0 To 31 Debug.Print Right("00" & Hex(shaHash(i)), 2) & " "; Next End Sub