Commits

Anonymous committed 4f7deea

[project @ 366]
Added files to repos that are distributed in public tarball

  • Participants
  • Parent commits a3e4c02

Comments (0)

Files changed (4)

+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+This code is not intended to be an out of the box solution for anyone
+-- it is a snapshot of the source code of the CCIW website made
+available simply for those who wish to browse the source (or copy it
+-- it is available under a BSD license).  I don't have the time to
+support anything here (apart from the 'validator' app which happens to
+be included but is distributed separately), so you are completely on
+your own in terms of working things out!
+
+Nor is it meant to be 'best practice' Django -- Django has changed
+since the project has started, and I don't claim to be the world's
+greatest Python/Django programmer anyway.
+
+It also doesn't include various bit and pieces that would not have
+been useful to other people e.g. my database migration scripts and
+various media files.
+
+Luke
+
+INSTALLATION HINTS
+==================
+- You need to have the unpacked directory in your Python path somewhere
+- The contents of 'misc_src' also need to be on your Python path somewhere

File misc_src/decorator.py

+## The basic trick is to generate the source code for a lambda function
+## with the right signature and to evaluate it.
+## Uncomment the 'print lambda_src' statement in _decorate
+## to understand what is going on.
+
+__all__ = ["decorator", "copyfunc", "getinfo"]
+
+import inspect, new, itertools
+
+def getinfo(func):
+    """Return an info dictionary containing:
+    - name (the name of the function : str)
+    - argnames (the names of the arguments : list)
+    - defarg (the values of the default arguments : list)
+    - fullsign (the full signature : str)
+    - shortsign (the short signature : str)
+    - arg0 ... argn (shortcuts for the names of the arguments)
+
+    >>> def f(self, x=1, y=2, *args, **kw): pass
+
+    >>> info = getinfo(f)
+
+    >>> info["name"]
+    'f'
+    >>> info["argnames"]
+    ['self', 'x', 'y', 'args', 'kw']
+    
+    >>> info["defarg"]
+    (1, 2)
+
+    >>> info["shortsign"]
+    'self, x, y, *args, **kw'
+    
+    >>> info["fullsign"]
+    'self, x=defarg[0], y=defarg[1], *args, **kw'
+
+    >>> info["arg0"], info["arg1"], info["arg2"], info["arg3"], info["arg4"]
+    ('self', 'x', 'y', 'args', 'kw')
+    """
+    assert inspect.ismethod(func) or inspect.isfunction(func)
+    regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
+    argnames = list(regargs)
+    if varargs: argnames.append(varargs)
+    if varkwargs: argnames.append(varkwargs)
+    counter = itertools.count()
+    fullsign = inspect.formatargspec(
+        regargs, varargs, varkwargs, defaults,
+        formatvalue=lambda value: "=defarg[%i]" % counter.next())[1:-1]
+    shortsign = inspect.formatargspec(
+        regargs, varargs, varkwargs, defaults,
+        formatvalue=lambda value: "")[1:-1]
+    dic = dict(("arg%s" % n, name) for n, name in enumerate(argnames))
+    dic.update(name=func.__name__, argnames=argnames, shortsign=shortsign,
+        fullsign = fullsign, defarg = func.func_defaults or ())
+    return dic
+
+def _contains_reserved_names(dic): # helper
+    return "_call_" in dic or "_func_" in dic
+
+def _decorate(func, caller):
+    """Takes a function and a caller and returns the function
+    decorated with that caller. The decorated function is obtained
+    by evaluating a lambda function with the correct signature.
+    """
+    infodict = getinfo(func)
+    assert not _contains_reserved_names(infodict["argnames"]), \
+           "You cannot use _call_ or _func_ as argument names!"
+    execdict = dict(_func_=func, _call_=caller, defarg=func.func_defaults or ())
+    if func.__name__ == "<lambda>":
+        lambda_src = "lambda %(fullsign)s: _call_(_func_, %(shortsign)s)" \
+                     % infodict
+        dec_func = eval(lambda_src, execdict)
+    else:
+        func_src = """def %(name)s(%(fullsign)s):
+        return _call_(_func_, %(shortsign)s)""" % infodict
+        exec func_src in execdict 
+        dec_func = execdict[func.__name__]
+    #import sys; print >> sys.stderr, func_src # for debugging 
+    dec_func.__doc__ = func.__doc__
+    dec_func.__dict__ = func.__dict__
+    dec_func.__module__ = func.__module__
+    return dec_func
+
+class decorator(object):
+    """General purpose decorator factory: takes a caller function as
+input and returns a decorator. A caller function is any function like this::
+
+    def caller(func, *args, **kw):
+        # do something
+        return func(*args, **kw)
+    
+Here is an example of usage:
+
+    >>> @decorator
+    ... def chatty(f, *args, **kw):
+    ...     print "Calling %r" % f.__name__
+    ...     return f(*args, **kw)
+    
+    >>> @chatty
+    ... def f(): pass
+    ...
+    >>> f()
+    Calling 'f'
+    """
+    def __init__(self, caller):
+        self.caller = caller
+    def __call__(self, func):
+        return _decorate(func, self.caller)
+
+def copyfunc(func): # not used internally
+    "Creates an independent copy of a function."
+    return new.function(func.func_code, func.func_globals, func.func_name,
+                        func.func_defaults, func.func_closure)
+
+if __name__ == "__main__":
+    import doctest; doctest.testmod()

File misc_src/p3.py

+# $Id: p3.py,v 1.2 2003/11/18 19:04:03 phr Exp phr $
+
+# Simple p3 encryption "algorithm": it's just SHA used as a stream
+# cipher in output feedback mode.  
+
+# Author: Paul Rubin, Fort GNOX Cryptography, <phr-crypto at nightsong.com>.
+# Algorithmic advice from David Wagner, Richard Parker, Bryan
+# Olson, and Paul Crowley on sci.crypt is gratefully acknowledged.
+
+# Copyright 2002,2003 by Paul Rubin
+# Copying license: same as Python 2.3 license
+
+# Please include this revision number in any bug reports: $Revision: 1.2 $.
+
+from string import join
+from array import array
+import sha
+from time import time
+
+class CryptError(Exception): pass
+def _hash(str): return sha.new(str).digest()
+
+_ivlen = 16
+_maclen = 8
+_state = _hash(`time()`)
+
+try:
+    import os
+    _pid = `os.getpid()`
+except ImportError, AttributeError:
+    _pid = ''
+
+def _expand_key(key, clen):
+    blocks = (clen+19)/20
+    xkey=[]
+    seed=key
+    for i in xrange(blocks):
+        seed=sha.new(key+seed).digest()
+        xkey.append(seed)
+    j = join(xkey,'')
+    return array ('L', j)
+
+def p3_encrypt(plain,key):
+    global _state
+    H = _hash
+
+    # change _state BEFORE using it to compute nonce, in case there's
+    # a thread switch between computing the nonce and folding it into
+    # the state.  This way if two threads compute a nonce from the
+    # same data, they won't both get the same nonce.  (There's still
+    # a small danger of a duplicate nonce--see below).
+    _state = 'X'+_state
+
+    # Attempt to make nlist unique for each call, so we can get a
+    # unique nonce.  It might be good to include a process ID or
+    # something, but I don't know if that's portable between OS's.
+    # Since is based partly on both the key and plaintext, in the
+    # worst case (encrypting the same plaintext with the same key in
+    # two separate Python instances at the same time), you might get
+    # identical ciphertexts for the identical plaintexts, which would
+    # be a security failure in some applications.  Be careful.
+    nlist = [`time()`, _pid, _state, `len(plain)`,plain, key]
+    nonce = H(join(nlist,','))[:_ivlen]
+    _state = H('update2'+_state+nonce)
+    k_enc, k_auth = H('enc'+key+nonce), H('auth'+key+nonce)
+    n=len(plain)                        # cipher size not counting IV
+
+    stream = array('L', plain+'0000'[n&3:]) # pad to fill 32-bit words
+    xkey = _expand_key(k_enc, n+4)
+    for i in xrange(len(stream)):
+        stream[i] = stream[i] ^ xkey[i]
+    ct = nonce + stream.tostring()[:n]
+    auth = _hmac(ct, k_auth)
+    return ct + auth[:_maclen]
+
+def p3_decrypt(cipher,key):
+    H = _hash
+    n=len(cipher)-_ivlen-_maclen        # length of ciphertext
+    if n < 0:
+        raise CryptError, "invalid ciphertext"
+    nonce,stream,auth = \
+      cipher[:_ivlen], cipher[_ivlen:-_maclen]+'0000'[n&3:],cipher[-_maclen:]
+    k_enc, k_auth = H('enc'+key+nonce), H('auth'+key+nonce)
+    vauth = _hmac (cipher[:-_maclen], k_auth)[:_maclen]
+    if auth != vauth:
+        raise CryptError, "invalid key or ciphertext"
+
+    stream = array('L', stream)
+    xkey = _expand_key (k_enc, n+4)
+    for i in xrange (len(stream)):
+        stream[i] = stream[i] ^ xkey[i]
+    plain = stream.tostring()[:n]
+    return plain
+
+# RFC 2104 HMAC message authentication code
+# This implementation is faster than Python 2.2's hmac.py, and also works in
+# old Python versions (at least as old as 1.5.2).
+from string import translate
+def _hmac_setup():
+    global _ipad, _opad, _itrans, _otrans
+    _itrans = array('B',[0]*256)
+    _otrans = array('B',[0]*256)    
+    for i in xrange(256):
+        _itrans[i] = i ^ 0x36
+        _otrans[i] = i ^ 0x5c
+    _itrans = _itrans.tostring()
+    _otrans = _otrans.tostring()
+
+    _ipad = '\x36'*64
+    _opad = '\x5c'*64
+
+def _hmac(msg, key):
+    if len(key)>64:
+        key=sha.new(key).digest()
+    ki = (translate(key,_itrans)+_ipad)[:64] # inner
+    ko = (translate(key,_otrans)+_opad)[:64] # outer
+    return sha.new(ko+sha.new(ki+msg).digest()).digest()
+
+#
+# benchmark and unit test
+#
+
+def _time_p3(n=1000,len=20):
+    plain="a"*len
+    t=time()
+    for i in xrange(n):
+        p3_encrypt(plain,"abcdefgh")
+    dt=time()-t
+    print "plain p3:", n,len,dt,"sec =",n*len/dt,"bytes/sec"
+
+def _speed():
+    _time_p3(len=5)
+    _time_p3()
+    _time_p3(len=200)
+    _time_p3(len=2000,n=100)
+
+def _test():
+    e=p3_encrypt
+    d=p3_decrypt
+
+    plain="test plaintext"
+    key = "test key"
+    c1 = e(plain,key)
+    c2 = e(plain,key)
+    assert c1!=c2
+    assert d(c2,key)==plain
+    assert d(c1,key)==plain
+    c3 = c2[:20]+chr(1+ord(c2[20]))+c2[21:] # change one ciphertext character
+
+    try:
+        print d(c3,key)         # should throw exception
+        print "auth verification failure"
+    except CryptError:
+        pass
+
+    try:
+        print d(c2,'wrong key')         # should throw exception
+        print "test failure"
+    except CryptError:
+        pass
+
+_hmac_setup()
+#_test()
+# _speed()                                # uncomment to run speed test