RC4 Verschlüsselung in MASM implementieren



  • Hallo! Ich bin Einsteiger im Gebiet von Assembler und möchte die RC4-Verschlüsselung implementieren.

    []0x1. Gibt es andere Möglichkeiten als Inline-Assembler zum Einfügen von Assembler in C/C++-Code?
    [
    ]0x2. Ist der Performancegewinn hoch?

    Ich kenne mich leider nur mit C/C++ aus, aber möchte den Teil in meinem C++ Projekt einfügen. Wie mache ich das und kennt jemand eine möglichst einfache Implementierung von RC4 in Asm? Meine IDE ist MS Visual C++ 2010, daher halte ich MASM für passend. Korrigiert mich, wenn ich falsch liege...

    Bitte um Nachsicht, da ich erst ins Thema einsteige...

    Danke.



  • Omicron schrieb:

    []0x1. Gibt es andere Möglichkeiten als Inline-Assembler zum Einfügen von Assembler in C/C++-Code?
    [
    ]0x2. Ist der Performancegewinn hoch?

    Ja, es gibt noch eine Möglichkeit. Du musst deine Funktion in Assembler implementieren, mit masm assemblieren und die resultierende Objektdatei mit deinem Programm verlinken. In deinem C/C++ Programm sagst du dann irgendwo

    extern "C" void RC4_encode(...);
    

    damit der Compiler weiss, wie die (externe) Funktion aussieht und das war's 🙂
    Um die Frage mit der Performance zu beantworten, musst du deine Assembler-Funktion mit irgend einer anderen Funktion vergleichen können, sonst kannst du nicht einfach so behaupten, die Funktion sei in Assembler geschrieben, deshalb schneller als alles andere. Das wäre falsch.
    Du musst eine zweite Funktion void RC_encode(...) rein in C/C++ implementieren, messen, wie schnell sie ist und die Ergebnisse mit deiner Assembler-Implementierung vergleichen.



  • .686
    .model flat,stdcall
    option casemap:none
    
    RC4Init proto :DWORD,:DWORD
    RC4Encrypt proto :DWORD,:DWORD
    
    .data?
    align 4
    rc4_key db 256 dup(?)
    rc4_x dd ?
    rc4_y dd ?
    
    .code
    
    align 4
    RC4Init proc uses esi edi ebx pKey:DWORD,dwKeyLen:DWORD
    	xor eax,eax
    	mov ecx,256-16
    	mov rc4_x,eax
    	mov rc4_y,eax
    	mov esi,offset rc4_key
    	mov edx,0FFFEFDFCh
    	mov eax,0FBFAF9F8h
    	mov ebx,0F7F6F5F4h
    	mov edi,0F3F2F1F0h
    	.repeat
    		mov [esi+ecx+3*4],edx
    		mov [esi+ecx+2*4],eax
    		mov [esi+ecx+1*4],ebx
    		mov [esi+ecx+0*4],edi
    		sub edx,010101010h
    		sub eax,010101010h
    		sub ebx,010101010h
    		sub edi,010101010h
    		sub ecx,16
    	.until sign?;esi < offset rc4_key
    	xor edx,edx
    	xor ecx,ecx
    	mov esi,pKey
    	xor ebx,ebx
    	mov edi,dwKeyLen
    	.repeat
    	@@:
    		mov al,rc4_key[ecx]
    		add dl,[esi+ebx]
    		add dl,al
    		mov ah,rc4_key[edx]
    		inc ebx
    		mov rc4_key[edx],al
    		mov rc4_key[ecx],ah
    		cmp ebx,edi
    		jae @F
    		inc cl
    		jnz @B
    		.break
    	@@:		
    		xor ebx,ebx
    		inc cl
    	.until zero?
    	ret
    RC4Init endp
    
    align 4
    RC4Encrypt proc uses esi edi ebx pBlock:DWORD,dwBlockLen:DWORD
    	mov edi,pBlock
    	mov edx,rc4_x
    	mov ecx,dwBlockLen
    	mov ebx,rc4_y
    	dec edi
    	xor eax,eax
    	.repeat
    		add bl,rc4_key[edx+1]
    		mov al,rc4_key[edx+1]
    		mov ch,rc4_key[ebx]
    		mov rc4_key[ebx],al
    		mov rc4_key[edx+1],ch
    		add al,ch
    		inc edi
    		mov al,rc4_key[eax]
    		inc dl
    		xor [edi],al
    		dec cl
    	.until zero?
    	mov rc4_x,edx
    	mov rc4_y,ebx
    	ret
    RC4Encrypt endp
    RC4Decrypt equ <RC4Encrypt>
    
    end
    

    Wie müsste ich das Extern bei dieser Implementierung aufrufen?



  • Bei den ganzen partiellen Registerzugriffen wird mir schlecht 😉
    Wie dem auch sei, bei RC4 ist so wie so die Geschwindigkeit des Datenträgers der limitierende Faktor.



  • Huh, dachte ich mir bei diesem Code auch gerade. Selbst die schlechteren aktuell verbreiteten C++-Compiler sollten wohl in der Lage sein, fuer eine gute Implementierung in C++ effizienteren Code zu generieren. Falls es dir wirklich um Geschwindigkeit dieses Codes geht (warum auch immer), such dir besser was anderes.

    Prinzipiell sollte sich das aber mit einer extern-Deklaration wie

    extern void RC4Encrypt (void* pBlock, uint32_t dwBlockLen);
    

    aufrufen lassen...



  • Ich bräuchte eine Implementation, wobei mich ausschließlich die RC4 Verschlüsselungsfunktion interessiert. Also ein reines Rc4-Snippet, wenn man so will, sodass ich das vlt. auch inline in meinem C++ Code verwenden kann... Leider fand ich bisher nichts gescheites... Hat jemand eine Idee?!

    Danke.



  • Darf ich fragen, warum die Funktion in Assembler sein muss... reicht die Performance der C oder C++ Implementierung nicht aus?



  • Weil ich zur Zeit mit Asm experimentiere.



  • Hier gibt es ausführliche Info: http://de.wikipedia.org/wiki/RC4#Algorithmus
    Implementiere es in Assembler und poste den Quellcode deiner Funktion hier im Forum 🙂 Wenn du es nicht machst, dann macht's auch keiner.



  • abc.w schrieb:

    Wenn du es nicht machst, dann macht's auch keiner.

    So, ich hab's gemacht und hier is mein Quellcode, habe ein wenig getestet, scheint so zu funktionieren und ich hoffe, habe keine Fehler eingebaut. Viel Spass damit.

    .global rc4init
    
    # Constants for accessing function parameters on stack:
    # int rc4init(const char key[], size_t L, char sbox[])
    .equ key, 4
    .equ L, 8
    .equ sbox, 12
    
    # Constants for accessing local stack frame
    .equ saved_ebx, -4
    .equ jcnt, -8
    .equ icnt, -12
    .equ kcnt, -16
    .equ tmp, -20
    .equ saved_esi, -28
    
    .section .text
    
    rc4init:
        xorl %eax, %eax
        cmpl %eax, key(%esp)    # Check for NULL pointer key[]
        je key_is_null
        cmpl $5, L(%esp)        # Check for valid range of L
        jl L_range_wrong
        cmpl $256, L(%esp)
        jg L_range_wrong
        cmpl %eax, sbox(%esp)   # Check for NULL pointer sbox[]
        je sbox_is_null
    
        movl %ebx, saved_ebx(%esp)  # Save registers
        movl %esi, saved_esi(%esp)
    
        movl sbox(%esp), %ebx       # Load address of sbox[0]
        movl key(%esp), %esi        # Load address of key[0]
    
        movl $63, %ecx          # Loop counter
        movl $0xFFFEFDFC, %eax  # Contains initial value for sbox[]
        movl $0x04040404, %edx  # Decrement value
    
    0:                              # Loop for initializing sbox[]
        movl %eax, (%ebx, %ecx, 4)  # Save new values in sbox[]
        subl %edx, %eax             # Compute next values
        decl %ecx
        jnz 0b
    
        movl %eax, (%ebx)       # Save rest values in sbox[]
    
        movl %ecx, jcnt(%esp)   # Reset the counters i, j and k (use the
        movl %ecx, icnt(%esp)   # loop counter, because it is zero here)
        movl %ecx, kcnt(%esp)
    
    1:
        movzbl (%esi, %ecx), %eax   # Load key[k]
    
        incl %ecx           # Compute k = ((k + 1) mod L)
        cmpl %ecx, L(%esp)
        jl 2f
        xorl %ecx, %ecx
    2:
        movl %ecx, kcnt(%esp)
    
        movl icnt(%esp), %ecx
        movzbl (%ebx, %ecx), %ecx   # Load sbox[i]
    
        addl %eax, %ecx     # Compute (sbox[i] + key[k])
    
        addl jcnt(%esp), %ecx   # Compute j = ((j + sbox[i] + key[k mod L]) mod 256)
        andl $0x000000FF, %ecx
        movl %ecx, jcnt(%esp)
    
        movl icnt(%esp), %eax
        movzbl (%ebx, %eax), %edx   # Load sbox[i] and save it in tmp
        movl %edx, tmp(%esp)
    
        movzbl (%ebx, %ecx), %edx   # Load sbox[j] and overwrite sbox[i] with it
        movb %dl, (%ebx, %eax)
        movl tmp(%esp), %edx        # Load saved sbox[i] and overwrite sbox[j] with it
        movb %dl, (%ebx, %ecx)
    
        incl %eax
        movl kcnt(%esp), %ecx       # Load k counter here, it will be used at top of the loop
        movl %eax, icnt(%esp)
        cmpl $256, %eax
        jb 1b
    
        movl saved_ebx(%esp), %ebx  # Restore registers
        movl saved_esi(%esp), %esi
    
        xorl %eax, %eax     # Return no errors
        ret
    
    key_is_null:
        movl $-1, %eax      # Return error code
        ret
    
    L_range_wrong:
        movl $-2, %eax      # Return error code
        ret
    
    sbox_is_null:
        movl $-3, %eax      # Return error code
        ret
    
    .global rc4run
    
    # Constants for accessing function parameters on stack:
    # int rc4run(const char buf_in[], size_t len, char buf_out[], char sbox[])
    .equ buf_in, 4
    .equ len, 8
    .equ buf_out, 12
    .equ sbox, 16
    
    # Constants for accessing local stack frame
    .equ saved_ebx, -4
    .equ saved_esi, -8
    .equ saved_edi, -12
    .equ jcnt, -16
    .equ icnt, -20
    .equ ncnt, -24
    .equ tmp, -28
    
    .section .text
    
    rc4run:
        xorl %eax, %eax
        cmpl %eax, buf_in(%esp)     # Check for NULL pointer buf_in[]
        je buf_in_is_null
        cmpl %eax, buf_out(%esp)    # Check for NULL pointer buf_out[]
        je buf_out_is_null
        cmpl %eax, sbox(%esp)       # Check for NULL pointer sbox[]
        je sbox_is_null
        cmpl %eax, len(%esp)        # Check for valid range of len
        je len_range_is_wrong
    
        movl %ebx, saved_ebx(%esp)  # Save registers
        movl %esi, saved_esi(%esp)
        movl %edi, saved_edi(%esp)
    
        movl sbox(%esp), %ebx       # Load address of sbox[0]
        movl buf_in(%esp), %esi     # Load address of buf_in[0]
        movl buf_out(%esp), %edi    # Load address of buf_out[0]
    
        movl %eax, icnt(%esp)       # Reset the counters i, j and n
        movl %eax, jcnt(%esp)
        movl %eax, ncnt(%esp)
    
    0:
        movl icnt(%esp), %eax   # Compute i = ((i + 1) mod 256)
        incl %eax
        andl $0x000000FF, %eax
        movl %eax, icnt(%esp)
    
        movzbl (%ebx, %eax), %edx   # Load sbox[i] and save it in tmp
        movl %edx, tmp(%esp)
    
        addl jcnt(%esp), %edx       # Compute j = ((j + sbox[i]) mod 256)
        andl $0x000000FF, %edx
        movl %edx, jcnt(%esp)
    
        movzbl (%ebx, %edx), %ecx   # Load sbox[j] and overwrite sbox[i] with it
        movb %cl, (%ebx, %eax)
        movl %ecx, %eax
    
        movl tmp(%esp), %ecx    # Load saved value sbox[i] and overwrite sbox[j] with it
        movb %cl, (%ebx, %edx)
    
        addl %ecx, %eax         # Compute index = ((sbox[i] + sbox[j]) mod 256)
        andl $0x000000FF, %eax
    
        movzbl (%ebx, %eax), %ecx   # Load sbox[index], this is a new random number
    
        movl ncnt(%esp), %eax       # Load buf_in[n]
        movzbl (%esi, %eax), %edx
    
        xorl %ecx, %edx     # Encrypt
    
        movb %dl, (%edi, %eax)      # Save new encrypted value in buf_out[n]
    
        incl %eax               # Compute n = (n + 1) and check, end of buf_in[] reached or not
        movl %eax, ncnt(%esp)
        cmpl len(%esp), %eax
        jb 0b
    
        movl saved_ebx(%esp), %ebx      # Restore registers
        movl saved_esi(%esp), %esi
        movl saved_edi(%esp), %edi
    
        xorl %eax, %eax     # Return no errors
        ret
    
    buf_in_is_null:
        movl $-1, %eax      # Return error code
        ret
    
    buf_out_is_null:
        movl $-2, %eax      # Return error code
        ret
    
    sbox_is_null:
        movl $-3, %eax      # Return error code
        ret
    
    len_range_is_wrong:
        movl $-4, %eax      # Return error code
        ret
    

    Die beiden Funktionen sehen so aus:

    int rc4init(const char key[], size_t L, char sbox[]);
    int rc4run(const char buf_in[], size_t len, char buf_out[], char sbox[]);
    

Anmelden zum Antworten