PHP Code for Direct Connect HUB Lock Decode | HELP

Problems compiling? Don't understand the source code? Don't know how to code your feature? Post here.

Moderator: Moderators

Locked
[RO]VeNoM
Posts: 11
Joined: 2003-05-04 14:36

PHP Code for Direct Connect HUB Lock Decode | HELP

Post by [RO]VeNoM » 2003-05-08 03:10

- From a network sniffer, DC++ connecting to a HUB :

$Lock : [>+j>4:-X8[8^AEb^<;L[lIDBkD/8[,oJ]_cltkJ\w2@>(SL?>Hu0B?w]4Vpj2e:jt
$Key : VQE àqW66fñ@rÃ&pwqsR�/%DCN096%/’ò¶q6w4Rq Ãð?ña²T'ça·ñ7gÓT'ׄ¢–&b¡…uõ/%DCN005%/á

Code: Select all

function decode ($lock) { 
      $key = ''; 

      $lockLength = strlen ($lock); 

      $a1 = $lock{0}; 
      $a2 = $lock{$lockLength - 1}; 
      $a3 = $lock{$lockLength - 2}; 

      $char1 = $a1 ^ $a2 ^ $a3 ^ 0x05; 
      $char2 = (($char1<<4) & 0xF0) | (($char1>>4) & 0x0F); 

      $key .= $char2; 

      for ($i = 1; $i < $lockLength; $i++) { 

            $a5 = $lock{$i}; 
            $a6 = $lock{$i-1}; 

            $char3 = $a5 ^ $a6; 
            $char4 = (($char3<<4) & 0xF0) | (($char3>>4) & 0x0F); 

            $key .= $char4; 
      } 

      return escapeChars($key); 
} 


function escapeChars($key) { 
      $encoded = ''; 

      for ($i = 0; $i  < strlen($key); $i++) 
      { 

        $a = $key{$i}; 
        if ($a == '126' or // '~' 
            $a == '124' or // '|' 
            $a == '96' or  // '`' 
            $a == '36' or  // '$' 
            $a == '5' or   // '^E' 
            $a == '0')     // NUL 
        { 
          $encoded .= "/%DCN"; 

          if ($a < 100) 
            $encoded .="0"; 
          if ($a < 10) 
            $encoded .="0"; 
      $encoded .= $a; // As a string integer 
          $encoded .= "%/"; 
        } else { 
          $encoded .= $a;  // No transformation. 
        } 
      } 

      return $encoded; 
} 
This doesn't work correctly in PHP :

$char2 = (($char1<<4) & 0xF0) | (($char1>>4) & 0x0F);
$char4 = (($char3<<4) & 0xF0) | (($char3>>4) & 0x0F);

The key decode documentation :
Except for the first, each key character is computed from the corresponding lock character and the one before it. If the first character has index 0 and the lock has a length of len then:

for (i = 1; i < len; i++)
key = lock xor lock[i-1];
The first key character is calculated from the first lock character and the last two lock characters:

key[0] = lock[0] xor lock[len-1] xor lock[len-2] xor 5
Next, every character in the key must be nibble-swapped:

for (i = 0; i < len; i++)
key = ((key<<4) & 240) | ((key>>4) & 15)
Finally, the characters with the decimal ASCII values of 0, 5, 36, 96, 124, and 126 cannot be sent to the server. Each character with this value must be substituted with the string /%DCN000%/, /%DCN005%/, /%DCN036%/, /%DCN096%/, /%DCN124%/, or /%DCN126%/, respectively. The resulting string is the key to be sent to the server.

If your programming language of choice doesn't have xor or shift operations on characters, convert them to integers. If it doesn't have a bit shift at all, then x << y = x*(2**y) and x >> y = x/(2**y) for all integers x and y (** is the exponent operation or "to the power of"). Be sure to use unsigned values everywhere and do not do sign extension. Shift operations always lose the high or low bit (they are not roll operations!). The & (and) and | (or) operations are all logical, not boolean (eg. 6 & 13 = 4, not 1).


Can somebody please help me ?

The PHP code was 'ported' form this (Java) :

Code: Select all

public class LockDecode
{
  /**
   * Computes the $Key response to a given $Lock command.
   *
   * @param lock is the Lock string in the middle of "$Lock (.*) Pk=".
   * @param xorKey is 0x05 for a connection from a client to a hub,
   * or (localPort+(localPort>>8))&0xFF for a connection from a hub
   * to the hublist.
   */
  static String decode(String lock, byte xorKey)
    {
      StringBuffer key = new StringBuffer();

      int lockLength = lock.length();

      // The first byte is handled separately from the first, last,
      // and second to last bytes.
      int a1 = (int)lock.charAt(0);
      int a2 = (int)lock.charAt(lockLength - 1);
      int a3 = (int)lock.charAt(lockLength - 2);

      // Xor them all and swap nibbles.
      int char1 = a1 ^ a2 ^ a3 ^ xorKey;
      int char2 = ((char1<<4)&0xF0) | ((char1>>4)&0x0F);

      key.append((char)char2);
      
      // And do the rest of the bytes.
      for (int i = 1; i < lockLength; i++)
      {
	// Each key byte is the xor of the corresponding lock byte
	// and the one before it, nibble-swapped (that's why the 
	// first is special).
	int a5 = (int)lock.charAt(i);
	int a6 = (int)lock.charAt(i-1);
	
	int char3 = a5 ^ a6;
	int char4 = ((char3<<4)&0xF0) | ((char3>>4)&0x0F);

	key.append((char)char4);
      }

      // Key has the right bytes, but it needs to have certain
      // characters escaped.
      return escapeChars(key);
    }


  static String escapeChars(StringBuffer key)
    {
      StringBuffer encoded = new StringBuffer();

      for (int i = 0; i  < key.length(); i++)
      {
	// You might think we'd have to add the '/' escape character
	// to this list.  Oh well.
	int a = (int)key.charAt(i);
	if (a == 126 || // '~'
	    a == 124 || // '|'
	    a == 96 ||  // '`'
	    a == 36 ||  // '$'
	    a == 5 ||   // '^E'
	    a == 0)     // NUL
	{
	  encoded.append("/%DCN");
	  // Ensure we have 3 digits.
	  if (a < 100)
	    encoded.append("0");
	  if (a < 10)
	    encoded.append("0");
	  encoded.append(a); // As a string integer
	  encoded.append("%/");
	} else {
	  encoded.append((char)a);  // No transformation.
	}
      }

      return encoded.toString();
    }
}

Locked