#1
  1. Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Dec 2004
    Location
    Meriden, Connecticut
    Posts
    1,797
    Rep Power
    154

    BNLS Checksum Algorithm


    Ok, this is one of the most important parts of my application and it is becoming very hard to translate. This code is needed for my bot, otherwise, it will not connect. I would like to know if the following code can be easily (or anyway) translated into Python. I'm not saying you have to do this for me unless you wan't to, this has just become very hard to accomplish. The following code is C++. I also have this code in VB6 and C# incase anyone would like to see that instead.

    Here is some information about the BNLS Checksum:
    The BNLS checksum algorithm calculates the checksum of a password using the 32-bit server code received in BNLS_AUTHORIZE (0x0e). You should create the BNLS checksum as follows:
    Create an ANSI string whose length is the length of the password + 8 characters.
    Copy the password to the beginning. (Note that the password is case sensitive.)
    In the last 8 characters, store the hexadecimal representation of the server code, in uppercase, padded with zeroes on the left.
    Calculate the standard CRC-32 checksum (using the standard polynomial 0xEDB88320) of the string. The result is the BNLS checksum, to be sent in BNLS_AUTHORIZEPROOF (0x0f).

    [C++]
    Code:
    #define CRC32_POLYNOMIAL 0xEDB88320
    unsigned long CRC32Table[256];
    
    void InitCRC32()
    {
    	static bool CRC32Initialized = false;
    	if(CRC32Initialized)
    		return;
    	CRC32Initialized = true;
    
    	for(unsigned long I = 0; I < 256; I++) {
    		unsigned long K = I;
    		for(unsigned long J = 0; J < 8; J++)
    			K = (K >> 1) ^ ((K & 1) ? CRC32_POLYNOMIAL : 0);
    		CRC32Table[I] = K;
    	}
    }
    
    unsigned long CRC32(unsigned char* Data, unsigned long Size)
    {
    	InitCRC32();
    
    	unsigned long CRC = 0xffffffff;
    	while(Size--)
    		CRC = (CRC >> 8) ^ CRC32Table[(CRC & 0xff) ^ *Data++];
    	return ~CRC;
    }
    
    inline unsigned char Hex(unsigned char Digit)
    {
    	if(Digit < 10)
    		return Digit + '0';
    	else
    		return Digit - 10 + 'A';
    }
    
    unsigned long BNLSChecksum(const char* Password, unsigned long ServerCode)
    {
    	unsigned long Size = (unsigned long)strlen(Password);
    	unsigned char* Data = new unsigned char[Size + 8];
    	memcpy(Data, Password, Size);
    	unsigned long I = 7;
    	do {
    		Data[Size + I] = Hex((unsigned char)ServerCode & 0xf);
    		ServerCode >>= 4;
    	}
    	while(I--);
    
    	unsigned long Checksum = CRC32(Data, Size + 8);
    	delete[] Data;
    	return Checksum;
    }
    Update: I figured I'd just add the rest of the languages as well (remember, I did not created this code).

    [C#]
    Code:
    using System;
    
    namespace Project1
    {
    	/// <summary>
    	/// Summary description for BNLSChecksumCls 1.03.
    	///
    	/// Copyright(c) 2004 - l)ragon
    	///
    	/// My representation of the CRC32 in C#
    	/// this is horible get a real language.
    	///
    	/// 1.03 { Removed CRCTables and added a conversion of Yoni's VB InitCRC.,
    	///		   Added HexValues table. }
    	/// 1.02 { N/A }
    	/// 1.01 { N/A }
    	/// 1.00 { N/A }
    	/// </summary>
    	public class BNLSChecksumCls
    	{
    		public BNLSChecksumCls()
    		{
    			//
    			// TODO: Add constructor logic here
    			//
    		}
    		static string[] HexValues = {   "00" ,"01" ,"02" ,"03" ,"04" ,"05" ,"06" ,"07" ,"08" ,"09" ,"0A" ,"0B" ,"0C" ,"0D" ,
    										"0E" ,"0F" ,"10" ,"11" ,"12" ,"13" ,"14" ,"15" ,"16" ,"17" ,"18" ,"19" ,"1A" ,"1B" ,
    										"1C" ,"1D" ,"1E" ,"1F" ,"20" ,"21" ,"22" ,"23" ,"24" ,"25" ,"26" ,"27" ,"28" ,"29" ,
    										"2A" ,"2B" ,"2C" ,"2D" ,"2E" ,"2F" ,"30" ,"31" ,"32" ,"33" ,"34" ,"35" ,"36" ,"37" ,
    										"38" ,"39" ,"3A" ,"3B" ,"3C" ,"3D" ,"3E" ,"3F" ,"40" ,"41" ,"42" ,"43" ,"44" ,"45" ,
    										"46" ,"47" ,"48" ,"49" ,"4A" ,"4B" ,"4C" ,"4D" ,"4E" ,"4F" ,"50" ,"51" ,"52" ,"53" ,
    										"54" ,"55" ,"56" ,"57" ,"58" ,"59" ,"5A" ,"5B" ,"5C" ,"5D" ,"5E" ,"5F" ,"60" ,"61" ,
    										"62" ,"63" ,"64" ,"65" ,"66" ,"67" ,"68" ,"69" ,"6A" ,"6B" ,"6C" ,"6D" ,"6E" ,"6F" ,
    										"70" ,"71" ,"72" ,"73" ,"74" ,"75" ,"76" ,"77" ,"78" ,"79" ,"7A" ,"7B" ,"7C" ,"7D" ,
    										"7E" ,"7F" ,"80" ,"81" ,"82" ,"83" ,"84" ,"85" ,"86" ,"87" ,"88" ,"89" ,"8A" ,"8B" ,
    										"8C" ,"8D" ,"8E" ,"8F" ,"90" ,"91" ,"92" ,"93" ,"94" ,"95" ,"96" ,"97" ,"98" ,"99" ,
    										"9A" ,"9B" ,"9C" ,"9D" ,"9E" ,"9F" ,"A0" ,"A1" ,"A2" ,"A3" ,"A4" ,"A5" ,"A6" ,"A7" ,
    										"A8" ,"A9" ,"AA" ,"AB" ,"AC" ,"AD" ,"AE" ,"AF" ,"B0" ,"B1" ,"B2" ,"B3" ,"B4" ,"B5" ,
    										"B6" ,"B7" ,"B8" ,"B9" ,"BA" ,"BB" ,"BC" ,"BD" ,"BE" ,"BF" ,"C0" ,"C1" ,"C2" ,"C3" ,
    										"C4" ,"C5" ,"C6" ,"C7" ,"C8" ,"C9" ,"CA" ,"CB" ,"CC" ,"CD" ,"CE" ,"CF" ,"D0" ,"D1" ,
    										"D2" ,"D3" ,"D4" ,"D5" ,"D6" ,"D7" ,"D8" ,"D9" ,"DA" ,"DB" ,"DC" ,"DD" ,"DE" ,"DF" ,
    										"E0" ,"E1" ,"E2" ,"E3" ,"E4" ,"E5" ,"E6" ,"E7" ,"E8" ,"E9" ,"EA" ,"EB" ,"EC" ,"ED" ,
    										"EE" ,"EF" ,"F0" ,"F1" ,"F2" ,"F3" ,"F4" ,"F5" ,"F6" ,"F7" ,"F8" ,"F9" ,"FA" ,"FB" ,
    										"FC" ,"FD" ,"FE" ,"FF" };
    
    		public long CRC32_POLYNOMIAL = 0xEDB88320;
    		public long[] CRC32Table;
    
    		private void InitCRC32()
    		{
    			long I, J, K, X, XorVal;
    
    			CRC32Table = new long[256];
    
    			for(I = 0; I < 256; I++) 
    			{
    				K = I;
            
    				for(J = 0; J < 8; J++)
    				{  
    					X = (K & ((long)1));
    
    					if(X > 0) 
    					{	
    						XorVal = CRC32_POLYNOMIAL; 
    					} 
    					else 
    					{	
    						XorVal = 0;	
    					}
    					if(K < 0) 
    					{	
    						K = ((K & 0x7FFFFFFF) / 2) | 0x40000000; 
    					} 
    					else	
    					{
    						K = K / 2; 
    					}
    					K ^= XorVal;
    				}
    				CRC32Table[I] = K;
    			}
    		}
    		private long CRC32(string txt) 
    		{
    			long c=-1;
    			int I = 0, J = 0, L = 0, U = 0, U2 = 0;
    			InitCRC32();
    
    			for(I = 0; I < txt.Length; I++)
    			{
    				L = (int)txt[I];
    				U2 = 0xFF;
    				U = (int)(c & U2);
    				J = (L ^ U);
    				if(c < 0) 
    				{ 
    					c = (((c & 0x7FFFFFFF) / 0x100) | 0x800000); 
    				} 
    				else 
    				{ 
    					c = (c / 0x100); 
    				}
    				c ^= CRC32Table[J];
    				c = ConvertLong(c);
    			}
    			c = ((c * -1) - 1);
    			return c; 
    		}
    		private long ConvertLong(long Value)
    		{
    			if(Value < 0xFFFFFFFF)
    			{
    				Value -= 0xFFFFFFFF;
    				Value -= 1;
    			}
    			if(Value > (0xFFFFFFFF * -1))
    			{
    				Value += 0xFFFFFFFF;
    				Value += 1;
    			}
    			return Value;
    		}
    		public string BNLSChecksum(string Password, long ServerCode)
    		{
    			string strSCode = "", strTm = "";
    			char[] scChC;
    			
    			scChC = ServerCode.ToString().ToCharArray();
    			strSCode = MakeDW(ConvertLong(ServerCode));
    			strTm = reverse(strSCode);
    			strTm = tohex(strTm);
    
    			return MakeDW(CRC32(Password+strTm));
    		}
    		private string tohex(string inBuf)
    		{
    			int x, numVal;
    			string outBuf="";
    
    			for(x = 0; x < inBuf.Length; x++)
    			{
    				numVal = inBuf[x];
    				outBuf = outBuf+HexValues[numVal];
    			}
    			return outBuf;
    		}
    		private string reverse(string inBuf)
    		{
    			int x;
    			string outBuf = "";
    			for(x = inBuf.Length - 1; x > -1; x--)
    			{
    				outBuf = outBuf+inBuf[x];
    			}
    			return outBuf;
    		}
    
    		private string MakeDW(long lngInt)
    		{
    			char a, b, c, d;
    			long tmpLng;
    			int tmpint;
    			string outBuf;
    
    			if(lngInt < -1) { lngInt += 0xFFFFFFFF; lngInt += 1; }
    				
    			tmpLng = lngInt;
    			
    			tmpint = (int)(((tmpLng / 256) / 256) / 256);
    			a = (char)(tmpint);
    			tmpLng -= (((tmpint* 256)* 256)* 256);
    			
    			tmpint = (int)((tmpLng / 256) / 256);
    			b = (char)(tmpint);
    			tmpLng -= ((tmpint*256)*256);
    			
    			tmpint = (int)(tmpLng / 256);
    			c = (char)(tmpint);
    			tmpLng -= (tmpint*256);
    			
    			tmpint = (int)(tmpLng);
    			d = (char)(tmpint);
    
    			outBuf = d.ToString()+c.ToString()+b.ToString()+a.ToString();
    			
    			return outBuf;
    		}
    	}
    }
    [VB6]
    Code:
    Private Sub InitCRC32()
        Dim i As Long, J As Long, K As Long, XorVal As Long
        
        Static CRC32Initialized As Boolean
        If CRC32Initialized Then Exit Sub
        CRC32Initialized = True
        
        For i = 0 To 255
            K = i
            
            For J = 1 To 8
                If K And 1 Then XorVal = CRC32_POLYNOMIAL Else XorVal = 0
                If K < 0 Then K = ((K And &H7FFFFFFF) \ 2) Or &H40000000 Else K = K \ 2
                K = K Xor XorVal
            Next
            
            CRC32Table(i) = K
        Next
    End Sub
    
    Private Function CRC32(ByVal Data As String) As Long
        Dim i As Long, J As Long
        
        Call InitCRC32
        
        CRC32 = &HFFFFFFFF
        
        For i = 1 To Len(Data)
            J = CByte(Asc(Mid(Data, i, 1))) Xor (CRC32 And &HFF&)
            If CRC32 < 0 Then CRC32 = ((CRC32 And &H7FFFFFFF) \ &H100&) Or &H800000 Else CRC32 = CRC32 \ &H100&
            CRC32 = CRC32 Xor CRC32Table(J)
        Next
        
        CRC32 = Not CRC32
    End Function
    
    Public Function BNLSChecksum(ByVal Password As String, ByVal ServerCode As Long) As Long
        BNLSChecksum = CRC32(Password & Right("0000000" & Hex(ServerCode), 8))
    End Function
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Posts
    624
    Rep Power
    34
    I found on their website:

    # Sample Checksums - These sample checksums can be used to check the correctness of your code.

    BNLSChecksum("Sample", 0x0123ABCD) == 0x12FDED88
    BNLSChecksum("Checksums", 0xBAADF00D) == 0x0098F911"


    You're going to love this.

    Code:
    >>> import binascii
    
    >>> crc = binascii.crc32("Sample0123ABCD")
    >>> print hex(crc)
    0x12FDED88
    
    >>> crc = binascii.crc32("ChecksumsBAADF00D")
    >>> print hex(crc)
    0x98F911

    All you need to do is work out if you're dealing with strings of hex, or if you need to convert the character codes into hex with ord() and worry about putting 0's at the front of the results.

  4. #3
  5. Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Dec 2004
    Location
    Meriden, Connecticut
    Posts
    1,797
    Rep Power
    154
    So pretty much, in Python, the code you showed me will operate just like the codes written in the other 3 languages?
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Posts
    624
    Rep Power
    34
    Yeah.

    "You should create the BNLS checksum as follows:
    Create an ANSI string whose length is the length of the password + 8 characters."

    You don't need to explicitly create strings with a particular length in Python, so there's no need for this.

    "Copy the password to the beginning. (Note that the password is case sensitive.)"
    You don't have to do anything special like strcpy to copy strings in Python, and it is case sensitive anyway by default.

    "In the last 8 characters, store the hexadecimal representation of the server code, in uppercase, padded with zeroes on the left"
    This matters, but how you do it depends on how you are reading the code elsewhere in your program.

    "test".zfill(n) will pad a string with zeros on the left up to n characters.

    To remove the "0x" from the start of a hex string and pad with zeros, it might be:
    textToCheck = password + serverCode[2:].zfill(8)

    I think you asked a while ago about changing a string into hex characters... so you could use that if you need to.

    "Calculate the standard CRC-32 checksum"
    Done with the library function binascii.crc32. I think this is what takes up most of the code in the other language examples.
  8. #5
  9. Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Dec 2004
    Location
    Meriden, Connecticut
    Posts
    1,797
    Rep Power
    154
    Ok, this is very hard. I don't even know where to start.

    This is what I've gotten so far:

    Code:
        def InitCRC32():
            CRC32Initialized = True
            for i in range(255)
                 K = i
                 for J in range(1, 8):
                     if K and 1:
                         XorVal = CRC32_POLYNOMIAL
                     else:
                         XorVal = 0
                     if K < 0:
                         K = K+0x7FFFFFFF/2 or 0x40000000
                     else:
                         K = K/2
                 return K # return CRC32Table(i)?
        def CRC32():
            InitCRC32()
            CRC32 = 0xFFFFFFFF
            for i in range(1, len(data))
                J = CByte(ord(data[i:1)) or CRC32 and 0xFF
                if CRC32 < 0:
                    CRC32 = CRC32 and 0x7FFFFFFF/0x100 or 0x800000
                else:
                    CRC32 = CRC32/0x100
                CRC32 = CRC32 or CRC32Table(J)
                CRC32 != CRC32
        def BNLSChecksum():
            BNLSChecksum = CRC32(bnetpass+"0000000"+hex(ServerCode)[8])
    Now, the example code on the bnetdocs didn't make much sense to me. The copying things to something else the polynomial stuff, etc. So I tried converting the code. I know that there are many errors in there. CByte and CRC32 are not recognized in Python. And a few of the statements need to be fixed in order to in Python. Do you have any ideas?

IMN logo majestic logo threadwatch logo seochat tools logo