Protocols/MSNP/TCL (Challenge Implementation)

From NINA Wiki
Jump to navigation Jump to search
MSNP Protocol
IntroductionTermsClients
Reference
Error ListCommandsRelaying Party SuiteSpotlife
Services
XMPPHTTP GatewayTabsActivities
Documentation
Development ToolsMSNP Grid
PolygamyURLs used by MSN
Documents
Protocol Versions
Version 21
Version 18
Version 16
Version 15
Version 14
Version 13
Version 12
Version 11
Version 9
Version 8
MSNC
IntroductionP2PObject DescriptorDisplay PicturesFile Transfer
Scenarios
Microsoft Messenger for Mac
MSNP on WebTV (MSNTV)
        proc CreateQRYHash {chldata} {
                set prodid "PROD0090YUAUV\{2B"
                set prodkey "YMM8C_H7KCQ2S_KL"

                # Create an MD5 hash out of the given data, then form 32 bit integers from it
                set md5hash [::md5::md5 -hex $chldata$prodkey]
                set md5parts [MD5HashToInt $md5hash]

                # Then create a valid productid string, divisable by 8, then form 32 bit integers from it
                set nrPadZeros [expr 8 - [string length $chldata$prodid] % 8]
                set padZeros [string repeat 0 $nrPadZeros]
                set chlprodid [CHLProdToInt $chldata$prodid$padZeros]

                # Create the key we need to XOR
                set key [KeyFromInt $md5parts $chlprodid]

                set low 0x[string range $md5hash 0 15]
                set high 0x[string range $md5hash 16 32]
                set low [expr {$low ^ $key}]
                set high [expr {$high ^ $key}]

                set p1 [format %8.8x [expr {$low / 0x100000000}]]
                set p2 [format %8.8x [expr {$low % 0x100000000}]]
                set p3 [format %8.8x [expr {$high / 0x100000000}]]
                set p4 [format %8.8x [expr {$high % 0x100000000}]]

                return $p1$p2$p3$p4
        }

        proc KeyFromInt { md5parts chlprod } {
                # Create a new series of numbers
                set key_temp 0
                set key_high 0
                set key_low 0

                # Then loop on the entries in the second array we got in the parameters
                for {set i 0} {$i < [llength $chlprod]} {incr i 2} {

                        # Make $key_temp zero again and perform calculation as described in the documents
                        set key_temp [lindex $chlprod $i]
                        set key_temp [expr {(wide(0x0E79A9C1) * wide($key_temp)) % wide(0x7FFFFFFF)}]
                        set key_temp [expr {wide($key_temp) + wide($key_high)}]
                        set key_temp [expr {(wide([lindex $md5parts 0]) * wide($key_temp)) + wide([lindex $md5parts 1])}]
                        set key_temp [expr {wide($key_temp) % wide(0x7FFFFFFF)}]

                        set key_high [lindex $chlprod [expr {$i+1}]]
                        set key_high [expr {(wide($key_high) + wide($key_temp)) % wide(0x7FFFFFFF)}]
                        set key_high [expr {(wide([lindex $md5parts 2]) * wide($key_high)) + wide([lindex $md5parts 3])}]
                        set key_high [expr {wide($key_high) % wide(0x7FFFFFFF)}]
                        set key_low [expr {wide($key_low) + wide($key_temp) + wide($key_high)}]
                }

                set key_high [expr {(wide($key_high) + wide([lindex $md5parts 1])) % wide(0x7FFFFFFF)}]
                set key_low [expr {(wide($key_low) + wide([lindex $md5parts 3])) % wide(0x7FFFFFFF)}]

                set key_high 0x[byteInvert [format %8.8X $key_high]]
                set key_low 0x[byteInvert [format %8.8X $key_low]]

                set long_key [expr {(wide($key_high) << 32) + wide($key_low)}]

                return $long_key
        }

        # Takes an CHLData + ProdID + Padded string and chops it in 4 bytes. Then converts to 32 bit integers
        proc CHLProdToInt { CHLProd } {
                set hexs {}
                set result {}
                while {[string length $CHLProd] > 0} {
                        lappend hexs [string range $CHLProd 0 3]
                        set CHLProd [string range $CHLProd 4 end]
                }
                for {set i 0} {$i < [llength $hexs]} {incr i} {
                        binary scan [lindex $hexs $i] H8 int
                        lappend result 0x[byteInvert $int]
                }
                return $result
        }

        # Takes an MD5 string and chops it in 4. Then "decodes" the HEX and converts to 32 bit integers. After that it ANDs
        proc MD5HashToInt { md5hash } {
                binary scan $md5hash a8a8a8a8 hash1 hash2 hash3 hash4
                set hash1 [expr "0x[byteInvert $hash1]" & 0x7FFFFFFF]
                set hash2 [expr "0x[byteInvert $hash2]" & 0x7FFFFFFF]
                set hash3 [expr "0x[byteInvert $hash3]" & 0x7FFFFFFF]
                set hash4 [expr "0x[byteInvert $hash4]" & 0x7FFFFFFF]

                return [list $hash1 $hash2 $hash3 $hash4]
        }

        proc byteInvert { hex } {
                set hexs {}
                while {[string length $hex] > 0} {
                        lappend hexs [string range $hex 0 1]
                        set hex [string range $hex 2 end]
                }
                set hex ""
                for {set i [expr [llength $hexs] -1]} {$i >= 0} {incr i -1} {
                        append hex [lindex $hexs $i]
                }
                return $hex
        }