Author | Message | Time |
---|---|---|
Ringo | So, I found a broken SHA function on this forum years ago, and optimized it (tryed to). so not sure who takes credits for the orginal vb6 port of broken SHA1, but thanks to them! Also thanks to iago/rob and warz for releaseing warden/lockdown SHA1 code! Lately i have broken it up and rewrote alot of it, in an attempt to support the warden and lockdown version of broken SHA1, but im having no luck! It works with normal BNCS cdkey/password hashing just fine, but when i try to add the mystery padding and 64bit int, it seems to return a hash that doesnt match up to iago's test hash's Im pretty sure my 64bit int math is bad. (maths has never been my strong point) But could also be the mystery buffer. :( Below is my code, hopefully somone can point out where im going wrong, and/or explain how the mystery padding and 64bit int takes effect, since that big int has me confused the most. thanks in advance! Oh and just a side note, I struggle to read C, so if you brake up an example in a native language (non-vb), please explain it step by step, thanks. [code] Public Function BSHA1(ByVal S As String, _ Optional ByVal bRE As Boolean = False, _ Optional ByVal bPad As Boolean = False) As String 'bRE = Reverse Endian 'bPad = lockdown/warden padding (mystery buffer) Dim LW As Long 'low word Dim HW As Long 'high word Dim B(21) As Long 'hash buffer '//Init the seeds B(0) = &H67452301 B(1) = &HEFCDAB89 B(2) = &H98BADCFE B(3) = &H10325476 B(4) = &HC3D2E1F0 '//Update the string buffer (to be hashed) Call SHA1Update(bRE, LW, HW, B(), S) '//If padding (lockdown/warden version) If bPad Then '//init the mystery buffer S = String(64, 0) Mid(S, 1, 1) = Chr(&H80) '//Switch the low/high words Dim LW2 As Long Dim HW2 As Long Call rEndian(HW, LW2) Call rEndian(LW, HW2) '//Update mystery buffer to the hash buffer (B) Call SHA1Update(bRE, LW, HW, B(), S) '//Update the 64bit int to the hash buffer (B) S = MakeDWORD(LW2) & MakeDWORD(HW2) Call SHA1Update(bRE, LW, HW, B(), S) End If '//Return the broken SHA1 hash BSHA1 = String(20, 0) Call CopyMemory(ByVal BSHA1, B(0), 20) End Function Private Sub SHA1Update(ByVal bRE As Boolean, _ ByRef LW As Long, _ ByRef HW As Long, _ ByRef B() As Long, _ ByVal S As String) Dim i As Long If ((Len(S) Mod 64) <> 0) Then '//buffer the string so its divisible by 64 (0x40) S = S & String(64 - (Len(S) Mod 64), 0) End If For i = 1 To Len(S) Step 64 '//do the thingy ding with the low/high word LW = LW + RS(64, 29) HW = HW + LS(64, 3) '//copy chunk of the string into the long array to be hashed Call CopyMemory(B(5), ByVal Mid$(S, i, 64), 64) '//transform Call SHA1Transform(bRE, B) Next i End Sub Private Sub SHA1Transform(ByVal bRE As Boolean, ByRef p() As Long) Dim hB(80) As Long Dim A As Long Dim B As Long Dim C As Long Dim D As Long Dim E As Long Dim G As Long Dim i As Long If bRE Then 'reverse endian For i = 0 To 15: Call rEndian(p(i + 5), hB(i)): Next i Else For i = 0 To 15: hB(i) = p(i + 5): Next i End If For i = 16 To 79 hB(i) = LSC(1, (hB(i - 16) Xor hB(i - 8) Xor hB(i - 14) Xor hB(i - 3)) And 31) Next A = p(0) B = p(1) C = p(2) D = p(3) E = p(4) For i = 0 To 19 G = Add(Add(Add(Add(hB(i), E), LSC(A, 5)), ((B And C) Or ((Not B) And D))), &H5A827999) E = D: D = C: C = LSC(B, 30): B = A: A = G Next i For i = 20 To 39 G = Add(Add(Add(Add(hB(i), E), LSC(A, 5)), (D Xor C Xor B)), &H6ED9EBA1) E = D: D = C: C = LSC(B, 30): B = A: A = G Next i For i = 40 To 59 G = Add(Add(Add(Add(hB(i), E), LSC(A, 5)), (C And B) Or (D And C) Or (D And B)), &H8F1BBCDC) E = D: D = C: C = LSC(B, 30): B = A: A = G Next i For i = 60 To 79 G = Add(Add(Add(Add(hB(i), E), LSC(A, 5)), (D Xor C Xor B)), &HCA62C1D6) E = D: D = C: C = LSC(B, 30): B = A: A = G Next i p(0) = Add(p(0), A) p(1) = Add(p(1), B) p(2) = Add(p(2), C) p(3) = Add(p(3), D) p(4) = Add(p(4), E) End Sub ' ~~~~~~ Extra functions ~~~~~~ Private Sub rEndian(ByVal V As Long, ByRef N As Long) '//dirty byte order switching Dim S As String * 4 Call CopyMemory(ByVal S, V, 4) S = StrReverse(S) Call CopyMemory(N, ByVal S, 4) End Sub Private Function LSC(ByVal N As Long, ByVal S As Long) As Long 'left shift circle LSC = (LS(N, S) Or RS(N, (32 - S))) End Function Private Function RS(ByVal N As Long, ByVal S As Long) As Long 'right shift bits If (S < 0) Or (S > 31) Then RS = 0 ElseIf (S = 0) Then RS = N Else If ((N And &H80000000) = &H80000000) Then RS = ((N And &H7FFFFFFF) \ (2 ^ S)) Or (2 ^ (31 - S)) Else RS = Int(CDbl(N) / CDbl(2 ^ S)) End If End If End Function Private Function LS(ByVal N As Long, ByVal S As Long) As Long 'left shift bits If (S < 0) Or (S > 31) Then LS = 0 ElseIf S = 0 Then LS = N Else N = N And (2 ^ (32 - S) - 1) LS = WDbl(CDbl(N) * CDbl(WDbl(2 ^ S))) End If End Function Private Function WDbl(ByVal N As Double) As Long 'wrap a double back to a long If N > &H7FFFFFFF Then N = N - 4294967296# ElseIf N < &H80000000 Then N = N + 4294967296# End If WDbl = N End Function Private Function Add(ByVal N1 As Long, ByVal N2 As Long, Optional ByVal D As Double) As Long 'add 2 longs to a double, then wrap round D = N1 D = D + N2 Add = WDbl(D) End Function [/code] | March 4, 2008, 1:52 PM |
FrOzeN | I just picked up on one thing that may benefit your code. You could use the two Winsock API functions htons() and htonl(). They stand for Host to Network Byte Order (Short/Long). Which basically converts a short (16-bit) / long (32-bit) to big endian. [code]Public Declare Function htonl Lib "ws2_32.dll" (ByVal hostlong As Long) As Long Public Declare Function htons Lib "ws2_32.dll" (ByVal hostshort As Integer) As Integer[/code] Also, I don't remember much about this. But when using CopyMemory() on strings in VB6, do you need to convert them to and from Unicode? [code]strAscii = Format(strUnicode, vbFromUnicode) strUnicode = Format(strAscii, vbUnicode)[/code] | March 4, 2008, 2:48 PM |
Ringo | [quote author=FrOzeN link=topic=17367.msg176789#msg176789 date=1204642125] I just picked up on one thing that may benefit your code. You could use the two Winsock API functions htons() and htonl(). They stand for Host to Network Byte Order (Short/Long). Which basically converts a short (16-bit) / long (32-bit) to big endian. [code]Public Declare Function htonl Lib "ws2_32.dll" (ByVal hostlong As Long) As Long Public Declare Function htons Lib "ws2_32.dll" (ByVal hostshort As Integer) As Integer[/code] Also, I don't remember much about this. But when using CopyMemory() on strings in VB6, do you need to convert them to and from Unicode? [code]strAscii = Format(strUnicode, vbFromUnicode) strUnicode = Format(strAscii, vbUnicode)[/code] [/quote] hi, thanks. I havent thought much about big endian converting, but i may use the htonl() function at a later date, to speed that process up a little. :) afaik, unicode shouldnt be a problem with rtlmovememory, i think it does it automaticly (not sure exacly how, but it works as desired when copying string to other forms of data types) I cant really say much more on the unicode subject, i dont have much exp with it, but i do know its not an issue with rtlmovememory (never experianced a problem so far anyway) My main issue is how to manage/hash the mystery buffer and the 64bit integer that seems to be computed each update. Thanks again m8 EDIT: Have some output dumps here, if this makes it any easyer to diagnose the problem: [code] String to be hashed: "The quick brown fox jumps over the lazy dog" The block of data to be updated: Low Word = 00 00 00 00 High Word = 00 02 00 00 54 68 65 20 71 75 69 63 6B 20 62 72 6F 77 6E 20 66 6F 78 20 6A 75 6D 70 73 20 6F 76 65 72 20 74 68 65 20 6C 61 7A 79 20 64 6F 67 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Block of data after being converted into big endian (in transform sub): 20 65 68 54 63 69 75 71 72 62 20 6B 20 6E 77 6F 20 78 6F 66 70 6D 75 6A 76 6F 20 73 74 20 72 65 6C 20 65 68 20 79 7A 61 00 67 6F 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Result of transforming the block of above data: F8 0E 4E 84 1E 6C 8D 83 9D 47 D0 BE 23 0F 1C D1 BD 34 45 EF [/code] Now the mystery buffer's turn: [code] The block of data to be updated: Low Word = 00 00 00 00 High Word = 00 04 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Block of data after being converted into big endian (in transform sub): 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Result of transforming the block of above data: D5 93 F2 AB D5 F8 CB 77 E9 70 93 51 07 60 6C 00 94 79 2B D0 [/code] now the 64bit ints turn to be updated: Note, i did not copy after updating the mystery buffer, as iagos code copys them before hand (i have also tryed before/after) [code] Int64 To update = 00 00 02 00 00 00 00 00 Update: 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Transform Dump 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 After/final Hash result: E7 40 D1 53 15 EA BD 9A 56 3A 5E 26 AD 7E 89 D2 D3 4F 3E 81 [/code] Can anyone compare this with iagos code/outputs and see where mines going wrong? If i switch the low/high word around before updating i get: [code] 5A E4 56 B2 33 62 25 45 A4 5C D9 C5 66 CC 97 E8 30 78 F4 D0 [/code] If i update the 64bit AFTER updating the mystery buffer, with out switching the 64int, i get: [code] E2 69 B0 68 FE 8D 99 63 BB CE 9A 10 CE 54 DE 53 77 FD 43 9B [/code] if i then switch the 64 int i get: [code] 06 49 38 1A 31 E1 55 CF A8 44 C6 F3 77 8B F3 43 9B 2D D0 81 [/code] But none of them come close to what its ment to be: [code] c6e1d42f fc282d7a e19e84ed 39e776bb 12eb931b [/code] Any ideas anyone? | March 4, 2008, 3:10 PM |
Ringo | Ah, rob just pointed out its bulk standard SHA1 and not standard broken SHA1 -- silly me :D I will rewrite all of this to support bulk standard SHA1 as well, then see if it solves the problem :) | March 4, 2008, 9:16 PM |
Ringo | yay, finaly! turned out warden uses 100% bulk standard SHA1 (i had to switch the byte order of dwords inorder to get correct standard SHA1 result, then noticed my test hash matched iagos!) The differnce between BNCS broken SHA1 and standard/warden SHA1 is, the left shift circulating when setting the dwords in the transform sub: [code] If bS Then 'standard SHA1 For i = 16 To 79 hB(i) = LSC((hB(i - 16) Xor hB(i - 8) Xor hB(i - 14) Xor hB(i - 3)), 1) Next i Else For i = 16 To 79 hB(i) = LSC(1, (hB(i - 16) Xor hB(i - 8) Xor hB(i - 14) Xor hB(i - 3)) And 31) Next i End If [/code] And the padding method in the update routine: (Fully explains the "mystery buffer" and the 64bit int) [code] If bS Then '//Standard SHA1 padding S = S & Chr(128) & _ String((128 - (Len(S) Mod 64) - 9) Mod 64, 0) & _ String(4, 0) & _ StrReverse(MakeDWORD((Len(S) * 8))) Else If ((Len(S) Mod 64) <> 0) Then '//buffer the string so its divisible by 64 (0x40) S = S & String(64 - (Len(S) Mod 64), 0) End If End If [/code] And byte order reverseing with the dwords: [code] If bRE Then 'reverse endian For i = 0 To 15: Call rEndian(P(i + 5), hB(i)): Next i Else For i = 0 To 15: hB(i) = P(i + 5): Next i End If [/code] Everything is pretty much the same. I dont see any point computing a 64bit int, when the chances of dumping a 268-536mb block of data into a SHA1 function is slim to none, so i just managed it in a dword when buffering the orginal data. Im guessing lockdown uses bulk standard SHA1, but with out byte order reverseing -- [s]need some lockdown SHA1 test hash to verify that tho.[/s] I also had to redo the right shift function, because once i switched the leftshift circulating arguments, VB love over flow long time. Big thanks to rob@east for being their to answer any question I had, and pointing me in the right direction with standard SHA1. Heres some useage code: [code] Const S As String = "The quick brown fox jumps over the lazy dog" Dim S2 As String '//BNCS Broken SHA1 S2 = BSHA1(S, False, False) A0 DB 6E 70 61 60 33 A7 B5 FD DA 37 CE E2 D4 3F 2D A1 02 88 '//Standard/Warden SHA1 S2 = BSHA1(S, True, True) 2F D4 E1 C6 7A 2D 28 FC ED 84 9E E1 BB 76 E7 39 1B 93 EB 12 '//Lockdown SHA1 (verifyed -- thx hdx) S2 = BSHA1(S, False, True) A8 68 FB 6C 0D 95 C4 8D 03 7E 9F 08 CE 6E 42 00 FD 43 5F A4 [/code] Main code: [code] Public Function BSHA1(ByVal S As String, _ Optional ByVal bRE As Boolean = False, _ Optional ByVal bStandard As Boolean = False) As String Dim B(21) As Long 'hash buffer Dim i As Long '//Init the seeds B(0) = &H67452301 B(1) = &HEFCDAB89 B(2) = &H98BADCFE B(3) = &H10325476 B(4) = &HC3D2E1F0 '//Update the string buffer (to be hashed) Call SHA1Update(bRE, bStandard, B(), S) '//Reverse endian if needed If bRE Then For i = 0 To 4 Call rEndian(B(i), B(i)) Next i End If '//Return the broken SHA1 hash BSHA1 = String(20, 0) Call CopyMemory(ByVal BSHA1, B(0), 20) End Function Private Sub SHA1Update(ByVal bRE As Boolean, _ ByVal bS As Boolean, _ ByRef B() As Long, _ ByVal S As String) Dim i As Long Dim A As String If bS Then '//Standard SHA1 padding A = Chr(128) & String((128 - (Len(S) Mod 64) - 9) Mod 64, 0) If bRE Then S = S & A & String(4, 0) & StrReverse(MakeDWORD((Len(S) * 8))) Else S = S & A & MakeDWORD((Len(S) * 8)) & String(4, 0) End If Else If ((Len(S) Mod 64) <> 0) Then '//buffer the string so its divisible by 64 (0x40) S = S & String(64 - (Len(S) Mod 64), 0) End If End If For i = 1 To Len(S) Step 64 '//copy chunk of the string into the long array to be hashed Call CopyMemory(B(5), ByVal Mid$(S, i, 64), 64) '//transform Call SHA1Transform(bRE, bS, B) Next i End Sub Private Sub SHA1Transform(ByVal bRE As Boolean, ByVal bS As Boolean, ByRef P() As Long) Dim hB(80) As Long Dim A As Long Dim B As Long Dim C As Long Dim D As Long Dim E As Long Dim G As Long Dim i As Long If bRE Then 'reverse endian For i = 0 To 15: Call rEndian(P(i + 5), hB(i)): Next i Else For i = 0 To 15: hB(i) = P(i + 5): Next i End If If bS Then 'standard SHA1 For i = 16 To 79 hB(i) = LSC((hB(i - 16) Xor hB(i - 8) Xor hB(i - 14) Xor hB(i - 3)), 1) Next i Else For i = 16 To 79 hB(i) = LSC(1, (hB(i - 16) Xor hB(i - 8) Xor hB(i - 14) Xor hB(i - 3)) And 31) Next i End If A = P(0) B = P(1) C = P(2) D = P(3) E = P(4) For i = 0 To 19 G = Add(Add(Add(Add(hB(i), E), LSC(A, 5)), ((B And C) Or ((Not B) And D))), &H5A827999) E = D: D = C: C = LSC(B, 30): B = A: A = G Next i For i = 20 To 39 G = Add(Add(Add(Add(hB(i), E), LSC(A, 5)), (D Xor C Xor B)), &H6ED9EBA1) E = D: D = C: C = LSC(B, 30): B = A: A = G Next i For i = 40 To 59 G = Add(Add(Add(Add(hB(i), E), LSC(A, 5)), (C And B) Or (D And C) Or (D And B)), &H8F1BBCDC) E = D: D = C: C = LSC(B, 30): B = A: A = G Next i For i = 60 To 79 G = Add(Add(Add(Add(hB(i), E), LSC(A, 5)), (D Xor C Xor B)), &HCA62C1D6) E = D: D = C: C = LSC(B, 30): B = A: A = G Next i P(0) = Add(P(0), A) P(1) = Add(P(1), B) P(2) = Add(P(2), C) P(3) = Add(P(3), D) P(4) = Add(P(4), E) End Sub '~~~~~~ Extra functions ~~~~~~~ Private Sub rEndian(ByVal V As Long, ByRef N As Long) '//dirty byte order switching Dim S As String * 4 Call CopyMemory(ByVal S, V, 4) S = StrReverse(S) Call CopyMemory(N, ByVal S, 4) End Sub Private Function LSC(ByVal N As Long, ByVal S As Long) As Long 'left shift circle LSC = (LS(N, S) Or RS(N, (32 - S))) End Function Private Function RS(ByVal N As Long, ByVal S As Long) As Long 'right shift bits If (S < 0) Or (S > 31) Then RS = 0 ElseIf (S = 0) Then RS = N Else If ((N And &H80000000) = &H80000000) Then N = (N And &H7FFFFFFF) If (S = 31) Then 'stop over flow when shifting 31bits N = N / 2147483648# Else N = N \ (2 ^ S) End If RS = N Or (2 ^ (31 - S)) Else RS = Int(CDbl(N) / CDbl(2 ^ S)) End If End If End Function Private Function LS(ByVal N As Long, ByVal S As Long) As Long 'left shift bits If (S < 0) Or (S > 31) Then LS = 0 ElseIf S = 0 Then LS = N Else N = N And (2 ^ (32 - S) - 1) LS = WDbl(CDbl(N) * CDbl(WDbl(2 ^ S))) End If End Function Private Function WDbl(ByVal N As Double) As Long 'wrap a double back to a long If N > &H7FFFFFFF Then N = N - 4294967296# ElseIf N < &H80000000 Then N = N + 4294967296# End If WDbl = N End Function Private Function Add(ByVal N1 As Long, ByVal N2 As Long, Optional ByVal D As Double) As Long 'add 2 longs to a double, then wrap round D = N1 D = D + N2 Add = WDbl(D) End Function [/code] If anyone wants to know anything about these SHA1 algorithm's, im happy to answer any question I can, I pretty much know them like the back of my hand at the moment ;p fun times! They are alot simpler than they 1st look! Also please point put any bugs any of you find, since i havent fulled tested them yet, only vs test hash's of broken sha1, warden sha1, standard sha1 -- lockdown sha1 [s]needs verifying[/s]. Anyway I REALLY must go to bed, and have nightmares about hex-binary! :( | March 5, 2008, 4:30 AM |
HdxBmx27 | Lockdown_SHA1.java: [code]Data: The quick brown fox jumps over the lazy dog 6CFB68A8 8DC4950D 89F7E03 426ECE A45F43FD Data: Peater Piper picked a peck of pickles 68D064CA D465B73C A557CCB3 30D3659B D67095D2 Data: I love you, you love me, Oh dear god I need sleep -.- 758B08DC 9A3A161F B8C009AD 715F5270 1D242A5F[/code] You might want to take another look at all the differences between Lockdown's and standard. As far as I recall the only diff from standard is the final function.... but iono *looks more into it tomorrow when he will be completely re-writing it* ~Hdx | March 5, 2008, 8:34 AM |
Ringo | Thanks for them test values HDX :) I woke up abit more today, and fixed a few bugs. 1st was, i wasnt returning reversed endian byte order on the return hash for warden/standard SHA1: [code] If bRE Then For i = 0 To 4 Call rEndian(B(i), B(i)) Next i End If [/code] And i was reverseing endian byte order on the stabndard SHA1 padding, and lockdown SHA1 doesnt -- forgot about that. [code] '//Standard SHA1 padding A = Chr(128) & String((128 - (Len(S) Mod 64) - 9) Mod 64, 0) If bRE Then S = S & A & String(4, 0) & StrReverse(MakeDWORD((Len(S) * 8))) Else S = S & A & MakeDWORD((Len(S) * 8)) & String(4, 0) End If [/code] Fixed my last post with these changes, so tuch wood, should work with all 3 now (broken, standard/warden, lockdown) thanks again. | March 5, 2008, 2:13 PM |