Deliberately does not use any API calls so is not the sharpest tool in the shed
CryptoHMAC224 and CryptoHMAC256 functions tested with hmac_sha224_test.json and hmac_sha256_test.json from Project Wycheproof test vectors.
cheers,
</wqw>
Code:
'--- mdSHA2.bas
Option Explicit
DefObj A-Z
Private PowerOf2(0 To 31) As Long
Private Function LShift(ByVal lX As Long, ByVal lN As Long) As Long
If lN = 0 Then
LShift = lX
Else
LShift = (lX And (PowerOf2(31 - lN) - 1)) * PowerOf2(lN) Or -((lX And PowerOf2(31 - lN)) <> 0) * &H80000000
End If
End Function
Private Function RShift(ByVal lX As Long, ByVal lN As Long) As Long
If lN = 0 Then
RShift = lX
Else
RShift = (lX And &H7FFFFFFF) \ PowerOf2(lN) Or -(lX < 0) * PowerOf2(31 - lN)
End If
End Function
Private Function RRotate(ByVal lX As Long, ByVal lN As Long) As Long
'--- RRotate = RShift(X, n) Or LShift(X, 32 - n)
Debug.Assert lN <> 0
RRotate = ((lX And &H7FFFFFFF) \ PowerOf2(lN) - (lX < 0) * PowerOf2(31 - lN)) Or _
((lX And (PowerOf2(lN - 1) - 1)) * PowerOf2(32 - lN) Or -((lX And PowerOf2(lN - 1)) <> 0) * &H80000000)
End Function
Private Function UAdd(ByVal lX As Long, ByVal lY As Long) As Long
If (lX Xor lY) > 0 Then
UAdd = ((lX Xor &H80000000) + lY) Xor &H80000000
Else
UAdd = lX + lY
End If
End Function
Private Function Ch(ByVal lX As Long, ByVal lY As Long, ByVal lZ As Long) As Long
Ch = (lX And lY) Xor ((Not lX) And lZ)
End Function
Private Function Maj(ByVal lX As Long, ByVal lY As Long, ByVal lZ As Long) As Long
Maj = (lX And lY) Xor (lX And lZ) Xor (lY And lZ)
End Function
Private Function BigSigma0(ByVal lX As Long) As Long
BigSigma0 = RRotate(lX, 2) Xor RRotate(lX, 13) Xor RRotate(lX, 22)
End Function
Private Function BigSigma1(ByVal lX As Long) As Long
BigSigma1 = RRotate(lX, 6) Xor RRotate(lX, 11) Xor RRotate(lX, 25)
End Function
Private Function SmallSigma0(ByVal lX As Long) As Long
SmallSigma0 = RRotate(lX, 7) Xor RRotate(lX, 18) Xor RShift(lX, 3)
End Function
Private Function SmallSigma1(ByVal lX As Long) As Long
SmallSigma1 = RRotate(lX, 17) Xor RRotate(lX, 19) Xor RShift(lX, 10)
End Function
Private Sub ToBigEndian(aRetVal() As Long, baBuffer() As Byte, ByVal lPos As Long, ByVal lSize As Long)
Dim lIdx As Long
Dim lOutSize As Long
Dim lOutIdx As Long
Dim lOffset As Long
If lSize < 0 Then
lSize = UBound(baBuffer) + 1
End If
lOutSize = ((lSize + 8) \ 64 + 1) * 16
ReDim aRetVal(0 To lOutSize - 1) As Long
For lIdx = 0 To lSize - lPos - 1
lOutIdx = lIdx \ 4
lOffset = 24 - (lIdx Mod 4) * 8
aRetVal(lOutIdx) = aRetVal(lOutIdx) Or LShift(baBuffer(lPos + lIdx), lOffset)
Next
lOutIdx = lIdx \ 4
lOffset = 24 - (lIdx Mod 4) * 8
aRetVal(lOutIdx) = aRetVal(lOutIdx) Or LShift(&H80, lOffset)
aRetVal(lOutSize - 1) = LShift(lSize, 3)
aRetVal(lOutSize - 2) = RShift(lSize, 29)
End Sub
Private Sub FromBigEndian(baRetVal() As Byte, aInput() As Long, ByVal lPos As Long, ByVal lSize As Long)
Dim lIdx As Long
Dim lWord As Long
If lSize < 0 Then
lSize = UBound(aInput) + 1
End If
ReDim baRetVal(0 To lSize * 4 - 1) As Byte
For lIdx = 0 To lSize - lPos - 1
lWord = aInput(lPos + lIdx)
baRetVal(4 * lIdx + 0) = RShift(lWord, 24) And &HFF&
baRetVal(4 * lIdx + 1) = (lWord And &HFF0000) \ &H10000 And &HFF&
baRetVal(4 * lIdx + 2) = (lWord And &HFF00) \ &H100& And &HFF&
baRetVal(4 * lIdx + 3) = lWord And &HFF&
Next
End Sub
Private Sub SHA2(baOutput() As Byte, ByVal lOutPos As Long, ByVal lOutSize As Long, baInput() As Byte, ByVal lPos As Long, ByVal lSize As Long, H() As Long)
Static K(0 To 63) As Long
Dim M() As Long
Dim W(0 To 63) As Long
Dim lA As Long
Dim lB As Long
Dim lC As Long
Dim lD As Long
Dim lE As Long
Dim lF As Long
Dim lG As Long
Dim lH As Long
Dim lT1 As Long
Dim lT2 As Long
Dim lIdx As Long
Dim lJdx As Long
Dim vElem As Variant
If PowerOf2(0) = 0 Then
For lIdx = 0 To 30
PowerOf2(lIdx) = 2& ^ lIdx
Next
PowerOf2(31) = &H80000000
'--- K: first 32 bits of the fractional parts of the cube roots of the first 64 primes
For Each vElem In Split("428A2F98 71374491 B5C0FBCF E9B5DBA5 3956C25B 59F111F1 923F82A4 AB1C5ED5 D807AA98 12835B01 243185BE 550C7DC3 72BE5D74 80DEB1FE 9BDC06A7 C19BF174 E49B69C1 EFBE4786 FC19DC6 240CA1CC 2DE92C6F 4A7484AA 5CB0A9DC 76F988DA 983E5152 A831C66D B00327C8 BF597FC7 C6E00BF3 D5A79147 6CA6351 14292967 27B70A85 2E1B2138 4D2C6DFC 53380D13 650A7354 766A0ABB 81C2C92E 92722C85 A2BFE8A1 A81A664B C24B8B70 C76C51A3 D192E819 D6990624 F40E3585 106AA070 19A4C116 1E376C08 2748774C 34B0BCB5 391C0CB3 4ED8AA4A 5B9CCA4F 682E6FF3 748F82EE 78A5636F 84C87814 8CC70208 90BEFFFA A4506CEB BEF9A3F7 C67178F2")
K(lJdx) = "&H" & vElem
lJdx = lJdx + 1
Next
End If
ToBigEndian M, baInput, lPos, lSize
For lIdx = 0 To UBound(M) Step 16
lA = H(0)
lB = H(1)
lC = H(2)
lD = H(3)
lE = H(4)
lF = H(5)
lG = H(6)
lH = H(7)
For lJdx = 0 To 63
If lJdx < 16 Then
W(lJdx) = M(lJdx + lIdx)
Else
W(lJdx) = UAdd(UAdd(UAdd(SmallSigma1(W(lJdx - 2)), W(lJdx - 7)), SmallSigma0(W(lJdx - 15))), W(lJdx - 16))
End If
lT1 = UAdd(UAdd(UAdd(UAdd(lH, BigSigma1(lE)), Ch(lE, lF, lG)), K(lJdx)), W(lJdx))
lT2 = UAdd(BigSigma0(lA), Maj(lA, lB, lC))
lH = lG
lG = lF
lF = lE
lE = UAdd(lD, lT1)
lD = lC
lC = lB
lB = lA
lA = UAdd(lT1, lT2)
Next
H(0) = UAdd(lA, H(0))
H(1) = UAdd(lB, H(1))
H(2) = UAdd(lC, H(2))
H(3) = UAdd(lD, H(3))
H(4) = UAdd(lE, H(4))
H(5) = UAdd(lF, H(5))
H(6) = UAdd(lG, H(6))
H(7) = UAdd(lH, H(7))
Next
FromBigEndian baOutput, H, lOutPos, lOutSize
End Sub
Public Sub CryptoSHA224(baRetVal() As Byte, baBuffer() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1)
Dim H(0 To 7) As Long
H(0) = &HC1059ED8
H(1) = &H367CD507
H(2) = &H3070DD17
H(3) = &HF70E5939
H(4) = &HFFC00B31
H(5) = &H68581511
H(6) = &H64F98FA7
H(7) = &HBEFA4FA4
SHA2 baRetVal, 0, 7, baBuffer, Pos, Size, H
End Sub
Public Sub CryptoSHA256(baRetVal() As Byte, baBuffer() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1)
Dim H(0 To 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
SHA2 baRetVal, 0, 8, baBuffer, Pos, Size, H
End Sub
Private Sub HMAC(baRetVal() As Byte, ByVal lHashSize As Long, baKey() As Byte, baBuffer() As Byte, ByVal lPos As Long, ByVal lSize As Long)
Const BLOCK_SIZE As Long = 64
Const INNER_PAD As Long = &H36
Const OUTER_PAD As Long = &H5C
Dim lIdx As Long
Dim baPass() As Byte
Dim baPad() As Byte
Dim baHash() As Byte
If UBound(baKey) < BLOCK_SIZE Then
baPass = baKey
ElseIf lHashSize = 256 Then
CryptoSHA256 baPass, baKey
Else
CryptoSHA224 baPass, baKey
End If
If lSize < 0 Then
lSize = UBound(baBuffer) + 1
End If
ReDim baPad(0 To lSize + BLOCK_SIZE - 1) As Byte
For lIdx = 0 To UBound(baPass)
baPad(lIdx) = baPass(lIdx) Xor INNER_PAD
Next
For lIdx = lIdx To BLOCK_SIZE - 1
baPad(lIdx) = INNER_PAD
Next
For lIdx = 0 To lSize - lPos - 1
baPad(BLOCK_SIZE + lIdx) = baBuffer(lPos + lIdx)
Next
If lHashSize = 256 Then
CryptoSHA256 baHash, baPad
Else
CryptoSHA224 baHash, baPad
End If
lSize = UBound(baHash) + 1
ReDim baPad(0 To lSize + BLOCK_SIZE - 1) As Byte
For lIdx = 0 To UBound(baPass)
baPad(lIdx) = baPass(lIdx) Xor OUTER_PAD
Next
For lIdx = lIdx To BLOCK_SIZE - 1
baPad(lIdx) = OUTER_PAD
Next
For lIdx = 0 To lSize - 1
baPad(BLOCK_SIZE + lIdx) = baHash(lIdx)
Next
If lHashSize = 256 Then
CryptoSHA256 baRetVal, baPad
Else
CryptoSHA224 baRetVal, baPad
End If
End Sub
Public Sub CryptoHMAC224(baRetVal() As Byte, baKey() As Byte, baBuffer() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1)
HMAC baRetVal, 224, baKey, baBuffer, Pos, Size
End Sub
Public Sub CryptoHMAC256(baRetVal() As Byte, baKey() As Byte, baBuffer() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1)
HMAC baRetVal, 256, baKey, baBuffer, Pos, Size
End Sub
cheers,
</wqw>