I’ve been working on a few projects that require blitzmax and a web-server (php/mysql) to communicate. Along came the need to hash files. This code archive entry was very useful :). I decided to wrap it into an object and add a new method to it. Even though it’s a series of functions I still tend to make types with functions in them to help me organize them (it’s like a cheap way of namespacing). I needed the ability to hash a file using Sha-1 hashing. Seeing that php has a function called sha1_file($pathToFile) I figured I’d implement the equivalent on blitzmax. With this THasher type, I’ve added a SHA1_File(path) function also.
Why hash files?
There are many reasons to use hashes, but recently I used it to check for file changes. If you’ve ever wanted to find out if some arbitrary file has ‘changed’ since the last time you’ve opened it this can prove to be useful. If you save the hash beforehand then recompute the hash now and if they are different, then something’s changed! Some applications of this are:
- Write a file-updater to quickly find out which new files need to be downloaded. Just comparing hashes would be sufficient in most cases, instead of having to go individually byte-by-byte or traversing the file structure to find a difference.
- help stop cheating. If you don’t want users changing texture files to gain an advantage or don’t want them ‘mucking’ with any other data file. If you check the current hash against a previously approved one and it doesn’t check out then the file has more than likely been tampered with.
How Do I Use THasher?
If you want to hash a string using SHA-1 then:
Local hashedFoo:String = THasher.sha1("Foo")
Want to hash a whole file? Then:
Local filehash:String = THasher.SHA1*File("someFile.txt")
Keep in mind you can hash _any* file, not just text files like in the above example.
Anyway, read on for the whole file. With the exception of SHA1_File() I did not write these hashing functions for Blitzmax. They were simply taken from Yan’s very helpful code archives post :).
Strict
Type THasher
Function MD5:String(in:String)
Local h0:Int = $67452301, h1 = $EFCDAB89, h2 = $98BADCFE, h3 = $10325476
Local r:Int[] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, ..
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, ..
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, ..
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
Local k:Int[] = [$D76AA478, $E8C7B756, $242070DB, $C1BDCEEE, $F57C0FAF, $4787C62A, ..
$A8304613, $FD469501, $698098D8, $8B44F7AF, $FFFF5BB1, $895CD7BE, ..
$6B901122, $FD987193, $A679438E, $49B40821, $F61E2562, $C040B340, ..
$265E5A51, $E9B6C7AA, $D62F105D, $02441453, $D8A1E681, $E7D3FBC8, ..
$21E1CDE6, $C33707D6, $F4D50D87, $455A14ED, $A9E3E905, $FCEFA3F8, ..
$676F02D9, $8D2A4C8A, $FFFA3942, $8771F681, $6D9D6122, $FDE5380C, ..
$A4BEEA44, $4BDECFA9, $F6BB4B60, $BEBFBC70, $289B7EC6, $EAA127FA, ..
$D4EF3085, $04881D05, $D9D4D039, $E6DB99E5, $1FA27CF8, $C4AC5665, ..
$F4292244, $432AFF97, $AB9423A7, $FC93A039, $655B59C3, $8F0CCC92, ..
$FFEFF47D, $85845DD1, $6FA87E4F, $FE2CE6E0, $A3014314, $4E0811A1, ..
$F7537E82, $BD3AF235, $2AD7D2BB, $EB86D391]
Local intCount = (((in:String.length + 8) Shr 6) + 1) Shl 4
Local data[intCount]
For Local c = 0 Until in:String.length
data[c Shr 2] = data[c Shr 2] | ((in:String[c] & $FF) Shl ((c & 3) Shl 3))
Next
data[in:String.length Shr 2] = data[in:String.length Shr 2] | ($80 Shl ((in:String.length & 3) Shl 3))
data[data.length – 2] = (Long(in:String.length) _ 8) & $FFFFFFFF
data[data.length – 1] = (Long(in:String.length) _ 8) Shr 32
For Local chunkStart = 0 Until intCount Step 16
Local a = h0, b = h1, c = h2, d = h3
For Local i = 0 To 15
Local f = d ~ (b & (c ~ d))
Local t = d
d = c ; c = b
b = Rol((a + f + k[i] + data[chunkStart + i]), r[i]) + b
a = t
Next
For Local i = 16 To 31
Local f = c ~ (d & (b ~ c))
Local t = d
d = c ; c = b
b = Rol((a + f + k[i] + data[chunkStart + (((5 * i) + 1) & 15)]), r[i]) + b
a = t
Next
For Local i = 32 To 47
Local f = b ~ c ~ d
Local t = d
d = c ; c = b
b = Rol((a + f + k[i] + data[chunkStart + (((3 * i) + 5) & 15)]), r[i]) + b
a = t
Next
For Local i = 48 To 63
Local f = c ~ (b | ~d)
Local t = d
d = c ; c = b
b = Rol((a + f + k[i] + data[chunkStart + ((7 * i) & 15)]), r[i]) + b
a = t
Next
h0:+a ; h1:+b
h2:+c ; h3:+d
Next
Return (LEHex(h0) + LEHex(h1) + LEHex(h2) + LEHex(h3)).ToLower()
End Function
Function SHA1_File:String(path:String)
If FileType(path) = 1 Then
Local bytes:Byte[] = New Byte[FileSize(path)]
Local s:TStream = ReadFile(path)
If s Then
s.ReadBytes(bytes, bytes.Length)
s.Close()
Local str:String = String.FromBytes(bytes, bytes.length)
Return THasher.SHA1(str)
End If
End If
Return ""
End Function
Function SHA1:String(in:String)
Local h0 = $67452301, h1 = $EFCDAB89, h2 = $98BADCFE, h3 = $10325476, h4 = $C3D2E1F0
Local intCount = (((in:String.length + 8) Shr 6) + 1) Shl 4
Local data[intCount]
For Local c = 0 Until in:String.length
data[c Shr 2] = (data[c Shr 2] Shl 8) | (in:String[c] & $FF)
Next
data[in:String.length Shr 2] = ((data[in:String.length Shr 2] Shl 8) | $80) Shl ((3 – (in:String.length & 3)) Shl 3)
data[data.length – 2] = (Long(in:String.length) _ 8) Shr 32
data[data.length – 1] = (Long(in:String.length) _ 8) & $FFFFFFFF
For Local chunkStart = 0 Until intCount Step 16
Local a = h0, b = h1, c = h2, d = h3, e = h4
Local w[] = data[chunkStart..chunkStart + 16]
w = w[..80]
For Local i = 16 To 79
w[i] = Rol(w[i – 3] ~ w[i – 8] ~ w[i – 14] ~ w[i – 16], 1)
Next
For Local i = 0 To 19
Local t = Rol(a, 5) + (d ~ (b & (c ~ d))) + e + $5A827999 + w[i]
e = d ; d = c
c = Rol(b, 30)
b = a ; a = t
Next
For Local i = 20 To 39
Local t = Rol(a, 5) + (b ~ c ~ d) + e + $6ED9EBA1 + w[i]
e = d ; d = c
c = Rol(b, 30)
b = a ; a = t
Next
For Local i = 40 To 59
Local t = Rol(a, 5) + ((b & c) | (d & (b | c))) + e + $8F1BBCDC + w[i]
e = d ; d = c
c = Rol(b, 30)
b = a ; a = t
Next
For Local i = 60 To 79
Local t = Rol(a, 5) + (b ~ c ~ d) + e + $CA62C1D6 + w[i]
e = d ; d = c
c = Rol(b, 30)
b = a ; a = t
Next
h0:+a ; h1:+b ; h2:+c
h3:+d ; h4:+e
Next
Return (Hex(h0) + Hex(h1) + Hex(h2) + Hex(h3) + Hex(h4)).ToLower()
End Function
Function SHA256:String(in:String)
Local h0 = $6A09E667, h1 = $BB67AE85, h2 = $3C6EF372, h3 = $A54FF53A
Local h4 = $510E527F, h5 = $9B05688C, h6 = $1F83D9AB, h7 = $5BE0CD19
Local k[] = [$428A2F98, $71374491, $B5C0FBCF, $E9B5DBA5, $3956C25B, $59F111F1, ..
$923F82A4, $AB1C5ED5, $D807AA98, $12835B01, $243185BE, $550C7DC3, ..
$72BE5D74, $80DEB1FE, $9BDC06A7, $C19BF174, $E49B69C1, $EFBE4786, ..
$0FC19DC6, $240CA1CC, $2DE92C6F, $4A7484AA, $5CB0A9DC, $76F988DA, ..
$983E5152, $A831C66D, $B00327C8, $BF597FC7, $C6E00BF3, $D5A79147, ..
$06CA6351, $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]
Local intCount = (((in:String.length + 8) Shr 6) + 1) Shl 4
Local data[intCount]
For Local c = 0 Until in:String.length
data[c Shr 2] = (data[c Shr 2] Shl 8) | (in:String[c] & $FF)
Next
data[in:String.length Shr 2] = ((data[in:String.length Shr 2] Shl 8) | $80) Shl ((3 – (in:String.length & 3)) Shl 3)
data[data.length – 2] = (Long(in:String.length) _ 8) Shr 32
data[data.length – 1] = (Long(in:String.length) _ 8) & $FFFFFFFF
For Local chunkStart = 0 Until intCount Step 16
Local a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7
Local w[] = data[chunkStart..chunkStart + 16]
w = w[..64]
For Local i = 16 To 63
w[i] = w[i – 16] + (Ror(w[i – 15], 7) ~ Ror(w[i – 15], 18) ~ (w[i – 15] Shr 3)) ..
- w[i – 7] + (Ror(w[i – 2], 17) ~ Ror(w[i – 2], 19) ~ (w[i – 2] Shr 10))
Next
For Local i = 0 To 63
Local t0 = (Ror(a, 2) ~ Ror(a, 13) ~ Ror(a, 22)) + ((a & b) | (b & c) | (c & a))
Local t1 = h + (Ror(e, 6) ~ Ror(e, 11) ~ Ror(e, 25)) + ((e & f) | (~e & g)) + k[i] + w[i]
h = g ; g = f ; f = e ; e = d + t1
d = c ; c = b ; b = a ; a = t0 + t1
Next
h0:+a ; h1:+b ; h2:+c ; h3:+d
h4:+e ; h5:+f ; h6:+g ; h7:+h
Next
Return (Hex(h0) + Hex(h1) + Hex(h2) + Hex(h3) + Hex(h4) + Hex(h5) + Hex(h6) + Hex(h7)).ToLower()
End Function
Function Rol:Int(val:Int, shift:Int)
Return (val Shl shift) | (val Shr (32 – shift))
End Function
Function Ror:Int(val:Int, shift:Int)
Return (val Shr shift) | (val Shl (32 – shift))
End Function
Function LEHex:String(val:Int)
Local out:String = Hex(val)
Return out:String[6..8] + out:String[4..6] + out:String[2..4] + out:String[0..2]
End Function
End Type
Enjoy!