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
       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
       }