Protocols/MSNP/TCL (Challenge Implementation)

From NINA Wiki
Revision as of 18:24, 20 September 2005 by AD (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
       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
       }