Valhalla Legends Forums Archive | Battle.net Bot Development | Explain M1 ?

AuthorMessageTime
iNsaNe
Client Password Proof (M1)

This value is sent to Battle.net to prove that you know your own password. Again, this differs from standard SRP. In this formula, commas (,) indicate concatenation:

M1 = SHA1(SHA1(g) xor SHA1(N), SHA1(Username), s, A, B, K)

Username and password are converted to UPPER CASE prior to hashing. This value is sent to the server in SID_AUTH_ACCOUNTLOGONPROOF

[hr]

I'm confused about the xor part of M1, can someone please explain? Every time i go to log in i'm receiving the invalid password message, and I'm sure it's because im not understanding the xor part of this formula.
August 13, 2007, 7:04 PM
HdxBmx27
Eah, it would be best if you showed some code and example cases.
But anyways, heres the general idea:
[code]byte[] g = SHA1.digest(47);
byte[] n = SHA1.digest(" \x87\xc7\x23\x85\x65\xf6\x16\x12\xd9...");
byte[] i = new byte[20];
for(int x = 0; x<20; x++)
  i[x] = g[x] ^ n[x];[/code]
~Hdx
August 13, 2007, 7:20 PM
Camel
[quote author=iNsaNe link=topic=16942.msg171547#msg171547 date=1187031878]I'm confused about the xor part of M1, can someone please explain? Every time i go to log in i'm receiving the invalid password message, and I'm sure it's because im not understanding the xor part of this formula.[/quote]
First, let's define XOR, exclusive or:

A Boolean operator that returns a value of TRUE only if just one of its operands is TRUE. In contrast, an inclusive OR operator returns a value of TRUE if either or both of its operands are TRUE.

So:
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

[IRRELEVANT]
Instead of thinking of it in this context, I think it's easier to think of it as the parity (read: "is the sum of the parts an odd number?") of all of the things being XORed. If I asked you what the answer to (1 ^ 0 ^ 0 ^ 1 ^ 0 ^ 1) was, you could spend 30 or so seconds doing each operation in your head, or you could just tell me if there are an odd number of ones in the expression. Algorithmically, the latter is much simpler, and always produces the same result.
[/IRRELEVANT]

As a bitwise operator, it works the same way, except the operation is done on each bit of the parts. A SHA1 hash is 160 bits wide, and therefore the operation is done on each of the 160 bits.

Since most processors are 32 bits, it's conventional (but far from necessary) to treat a 160bit SHA1 hash as 5 DWords. In Hdx's code above, he treats it as 20 bytes, which is also acceptable - and is probably the simplest solution in Java.

Hope this helps.
August 13, 2007, 8:37 PM
iago
If you need more info on formulas, check out the document I wrote forever ago, when we first reversed it: http://www.javaop.com/~ron/documents/SRP.html

It contains code snippits for every step, so it should be reasonably easy to follow.
August 14, 2007, 2:26 AM
Barabajagal
On this topic/line of inquiry... I'd like to ask if anyone has a BigNum system for a BASIC language...  I've written most of one, but it doesn't have exponents yet, and some stuff (like modulo) is extremely slow.
August 14, 2007, 2:46 AM
leax
if ur in .NET say VB
u can actaully import the java class so essentiall u can access the BigInteger class (ref: vjslib.dll)
though u gota manually convert signed and unsigned byte arrays

also regarding  SHA1(g) XOR SHA1(N) in this case is pretty much a constant which you can also dig up from iago's NLS class in javaOP


*edit
result = New Byte() {108, 14, 151, 237, 10, 249, 107, 171, 177, 88, 137, 235, 139, 186, 37, 164, 240, 140, 1, 248}
August 14, 2007, 8:43 AM
Barabajagal
I refuse to use .NET languages. I'm writing my system in PowerBasic, and I have the following untested code for my class:
[code]#Include "StandardSHA"

Sub MakeArray(Num() As Byte, Vals() As Byte)
Dim I As Integer
Dim J As Integer
    J = 0
    For I = &HFF - UBound(Vals) To &HFF
        Num(I) = Vals(J)
        J = J + 1
    Next I
End Sub

Function BigNum_Compare(NumA() As Byte, NumB() As Byte) As Byte
Dim I As Integer
Dim Dif As Byte
    For I = 0 To &HFF
        If NumA(I) > NumB(I) Then
            Function = 1
            Exit For
        ElseIf NumA(I) < NumB(I) Then
            Function = 2
            Exit For
        End If
    Next I
End Function

Sub BigNum_ToString(NumA() As Byte, Ret As String)
Dim strS As String
Dim I    As Integer
    For I = 0 To UBound(NumA)
        strS = strS & Chr$(NumA(I))
    Next I
    Ret = strS
End Sub

Sub BigNum_FromString(NumA As String, Ret() As Byte)
Dim I    As Integer
    For I = UBound(Ret()) - Len(NumA) To UBound(Ret())
        Ret(I) = Asc(Mid$(NumA, I - (UBound(Ret()) - Len(NumA)), 1))
    Next I
End Sub

Sub AddVal(Num() As Byte, ByVal AddLoc As Long, ByVal ToAdd As Byte, RetNum() As Byte)
    If Num(AddLoc) + ToAdd > &HFF Then
        AddVal(Num(), AddLoc - 1, 1, Num())
        RetNum(AddLoc) = (Num(AddLoc) + ToAdd) - &H100
    Else
        RetNum(AddLoc) = Num(AddLoc) + ToAdd
    End If
End Sub

Sub SubVal(Num() As Byte, ByVal SubLoc As Long, ByVal ToSub As Byte, RetNum() As Byte)
    If Num(SubLoc) - ToSub < &H0 Then
        SubVal(Num(), SubLoc - 1, 1, Num())
        RetNum(SubLoc) = (Num(SubLoc) - ToSub) + &H100
    Else
        RetNum(SubLoc) = Num(SubLoc) - ToSub
    End If
End Sub

Sub BigNum_Add(NumA() As Byte, NumB() As Byte, Ret() As Byte)
Dim I As Integer
    For I = UBound(NumA) To 0 Step -1
        AddVal NumA(), I, NumB(I), Ret()
    Next I
End Sub

Sub BigNum_Subtract(NumA() As Byte, NumB() As Byte, Ret() As Byte)
Dim I As Integer
    For I = UBound(NumA) To 0 Step -1
        SubVal NumA(), I, NumB(I), Ret()
    Next I
End Sub

Sub BigNum_Multiply(NumA() As Byte, NumB() As Byte, Ret() As Byte)
Dim I As Integer
Dim J As Integer
Dim rVal            As Integer
Dim rCarry          As Byte
Dim rLast            As Byte
Dim tRet(&HFF)      As Byte
Dim uRet(&HFF)      As Byte
Dim fRet(&HFF, &HFF) As Byte
    For I = UBound(NumB) To 0 Step -1
        For J = UBound(NumA) To 0 Step -1
            RVal = NumA(J) * NumB(I) + RLast
            RCarry = 0
            If RVal > &HFF Then
                RCarry = RVal \ 256
                RVal = RVal Mod 256
            End If
            fRet(I, J) = RVal
            rLast = rCarry
        Next J
    Next I
    For I = &HFF To 0 Step - 1
        For J = 0 To &HFF
            tRet(J) = fRet(I, J)
        Next J
        BigNum_Add Ret(), tRet(), uRet()
        For J = 0 To &HFF
            Ret(J) = uRet(J)
        Next J
    Next I
End Sub

Sub BigNum_Modulo(NumA() As Byte, NumB() As Byte, Ret() As Byte)
Dim I          As Integer
    Do While BigNum_Compare(NumA(), NumB()) = 1
        BigNum_Subtract NumA(), NumB(), NumA()
    Loop
    For I = 0 To &HFF
        Ret(I) = NumA(I)
    Next I
End Sub

Sub BigNum_Hash(NumA() As Byte, Ret() As Byte)
Dim strToHash As String
Dim strHash  As String
    BigNum_ToString NumA(), strToHash
    strHash = StandardSHA1(strToHash)
    BigNum_FromString strHash, Ret()
End Sub[/code]
It's not very well made, I know, but I don't know this language's capabilities very well yet, and I really don't know how the hell bignum stuff should work in the least.
August 15, 2007, 6:00 AM
iNsaNe
Sorry guys this is a somewhat old topic I just came back to my bot so far in C# and I'm still getting an invalid password response. I feel stupid asking for help what's wrong with the M1 code I have because I've been looking at iago's and myndfyre's codes for a while now. But I'm getting an invalid password response every time..

I'll post the full log, but if you need the code (I'm not going to consider it fully mine) I'll post it.

Connecting with WAR3 ...
.
[code]
C -> S 0x50:
                    ff 50 3a 00 00 00 00 00 36        .P:.....6
38 58 49 33 52 41 57 15 00 00 00 00 00 00 00 00  8XI3RAW.........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55  ...............U
53 41 00 55 6e 69 74 65 64 20 53 74 61 74 65 73  SA.United States
00                                              .

S -> C 0x25:

                        ff 25 08 00 83 be 71 73  .......%....qs

S -> C 0x50:

                  ff 50 e6 00 02 00 00 00 dc 85  ..2....P........
3b 83 5f 3f 1c 00 00 4d 89 7e 99 cb c6 01 76 65  ;._?...M.~....ve
72 2d 49 58 38 36 2d 34 2e 6d 70 71 00 43 3d 33  r-IX86-4.mpq.C=3
30 33 39 35 32 35 31 38 34 20 41 3d 31 39 39 36  039525184 A=1996
30 35 35 34 38 32 20 42 3d 34 30 36 32 38 35 38  055482 B=4062858
34 20 34 20 41 3d 41 5e 53 20 42 3d 42 5e 43 20  4 4 A=A^S B=B^C
43 3d 43 2d 41 20 41 3d 41 5e 42 00 f7 f9 67 a6  C=C-A A=A^B...g.
a0 93 85 48 39 58 b6 61 98 de 6d df ee 9b 1d 39  ...H9X.a..m....9
b8 57 69 87 cf 36 ae ef 43 e2 f8 f4 19 0a 6a 1b  .Wi..6..C.....j.
0a f0 f7 03 3f d6 ea 75 9b 93 0a 31 ea ad 4f 13  ....?..u...1..O.
d5 4e a8 6c c2 1b df 8a c9 bf 88 d7 26 ae 0f 3d  .N.l........&..=
9b 77 a7 04 44 42 41 c1 be 5b d2 fe 73 93 f0 6c  .w..DBA..[..s..l
0f 60 5a 43 62 58 fa 41 f2 d5 b4 9b 4c 43 ec 94  .`ZCbX.A....LC..
74 7c d8 06 de de a5 76 fe f3 8b 19 e5 2d cb fb  t|.....v.....-..
b1 f7 1d 74 b9 31 26 3d 43 2d 02 2b              ...t.1&=C-.+

C -> S 0x51:

                  ff 51 63 00 e7 eb e4 02 15 00  ..t....Qc.......
01 00 28 97 71 79 01 00 00 00 00 00 00 00 1a 00  ..(.qy..........
00 00 0e 00 00 00 0a 66 70 00 00 00 00 00 d8 7f  .......fp.......
6e e7 68 c1 41 e5 a8 17 49 34 99 d5 9a 6b 2d 9f  n.h.A...I4...k-.
68 00 77 61 72 33 2e 65 78 65 20 31 32 2f 32 38  h.war3.exe 12/28
2f 30 36 20 33 30 3a 33 35 3a 32 31 20 31 35 37  /06 30:35:21 157
32 33 30 37 00 34 32 32 00                      2307.422.

(422 is my account name which is the cd key owner name :P dont be confused)

S -> C 0x51:

                    ff 51 09 00 00 00 00 00 00  .a.....Q.......

C -> S 0x53:

                  ff 53 28 00 72 c0 76 88 d5 31  ..#....S(.r.v..1
2d 42 18 48 55 c9 a7 ea 20 ea fd 81 1f 22 ce 8a  -B.HU... ...."..
f9 4f c2 7b d8 03 78 64 10 a1 34 32 32 00        .O.{..xd..422.

(422 is my account name again)

S -> C 0x53:

                  ff 53 48 00 00 00 00 00 88 db  .9.@...SH.......
2c 8a a2 57 ff 16 fa 03 79 df b0 00 4c be 95 4a  ,..W....y...L..J
7f 4c d2 23 63 85 0f e9 ff 27 7f a7 2c a2 42 88  .L.#c....'..,.B.
01 01 f9 c8 58 d7 da af 19 17 35 2a a8 4d 67 60  ....X.....5*.Mg`
b0 7f c8 07 96 58 9a fd 0a 35 85 f8 e4 28        .....X...5...(

C -> S 0x54:

                  ff 54 18 00 79 71 59 49 7c 4a  ...j...T..yqYI|J
23 4c 3d 37 a5 27 16 a4 9e 45 49 db 6c d0        #L=7.'...EI.l.

S -> C 0x54:

                  ff 54 1c 00 02 00 00 00 00 00  .!.2...T........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00                                            ..
[/code]

02 00 00 00 of death -.-
any help?
October 5, 2007, 3:50 AM
HdxBmx27
From what you posted, I would have to say you entered the wrong password. As I would assume your SRP class is perfect. As you deemed it unnessasary to post.
AE: Post your code -.-
And don't bump old ass threads.
~Hdx
October 5, 2007, 2:02 PM
iNsaNe
[code]
using System;
using System.Collections.Generic;
using System.Text;
namespace Infinite_Bot_v1
{
    class NLS
    {
        bool INIT = false;
        string Username;
        string Password;
        BigInteger g = new BigInteger("47", 10);
        BigInteger N = new BigInteger("112624315653284427036559548610503669920632123929604336254260115573677366691719", 10);
        BigInteger B;
        BigInteger A;
        BigInteger a;
        BigInteger S;
        BigInteger u;
        BigInteger x;
        BigInteger v;
        byte[] Salt;
        byte[] ServerKey;
        byte[] K;
        bool CLIENTKEYUSED = false;
        bool VERIFIERUSED = false;
        bool USERNAMEPWHASHUSED = false;
        System.Security.Cryptography.SHA1 Sha = new System.Security.Cryptography.SHA1Managed();
        System.Security.Cryptography.RandomNumberGenerator RNGen = new System.Security.Cryptography.RNGCryptoServiceProvider();
        private void CHECKINIT()
        {
            if (!INIT)
                throw new Exception("NLS has not been initialized.");
        }
        private byte[] GetUsernamePWHash(byte[] salt)
        {
            if (USERNAMEPWHASHUSED)
                return x.getBytes();
            USERNAMEPWHASHUSED = true;
            byte[] AccPw = System.Text.Encoding.ASCII.GetBytes(Username.ToUpper() + ":" + Password.ToUpper());
            byte[] hashAccPw = Sha.ComputeHash(AccPw);
            byte[] salt_and_hashAccPw = new byte[52];
            Array.Copy(salt, 0, salt_and_hashAccPw, 0, 32);
            Array.Copy(hashAccPw, 0, salt_and_hashAccPw, 32, 20);
            byte[] vData = Sha.ComputeHash(salt_and_hashAccPw);
            x = new BigInteger(vData);
            return x.getBytes();
        }
        public NLS()
        {
        }
        public NLS(string username, string password)
        {
            if (INIT)
                throw new Exception("NLS has already been initialized.");
            INIT = true;
            Username = username;
            Password = password;
        }
        public byte[] GetClientKey()
        {
            if (CLIENTKEYUSED)
                return A.getBytes();
            CLIENTKEYUSED = true;
            byte[] NonZeroBytes = new byte[32];
            RNGen.GetNonZeroBytes(NonZeroBytes);
            a = new BigInteger(NonZeroBytes);
            a %= N;
            A = g.modPow(a, N);
            return A.getBytes();
        }
        public byte[] GetVerifier(byte[] salt)
        {
            if (VERIFIERUSED)
                return v.getBytes();
            VERIFIERUSED = true;
            if (USERNAMEPWHASHUSED)
            {
                v = new BigInteger(g.modPow(x, N));
                return v.getBytes();
            }
            else
            {
                BigInteger bi_x = new BigInteger(GetUsernamePWHash(salt));
                v = new BigInteger(g.modPow(bi_x, N));
                return v.getBytes();
            }
        }
        public byte[] CreateSalt()
        {
            Salt = new byte[32];
            RNGen.GetNonZeroBytes(Salt);
            return Salt;
        }
        public byte[] GetM1(byte[] salt, byte[] serverkey)
        {
            if (salt.Length != 32)
                throw new Exception("Salt index out of bounds.");
            if (serverkey.Length != 32)
                throw new Exception("Server Key index out of bounds.");
            if (!CLIENTKEYUSED)
                throw new Exception("You must generate a Client Key before accessing this function.");
            Salt = salt;
            ServerKey = serverkey;
            B = new BigInteger(serverkey);
            //B
            if (!USERNAMEPWHASHUSED)
                GetUsernamePWHash(salt);
            //x
            if (!VERIFIERUSED)
                GetVerifier(salt);
            BigInteger g_XoR_N = new BigInteger("1415864289515498529999010855430909456942718455404", 10);
            //Sha1(g) xor Sha1(N)
            byte[] Acc = System.Text.Encoding.ASCII.GetBytes(Username.ToUpper());
            byte[] hashAcc = Sha.ComputeHash(Acc);
            //Username hash
            byte[] hashB = Sha.ComputeHash(serverkey);
            byte[] uBytes = new byte[4];
            for (int i = 0; i <= 3; i++)
                uBytes[i] = hashB[3 - i];
            u = new BigInteger(uBytes);
            //u
            S = new BigInteger(((N + B) - v) % N);
            S = S.modPow(a + (u * x), N);
            //S
            K = new byte[40];
            byte[] SBytes = S.getBytes();
            byte[] EvensIN = new byte[SBytes.Length / 2];
            byte[] OddsIN = new byte[SBytes.Length / 2];
            for (int i = 0; i < EvensIN.Length; i++)
            {
                EvensIN[i] = SBytes[i * 2];
                OddsIN[i] = SBytes[(i * 2) + 1];
            }
            byte[] EvensOUT = Sha.ComputeHash(EvensIN);
            byte[] OddsOUT = Sha.ComputeHash(OddsIN);
            for (int i = 0; i < EvensOUT.Length; i++)
            {
                K[i * 2] = EvensOUT[i];
                K[(i * 2) + 1] = OddsOUT[i];
            }
            //K
            System.IO.MemoryStream memStream = new System.IO.MemoryStream();
            System.IO.BinaryWriter BW = new System.IO.BinaryWriter(memStream);
            BW.Write(g_XoR_N.getBytes());
            BW.Write(hashAcc);
            BW.Write(salt);
            BW.Write(A.getBytes());
            BW.Write(serverkey);
            BW.Write(K);
            BW.Close();
            byte[] M1 = Sha.ComputeHash(memStream.GetBuffer());
            memStream.Close();
            return M1;
        }
    }
}
[/code]

That's the whole class. You'll see a lot of code from iago and myndfyre so I'd like to thank them for all the help they do for valhallalegends and/or other communities.
October 5, 2007, 10:30 PM

Search