[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[minion-cvs] HACKING: add note on magic comments
Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.seul.org:/tmp/cvs-serv10387/lib/mixminion
Modified Files:
BuildMessage.py Common.py Crypto.py HashLog.py MMTPClient.py
MMTPServer.py Packet.py PacketHandler.py Queue.py benchmark.py
test.py
Log Message:
HACKING: add note on magic comments
Packet/PacketHandler/BuildMessage/test:
Implement Reply Block format recently added to spec.
Common:
Improve documentation on secure deleting
MMTPServer/client:
Add stubs for keyid checking. Now blocking on spec for how to
hash a public key.
tls.c:
Fix mm_TLSSock_check -> mm_TLSSock_Check.
Everywhere else:
- Fix code style according to PEP-0008 guidelines
- Improve doc style to be closer to PEP-0257 guidelines
- General cleanups and removal of dead code.
Index: BuildMessage.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/BuildMessage.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- BuildMessage.py 24 Jun 2002 20:28:19 -0000 1.6
+++ BuildMessage.py 25 Jun 2002 11:41:07 -0000 1.7
@@ -5,62 +5,56 @@
Code to construct messages and reply blocks."""
+import operator
from mixminion.Packet import *
from mixminion.Common import MixError
import mixminion.Crypto as Crypto
import mixminion.Modules as Modules
-import operator
__all__ = [ 'buildForwardMessage', 'buildReplyBlock', 'buildReplyMessage',
'buildStatelessReplyBlock' ]
def buildForwardMessage(payload, exitType, exitInfo, path1, path2):
- """buildForwardMessage(payload, exitType, exitInfo, path1, path2) ->str
-
- Constructs a forward message.
+ """Construct a forward message.
payload: The payload to deliver.
exitType: The routing type for the final node
exitType: The routing info for the final node
path1: Sequence of ServerInfo objects for the first leg of the path
path1: Sequence of ServerInfo objects for the 2nd leg of the path
- """
+ """
return _buildMessage(payload, exitType, exitInfo, path1, path2)
def buildReplyMessage(payload, path1, replyBlock):
- """buildReplyMessage(payload, path1, replyBlock) ->str
-
- Builds a message using a reply block. 'path1' is a sequence of
- ServerInfo for the nodes on the first leg of the path."""
+ """Build a message using a reply block. 'path1' is a sequence of
+ ServerInfo for the nodes on the first leg of the path.
+ """
return _buildMessage(payload, None, None,
- path1=path1,
- reply=replyBlock)
-
-def buildReplyBlock(path, exitType, exitInfo, secretPRNG=None):
- """buildReplyBlock(path, exitType, exitInfo, secretPRNG=None)
- -> (Reply block, secret list)
+ path1=path1, path2=replyBlock)
- Returns a newly-constructed reply block and a list of secrets used
+def buildReplyBlock(path, exitType, exitInfo, expiryTime=0, secretPRNG=None):
+ """Return a newly-constructed reply block and a list of secrets used
to make it.
path: A list of ServerInfo
exitType: Routing type to use for the final node
exitInfo: Routing info for the final node
+ expiryTime: The time at which this block should expirt.
secretPRNG: A PRNG to use for generating secrets. If not
provided, uses an AES counter-mode stream seeded from our
entropy source.
"""
- if secretPRNG == None:
+ if secretPRNG is None:
secretPRNG = Crypto.AESCounterPRNG()
secrets = [ secretPRNG.getBytes(SECRET_LEN) for _ in path ]
header = _buildHeader(path, secrets, exitType, exitInfo,
paddingPRNG=Crypto.AESCounterPRNG())
- return ReplyBlock(header, path[0]), secrets
+ return ReplyBlock(header, expiryTime,
+ Modules.SWAP_FWD_TYPE,
+ path[0].getRoutingInfo().pack()), secrets
# Maybe we shouldn't even allow this to be called with userKey==None.
-def buildStatelessReplyBlock(path, user, userKey, email=0):
- """buildStatelessReplyBlock(path, user, userKey, email=0) -> ReplyBlock
-
- Constructs a 'stateless' reply block that does not require the
+def buildStatelessReplyBlock(path, user, userKey, email=0, expiryTime=0):
+ """Construct a 'stateless' reply block that does not require the
reply-message recipient to remember a list of secrets.
Instead, all secrets are generated from an AES counter-mode
stream, and the seed for the stream is stored in the 'tag'
@@ -78,6 +72,7 @@
userKey: an AES key to encrypt the seed, or None.
email: If true, delivers via SMTP; else delivers via LOCAL.
"""
+ #XXXX Out of sync with the spec.
if email and userKey:
raise MixError("Requested EMail delivery without password-protection")
@@ -95,15 +90,12 @@
exitInfo = LocalInfo(user, "RTRN"+tag).pack()
prng = Crypto.AESCounterPRNG(seed)
- return buildReplyBlock(path, exitType, exitInfo, prng)[0]
+ return buildReplyBlock(path, exitType, exitInfo, expiryTime, prng)[0]
#----------------------------------------------------------------------
def _buildMessage(payload, exitType, exitInfo,
- path1, path2=None, reply=None, paddingPRNG=None, paranoia=0):
- """_buildMessage(payload, exitType, exitInfo, path1, path2=None,
- reply=None, paddingPRNG=None, paranoia=0) -> str
-
- Helper method to create a message.
+ path1, path2, paddingPRNG=None, paranoia=0):
+ """Helper method to create a message.
The following fields must be set:
payload: the intended exit payload.
@@ -113,11 +105,11 @@
on the first leg of the path.
The following fields must be set for a forward message:
- path2: a sequence of ServerInfo objects, one for each of the nodes
- on the second leg of the path.
-
- The following fields must be set for a reply message:
- reply: a ReplyBlock object
+ path2: EITHER
+ a sequence of ServerInfo objects, one for each of the nodes
+ on the second leg of the path.
+ OR
+ a replyBlock object.
The following fields are optional:
paddingPRNG: A pseudo-random number generator used to pad the headers
@@ -127,13 +119,15 @@
header secrets too. Otherwise, we read all of our header secrets
from the true entropy source.
"""
- assert path2 or reply
- assert not (path2 and reply)
+ reply = None
+ if isinstance(path2, ReplyBlock):
+ reply = path2
+ path2 = None
### SETUP CODE: let's handle all the variant cases.
# Set up the random number generators.
- if paddingPRNG == None:
+ if paddingPRNG is None:
paddingPRNG = Crypto.AESCounterPRNG()
if paranoia:
nHops = len(path1)
@@ -144,8 +138,10 @@
# Determine exit routing for path1 and path2.
if reply:
- path1exitinfo = reply.addr.getRoutingInfo().pack()
+ path1exittype = reply.routingType
+ path1exitinfo = reply.routingInfo
else:
+ path1exittype = Modules.SWAP_FWD_TYPE
path1exitinfo = path2[0].getRoutingInfo().pack()
# Pad the payload, as needed.
@@ -166,21 +162,20 @@
header2 = reply.header
# Construct header1.
- header1 = _buildHeader(path1,secrets1,Modules.SWAP_FWD_TYPE,path1exitinfo,
+ header1 = _buildHeader(path1,secrets1,path1exittype,path1exitinfo,
paddingPRNG)
return _constructMessage(secrets1, secrets2, header1, header2, payload)
def _buildHeader(path,secrets,exitType,exitInfo,paddingPRNG):
- """_buildHeader(path, secrets, exitType, exitInfo, paddingPRNG) -> str
-
- Helper method to construct a single header.
+ """Helper method to construct a single header.
path: A sequence of serverinfo objects.
secrets: A list of 16-byte strings to use as master-secrets for
each of the subeaders.
exitType: The routing for the last node in the header
exitInfo: The routing info for the last node in the header
- paddingPRNG: A pseudo-random number generator to generate padding"""
+ paddingPRNG: A pseudo-random number generator to generate padding
+ """
assert len(path) == len(secrets)
if len(path) * ENC_SUBHEADER_LEN > HEADER_LEN:
@@ -189,10 +184,10 @@
# Construct a list 'routing' of exitType, exitInfo.
routing = [ (Modules.FWD_TYPE, node.getRoutingInfo().pack()) for
node in path[1:] ]
- routing.append( (exitType, exitInfo) )
+ routing.append((exitType, exitInfo))
# sizes[i] is size, in blocks, of subheaders for i.
- sizes =[ getTotalBlocksForRoutingInfoLen(len(info)) for t, info in routing]
+ sizes =[ getTotalBlocksForRoutingInfoLen(len(ri)) for _, ri in routing]
# totalSize is number total number of blocks.
totalSize = reduce(operator.add, sizes)
@@ -207,7 +202,7 @@
# junkSeen[i]==the junk that node i will see, before it does any
# encryption. Note that junkSeen[0]=="", because node 0
# sees no junk.
- junkSeen = [ "" ]
+ junkSeen = [""]
for secret, headerKey, size in zip(secrets, headerKeys, sizes):
# Here we're calculating the junk that node i+1 will see.
#
@@ -256,10 +251,10 @@
"""Helper method: Builds a message, given both headers, all known
secrets, and the padded payload.
- If using a reply block, secrets2 should be null."""
+ If using a reply block, secrets2 should be null.
+ """
assert len(payload) == PAYLOAD_LEN
assert len(header1) == len(header2) == HEADER_LEN
-
if secrets2:
# (Copy secrets2 so we don't reverse the original)
Index: Common.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Common.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- Common.py 24 Jun 2002 20:28:19 -0000 1.4
+++ Common.py 25 Jun 2002 11:41:08 -0000 1.5
@@ -9,7 +9,10 @@
'installSignalHandlers', 'secureDelete', 'secureRename',
'ceilDiv', 'floorDiv', 'log', 'debug' ]
-import os, signal, sys
+import os
+import signal
+import sys
+from types import StringType
class MixError(Exception):
"""Base exception class for all Mixminion errors"""
@@ -38,11 +41,12 @@
# Python 3.0 is off in the distant future, but I like to plan ahead.
def floorDiv(a,b):
- "Computes floor(a / b). See comments for portability notes."
+ "Compute floor(a / b). See comments for portability notes."
return divmod(a,b)[0]
+
def ceilDiv(a,b):
- "Computes ceil(a / b). See comments for portability notes."
+ "Compute ceil(a / b). See comments for portability notes."
return divmod(a-1,b)[0]+1
#----------------------------------------------------------------------
@@ -52,12 +56,20 @@
_SHRED_CMD = "/usr/bin/shred"
def secureDelete(fnames, blocking=0):
- """ Given a list of filenames, removes the contents of all of those files,
- from the disk, 'securely'. If blocking=1, does not return until the
- remove is complete. If blocking=0, returns immediately, and returns
- the PID of the process removing the files. (Returns None if this
- process unlinked the files itself) XXXX Clarify this."""
- if type(fnames) == type(""):
+ """Given a list of filenames, removes the contents of all of those
+ files, from the disk, 'securely'. If blocking=1, does not
+ return until the remove is complete. If blocking=0, returns
+ immediately, and returns the PID of the process removing the
+ files. (Returns None if this process unlinked the files
+ itself) XXXX Clarify this.
+
+ XXXX Securely deleting files only does so much good. Metadata on
+ XXXX the file system, such as atime and dtime, can still be used
+ XXXX to reconstruct information about message timings. To be
+ XXXX really safe, we should use a loopback device and shred _that_
+ XXXX from time to time.
+ """
+ if isinstance(fnames, StringType):
fnames = [fnames]
if blocking:
mode = os.P_WAIT
@@ -77,8 +89,6 @@
# XXXX Placeholder for a real logging mechanism
def log(s):
print s
-def debug(s):
- print s
#----------------------------------------------------------------------
# Signal handling
@@ -90,17 +100,19 @@
terminateHooks = []
def onReset(fn):
- """Given a 0-argument function fn, causes fn to be invoked when
+ """Given a 0-argument function fn, cause fn to be invoked when
this process next receives a SIGHUP."""
resetHooks.append(fn)
+
def onTerminate(fn):
- """Given a 0-argument function fn, causes fn to be invoked when
+ """Given a 0-argument function fn, cause fn to be invoked when
this process next receives a SIGTERM."""
terminateHooks.append(fn)
+
def waitForChildren():
- """Waits until all subprocesses have finished. Useful for testing."""
+ """Wait until all subprocesses have finished. Useful for testing."""
while 1:
try:
# FFFF This won't work on Windows. What to do?
@@ -108,12 +120,13 @@
except:
break
+
def _sigChldHandler(signal_num, _):
'''(Signal handler for SIGCHLD)'''
# Because of the peculiarities of Python's signal handling logic, I
# believe we need to re-register ourself.
- signal.signal(signal.SIGCHLD, _sigChldHandler)
-
+ signal.signal(signal_num, _sigChldHandler)
+
while 1:
try:
# This waitpid call won't work on Windows. What to do?
@@ -126,7 +139,8 @@
#outcome, core, sig = status & 0xff00, status & 0x0080, status & 0x7f
# FFFF Log if outcome wasn't as expected.
-def _sigHandler(signal_num, frame):
+
+def _sigHandler(signal_num, _):
'''(Signal handler for SIGTERM and SIGHUP)'''
signal.signal(signal_num, _sigHandler)
if signal_num == signal.SIGTERM:
@@ -137,8 +151,9 @@
for hook in resetHooks:
hook()
+
def installSignalHandlers(child=1,hup=1,term=1):
- '''Registers signal handlers for this process. If 'child', registers
+ '''Register signal handlers for this process. If 'child', registers
a handler for SIGCHLD. If 'hup', registers a handler for SIGHUP.
If 'term', registes a handler for SIGTERM.'''
if child:
Index: Crypto.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Crypto.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- Crypto.py 24 Jun 2002 20:28:19 -0000 1.7
+++ Crypto.py 25 Jun 2002 11:41:08 -0000 1.8
@@ -8,6 +8,8 @@
the functions in mixminion.Crypto, and not call _minionlib's crypto
functionality themselves."""
+from types import StringType
+
import mixminion._minionlib as _ml
from mixminion.Common import MixError, MixFatalError, floorDiv, ceilDiv
@@ -56,13 +58,13 @@
"""Given a string s and a 16-byte key key, computes the AES counter-mode
encryption of s using k. The counter begins at idx.
"""
- if type(key) == type(""):
+ if isinstance(key, StringType):
key = _ml.aes_key(key)
return _ml.aes_ctr128_crypt(key,s,idx)
def prng(key,count,idx=0):
"""Returns the bytestream 0x00000000...., encrypted in counter mode."""
- if type(key) == type(""):
+ if isinstance(key, StringType):
key = _ml.aes_key(key)
return _ml.aes_ctr128_crypt(key,"",idx,count)
@@ -71,8 +73,8 @@
s using the LIONESS super-pseudorandom permutation.
"""
- assert len(key1)==len(key3)==DIGEST_LEN
- assert len(key2)==len(key4)==DIGEST_LEN
+ assert len(key1) == len(key3) == DIGEST_LEN
+ assert len(key2) == len(key4) == DIGEST_LEN
assert len(s) > DIGEST_LEN
left = s[:DIGEST_LEN]
@@ -152,15 +154,11 @@
return _ml.rsa_make_public_key(long(n),long(e))
def pk_encode_private_key(key):
- """pk_encode_private_key(rsa)->str
-
- Creates an ASN1 representation of a keypair for external storage."""
+ """Creates an ASN1 representation of a keypair for external storage."""
return key.encode_key(0)
def pk_decode_private_key(s):
- """pk_encode_private_key(str)->rsa
-
- Reads an ASN1 representation of a keypair from external storage."""
+ """Reads an ASN1 representation of a keypair from external storage."""
return _ml.rsa_decode_key(s,0)
#----------------------------------------------------------------------
@@ -202,8 +200,8 @@
If rng is None, uses the general purpose RNG. The parameter may
be any length. len(data) must be <= bytes-42. '''
- if rng==None:
- rng=getCommonPRNG()
+ if rng is None:
+ rng = getCommonPRNG()
bytes = bytes-1
mLen = len(data)
paddingLen = bytes-mLen-2*DIGEST_LEN-1
@@ -242,7 +240,7 @@
pass
else:
raise CryptoError("Decoding error")
- if m == None:
+ if m is None:
raise CryptoError("Decoding error")
return m
@@ -291,12 +289,12 @@
def get(self, mode, bytes=AES_KEY_LEN):
"""Creates a new key from the master secret, using the first <bytes>
bytes of SHA1(master||mode)."""
- assert 0<bytes<=DIGEST_LEN
+ assert 0 < bytes <= DIGEST_LEN
return sha1(self.master+mode)[:bytes]
def getLionessKeys(self, mode):
"""Returns a set of 4 lioness keys, as described in the Mixminion
specification."""
- z19="\x00"*19
+ z19 = "\x00"*19
key1 = sha1(self.master+mode)
key2 = _ml.strxor(sha1(self.master+mode), z19+"\x01")
key3 = _ml.strxor(sha1(self.master+mode), z19+"\x02")
@@ -322,8 +320,8 @@
def __init__(self, chunksize):
"""Initializes a RNG. Bytes will be fetched from _prng by 'chunkSize'
bytes at a time."""
- self.bytes=""
- self.chunksize=chunksize
+ self.bytes = ""
+ self.chunksize = chunksize
def getBytes(self, n):
"""Returns a string of 'n' random bytes."""
@@ -333,11 +331,11 @@
nMore = n+self.chunksize-len(self.bytes)
morebytes = self._prng(nMore)
res = self.bytes+morebytes[:n-len(self.bytes)]
- self.bytes=morebytes[n-len(self.bytes):]
+ self.bytes = morebytes[n-len(self.bytes):]
return res
else:
res = self.bytes[:n]
- self.bytes=self.bytes[n:]
+ self.bytes = self.bytes[n:]
return res
def getInt(self, max):
@@ -387,14 +385,14 @@
is specified, gets one from the true random number generator."""
RNG.__init__(self, 16*1024)
self.counter = 0
- if seed == None:
+ if seed is None:
seed = trng(AES_KEY_LEN)
self.key = aes_key(seed)
def _prng(self, n):
"""Implementation: uses the AES counter stream to generate entropy."""
c = self.counter
- self.counter+=n
+ self.counter += n
# On python2.0, we overflow and wrap around.
if (self.counter < c) or (self.counter >> 32):
raise MixFatalError("Exhausted period of PRNG.")
@@ -404,7 +402,7 @@
def getCommonPRNG():
'''Returns a general-use AESCounterPRNG, initializing it if necessary.'''
global _theSharedPRNG
- if _theSharedPRNG == None:
+ if _theSharedPRNG is None:
_theSharedPRNG = AESCounterPRNG()
return _theSharedPRNG
Index: HashLog.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/HashLog.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- HashLog.py 24 Jun 2002 20:28:19 -0000 1.4
+++ HashLog.py 25 Jun 2002 11:41:08 -0000 1.5
@@ -30,9 +30,7 @@
The base HashLog implementation assumes an 8-bit-clean database that
maps strings to strings."""
def __init__(self, filename, keyid):
- """HashLog(filename, keyid) -> hashlog
-
- Creates a new HashLog to store data in 'filename' for the key
+ """Create a new HashLog to store data in 'filename' for the key
'keyid'."""
self.log = anydbm.open(filename, 'c')
#FFFF Warn if we're using dumbdbm
@@ -43,9 +41,7 @@
self.log["KEYID"] = keyid
def seenHash(self, hash):
- """seenHash(hash) -> bool
-
- Returns true iff 'hash' has been logged before."""
+ """Return true iff 'hash' has been logged before."""
try:
_ = self.log[hash]
return 1
@@ -53,22 +49,16 @@
return 0
def logHash(self, hash):
- """logHash(hash)
-
- Inserts 'hash' into the database."""
+ """Insert 'hash' into the database."""
self.log[hash] = "1"
def sync(self):
- """sync()
-
- Flushes changes to this log to the filesystem."""
+ """Flushes changes to this log to the filesystem."""
if hasattr(self.log, "sync"):
self.log.sync()
def close(self):
- """close()
-
- Closes this log."""
+ """Closes this log."""
self.sync()
self.log.close()
Index: MMTPClient.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/MMTPClient.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- MMTPClient.py 24 Jun 2002 20:28:19 -0000 1.1
+++ MMTPClient.py 25 Jun 2002 11:41:08 -0000 1.2
@@ -36,32 +36,34 @@
self.sock.setblocking(1)
self.sock.connect((self.targetIP,self.targetPort))
- self.ssl = self.context.sock(self.sock.fileno())
+ self.tls = self.context.sock(self.sock.fileno())
#XXXX session resumption
- self.ssl.connect()
- # XXXX CHECK KEY XXXX rsa = ssl.get_peer_cert_pk()
+ self.tls.connect()
+ peer_pk = self.tls.get_peer_cert_pk()
+ # XXXX Check the key ... how exactly is this to be hashed?
+
####
# Protocol negotiation
- self.ssl.write("PROTOCOL 1.0\n")
- inp = self.ssl.read(len("PROTOCOL 1.0\n"))
+ self.tls.write("PROTOCOL 1.0\n")
+ inp = self.tls.read(len("PROTOCOL 1.0\n"))
if inp != "PROTOCOL 1.0\n":
raise MixProtocolError("Protocol negotiation failed")
def sendPacket(self, packet):
"""Send a single packet to a server."""
assert len(packet) == 1<<15
- self.ssl.write("SEND\n")
- self.ssl.write(packet)
- self.ssl.write(sha1(packet+"SEND"))
+ self.tls.write("SEND\n")
+ self.tls.write(packet)
+ self.tls.write(sha1(packet+"SEND"))
- inp = self.ssl.read(len("RECEIVED\n")+20)
+ inp = self.tls.read(len("RECEIVED\n")+20)
if inp != "RECEIVED\n"+sha1(packet+"RECEIVED"):
raise MixProtocolError("Bad ACK received")
def shutdown(self):
"""Close this connection."""
- self.ssl.shutdown()
+ self.tls.shutdown()
self.sock.close()
def sendMessages(targetIP, targetPort, targetKeyID, packetList):
@@ -71,11 +73,3 @@
for p in packetList:
con.sendPacket(p)
con.shutdown()
-
-# ----------------------------------------------------------------------
-# Old defunct testing code. Will remove.
-
-## if __name__=='__main__':
-## msg = "helloxxx"*4096
-## assert len(msg) == (1<<15)
-## sendMessages("127.0.0.1",9001,None,[msg])
Index: MMTPServer.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/MMTPServer.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- MMTPServer.py 24 Jun 2002 20:28:19 -0000 1.1
+++ MMTPServer.py 25 Jun 2002 11:41:08 -0000 1.2
@@ -12,7 +12,9 @@
XXXX As yet unsupported are: Session resumption, key renegotiation,
XXXX checking KeyID."""
-import socket, select, re
+import socket
+import select
+import re
import mixminion._minionlib as _ml
from types import StringType
from mixminion.Common import MixError, MixFatalError, log
@@ -23,6 +25,7 @@
'MMTPClientConnection' ]
def debug(s):
+ '''placeholder; all calls should go away.'''
#print s
pass
@@ -37,8 +40,6 @@
"""Create a new AsyncServer with no readers or writers."""
self.writers = {}
self.readers = {}
- ## Defunct code for poll-based implementation.
- #self.p = select.poll()
def process(self, timeout):
"""If any relevant file descriptors become available within
@@ -49,23 +50,6 @@
debug("%s readers, %s writers" % (len(self.readers),
len(self.writers)))
-### Defunct code for for poll-based implementation
-# res = self.p.poll(timeout*1000)
-# for fd, event in res:
-# if event == select.POLLIN:
-# print "Got a read on", fd
-# self.readers[fd].handleRead()
-# elif event == select.POLLOUT:
-# print "Got a write on", fd
-# self.writers[fd].handleWrite()
-# elif event == select.POLLNVAL:
-# #XXXX Should never happen
-# print "Bad FD: ",fd, "unregistered."
-# self.p.unregister(fd)
-# else:
-# # XXXX Should never happen
-# print "????", fd,event
-
readfds = self.readers.keys()
writefds = self.writers.keys()
readfds, writefds, exfds = select.select(readfds, writefds,[], timeout)
@@ -84,7 +68,6 @@
"""Register a connection as a reader. The connection's 'handleRead'
method will be called whenever data is available for reading."""
fd = reader.fileno()
- #self.p.register(fd, select.POLLIN)
self.readers[fd] = reader
if self.writers.has_key(fd):
del self.writers[fd]
@@ -94,7 +77,6 @@
method will be called whenever the buffer is free for writing.
"""
fd = writer.fileno()
- #self.p.register(fd, select.POLLOUT)
self.writers[fd] = writer
if self.readers.has_key(fd):
del self.readers[fd]
@@ -215,7 +197,8 @@
self.__state = self.__connectFn
def isShutdown(self):
- return self.__state == None
+ """Returns true iff this connection is finished shutting down"""
+ return self.__state is None
def register(self, server):
self.__server = server
@@ -258,18 +241,20 @@
self.__server.registerWriter(self)
def __acceptFn(self):
- # may throw wantread, wantwrite.
- self.__con.accept()
+ """Hook to implement server-side handshake."""
+ self.__con.accept() #may throw want*
self.__server.unregister(self)
self.finished()
def __connectFn(self):
- self.__con.connect()
+ """Hook to implement client-side handshake."""
+ self.__con.connect() #may throw want*
self.__server.unregister(self)
self.finished()
def __shutdownFn(self):
- r = self.__con.shutdown()
+ """Hook to implement shutdown."""
+ r = self.__con.shutdown() #may throw want*
if r == 1:
debug("Got a 1 on shutdown")
self.__server.unregister(self)
@@ -280,14 +265,15 @@
debug("Got a 0 on shutdown")
def __readFn(self):
+ """Hook to implement read"""
while 1:
- r = self.__con.read(1024)
+ r = self.__con.read(1024) #may throw want*
if r == 0:
debug("read returned 0.")
self.shutdown()
return
else:
- assert type(r) == StringType
+ assert isinstance(r, StringType)
debug("read got %s bytes" % len(r))
self.__inbuf.append(r)
self.__inbuflen += len(r)
@@ -295,30 +281,28 @@
break
if self.__terminator and len(self.__inbuf) > 1:
- self.__inbuf = [ "".join(self.__inbuf) ]
+ self.__inbuf = ["".join(self.__inbuf)]
if self.__maxReadLen and self.__inbuflen > self.__maxReadLen:
debug("Read got too much.")
self.shutdown(err=1)
return
- if (self.__terminator and self.__inbuf[0].find(self.__terminator)>-1):
+ if self.__terminator and self.__inbuf[0].find(self.__terminator) > -1:
debug("read found terminator")
self.__server.unregister(self)
self.finished()
- if (self.__expectReadLen and
- (self.__inbuflen >= self.__expectReadLen)):
-
+ if self.__expectReadLen and (self.__inbuflen >= self.__expectReadLen):
debug("read got enough.")
self.__server.unregister(self)
self.finished()
def __writeFn(self):
+ """Hook to implement write"""
out = self.__outbuf
while len(out):
- # may throw
- r = self.__con.write(out)
+ r = self.__con.write(out) # may throw
if r == 0:
self.shutdown() #XXXX
@@ -337,22 +321,31 @@
self.__handleAll()
def __handleAll(self):
- try:
- while self.__state is not None:
- self.__state()
- except _ml.TLSWantWrite:
- self.__server.registerWriter(self)
- except _ml.TLSWantRead:
- self.__server.registerReader(self)
- except _ml.TLSError:
- if self.__state != self.__shutdownFn:
- debug("Unexpected error: closing connection.")
- self.shutdown(1)
- else:
- debug("Error while shutting down: closing connection.")
- self.__server.unregister(self)
- else:
- self.__server.unregister(self)
+ """Underlying implementation of TLS connection: traverses as
+ many states as possible until some operation blocks on
+ reading or writing, or until the current __state becomes
+ None.
+ """
+ try:
+ # We have a while loop here so that, upon entering a new
+ # state, we immediately see if we can go anywhere with it
+ # without blocking.
+ while self.__state is not None:
+ self.__state()
+ except _ml.TLSWantWrite:
+ self.__server.registerWriter(self)
+ except _ml.TLSWantRead:
+ self.__server.registerReader(self)
+ except _ml.TLSError:
+ if self.__state != self.__shutdownFn:
+ debug("Unexpected error: closing connection.")
+ self.shutdown(1)
+ else:
+ debug("Error while shutting down: closing connection.")
+ self.__server.unregister(self)
+ else:
+ # We are in no state at all.
+ self.__server.unregister(self)
def finished(self):
"""Called whenever a connect, accept, read, or write is finished."""
@@ -364,6 +357,7 @@
def shutdown(self, err=0):
"""Begin a shutdown on this connection"""
+
self.__state = self.__shutdownFn
#self.__server.registerWriter(self)
@@ -373,6 +367,9 @@
def getInput(self):
"""Returns the current contents of the input buffer."""
return "".join(self.__inbuf)
+
+ def getPeerPK(self):
+ return self.__con.get_peer_cert_pk()
#----------------------------------------------------------------------
# XXXX Need to support future protos.
@@ -452,11 +449,12 @@
#----------------------------------------------------------------------
class MMTPClientConnection(SimpleTLSConnection):
- def __init__(self, context, ip, port, keyId, messageList,
+ def __init__(self, context, ip, port, keyID, messageList,
sentCallback=None):
debug("CLIENT CON")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)
+ self.keyID = keyID
try:
sock.connect((ip, port))
except socket.error:
@@ -471,14 +469,18 @@
self.sentCallback = sentCallback
def __setupFinished(self):
- '''Called when we're done with the client side negotations.
- Begins sending the protocol string.'''
+ """Called when we're done with the client side negotations.
+ Begins sending the protocol string.
+ """
+ peer_pk = self.getPeerPK()
+ # Check this!
self.beginWrite(PROTOCOL_STRING)
self.finished = self.__sentProtocol
def __sentProtocol(self):
- '''Called when we're done sending the protocol string. Begins
- reading the server's response.'''
+ """Called when we're done sending the protocol string. Begins
+ reading the server's response.
+ """
self.expectRead(len(PROTOCOL_STRING), len(PROTOCOL_STRING))
self.finished = self.__receivedProtocol
@@ -493,6 +495,7 @@
self.beginNextMessage()
def beginNextMessage(self):
+ """Start writing a message to the connection."""
if not self.messageList:
self.shutdown(0)
return
@@ -533,46 +536,3 @@
self.beginNextMessage()
-# ----------------------------------------------------------------------
-# Old defunct testing code. Will remove
-
-## if __name__=='__main__':
-## import sys
-## if len(sys.argv) == 1:
-## d = "/home/nickm/src/ssl_sandbox/"
-## for f in (d+"server.cert",d+"server.pk",d+"dh"):
-## assert os.path.exists(f)
-## context = _ml.TLSContext_new(d+"server.cert",d+"server.pk",d+"dh")
-
-## _server = AsyncServer()
-## def receiveMessage(pkt):
-## print "Received packet beginning with %r" % pkt[:16]
-## def conFactory(con,context=context,receiveMessage=receiveMessage):
-## tls = context.sock(con)
-## con.setblocking(0)
-## return MMTPServerConnection(con, tls, receiveMessage)
-
-## listener = ListenConnection("127.0.0.1", 9002, 5, conFactory)
-## listener.register(_server)
-## try:
-## while 1:
-## print "."
-## _server.process(10)
-## finally:
-## listener.shutdown()
-## else:
-## context = _ml.TLSContext_new()
-## _server = AsyncServer()
-## def sentMessage():
-## print "Done sending a message"
-## msg = "helloxxx"*4096
-## clientDone = 0
-## def onSend():
-## global clientDone
-## clientDone = 1
-## sender = MMTPClientConnection(context, "127.0.0.1", 9002, None,
-## [msg], onSend)
-## sender.register(_server)
-## while 1 and not clientDone:
-## print "."
-## _server.process(10)
Index: Packet.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Packet.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- Packet.py 24 Jun 2002 20:28:19 -0000 1.2
+++ Packet.py 25 Jun 2002 11:41:08 -0000 1.3
@@ -9,7 +9,8 @@
'parseMessage', 'parseHeader', 'parseSubheader',
'getTotalBlocksForRoutingInfoLen', 'ReplyBlock',
'IPV4Info', 'SMTPInfo', 'LocalInfo', 'parseIPV4Info',
- 'parseSMTPInfo', 'parseLocalInfo', 'ENC_SUBHEADER_LEN',
+ 'parseSMTPInfo', 'parseLocalInfo', 'ReplyBlock',
+ 'parseReplyBlock', 'ENC_SUBHEADER_LEN',
'HEADER_LEN', 'PAYLOAD_LEN', 'MAJOR_NO', 'MINOR_NO',
'SECRET_LEN']
@@ -49,9 +50,7 @@
pass
def parseMessage(s):
- """parseMessage(s) -> Message
-
- Given a 32K string, returns a Message object that breaks it into
+ """Given a 32K string, returns a Message object that breaks it into
two headers and a payload."""
if len(s) != MESSAGE_LEN:
raise ParseError("Bad message length")
@@ -65,21 +64,17 @@
Fields: header1, header2, payload"""
def __init__(self, header1, header2, payload):
- """Message(header1, header2, payload) -> msg
-
- Creates a new Message object from three strings."""
+ """Create a new Message object from three strings."""
self.header1 = header1
self.header2 = header2
self.payload = payload
def pack(self):
- """Returns the 32K string value of this message."""
+ """Return the 32K string value of this message."""
return "".join([self.header1,self.header2,self.payload])
def parseHeader(s):
- """parseHeader(s) -> Header
-
- Converts a 2K string into a Header object"""
+ """Convert a 2K string into a Header object"""
if len(s) != HEADER_LEN:
raise ParseError("Bad header length")
@@ -88,6 +83,7 @@
class Header:
"""Represents a 2K Mixminion header"""
def __init__(self, contents):
+ """Initialize a new header from its contents"""
self.contents = contents
def __getitem__(self, i):
@@ -99,16 +95,17 @@
(i+1)*ENC_SUBHEADER_LEN]
def __getslice__(self, i, j):
- """header[i] -> str
+ """header[i:j] -> str
Returns a slice of the i-j'th subheaders of this header."""
if j > 16: j = 16
- if i < 0: i=16+i
- if j < 0: j=16+j
+ if i < 0: i += 16
+ if j < 0: j += 16
return self.contents[i*ENC_SUBHEADER_LEN:
j*ENC_SUBHEADER_LEN]
def __len__(self):
+ """Return the number of subheaders in this header (always 16)"""
return 16
# A subheader begins with: a major byte, a minor byte, SECRET_LEN secret
@@ -117,9 +114,7 @@
SH_UNPACK_PATTERN = "!BB%ds%dsHH" % (SECRET_LEN, DIGEST_LEN)
def parseSubheader(s):
- """parseSubheader(s) -> Subheader
-
- Converts a decoded Mixminion subheader into a Subheader object"""
+ """Convert a decoded Mixminion subheader into a Subheader object"""
if len(s) < MIN_SUBHEADER_LEN:
raise ParseError("Header too short")
if len(s) > MAX_SUBHEADER_LEN:
@@ -136,7 +131,7 @@
return Subheader(major,minor,secret,digest,rt,ri,rlen)
def getTotalBlocksForRoutingInfoLen(bytes):
- """Returns the number of subheraders that will be needed for a hop
+ """Return the number of subheaders that will be needed for a hop
whose routinginfo is (bytes) long."""
if bytes <= MAX_ROUTING_INFO_LEN:
return 1
@@ -157,11 +152,12 @@
def __init__(self, major, minor, secret, digest, routingtype,
routinginfo, routinglen=None):
+ """Initialize a new subheader"""
self.major = major
self.minor = minor
self.secret = secret
self.digest = digest
- if routinglen == None:
+ if routinglen is None:
self.routinglen = len(routinginfo)
else:
self.routinglen = routinglen
@@ -175,25 +171,25 @@
"routinglen=%(routinglen)r)")% self.__dict__
def setRoutingInfo(self, info):
- """Changes the routinginfo, and the routinglength to correspond."""
+ """Change the routinginfo, and the routinglength to correspond."""
self.routinginfo = info
self.routinglen = len(info)
def isExtended(self):
- """Returns true iff the routinginfo is too long to fit in a single
+ """Return true iff the routinginfo is too long to fit in a single
subheader."""
return self.routinglen > MAX_ROUTING_INFO_LEN
def getNExtraBlocks(self):
- """Returns the number of extra blocks that will be needed to fit
+ """Return the number of extra blocks that will be needed to fit
the routinginfo."""
return getTotalBlocksForRoutingInfoLen(self.routinglen)-1
def appendExtraBlocks(self, data):
- """appendExtraBlocks(str)
-
- Given additional (decoded) blocks of routing info, adds them
- to the routinginfo of this object."""
+ """Given a string containing additional (decoded) blocks of
+ routing info, add them to the routinginfo of this
+ object.
+ """
nBlocks = self.getNExtraBlocks()
assert len(data) == nBlocks * ENC_SUBHEADER_LEN
raw = [self.routinginfo]
@@ -203,7 +199,7 @@
self.routinginfo = ("".join(raw))[:self.routinglen]
def pack(self):
- """Returns the (unencrypted) string representation of this Subhead.
+ """Return the (unencrypted) string representation of this Subhead.
Does not include extra blocks"""
assert self.routinglen == len(self.routinginfo)
@@ -216,9 +212,7 @@
self.routinglen, self.routingtype)+info
def getExtraBlocks(self):
- """getExtraBlocks() -> [ str, ...]
-
- Returns a list of (unencrypted) blocks of extra routing info."""
+ """Return a list of (unencrypted) blocks of extra routing info."""
if not self.isExtended():
return []
else:
@@ -234,17 +228,51 @@
return result
-#FFFF We don't have an interchange format for these yet, so there's no way
-#FFFF to parse or unparse 'em.
+RB_UNPACK_PATTERN = "!4sBBL%ssHH" % (HEADER_LEN)
+MIN_RB_LEN = 14+HEADER_LEN
+
+def parseReplyBlock(s):
+ """Return a new ReplyBlock object for an encoded reply block"""
+ if len(s) < MIN_RB_LEN:
+ raise ParseError("Reply block too short")
+
+ try:
+ magic, major, minor, timestamp, header, rlen, rt = \
+ struct.unpack(RB_UNPACK_PATTERN, s[:MIN_RB_LEN])
+ except struct.error:
+ raise ParseError("Misformatted reply block")
+
+ if magic != 'SURB':
+ raise ParseError("Misformatted reply block")
+
+ if major != 0x01 or minor != 0x00:
+ raise ParseError("Unrecognized version on reply block")
+
+ ri = s[MIN_RB_LEN:]
+ if len(ri) != rlen:
+ raise ParseError("Misformatted reply block")
+
+ return ReplyBlock(header, timestamp, rt, ri)
+
class ReplyBlock:
"""A mixminion reply block, including the address of the first hop
- on the path, and a ServerInfo for the server."""
- def __init__(self, header, addr):
+ on the path, and the RoutingType and RoutingInfo for the server."""
+ def __init__(self, header, useBy, rt, ri):
+ """Construct a new Reply Block."""
self.header = header
- self.addr = addr
+ self.timestamp = useBy
+ self.routingType = rt
+ self.routingInfo = ri
+
+ def pack(self):
+ """Returns the external representation of this reply block"""
+ return struct.pack(RB_UNPACK_PATTERN,
+ "SURB", 0x01, 0x00, self.timestamp,
+ self.header, len(self.routingInfo),
+ self.routingType)+self.routingInfo
def _packIP(s):
- """Helper method: converts a dotted-decimal IPv4 address into a
+ """Helper method: convert a dotted-decimal IPv4 address into a
four-byte encoding. Raises ParseError if the input is not a
dotted quad of 0..255"""
addr = s.split(".")
@@ -259,7 +287,7 @@
return struct.pack("!BBBB", *addr)
def _unpackIP(s):
- """Helper method: convers a four-byte IPv4 address into a dotted quad."""
+ """Helper method: convert a four-byte IPv4 address into a dotted quad."""
if len(s) != 4: raise ParseError("Malformed IP")
return ".".join(map(str, struct.unpack("!BBBB", s)))
@@ -268,9 +296,7 @@
IPV4_PAT = "!4sH%ds" % DIGEST_LEN
def parseIPV4Info(s):
- """parseIP4VInfo(s) -> IPV4Info
-
- Converts routing info for an IPV4 address into an IPV4Info object,
+ """Converts routing info for an IPV4 address into an IPV4Info object,
suitable for use by FWD or SWAP_FWD modules."""
if len(s) != 4+2+DIGEST_LEN:
raise ParseError("IPV4 information with wrong length")
@@ -287,17 +313,19 @@
Fields: ip (a dotted quad), port (an int from 0..65535), and keyinfo
(a digest)."""
def __init__(self, ip, port, keyinfo):
- assert 0<=port<=65535
+ """Construct a new IPV4Info"""
+ assert 0 <= port <= 65535
self.ip = ip
self.port = port
self.keyinfo = keyinfo
def pack(self):
+ """Return the routing info for this address"""
assert len(self.keyinfo) == DIGEST_LEN
return struct.pack(IPV4_PAT, _packIP(self.ip), self.port, self.keyinfo)
def parseSMTPInfo(s):
- """Converts the encoding of an SMTP routinginfo into an SMTPInfo object."""
+ """Convert the encoding of an SMTP routinginfo into an SMTPInfo object."""
lst = s.split("\000",1)
if len(lst) == 1:
return SMTPInfo(s,None)
@@ -313,13 +341,14 @@
self.tag = tag
def pack(self):
+ """Returns the wire representation of this SMTPInfo"""
if self.tag != None:
return self.email+"\000"+self.tag
else:
return self.email
def parseLocalInfo(s):
- """Converts the encoding of an LOCAL routinginfo into an LocalInfo
+ """Convert the encoding of an LOCAL routinginfo into an LocalInfo
object."""
lst = s.split("\000",1)
if len(lst) == 1:
@@ -337,6 +366,7 @@
self.tag = tag
def pack(self):
+ """Return the external representation of this routing info."""
if self.tag:
return self.user+"\000"+self.tag
else:
Index: PacketHandler.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/PacketHandler.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- PacketHandler.py 24 Jun 2002 20:28:19 -0000 1.2
+++ PacketHandler.py 25 Jun 2002 11:41:08 -0000 1.3
@@ -22,9 +22,7 @@
an exist handler."""
def __init__(self, privatekey, hashlog):
- """PacketHandler(privatekey, hashlog)
-
- Constructs a new packet handler, given a private key object for
+ """Constructs a new packet handler, given a private key object for
header encryption, and a hashlog object to prevent replays.
A sequence of private keys may be provided, if you'd like the
@@ -32,16 +30,17 @@
though: this slows down the packet handler a lot.
"""
# ???? Any way to support multiple keys in protocol?
- if type(privatekey) in (type(()), type([])):
+ try:
+ # Check whether we have a key or a tuple of keys.
+ _ = privatekey[0]
self.privatekey = privatekey
- else:
+ except:
self.privatekey = (privatekey, )
+
self.hashlog = hashlog
def processMessage(self, msg):
- """ph.processMessage(msg)
-
- Given a 32K mixminion message, processes it completely.
+ """Given a 32K mixminion message, processes it completely.
Returns one of:
None [if the mesesage should be dropped.
@@ -64,17 +63,17 @@
msg = Packet.parseMessage(msg)
header1 = Packet.parseHeader(msg.header1)
- # Try to decrypt the first subheader.
- enc_subh = header1[0]
+ # Try to decrypt the first subheader. Try each private key in
+ # order. Only fail if all private keys fail.
subh = None
- err = None
+ e = None
for pk in self.privatekey:
try:
- subh = Crypto.pk_decrypt(enc_subh, pk)
- except Crypto.CryptoError, e:
- err = e
+ subh = Crypto.pk_decrypt(header1[0], pk)
+ except Crypto.CryptoError, err:
+ e = err
if not subh:
- raise err
+ raise e
subh = Packet.parseSubheader(subh)
# Check the version: can we read it?
@@ -82,8 +81,7 @@
raise ContentError("Invalid protocol version")
# Check the digest: is it correct?
- digest = Crypto.sha1(header1[1:])
- if digest != subh.digest:
+ if subh.digest != Crypto.sha1(header1[1:]):
raise ContentError("Invalid digest")
# Get ready to generate message keys.
Index: Queue.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Queue.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- Queue.py 24 Jun 2002 20:28:19 -0000 1.1
+++ Queue.py 25 Jun 2002 11:41:08 -0000 1.2
@@ -6,7 +6,10 @@
Facility for a fairly secure, directory-based, unordered queue.
"""
-import os, base64, time, stat
+import os
+import base64
+import time
+import stat
from mixminion.Common import MixError, MixFatalError, secureDelete
from mixminion.Crypto import AESCounterPRNG
@@ -97,7 +100,7 @@
messages = [fn for fn in os.listdir(self.dir) if fn.startswith("msg_")]
n = len(messages)
- if count == None:
+ if count is None:
count = n
else:
count = min(count, n)
Index: benchmark.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/benchmark.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- benchmark.py 24 Jun 2002 20:28:19 -0000 1.6
+++ benchmark.py 25 Jun 2002 11:41:08 -0000 1.7
@@ -35,7 +35,7 @@
nones = [None]*iters
if ov:
overhead = loop_overhead.get(iters, None)
- if overhead == None:
+ if overhead is None:
overhead = loop_overhead[iters] = timeit_((
lambda:(lambda:None)()), iters, 0)
else:
@@ -94,12 +94,12 @@
def cryptoTiming():
print "#==================== CRYPTO ======================="
- print "SHA1 (short)", timeit((lambda : sha1(short)), 100000)
- print "SHA1 (64b)", timeit((lambda : sha1(s64b)), 100000)
- print "SHA1 (2K)", timeit((lambda : sha1(s2K)), 10000)
- print "SHA1 (8K)", timeit((lambda : sha1(s8K)), 10000)
- print "SHA1 (28K)", timeit((lambda : sha1(s28K)), 1000)
- print "SHA1 (32K)", timeit((lambda : sha1(s32K)), 1000)
+ print "SHA1 (short)", timeit((lambda: sha1(short)), 100000)
+ print "SHA1 (64b)", timeit((lambda: sha1(s64b)), 100000)
+ print "SHA1 (2K)", timeit((lambda: sha1(s2K)), 10000)
+ print "SHA1 (8K)", timeit((lambda: sha1(s8K)), 10000)
+ print "SHA1 (28K)", timeit((lambda: sha1(s28K)), 1000)
+ print "SHA1 (32K)", timeit((lambda: sha1(s32K)), 1000)
shakey = "8charstr"*2
print "Keyed SHA1 for lioness (28K, unoptimized)", timeit(
@@ -147,11 +147,11 @@
c = AESCounterPRNG()
print "aesprng.getInt (10)", \
- timeit((lambda c=c : c.getInt(10)), 10000)
+ timeit((lambda c=c: c.getInt(10)), 10000)
print "aesprng.getInt (1000)", \
- timeit((lambda c=c : c.getInt(1000)), 10000)
+ timeit((lambda c=c: c.getInt(1000)), 10000)
print "aesprng.getInt (513)", \
- timeit((lambda c=c : c.getInt(513)), 10000)
+ timeit((lambda c=c: c.getInt(513)), 10000)
lkey = Keyset("keymaterial foo bar baz").getLionessKeys("T")
print "lioness E (1K)", timeit((
@@ -216,7 +216,9 @@
print "Timing overhead: %s...%s" % (timestr(min(o)),timestr(max(o)))
#----------------------------------------------------------------------
-import tempfile, os, stat
+import tempfile
+import os
+import stat
def hashlogTiming():
print "#==================== HASH LOGS ======================="
@@ -242,20 +244,20 @@
for hash in hashes:
h.logHash(hash)
t = time()-t
- print "Add entry (up to %s entries)" %load, timestr( t/float(load) )
+ print "Add entry (up to %s entries)" %load, timestr(t/float(load))
t = time()
for hash in hashes[0:1000]:
h.seenHash(hash)
t = time()-t
- print "Check entry [hit] (%s entries)" %load, timestr( t/1000.0 )
+ print "Check entry [hit] (%s entries)" %load, timestr(t/1000.0)
hashes =[ prng.getBytes(20) for _ in xrange(1000) ]
t = time()
for hash in hashes:
h.seenHash(hash)
t = time()-t
- print "Check entry [miss] (%s entries)" %load, timestr( t/1000.0 )
+ print "Check entry [miss] (%s entries)" %load, timestr(t/1000.0)
hashes =[ prng.getBytes(20) for _ in xrange(1000) ]
t = time()
@@ -263,7 +265,7 @@
h.seenHash(hash)
h.logHash(hash)
t = time()-t
- print "Check entry [miss+add] (%s entries)" %load, timestr( t/1000.0 )
+ print "Check entry [miss+add] (%s entries)" %load, timestr(t/1000.0)
h.close()
size = 0
@@ -283,15 +285,16 @@
print "#================= BUILD MESSAGE ====================="
pk = pk_generate()
payload = ("Junky qoph flags vext crwd zimb."*1024)[:22*1024]
- serverinfo = [ ServerInfo("127.0.0.1", 48099, pk_get_modulus(pk),
- "x"*20) ] * 16
+ serverinfo = [ServerInfo("127.0.0.1", 48099, pk_get_modulus(pk),"x"*20)
+ ] * 16
+
def bh(np,it, serverinfo=serverinfo):
ctr = AESCounterPRNG()
tm = timeit_(
lambda np=np,it=it,serverinfo=serverinfo,ctr=ctr:
_buildHeader(serverinfo[:np], ["Z"*16]*np,
- 99, "Hello", ctr), it )
+ 99, "Hello", ctr), it)
print "Build header (%s)" %(np), timestr(tm)
@@ -335,13 +338,13 @@
[server, server], [server, server])
print "Server process (no swap, no log)", timeit(
- lambda sp=sp, m_noswap=m_noswap : sp.processMessage(m_noswap), 100)
+ lambda sp=sp, m_noswap=m_noswap: sp.processMessage(m_noswap), 100)
m_swap = buildForwardMessage("Hello world", SMTP_TYPE, "f@invalid",
[server], [server, server])
print "Server process (swap, no log)", timeit(
- lambda sp=sp, m_swap=m_swap : sp.processMessage(m_swap), 100)
+ lambda sp=sp, m_swap=m_swap: sp.processMessage(m_swap), 100)
#----------------------------------------------------------------------
def timeEfficiency():
@@ -414,7 +417,7 @@
[server, server], [server, server])
sp_ns = timeit_(
- lambda sp=sp, m_noswap=m_noswap : sp.processMessage(m_noswap), 100)
+ lambda sp=sp, m_noswap=m_noswap: sp.processMessage(m_noswap), 100)
expected = rsa_128b+sha1_hdr+sha1_key*5+aes_2k+lioness_28k+prng_128b
expected += lioness_2k
@@ -435,7 +438,8 @@
#----------------------------------------------------------------------
-from mixminion.Common import secureDelete, installSignalHandlers, waitForChildren
+from mixminion.Common import secureDelete, installSignalHandlers, \
+ waitForChildren
def fileOpsTiming():
print "#================= File ops ====================="
Index: test.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/test.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- test.py 24 Jun 2002 20:28:19 -0000 1.7
+++ test.py 25 Jun 2002 11:41:08 -0000 1.8
@@ -274,7 +274,7 @@
eq(msg, pk_decrypt(pk_encrypt(msg, k1024),k1024))
eq(msg, pk_decrypt(pk_encrypt(msg, pub1024),k1024))
- # Make sure that CH_OAEP(RSA( )) inverts pk_encrypt.
+ # Make sure that CH_OAEP(RSA()) inverts pk_encrypt.
eq(msg, _ml.check_oaep_padding(
k512.crypt(pk_encrypt(msg,k512), 0, 0),
mixminion.Crypto.OAEP_PARAMETER, 64))
@@ -313,9 +313,9 @@
left = plain[:20]
right = plain[20:]
- right = ctr_crypt( right, sha1(key1+left+key1)[:16] )
+ right = ctr_crypt(right, sha1(key1+left+key1)[:16])
left = strxor(left, sha1(key2+right+key2))
- right = ctr_crypt( right, sha1(key3+left+key3)[:16] )
+ right = ctr_crypt(right, sha1(key3+left+key3)[:16])
left = strxor(left, sha1(key4+right+key4))
key = (key1,key2,key3,key4)
@@ -331,9 +331,9 @@
eq(s("aBar")[:16], k.get("Bar"))
z19 = "\x00"*19
- eq( (s("aBaz"), x(s("aBaz"), z19+"\x01"),
- x(s("aBaz"),z19+"\x02"), x(s("aBaz"), z19+"\x03") ),
- k.getLionessKeys("Baz"))
+ eq((s("aBaz"), x(s("aBaz"), z19+"\x01"),
+ x(s("aBaz"),z19+"\x02"), x(s("aBaz"), z19+"\x03")),
+ k.getLionessKeys("Baz"))
def test_aesprng(self):
# Make sure that AESCounterPRNG is really repeatable.
@@ -462,6 +462,7 @@
self.failUnlessRaises(ParseError, parseIPV4Info, ri[:-1])
self.failUnlessRaises(ParseError, parseIPV4Info, ri+"x")
+
def test_smtpinfolocalinfo(self):
for _class, _parse, _key in ((SMTPInfo, parseSMTPInfo, 'email'),
@@ -486,6 +487,15 @@
self.assertEquals(inf.tag, "xyzzy\x00plover")
self.assertEquals(inf.pack(), ri)
+ def test_replyblock(self):
+ r = ("SURB\x01\x00"+"\x00\x00\x00\x00"+("Z"*2048)+"\x00\x0A"+"\x00\x01"
+ +("F"*10))
+ rb = parseReplyBlock(r)
+ self.assertEquals(rb.timestamp, 0)
+ self.assertEquals(rb.header, "Z"*2048)
+ self.assertEquals(rb.routingType, 1)
+ self.assertEquals(rb.routingInfo, "F"*10)
+ self.assertEquals(r, rb.pack())
#----------------------------------------------------------------------
from mixminion.HashLog import HashLog
@@ -635,8 +645,8 @@
"""
retsecrets = []
retinfo = []
- if secrets == None:
- secrets = [ None ] * len(pks)
+ if secrets is None:
+ secrets = [None] * len(pks)
self.assertEquals(len(head), mixminion.Packet.HEADER_LEN)
for pk, secret, rt, ri in zip(pks, secrets,rtypes,rinfo):
subh = mixminion.Packet.parseSubheader(pk_decrypt(head[:128], pk))
@@ -683,9 +693,9 @@
def test_extended_routinginfo(self):
bhead = BuildMessage._buildHeader
- secrets = ["9"*16 ]
+ secrets = ["9"*16]
longStr = "Foo"*50
- head = bhead([self.server1 ], secrets, 99, longStr, AESCounterPRNG())
+ head = bhead([self.server1], secrets, 99, longStr, AESCounterPRNG())
pks = (self.pk1,)
rtypes = (99,)
rinfo = (longStr,)
@@ -826,20 +836,20 @@
(FWD_TYPE, 99),
(self.server2.getRoutingInfo().pack(),
"Goodbye") ),
- "Hello" )
+ "Hello")
m = bfm(payload, 99, "Goodbye",
- [self.server1, ],
- [self.server3, ])
+ [self.server1,],
+ [self.server3,])
self.do_message_test(m,
( (self.pk1,), None,
- (SWAP_FWD_TYPE, ),
- ( self.server3.getRoutingInfo().pack(), ) ),
- ( (self.pk3, ), None,
+ (SWAP_FWD_TYPE,),
+ (self.server3.getRoutingInfo().pack(),) ),
+ ( (self.pk3,), None,
(99,),
("Goodbye",) ),
- "Hello" )
+ "Hello")
def test_buildreply(self):
brb = BuildMessage.buildReplyBlock
@@ -848,8 +858,8 @@
## Stateful reply blocks.
reply, secrets = \
- brb([ self.server3, self.server1, self.server2,
- self.server1, self.server3 ],
+ brb([self.server3, self.server1, self.server2,
+ self.server1, self.server3],
SMTP_TYPE,
SMTPInfo("no-such-user@invalid", None).pack())
pks_1 = (self.pk3, self.pk1, self.pk2, self.pk1, self.pk3)
@@ -858,7 +868,7 @@
self.server1.getRoutingInfo().pack(),
self.server3.getRoutingInfo().pack())
- self.assert_(reply.addr == self.server3)
+ self.assert_(reply.routingInfo == self.server3.getRoutingInfo().pack())
m = brm("Information?",
[self.server3, self.server1],
@@ -877,8 +887,8 @@
"Information?")
## Stateless replies
- reply = bsrb([ self.server3, self.server1, self.server2,
- self.server1, self.server3 ],
+ reply = bsrb([self.server3, self.server1, self.server2,
+ self.server1, self.server3],
"fred", "Galaxy Far Away.", 0)
sec,(loc,) = self.do_header_test(reply.header, pks_1, None,
@@ -888,11 +898,11 @@
self.assert_(loc.startswith(s))
seed = ctr_crypt(loc[len(s):], "Galaxy Far Away.")
prng = AESCounterPRNG(seed)
- self.assert_(sec == [ prng.getBytes(16) for _ in range(5)])
+ self.assert_(sec == [ prng.getBytes(16) for _ in range(5) ])
## Stateless reply, no user key (trusted server)
- reply = bsrb([ self.server3, self.server1, self.server2,
- self.server1, self.server3 ],
+ reply = bsrb([self.server3, self.server1, self.server2,
+ self.server1, self.server3],
"fred", None)
sec,(loc,) = self.do_header_test(reply.header, pks_1, None,
(FWD_TYPE,FWD_TYPE,FWD_TYPE,FWD_TYPE,LOCAL_TYPE),
@@ -900,7 +910,7 @@
self.assert_(loc.startswith(s))
seed = loc[len(s):]
prng = AESCounterPRNG(seed)
- self.assert_(sec == [ prng.getBytes(16) for _ in range(5)])
+ self.assert_(sec == [ prng.getBytes(16) for _ in range(5) ])
#----------------------------------------------------------------------
# Having tested BuildMessage without using PacketHandler, we can now use
@@ -1020,7 +1030,7 @@
server1X = ServerInfo("127.0.0.1", 1, pk_get_modulus(self.pk1), "X"*20)
class _packable:
def pack(self): return "x"*200
- server1X.getRoutingInfo = lambda _packable=_packable : _packable()
+ server1X.getRoutingInfo = lambda _packable=_packable: _packable()
m = bfm("Z", LOCAL_TYPE, "hello\000bye",
[self.server2, server1X, self.server3],
@@ -1044,9 +1054,9 @@
# Even duplicate secrets need to go.
prng = AESCounterPRNG(" "*16)
- reply1,s = brb([self.server1], SMTP_TYPE, "fred@invalid",prng)
+ reply1,s = brb([self.server1], SMTP_TYPE, "fred@invalid",0,prng)
prng = AESCounterPRNG(" "*16)
- reply2,s = brb([self.server2], LOCAL_TYPE, "foo",prng)
+ reply2,s = brb([self.server2], LOCAL_TYPE, "foo",0,prng)
m = brm("Y", [self.server3], reply1)
m2 = brm("Y", [self.server3], reply2)
q, (a,m) = self.sp3.processMessage(m)
@@ -1189,8 +1199,8 @@
queue1 = Queue(self.d1, create=1)
queue2 = Queue(self.d2, create=1)
- handles = [ queue1.queueMessage("Sample message %s" % i)
- for i in range(100) ]
+ handles = [queue1.queueMessage("Sample message %s" % i)
+ for i in range(100)]
hdict = {}
for i in range(100): hdict[handles[i]] = i
self.assertEquals(queue1.count(), 100)
@@ -1208,7 +1218,7 @@
q2h = []
for h in handles[:30]:
- q2h.append( queue1.moveMessage(h, queue2) )
+ q2h.append(queue1.moveMessage(h, queue2))
from string import atoi
seen = {}
@@ -1295,7 +1305,7 @@
class MMTPTests(unittest.TestCase):
def testBlockingTransmission(self):
server, listener, messagesIn = _getMMTPServer()
- messages = [ "helloxxx"*4096, "helloyyy"*4096 ]
+ messages = ["helloxxx"*4096, "helloyyy"*4096]
server.process(0.1)
t = threading.Thread(None,
@@ -1313,7 +1323,7 @@
def testNonblockingTransmission(self):
server, listener, messagesIn = _getMMTPServer()
- messages = [ "helloxxx"*4096, "helloyyy"*4096 ]
+ messages = ["helloxxx"*4096, "helloyyy"*4096]
async = mixminion.MMTPServer.AsyncServer()
clientcon = mixminion.MMTPServer.MMTPClientConnection(
_getTLSContext(0), "127.0.0.1", TEST_PORT, None, messages[:], None)