RC4 encryption in C# to C/C++



  • Hi!

    Ich bin mir nicht sicher, ob dies der richtige Bereich für dieses Thema ist, denn eigentlich gehört das ja in einen "C# und C++" Bereich.

    Ich habe diesen C# Code im Internet gefunden. Es ist ein RC4 Stromverschlüsselungs Algorithmus. Ich kann leider kein C# und ein passendes C++ Beispiel habe ich nicht gefunden. Deshalb wollte ich mal ganz höflich fragen, ob es (nur wenn es kein zu großer Aufwand ist) möglich wäre, dass jemand den Code in C/C++ übersetzt?

    public void RC4(ref Byte[] bytes, Byte[] key)
    {
        Byte[] s = new Byte[256];
        Byte[] k = new Byte[256];
        Byte temp;
        int i, j;
    
        for (i = 0; i < 256; i++)
        {
            s[i] = (Byte)i;
            k[i] = key[i % key.GetLength(0)];
        }
    
        j = 0;
        for (i = 0; i < 256; i++)
        {
            j = (j + s[i] + k[i]) % 256;
            temp = s[i];
            s[i] = s[j];
            s[j] = temp;
        }
    
        i = j = 0;
        for (int x = 0; x < bytes.GetLength(0); x++)
        {
            i = (i + 1) % 256;
            j = (j + s[i]) % 256;
            temp = s[i];
            s[i] = s[j];
            s[j] = temp;
            int t = (s[i] + s[j]) % 256;
            bytes[x] ^= s[t];
        }
    }
    

    Link: http://dotnet-snippets.de/dns/c-rc4-verschluesselung-SID594.aspx

    Danke für eure Hilfe!



  • Als C++ Programmierer sollte man den Code ganz gut verstehen können, ist eigentlich wenig spezielles von .Net dabei.

    Das ref in der Signatur heißt nichts anderes als dass eine Referenz auf das bytes Array übergeben wird. Und das key.GetLength(0) bzw. bytes.GetLength(0) geben die Größe des entsprechenden Arrays zurück. Der Rest müsste an sich fast ohne Änderungen auch in C++ laufen.



  • Ok ich habe jetzt alles übersetzt. Aber irgendwo muss noch ein Fehler sein, denn sobald RC4 aufgerufen wird, stürzt die Applikation ab. Habe ich irgendetwas falsch übersetzt?

    void RC4(char* content, int content_length, char* key, int key_length) 
    { 
    	char *s,*k;
    	s = (char*)malloc(256*sizeof(char));
    	k = (char*)malloc(256*sizeof(char));
        char temp; 
        int i, j; 
    
        for (i = 0; i < 256; i++) 
        { 
            s[i] = (char)i; 
            k[i] = key[i % key_length]; 
        } 
    
        j = 0; 
        for (i = 0; i < 256; i++) 
        { 
            j = (j + s[i] + k[i]) % 256; 
            temp = s[i]; 
            s[i] = s[j]; 
            s[j] = temp; 
        } 
    
        i = j = 0; 
        for (int x = 0; x < content_length; x++) 
        { 
            i = (i + 1) % 256; 
            j = (j + s[i]) % 256; 
            temp = s[i]; 
            s[i] = s[j]; 
            s[j] = temp; 
            int t = (s[i] + s[j]) % 256; 
            content[x] ^= s[t]; 
        }
    	free((void*)s);
    	free((void*)k);
    }
    


  • Und wieso stürzt sie ab? Ich meine "stürzt ab" ist keine Fehlerbeschreibung. Geh mitm Debugger ran und guck welche Anweisung den Fehler verursacht. Erst wenn man dass weiß kann man ja erst Verbesserungsvorschläge unterbreiten.



  • Ok, der Fehler passiert beim Aufruf von free((void*)s);. Aber ich muss ehrlich sagen, dass ich keinen Plan habe wieso das passiert. Die genaue Absturznachricht sieht so aus: http://mail.aauer.com/images/fehler.JPG

    Testweise habe ich die 2 free Anweisungen auskommentiert. Leider wird mein String auch nicht richtig ver/entschlüsselt:

    http://mail.aauer.com/images/RC4.JPG

    Das Bild zeigt der Reihe nach:
    Unverschlüsselt
    Verschlüsselt
    Entschlüsselt



  • C_Cheaf schrieb:

    Ok ich habe jetzt alles übersetzt. Aber irgendwo muss noch ein Fehler sein, denn sobald RC4 aufgerufen wird, stürzt die Applikation ab. Habe ich irgendetwas falsch übersetzt?

    Folgendes ist ungetestet

    void RC4(char* content, int content_length, char* key, int key_length) 
    { 
        char *s = new char[256];
        char *k = new char[256];
    
        for(int i = 0; i < 256; ++i) 
        { 
            s[i] = (char)i; 
            k[i] = key[i % key_length]; 
        } 
    
        char temp;
        for(int i = 0, j = 0; i < 256; ++i) 
        { 
            j = (j + s[i] + k[i]) % 256; 
            temp = s[i]; 
            s[i] = s[j]; 
            s[j] = temp; 
        } 
    
        for(int x = 0, i = 0, j = 0; x < content_length; ++x) 
        { 
            i = (i + 1) % 256; 
            j = (j + s[i]) % 256; 
            temp = s[i]; 
            s[i] = s[j]; 
            s[j] = temp; 
            int t = (s[i] + s[j]) % 256; 
            content[x] ^= s[t]; 
        }
    
        delete[] s;
        delete[] k;
    }
    

    cu André



  • C_Cheaf schrieb:

    Deshalb wollte ich mal ganz höflich fragen, ob es (nur wenn es kein zu großer Aufwand ist) möglich wäre, dass jemand den Code in C/C++ übersetzt?

    nimm doch gleich einen fertigen c-code: http://www.ussrback.com/crypto/libraries/rc4/rc4.c
    kleiner tip: beim nächsten googlen einfach filetype:c mit angeben.
    🙂



  • @asc: Danke für deine Mühe. Leider passiert bei deinem Code genau das selbe wie bei meinem. Crash bei delete und wenn man delete auskommentiert, wird der String falsch ver/entschlüsselt.

    @~fricky: Danke für den hilfreichen Tipp! Das erklärt wahrscheinlich, warum ich nichts gefunden habe ^^
    Ich werde den Code gleich testen.



  • C_Cheaf schrieb:

    @~fricky: Danke für den hilfreichen Tipp! Das erklärt wahrscheinlich, warum ich nichts gefunden habe ^^

    ne, du musst irgendwas falsch gemacht haben. wenn ich suche:
    --> http://www.google.com/search?hl=en&q=rc4&btnG=Search
    finde ich als ersten eintrag:
    --> http://en.wikipedia.org/wiki/RC4
    und etwa in der mitte der seite ist gleich ein quellcode.
    🙂



  • C_Cheaf schrieb:

    [...] und wenn man delete auskommentiert, wird der String falsch ver/entschlüsselt.

    Wahrschenlich wird der Code in jedem Fall falsch ver/entschlüsselt nur das Du das im Crash nicht mehr sehen kannst.

    Der Fehler kann auch in dem aufrufenden Code liegen, z.B. wenn content und key nicht richtig initialisiert sind. Das Problem mit Speicherzugriffsfehlern ist ja, daß die Fehlermeldung nur sagt wo der Speicher beschädigt war, nicht durch was.



  • @loks: Ich habe auch das Gefühl, dass mit dem Code etwas nicht stimmt...

    Hmmm... Irgend etwas habe ich falsch verstanden fürchte ich.

    Ich habe jetzt den Code, den ~fricky gepostet hat getestet. Aber ich bekomme das immer noch nicht richtig hin:

    strcpy(test_string,"Das ist ein Test!");
    	prepare_key((unsigned char*)"12345678912345678",17,&key);
    	printf("%s\n",test_string);
    	rc4((unsigned char*)test_string,17,&key);
    	printf("%s\n",test_string);
    	rc4((unsigned char*)test_string,17,&key);
    	printf("%s\n",test_string);
    

    Am Ende sollte wieder "Das ist ein Test!" ausgegeben werden. Doch leider kommt etwas völlig anderes heraus.

    Kann ich als Schlüssel irgend einen beliebigen Schlüssel verwenden? Muss der Schlüssel genau so lang sein wie der zu verschlüsselnde Text?



  • probier's mal mit dem aus dem wikipedia-artikel:

    unsigned char S[256];
    unsigned int i, j;
    
    /* KSA */
    void rc4_init(unsigned char *key, size_t key_length) 
    {
        for (i = 0; i < 256; i++)
            S[i] = i;
    
        for (i = j = 0; i < 256; i++) 
        {
          unsigned char temp;  
          j = (j + key[i % key_length] + S[i]) & 255;
          temp = S[i];
          S[i] = S[j];
          S[j] = temp;
        }
    
        i = j = 0;
    }
    
    /* PRGA */
    unsigned char rc4_output() 
    {
      unsigned char temp;
      i = (i + 1) & 255;
      j = (j + S[i]) & 255;
    
      temp = S[i];
      S[i] = S[j];
      S[j] = temp;
    
      return S[(S[i] + S[j]) & 255];
    }
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main() 
    {
      unsigned char text[] = "Das ist ein Test!";   // original
      int length = sizeof(text);
      unsigned char key[] = "Key";                  // key
      unsigned char encrypted[256];                 // verschlüsselt
      unsigned char decrypted[256];                 // entschlüsselt
      int i;
    
      // verschlüsseln
      rc4_init (key, strlen(key));
      for (i=0; i<length; i++)
      {
        encrypted[i] = text[i] ^ rc4_output();
        printf ("%02x", encrypted[i]);
      }
      printf ("\n");
    
      // entschlüsseln
      rc4_init (key, strlen(key));
      for (i=0; i<length; i++)
      {
        decrypted[i] = encrypted[i] ^ rc4_output();
      }
      decrypted[i] = 0;
      puts (decrypted);
    }
    

    🙂



  • @~fricky: Wow der Code klappt!!! Vielen Dank!

    Ich habe den Code noch etwas modifiziert. Ich habe alles in eine Funktion gepackt, um das ganze noch einfacher zu gestalten. Vielleicht hilft es dem ein oder anderen weiter:

    void rc4_encryption(char* content, int content_length, char* key, int key_length)
    {
    	unsigned char S[256]; //S-Box
    	unsigned int i=0,j=0,n=0; //Laufvariablen
    	unsigned char temp;
    
    	//KSA (key-scheduling algorithm) - Berechnet die S-Box
    	for(i=0;i<256;i++) 
    	{S[i] = i;}
        for (i=j=0;i<256;i++) 
        {
    		j = (j + key[i % key_length] + S[i]) & 255;
    		temp = S[i];
    		S[i] = S[j];
    		S[j] = temp;
        } 
        i=j=0;
    
    	for (n=0; n<content_length; n++) //Läuft den gesamten Inhalt durch
    	{
    		//PRGA (pseudo-random generation algorithm)
    		i = (i + 1) & 255; 
    		j = (j + S[i]) & 255; 
    		temp = S[i]; 
    		S[i] = S[j]; 
    		S[j] = temp;
    
    		content[n] = content[n] ^ S[(S[i] + S[j]) & 255];  //XOR Verknüpfung mit dem Inhalt
    	}
    }
    


  • C_Cheaf schrieb:

    Ich habe den Code noch etwas modifiziert. Ich habe alles in eine Funktion gepackt, um das ganze noch einfacher zu gestalten. Vielleicht hilft es dem ein oder anderen weiter...

    sehr gut. weiter so!

    Talla schrieb:

    Das ref in der Signatur heißt nichts anderes als dass eine Referenz auf das bytes Array übergeben wird.

    ohne 'ref' zieht der compiler eine kopie vom ganzen array-inhalt? egal wie gross?
    🙂



  • Ich tippe auf ein Problem mit dem Vorzeichen. Versuch es mal mit unsigned char.



  • ~fricky schrieb:

    Talla schrieb:

    Das ref in der Signatur heißt nichts anderes als dass eine Referenz auf das bytes Array übergeben wird.

    ohne 'ref' zieht der compiler eine kopie vom ganzen array-inhalt? egal wie gross?
    🙂

    Nein! 😉

    Arrays sind immer reference types. Der ref modifier ist hier total überflüssig (sozusagen pointer auf pointer).

    🙂



  • gnarfield schrieb:

    Arrays sind immer reference types.

    ok, dann ist die welt ja in ordnung. hätte mich auch verblüfft, wenn's anders gewesen wäre.
    🙂



  • Nur meiner Detailverliebheit willen... Im konkreten Beispiel ist der ref tatsächlich überflüssig weil nur der Inhalt des Arrays verändert wird. Anders wäre es wenn das Array selbst verändert wird.

    Beispiel:

    void TestRef(ref byte[] arr)
    {
      arr = new byte[5];
    }
    
    void TestNoRef(byte[] arr)
    {
      arr = new byte[5];
    }
    
    void main()
    {
       byte[] a = new byte[6];
       TestNoRef(a);
       // Hier ist a.Length == 6. das von TestNoRef neu angelegte array wurde verworfen
    
       TestRef(ref a);
       // Hier ist a.Length == 5. Das usprüngliche array wurde verworfen.
    }
    

Anmelden zum Antworten