#!/usr/local/bin/perl -s-- #export-a-crypto-system sig, RSA in 4 lines PERL:
#
# -d (decrypt)
# or -e (encrypt)
#
# $k is exponent, $n is modulus; $k and $n in hex
#
# use of -s was contributed by Jeff Friedl, a cool perl hacker
#
# the $e-$d (grok that? awesome hack by Jeff also) checks for -d or -e:
#
# when perl -s sets $x for -x so that means $d is set for -d, $e for -e
# if they are both set 1-1 = 0 so it fails if neither are set it fails
# and if either one is set we're ok! This is to get around using | ,
# as | has higher precedence than & things group wrongly.
#
$e-$d&(($k,$n)=@ARGV)==2||die"$0 -d|-e key mod out\n";
#
# $v will be the digits of output per block, $w the digits of input per block.
# If encrypting need to reduce $w so input is guaranteed to be less than
# modulus; for decrypting reduce $v to match.
#
# blocks are based on modulus size in hex digits rounded up to nearest even
# length (~1&1+length$n) so that things will unpack properly
#
$v=$w=1+length$n&~1;
$v-=$d*2:$w-=$e*2;
#
# Make $_ be the exponent $k as a binary bit string
#
# Add a leading 0 to make length of $k be even so that it will fill
# Bytes when packed as 2 digits per byte
#
$_=unpack('B*',pack('H*',1&length$k?"0$k":$k));
#
# strip leading 0's from $_
#
s/^0+//;
#
# Turn every 0 into "d*ln%", every 1 into "d*ln%lm*ln%". These are dc codes
# which construct an exponentiation algorithm for that exponent.
# "d*ln%" is duplicate, square, load n, modulus; e.g. square the number
# on the stack, mod n. "d*ln%lm*ln%" does this then, load m, multiply,
# load n, modulus; e.g. then multiply by m mod n. This is the square and
# multiply algorithm for modular exponentiation.
#
# (Kudos to Hal for shortened this one by 4 chars)
#
s/1/0lM*ln%/g;
s/0/d*ln%/g;
#
# Encryption/decryption loop. Read $w/2 bytes of data to $m.
#
while(read(STDIN,$m,$w/2)){
#
# Turn data into equivalent hex digits in $m
#
$m=unpack("H$w",$m);
#
# Run dc: 16 bit radix for input and output; $m into dc register "M";
# $n into dc register "n"; execute $_, the exponentiation program above.
# "\U...\E" forces upper case on the hex digits as dc requires.
# Put the result in $e.
#
$a=`echo 16oOi\U$m SM$n\Esn1$_ p|dc`;
#
# Pad the result with leading 0's to $v digits, pack to raw data and output.
#
print pack("H$v",'0'x($v+1-length$a).$a);
}