/* * cs.s - Linux i386 GNU Assembler implementation of CipherSaber-1 * By Dave Maez * September 2003 * Released into the public domain. * To Compile: * as cs.s -o cs.o && ld cs.o -o cs && strip cs * * This code can be linked to in C. The header file would look like: * struct ARC4cx { * unsigned char state[256]; * unsigned char i,j; * }; * extern void keyinit(struct ARC4cx *cx, unsigned char *key, int keylen); * extern void cryptbyte(struct ARC4cx *cx, unsigned char *cbyte); * * The keyinit() function initializes the ARC4cx struct, and the cryptbyte() * funtion encrypts cbyte. */ .bss .lcomm ARC4cx, 258 .lcomm inbuf, 1024 .lcomm inkey, 256 .data prngfn: .string "/dev/random" useage1: .ascii "Usage: " useage2: .ascii " [-d] key < infile > outfile", "\n" .text .globl keyinit .globl cryptbyte .globl _start /* extern void keyinit(ARC4cx *cx, unsigned char *key, int keylen); */ keyinit: pushl %ebx pushl %ecx pushl %edx pushl %ebp pushl %esi pushl %edi movl 28(%esp),%ebp # Set EBP to the offset of the state array. xorb %al,%al # set AL to 0. sloop: movb %al,(%ebp) # begin loop, set state[al] to al incb %al # increment AL incl %ebp # increment state position. testb %al,%al # Test if AL is zero. jnz sloop # if not, loop again movw $0,(%ebp) # Set i and j to 0. xorl %eax,%eax # set EAX to 0. xorl %ebx,%ebx # set EBX to 0. movl 36(%esp),%ecx # set ECX to the key length. cmpl $0,%ecx # Check if key length is zero. je ki_end # if it is, exit. movl 32(%esp),%edx # set EDX to the offset of key[0]. addl %edx,%ecx # set ECX to the end of the key array. kloopM: movl 32(%esp),%esi # set ESI to the offset of key[0]. kloop: cmpl %esi,%ecx # see if we're at the end of the key, je kloopM # if so, then reset the key to the beginning. movb (%esi),%dh # set DH to the keybyte. movl 28(%esp),%ebp # set EBP to the offset of state[0]. movl %ebp,%edi # set EDI to " " ". addl %eax,%ebp # set EDI to offset of state[AL]. movb (%ebp),%dl # set DL to state[AL]. addb %dl,%bl # set BL to BL + DL. addb %dh,%bl # set BL to BL + DH. addl %ebx,%edi # set EDI to state[BL] movb (%edi),%dh # set DH to state[BL]. movb %dh,(%ebp) # set state[AL] to DH. movb %dl,(%edi) # set setate[BL] to DL. incb %al # AL + 1 incl %esi # key + 1 testb %al,%al # test if AL = 0. jnz kloop # if not, loop again. ki_end: popl %edi popl %esi popl %ebp popl %edx popl %ecx popl %ebx xorl %eax,%eax ret /* extern unsigned char cryptbyte(ARC4cx *cx, unsigned char *cbyte); */ cryptbyte: pushl %ebx pushl %ecx pushl %edx pushl %ebp pushl %esi pushl %edi xorl %eax,%eax # set EAX to 0. movl 32(%esp),%ecx # set AL to the byte to be encrypted. movb (%ecx),%al movl 28(%esp),%ebp # set EBP to the offset of the state array. movl %ebp,%esi addl $256,%esi # set ESI to the offset of i. movl %esi,%edi incl %edi # set EDI to the offset of j. xorl %ebx,%ebx # set EBX to 0. xorl %ecx,%ecx # set ECX to 0. movb (%esi),%bl # set BL to i. incb %bl # increment i. movb %bl,(%esi) # update i. movb (%edi),%cl # set CL to j. movl %ebp,%esi # set ESI to the offset of the state array. addl %ebx,%esi # set ESI to the offset of state[i] movb (%esi),%dl # set DL to state[i] addb %dl,%cl # add state[i] to j. movb %cl,(%edi) # update j. movl %ebp,%edi # set EDI to the offest of the state array. addl %ecx,%edi # set EDI to the offset of state[j] movb (%edi),%dh # set DH to state[j] movb %dh,(%esi) # set state[i] to DH movb %dl,(%edi) # set state[j] to DL addb %dh,%dl # add DL and DL (state[i]+state[j]) xorb %dh,%dh # zero out DH addl %edx,%ebp # set EBP to offset of state[s[i]+s[j]] movb (%ebp),%dl # set DL to state[s[i]+s[j]] xorb %dl,%al # XOR the result... movl 32(%esp),%ecx # set AL to the byte to be encrypted. movb %al,(%ecx) popl %edi popl %esi popl %ebp popl %edx popl %ecx popl %ebx ret showuseage: movl $4,%eax movl $1,%ebx movl $useage1,%ecx movl $7,%edx int $0x80 popl %ecx movl %ecx,%ebx xorl %edx,%edx slen: movb (%ebx),%al incl %edx incl %ebx cmpb $0,%al jne slen movl $4,%eax movl $1,%ebx int $0x80 movl $4,%eax movl $useage2,%ecx movl $29,%edx int $0x80 jmp _end /* The following code is just plain stupid. Dealing with command line * arguments in Assmbler?!?! No, that's idiotic. This part should be done * in C and call the two ARC4 functions. Oh well. This was done to make * the CipherSaber-1 Linux GNU ASM implementation complete. */ _start: popl %ecx # Set ECX to ARGC. cmpl $2,%ecx # Check ARGC. jb showuseage # If ARGC < 2, showuseage. je encodekey # If ARGC = 2, encode. cmpl $3,%ecx # Check ARGC again. ja showuseage # If ARGC > 3, showuseage. je decodekey # If ARGC = 3, decode. encodekey: popl %ecx # ARGV0 popl %ecx # ARGV1 - the key. movl $inkey,%ebp # Set EBP to the keybuffer movl %ebp,%esi # Set ESI = EBP addl $256,%esi # Set ESI to end of keybuffer. xorl %edi,%edi ekloop: movb (%ecx),%al # AL = keybyte. movb %al,(%ebp) # Set keybuf to AL. incl %ecx incl %ebp incl %edi cmpl %esi,%ebp je ekdone cmpb $0,%al jne ekloop decl %ebp decl %edi ekdone: movl $5,%eax # Set EAX to system open(2) command. movl $prngfn,%ebx # Set EBX to /dev/random. xorl %ecx,%ecx # Set ECX = 0 (O_RDONLY). int $0x80 # Linux Syscall. cmpl $0,%eax # Test EAX jbe _end # Finish if it couldn't open. movl %eax,%ebx # Set EBX to the FD. movl $3,%eax # Set EAX to system read(2) command. movl $inbuf,%ecx # Set ECX to the inbuf. movl $10,%edx # Set EDX to 10, the size of the IV. int $0x80 # Linux Syscall. cmpl $10,%eax # Test EAX. jne finish # If we didn't get all 10 bytes, exit. movl $6,%eax # Set EAX to close(2) command. int $0x80 # Linux Syscall. movl $4,%eax # Set EAX to write(2) command. movl $1,%ebx # Set EBX to 1 (stdout). int $0x80 # Write the IV to stdout. movb $10,%al eivloop: cmpl %ebp,%esi # Test EBP == ESI. je eivdone # Finish if they equal. movb (%ecx),%ah movb %ah,(%ebp) incl %ebp incl %ecx incl %edi decb %al test %al,%al jnz eivloop eivdone: pushl %edi # Push it to the stack. movl $inkey,%ebp # Get the Key offset. pushl %ebp # Push it to the stack. movl $ARC4cx,%esi # Get the ARC4cx. pushl %esi # Push it to the stack. call keyinit # Init the key. popl %esi popl %esi popl %esi jmp mloop decodekey: popl %ecx # ARGV0 popl %ecx # ARGV1 popl %ecx # ARGV2 - the key. movl $inkey,%ebp # Set EBP to the keybuffer movl %ebp,%esi # Set ESI = EBP addl $256,%esi # Set ESI to end of keybuffer. xorl %edi,%edi dkloop: movb (%ecx),%al # AL = keybyte. movb %al,(%ebp) # Set keybuf to AL. incl %ecx incl %ebp incl %edi cmpl %esi,%ebp je dkdone cmpb $0,%al jne dkloop decl %ebp decl %edi dkdone: xorl %ebx,%ebx # Set EBX to 0 (stdin) movl $3,%eax # Set EAX to system read(2) command. movl $inbuf,%ecx # Set ECX to the inbuf. movl $10,%edx # Set EDX to 10, the size of the IV. int $0x80 # Linux Syscall. cmpl $10,%eax # Test EAX. jne finish # If we didn't get all 10 bytes, exit. divloop: cmpl %ebp,%esi # Test EBP == ESI. je divdone # Finish if they equal. movb (%ecx),%ah movb %ah,(%ebp) incl %ebp incl %ecx incl %edi decb %al test %al,%al jnz divloop divdone: pushl %edi # Push it to the stack. movl $inkey,%ebp # Get the Key offset. pushl %ebp # Push it to the stack. movl $ARC4cx,%esi # Get the ARC4cx. pushl %esi # Push it to the stack. call keyinit # Init the key. popl %esi popl %esi popl %esi jmp mloop mloop: # The main encryption loop. movl $inbuf,%ecx # Set ECX to the input buffer movl $1024,%edx # Set EDX to maxlen movl $3,%eax # Set EAX to system read(2) command xorl %ebx,%ebx # Set EBX to 0 (stdin) int $0x80 # Linux Syscall. cmpl $0,%eax # Check the return value. jbe finish # If it's <= 0 then we're done. movl %eax,%edx # Set EDX to the # of bytes read. movl %ecx,%ebx # Set EBX to the end of the input buffer. addl %edx,%ebx pushl %ecx # Push the location of the inbuf to the stack movl $ARC4cx,%ebp pushl %ebp # Push the ARC4cx buffer to the stack. iloop: movl %ecx,4(%esp) # Push the location of the inbuf to the stack. call cryptbyte # Call the Cryptbyte function. incl %ecx # Incrment the inbuf pointer. cmpl %ecx,%ebx # See if we're at the end of the input. jne iloop # if not, loop again. movl $4,%eax # Set EAX to system write(2) command. movl $inbuf,%ecx # Set ECX to the input buffer movl $1,%ebx # Set EBX to 1 (stdout) int $0x80 # Linux Syscall popl %esi # Pop the inbuf and ARC4cx pointers. popl %esi jmp mloop # Wash, rinse, repeat. finish: movl $ARC4cx,%edi movl $258,%ecx call clrmem movl $inbuf,%edi movl $1024,%ecx call clrmem movl $inkey,%edi movl $256,%ecx call clrmem jmp _end clrmem: movb $0,(%edi) # Clear the memory... incl %edi decl %ecx test %ecx,%ecx jnz clrmem ret _end: movl $1,%eax # Set EAX to system exit(2) command. xorl %ebx,%ebx # Return code of 0. int $0x80 # Linux Syscall. ret