pct-README.html
23d552dfab99718cc78e7670a4c862964a44fc74a03c3984cc9a678e2461ed5d
<title>Python Crypto Toolkit - curiosa</title>
<h1>Python Crypto Toolkit - curiosa</h1>
This is the README file from the curiosa directory of Andrew
Kuchling's Python Crypto Toolkit.
<xmp>
-----BEGIN PGP SIGNED MESSAGE-----
The curiosa/ directory contains various cryptography-related
hacks that may of interest, but aren't really practical for real use.
One amusement is to try to write the shortest possible
encryption program. Recently numerous people have started exporting
cryptographic systems in their .signatures (and on mailing labels,
T-shirts, ...). This is aimed at making the North American export
regulations look silly. The most common one seen in .sig files on
Usenet is RSA in 3 lines of Perl:
#!/usr/local/bin/perl -s-- -export-a-crypto-system-sig -RSA-in-3-lines-PERL
($k,$n)=@ARGV;$m=unpack(H.$w,$m."\0"x$w),$_=`echo "16do$w 2+4Oi0$d*-^1[d2%
Sa2/d0<X+d*La1=z\U$n%0]SX$k"[$m*]\EszlXx++p|dc`,s/^.|\W//g,print pack('H*'
,$_)while read(STDIN,$m,($w=2*$d-1+length($n||die"$0 [-d] k n\n")&~1)/2)
Usually we think of Python as a very clearly and spaciously
formatted language, because the program structure is indicated by
whitespace. However, it is possible to produce very compact code, as
the following programs demonstrate:
* rsa.py (4 lines): Performs RSA public key
encryption/decryption. It requires two arguments, and can accept a
single option: '-d' for decryption (the default action is encryption).
The first argument must be the required exponent, expressed in
hexadecimal, and the second is the modulus, also in hex. You still
have to choose the correct exponent, whether the '-d' option is
present or not; '-d' simply changes the number of bytes read at a
single time.
As an example: Let us assume the modulus is 6819722537, the
encryption exponent is 65537, and the decryption exponent is
2889233921. Then, after converting the numbers to hex, we can encrypt
and then decrypt by the following commands:
echo 'Top secret message.' | rsa.py 10001 1967cb529 >ciphertext
cat ciphertext | rsa.py -d ac363601 1967cb529
#!/usr/local/bin/python
from sys import*;from string import*;a=argv;[s,p,q]=filter(lambda x:x[:1]!=
'-',a);d='-d'in a;e,n=atol(p,16),atol(q,16);l=(len(q)+1)/2;o,inb=l-d,l-1+d
while s:s=stdin.read(inb);s and map(stdout.write,map(lambda i,b=pow(reduce(
lambda x,y:(x<<8L)+y,map(ord,s)),e,n):chr(b>>8*i&255),range(o-1,-1,-1)))
* arc4.py (5 lines): ARC4 is short for `Alleged RC4'. The
real RC4 algorithm is proprietary to RSA Data Security Inc. In
September of 1994, someone posted C code to both the Cypherpunks
mailing list and to the Usenet newsgroup @code{sci.crypt}, claiming
that it implemented the RC4 algorithm. This posted code is what I'm
calling Alleged RC4, or ARC4 for short.
ARC4 is a private-key cipher; the same key is used to both
encrypt and decrypt. This is the script most likely to be of
practical use. It takes one argument, which is the key expressed in
hex bytes. The key can have any non-zero length.
An example: To encrypt and then decrypt a message with the key
'foo', or, in hex, 0x66 0x6f 0x6f:
cat 'Message.' | arc4.py 666f6f >ciphertext
cat ciphertext | arc4.py 666f6f
#!/usr/local/bin/python
from sys import*;from string import *;t,x,y,j,s,a=range(256),0,0,0,1,argv[1]
k=(map(lambda b:atoi(a[b:b+2],16), range(0,len(a),2))*256)[:256]
for i in t[:]:j=(k[i]+t[i]+j)%256;t[i],t[j]=t[j],t[i]
while(s):s=stdin.read(1);l,x=len(s),(x+1)%256;y,c=(y+t[x])%256,l and ord(s);(
t[x],t[y])=t[y],t[x];stdout.write(chr(c^t[(t[x]+t[y])%256])[:l])
* otp.py (2 lines): The only truly unbreakable encryption
method is the one-time pad, or OTP. In the OTP, the plaintext is
XORed with a stream of random data (the pad) to produce the
ciphertext. The recipient then XORs the ciphertext and gets the
plaintext again. This is secure because there is no way for an
eavesdropper to determine what the intended message is; the only thing
that can be learned is the length of the message.
This sounds trivial; just get some random data, XOR it with
the message, and there you go! But the problem is with that word
"random"; how do you get truly random data? The rand() function in C
or your favorite programming language is almost certainly a
pseudo-random generator; a small amount of state is used to generate a
sequence of numbers that *looks* random to various statistical tests.
However, given a few numbers of the sequence, it may be possible to
derive the rest of the sequence in either the backward or forward
direction. This is obviously unsafe for a one-time pad; if you could
get just a few characters of the plaintext, you can compute the value
of the pad at that point and then derive the rest of the pad.
Generating truly random numbers is difficult; usually some
physical phenomenon like keystroke timings, radioactive decay, or the
noise in a transistor is used. Then there's the problem of key
distribution; how does your correspondent get the random numbers?
Governments can afford to send a courier who carries the data in a
briefcase chained to his/her wrist; can you?
In any event, let us assume you've magically obtained some
random numbers and placed them in a file called "pad". otp.py simply
XORs two files together, so to encrypt a file called "message":
otp.py pad message >ciphertext
Decryption is similar:
otp.py pad ciphertext >output
#!/usr/local/bin/python
from sys import*;t=p=1;s=stdout;[i,j]=map(lambda f: open(f, 'r'), argv[1:3])
while(t and p):t,p=i.read(1),j.read(1);t and p and s.write(chr(ord(t)^ord(p)))
Andrew Kuchling
andrewk@cst.ca
fnord@cs.mcgill.ca
-----BEGIN PGP SIGNATURE-----
Version: 2.6.2
iQCVAwUBMBGDBgRXhWZuGe+lAQE6KwP8DRr89B8IXPsGx51dm4/niX5pZYAIL9kZ
EoG6ZzpoN2WV49bIgWlBm7WYZH1Y9s76pC9h8gWrxJ4/YZIwAsNFLIN9NwNXu4OC
djnmpviI9OQhxSXcTs6JO3zL/OUyOCU43rYWYups+IzBeWydvC+PB2jpNzyNZBkS
ph6VekHeTfk=
=VPco
-----END PGP SIGNATURE-----
</xmp>