Wednesday, June 18, 2008

Pure ASP Hashing Function

Found this in some files I'd written a while back:


<% Option Explicit

' TITLE:
' Secure Hash Algorithm, SHA-1
'
' AUTHORS:
' Adapted by Ben Finnigan from VBA code by Iain Buchan
' http://wikisource.org/wiki/SHA-1_hash
' http://www.nwpho.man.ac.uk/Methods/Forms/DispForm.aspx?ID=6&Source=http:%2F%2Fwww.nwpho.man.ac.uk%2FMethods%2FForms%2FAllItems.aspx&RootFolder=%2FMethods
'
' PURPOSE:
' Creating a secure identifier from person-identifiable data
'
' The function SecureHash generates a 160-bit (20-hex-digit) message digest for a given message (String).
' It is computationally infeasable to recover the message from the digest.
' The digest is unique to the message within the realms of practical probability.
' The only way to find the source message for a digest is by hashing all possible messages and comparison of their digests.

' REFERENCES:
' For a fuller description see FIPS Publication 180-1:
' http://www.itl.nist.gov/fipspubs/fip180-1.htm

' SAMPLE:
' Message: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
' Returns Digest: "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"
' Message: "abc"
' Returns Digest: "A9993E364706816ABA3E25717850C26C9CD0D89D"

Function AndW(w1, w2)
Dim arr(3)
arr(0) = w1(0) And w2(0)
arr(1) = w1(1) And w2(1)
arr(2) = w1(2) And w2(2)
arr(3) = w1(3) And w2(3)
AndW = arr
End Function
Function OrW(w1, w2)
Dim arr(3)
arr(0) = w1(0) Or w2(0)
arr(1) = w1(1) Or w2(1)
arr(2) = w1(2) Or w2(2)
arr(3) = w1(3) Or w2(3)
OrW = arr
End Function
Function XorW(w1, w2)
Dim arr(3)
arr(0) = w1(0) Xor w2(0)
arr(1) = w1(1) Xor w2(1)
arr(2) = w1(2) Xor w2(2)
arr(3) = w1(3) Xor w2(3)
XorW = arr
End Function
Function NotW(w)
Dim arr(3)
arr(0) = Not w(0)
arr(1) = Not w(1)
arr(2) = Not w(2)
arr(3) = Not w(3)
NotW = arr
End Function
Function AddW(w1, w2)
Dim I, arr(3)

I = CLng(w1(3)) + w2(3)
arr(3) = I Mod 256
I = CLng(w1(2)) + w2(2) + (I \ 256)
arr(2) = I Mod 256
I = CLng(w1(1)) + w2(1) + (I \ 256)
arr(1) = I Mod 256
I = CLng(w1(0)) + w2(0) + (I \ 256)
arr(0) = I Mod 256

AddW = arr
End Function
Function CircShiftLeftW(w, n)
Dim d1, d2

d1 = WordToDouble(w)
d2 = d1
d1 = d1 * (2 ^ n)
d2 = d2 / (2 ^ (32 - n))
CircShiftLeftW = OrW(DoubleToWord(d1), DoubleToWord(d2))
End Function
Function WordToHex(w)
WordToHex = Right("0" & Hex(w(0)), 2) & Right("0" & Hex(w(1)), 2) & Right("0" & Hex(w(2)), 2) & Right("0" & Hex(w(3)), 2)
End Function
Function HexToWord(H)
HexToWord = DoubleToWord(CDbl("&H" & H))
End Function
Function DoubleToWord(n)
Dim arr(3)
arr(0) = Int(DMod(n, 2 ^ 32) / (2 ^ 24))
arr(1) = Int(DMod(n, 2 ^ 24) / (2 ^ 16))
arr(2) = Int(DMod(n, 2 ^ 16) / (2 ^ 8))
arr(3) = Int(DMod(n, 2 ^ 8))
DoubleToWord = arr
End Function
Function WordToDouble(w)
WordToDouble = (w(0) * (2 ^ 24)) + (w(1) * (2 ^ 16)) + (w(2) * (2 ^ 8)) + w(3)
End Function
Function DMod(value, divisor)
DMod = value - (Int(value / divisor) * divisor)
If DMod < 0 Then DMod = DMod + divisor
End Function
Function F(t, B, C, D)
Dim casenum
If t <= 19 Then casenum = 1
If t <= 39 And t > 19 Then casenum = 2
If t <= 59 And t > 39 Then casenum = 3
If t > 59 Then casenum = 4
Select Case casenum
Case 1
F = OrW(AndW(B, C), AndW(NotW(B), D))
Case 2
F = XorW(XorW(B, C), D)
Case 3
F = OrW(OrW(AndW(B, C), AndW(B, D)), AndW(C, D))
Case 4
F = XorW(XorW(B, C), D)
End Select
End Function
Function sha1(inMessage)

Dim inLenW
Dim w(79)
Dim temp
Dim A, B, C, D, E
Dim H0, H1, H2, H3, H4
Dim K(3)
Dim arr(3)
Dim inLen, padMessage, numBlocks, blockText, wordText, I, t

inLen = Len(inMessage)
inLenW = DoubleToWord(CDbl(inLen) * 8)

padMessage = inMessage & Chr(128) & String((128 - (inLen Mod 64) - 9) Mod 64, Chr(0)) & String(4, Chr(0)) & Chr(inLenW(0)) & Chr(inLenW(1)) & Chr(inLenW(2)) & Chr(inLenW(3))

numBlocks = Len(padMessage) / 64

' initialize constants
K(0) = HexToWord("5A827999")
K(1) = HexToWord("6ED9EBA1")
K(2) = HexToWord("8F1BBCDC")
K(3) = HexToWord("CA62C1D6")

'initialize 160-bit (5 words) buffer
H0 = HexToWord("67452301")
H1 = HexToWord("EFCDAB89")
H2 = HexToWord("98BADCFE")
H3 = HexToWord("10325476")
H4 = HexToWord("C3D2E1F0")

'each 512 byte message block consists of 16 words (W) but W is expanded to 80 words
For I = 0 To numBlocks - 1
blockText = Mid(padMessage, (I * 64) + 1, 64)
'initialize a message block
For t = 0 To 15
wordText = Mid(blockText, (t * 4) + 1, 4)
arr(0) = Asc(Mid(wordText, 1, 1))
arr(1) = Asc(Mid(wordText, 2, 1))
arr(2) = Asc(Mid(wordText, 3, 1))
arr(3) = Asc(Mid(wordText, 4, 1))
w(t) = arr
Next
'create extra words from the message block
For t = 16 To 79
'W(t) = S^1 (W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16))
w(t) = CircShiftLeftW(XorW(XorW(XorW(w(t - 3), w(t - 8)), w(t - 14)), w(t - 16)), 1)
Next

'make initial assignments to the buffer
A = H0
B = H1
C = H2
D = H3
E = H4

'process the block
For t = 0 To 79
temp = AddW(AddW(AddW(AddW(CircShiftLeftW(A, 5), F(t, B, C, D)), E), w(t)), K(t \ 20))
E = D
D = C
C = CircShiftLeftW(B, 30)
B = A
A = temp
Next

H0 = AddW(H0, A)
H1 = AddW(H1, B)
H2 = AddW(H2, C)
H3 = AddW(H3, D)
H4 = AddW(H4, E)
Next

sha1 = WordToHex(H0) & WordToHex(H1) & WordToHex(H2) & WordToHex(H3) & WordToHex(H4)
End Function
%>

If you find it useful, please post a comment letting me know.

2 comments:

noelle said...

hey Ben i found it very useful, thank you.

Zevers said...

man, i really thank ya