Clubhouse crypto:  simple substitution, easily cracked
(but useful for learning purposes).

Permutation class S appended to facilitate group theory
approach to permutations as per this thread archived
at the Math Forum:

import string, random

def permute(pool):
    Randomly permute whatever list is passed in as pool
    oldlist = []+list(pool)
    newlist = []
    for i in range(len(oldlist)): # = range(26)

        randitem = random.choice(oldlist)
    return newlist

def mkdict(n=0):
    Pair uppercase alphabet or integers 1...n with
    randomly permuted version of same
    if n>0:  pool = range(1,n+1)
    else:    pool = string.uppercase
    tuples = zip(pool,permute(pool))
    codedict = {}
    for pair in tuples:
    return codedict

def mkkey(codedict):
    Return key as a list of cyclic tuples, e.g.
    dictkeys = codedict.keys()
    result = []
    for i in dictkeys[:]:  # using copy of dictkeys

        newtuple = ()      
        if i in dictkeys and not codedict[i]==i:
            initval,nextval = i,i
            while 1:
               newtuple += (nextval,)
               nextval = codedict[nextval]
               if nextval==initval:  # cycle complete

    return result

def gendict(keytuples):
    generate a dictionary from a list of cyclic tuples
    result = {} # return a dictionary

    for cycle in keytuples:
        rot1 = (cycle+(cycle[0],))[1:]
        for i in range(len(cycle)):
    return result

def revkey(keytuples):
    Reverse all the cyclic tuples in a list of tuples
    result = []
    for i in keytuples:
        temp = list(i)
    return result
def encrypt(filename):
    Use a permuted alphabet to encrypte a .txt file --
    saving the key and file separately.  Save file
    as filename.cpt, the codekey as filename.key
    encfile = filename[:string.rfind(filename,".")]+".cpt"
    keyfile = filename[:string.rfind(filename,".")]+".key"
    print "Writing to " + encfile
    print "Saving key as " + keyfile

    txtfileobj = open(filename,'r')    
    encfileobj = open(encfile,'w')
    keyfileobj = open(keyfile,'w')
    thedict = mkdict()
    for line in txtfileobj.readlines():
        uline = string.upper(line)
        encline = ""
        for char in uline:
            if char in string.uppercase:
               encline = encline + thedict[char]
               encline = encline + char            
    keyfileobj.write(str(mkkey(thedict)) + "\n")
def decrypt(filename):
    Use a codekey to decrypt a file (see encrypt)

    txtfile  = filename[:string.rfind(filename,".")]+".dcp"
    keyfile  = filename[:string.rfind(filename,".")]+".key"
    print "Reading from " + filename
    print "Writing to " + txtfile
    print "Using key " + keyfile
    print ""

    encfileobj = open(filename,'r')
    txtfileobj = open(txtfile,'w')    
    keyfileobj = open(keyfile,'r')

    temp    = eval(keyfileobj.readline())
    thekey  = revkey(temp)    # reverse the key tuples

    thedict = gendict(thekey) # generate reverse lookup dictionary

    for line in encfileobj.readlines():
        dcpline = ""        
        for char in line:
            if char in thedict.keys():
               dcpline = dcpline + thedict[char]
               dcpline = dcpline + char
        print dcpline[:-1]

def gcd(a,b):
   """Return greatest common divisor using Euclid's Algorithm."""
   while b:      
	a, b = b, a % b
   return a

def lcm(a,b):
   Return lowest common multiple."""
   return (a*b)/gcd(a,b)

def LCM(terms):
   "Return lcm of a list of numbers."   
   return reduce(lambda a,b: lcm(a,b), terms)

class S:
    Defines a permuation and operations therewith

    def __init__(self,n=0,dict={}):
        # specify n>0 for permutation of integers 1...n

        # specify dict={...} to initialize w/ specific dictionary

        # p1 = S() defaults to permutation of uppercase A-Z

        if len(dict.keys())>0:
            self.dict = dict
        elif n==0:
            self.dict = mkdict()
            self.dict = mkdict(n)

    def __mul__(self,other):
        newdict = {}
        for i in other.dict.keys():
            newdict[i] = self.dict[other.dict[i]]
        return S(dict=newdict)

    def __repr__(self):
        return str(mkkey(self.dict))
    def __pow__(self,n):
        r = S(dict=self.dict)
        if n==0:  # return identity 

            return r*r.inv()
        elif abs(n)>1:
            for i in range(1,abs(n)):
               r *= S(dict=self.dict)
        if n<0:
            r = r.inv()
        return r

    def __eq__(self,other):  # new syntax ver. 2.1

        rtn = 1
        for i in self.dict.keys():
            if self.dict[i] != other.dict[i]:
                rtn = 0
        return rtn

    def len(self):
        return len(self.dict)
    def inv(self):
        newdict = {}
        for i in self.dict.keys():
            newdict[self.dict[i]] = i
        return S(dict=newdict)
    def order(self):
        tuples = mkkey(self.dict)
        return LCM(map(len,tuples))
# code highlighted using py2html.py version 0.8