2012-02-07 26 views
6

Próbuję odszyfrować ramkę websocket, ale nie udaje mi się, jeśli chodzi o dekodowanie rozszerzonego ładunku. Oto, co osiągnąłem do tej pory:Dekodowanie ramki sieciowej

char *in = data; 
char *buffer; 
unsigned int i; 
unsigned char mask[4]; 
unsigned int packet_length = 0; 
int rc; 

/* Expect a finished text frame. */ 
assert(in[0] == '\x81'); 
packet_length = ((unsigned char) in[1]) & 0x7f; 

mask[0] = in[2]; 
mask[1] = in[3]; 
mask[2] = in[4]; 
mask[3] = in[5]; 

if (packet_length <= 125) {   **// This decoding works** 
    /* Unmask the payload. */ 
    for (i = 0; i < packet_length; i++) 
     in[6 + i] ^= mask[i % 4]; 
    rc = asprintf(&buffer, "%.*s", packet_length, in + 6); 
} else 
    if (packet_length == 126) {  **//This decosing does NOT work** 
     /* Unmask the payload. */ 
     for (i = 0; i < packet_length; i++) 
      in[8 + i] ^= mask[i % 4]; 
     rc = asprintf(&buffer, "%.*s", packet_length, in + 8); 
} 

Co robię źle? Jak mogę zakodować rozszerzony ładunek?

Odpowiedz

5

Jeśli długość_pakietu wynosi 126, kolejne 2 bajty podają długość danych do odczytania.
Jeśli długość_pakietu wynosi 127, kolejne 8 bajtów podaje długość danych do odczytania.
Maska zawiera się w 4 bajtach (po długości).
Komunikat do dekodowania następuje po tym.

Na rysunku data framing section znajduje się przydatna ilustracja tego.

Jeśli ponownie kolejność kodu coś jak

  • Czytaj packet_length
  • Sprawdzenie packet_length 126 lub 127. przypisanie packet_length do wartości po 2/4 bajtów w razie potrzeby.
  • Odczytaj maskę (4 bajty po długości pakietu, w tym wszelkie dodatkowe 2 lub 8 bajtów odczytanych dla powyższego kroku).
  • Dekoduje wiadomość (wszystko po masce).

następnie rzeczy powinny działać.

+0

dokonał niewielkiej korekty: 127 na długości oznacza, że ​​kolejne 8 bajtów ma długość ładunku (nie 4) – kanaka

+1

@kanaka oops, dzięki za spostrzeżenie, że – simonc

4

Punkt przyczepności ma> 125 bajtów ładunku.

Format jest dość proste, powiedzmy, że wyślesz dziesiątej w JavaScript:

ws.send("a".repeat(10)) 

Następnie serwer otrzyma:

bytes[16]=818a8258a610e339c771e339c771e339 
  • Bajt 0: 0x81 jest tylko wskaźnikiem wiadomość otrzymana
  • bajt 1: 0x8a jest długością, odjąć 80 od niej, 0x0A == 10
  • bajt 2, 3, 4, 5: klucz xor 4 bajt do odszyfrowania ładowność
  • reszta: ładowność

Ale teraz powiedzmy, że wyślesz 126 do w JavaScript:

ws.send("a".repeat(126)) 

następnie serwer otrzyma:

bytes[134]=81fe007ee415f1e5857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574 

Jeśli długość ładunku wynosi> 125, bajt 1 będzie miał 0xfe wartości, zmiany formatu następnie:

  • Bajt 0: 0x81 jest to wskazówką, że odebrany komunikat
  • Bajt 1: będzie 0xFE
  • bajt 2, 3: długość bloku danych w wielu Uint16
  • bajtów 4 5, 6, 7: klucz XOR 4 bajtów do deszyfrowania ładunek
  • reszty: ładunek

przykład kodu C#:

List<byte[]> decodeWebsocketFrame(Byte[] bytes) 
{ 
    List<Byte[]> ret = new List<Byte[]>(); 
    int offset = 0; 
    while (offset + 6 < bytes.Length) 
    { 
     // format: 0==ascii/binary 1=length-0x80, byte 2,3,4,5=key, 6+len=message, repeat with offset for next... 
     int len = bytes[offset + 1] - 0x80; 

     if (len <= 125) 
     { 

      //String data = Encoding.UTF8.GetString(bytes); 
      //Debug.Log("len=" + len + "bytes[" + bytes.Length + "]=" + ByteArrayToString(bytes) + " data[" + data.Length + "]=" + data); 
      Debug.Log("len=" + len + " offset=" + offset); 
      Byte[] key = new Byte[] { bytes[offset + 2], bytes[offset + 3], bytes[offset + 4], bytes[offset + 5] }; 
      Byte[] decoded = new Byte[len]; 
      for (int i = 0; i < len; i++) 
      { 
       int realPos = offset + 6 + i; 
       decoded[i] = (Byte)(bytes[realPos]^key[i % 4]); 
      } 
      offset += 6 + len; 
      ret.Add(decoded); 
     } else 
     { 
      int a = bytes[offset + 2]; 
      int b = bytes[offset + 3]; 
      len = (a << 8) + b; 
      //Debug.Log("Length of ws: " + len); 

      Byte[] key = new Byte[] { bytes[offset + 4], bytes[offset + 5], bytes[offset + 6], bytes[offset + 7] }; 
      Byte[] decoded = new Byte[len]; 
      for (int i = 0; i < len; i++) 
      { 
       int realPos = offset + 8 + i; 
       decoded[i] = (Byte)(bytes[realPos]^key[i % 4]); 
      } 

      offset += 8 + len; 
      ret.Add(decoded); 
     } 
    } 
    return ret; 
}