#!/bin/ksh
#
# RC4 in ksh
#
# Usage: cat file | rc4.sh k1 k2 k3 k4 k5 k6 ...
#
# The k1,k2,... are the keybytes in decimal
# 
# Streamcipher, so:
#   encryption == decryption
#
# To get a PRNG and output k bytes of randomness:
#
# dd if=/dev/zero bs=1 count=$k | $0 key
#

# just in case jot does not exists
function jot {
  echo "$1 1-sb$2[p1+dlb>x]dsxxp" | dc
}

# global counter of generated keystream bytes
keybytes_i=0
keybytes_j=0

# global keylength
keylength=0

# convert number to char
function find_ord {
  if [ $1 -eq 0 ]; then
    printf "\000"
  else
    echo "$1 P"|dc
  fi
}

function key_setup {
  keylength=$1
  for i in `jot 256 0`; do
    S[$i]=$i
  done
  for i in `jot 256 0`; do
	koff=$((i % keylength))
	j1=$((j + S[$i] + arr[$koff]))
	j=$((j1 % 256))

	# swap S[i],S[j]
	tmp=${S[$i]}
	S[$i]=${S[$j]}
	S[$j]=$tmp
  done
}

# read key from command line arg
i=0
keylength=$#
while [ $i -lt $keylength ]; do
  arr[$i]=$1
  shift
  i=$((i + 1))
done

# setup
key_setup $keylength

# dc programming is fun
dc=""
for i in `jot 256 0`; do
   dc="$dc ${S[$i]} $i :S"                # Store the S array in stack S
done
dc="$dc 0si 0sj"                          # i=0; j=0
                                          # while true:
dc="$dc [li 1+ 256%si"                    # i = i + 1 % 256 
dc="$dc lj li ;S + 256%sj"                # j = j + S[i] % 256
dc="$dc li ;S st lj ;S li :S lt lj :S"    # swap S[i], S[j]
dc="$dc li ;S lj ;S + 256% ;S plxx]dsxx"  # print S[S[i]+S[j] % 256]

# start in sub-process
FIOUT=/tmp/rc4.fifo.$$
FIIN=/tmp/rc4.dummy.$$
mkfifo $FIOUT
mkfifo $FIIN
(echo $dc; cat < $FIIN; rm -f $FFIN $FIOUT) | dc > $FIOUT &
exec 4<$FIOUT

# read from stdin, encryption to stdout
hexdump -ve '"" 1/1 "%3d " ""' | tr -s " " | cut -c2- | \
sed -e 's/ $//' | tr " " "\012" | while read X;  do
   in="${X}"
   read -u4 xor
   out=$((in ^ xor))

   # revert to ascii
   find_ord "${out}"
done
