/*
* cs.s - Linux i386 GNU Assembler implementation of CipherSaber-1
* By Dave Maez <sellout@dharmadevil.com>
* 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