[Nym3-commit] r111 - in trunk: . doc

nym3-devel@lists.noreply.org nym3-devel@lists.noreply.org
Wed, 18 Aug 2004 22:29:06 +0200


Author: jr
Date: 2004-08-18 22:29:02 +0200 (Wed, 18 Aug 2004)
New Revision: 111

Added:
   trunk/Client/
Removed:
   trunk/Config.py
   trunk/Main.py
   trunk/Makefile
   trunk/User.py
   trunk/crypto/
Modified:
   trunk/Crypto.py
   trunk/TODO
   trunk/doc/nym-spec.txt
Log:
- remove the last files in OCaml and the Makefile
- remove Main, User, Config from the root (moved to Server/)
- update TODO
- the size of the stream key changed in the specs, we can use
the mixminion lioness_encrypt function


Deleted: trunk/Config.py
===================================================================
--- trunk/Config.py	2004-08-18 15:52:49 UTC (rev 110)
+++ trunk/Config.py	2004-08-18 20:29:02 UTC (rev 111)
@@ -1,20 +0,0 @@
-# $Id$
-
-#path = '/var/lib/nym3'
-
-DEBUG = False
-
-serverName = 'nymserv.komite.net'
-
-path = '.'
-
-default_settings = { 'quota' : 10 * 2**20, 'usage' : 0,
-		     'idKey' : None, 'encKey' : None, 'policy' : None,
-		     'SendMsgAfter' : 24, 'SendSummaryAfter' : 12, 
-		     'MaxSURBsPerDay' : 10, 'EncryptSummaryAfter' : 24,
-		     'HoldUntilAck' : 'always', 'ShutdownPhrase' : None,
-		     'HoldSURBs' : 5,
-		     'nSurbs' : 0, 'up' : False, 'cr' : ""}
-
-#up : the user account has been initialized and the answer to the challenge is correct
-#cr : response to the challenge

Modified: trunk/Crypto.py
===================================================================
--- trunk/Crypto.py	2004-08-18 15:52:49 UTC (rev 110)
+++ trunk/Crypto.py	2004-08-18 20:29:02 UTC (rev 111)
@@ -1,104 +1,22 @@
 import random
-from mixminion.Packet import compressData
+from mixminion.Packet import compressData, OAEP_OVERHEAD
 import mixminion.Crypto as _cr
-import mixminion._minionlib as _ml
 
-
-DIGEST_LEN = 20
-AES_KEY_LEN = _cr.AES_KEY_LEN
-
-#stealing and adapting mixminion lioness encryption / decryption
-def lioness_encrypt(s,key):
-    """Given a 16-byte key, encrypts s using the LIONESS
-       super-pseudorandom permutation.
-    """
-
-    assert len(key) == AES_KEY_LEN
-    assert len(s) > DIGEST_LEN
-    z15 = "\x00"*15
-    key1 = key
-    key2 = _ml.strxor(key1, z15+"\x01")
-    key3 = _ml.strxor(key1, z15+"\x02")
-    key4 = _ml.strxor(key1, z15+"\x03")
-        
-    # Split the message.
-    left = s[:DIGEST_LEN]
-    right = s[DIGEST_LEN:]
-    del s
-    # Performance note: This business with sha1("".join((key,right,key)))
-    # may look slow, but it contributes only .7% to the total time for
-    # LIONESS.
-    right = _ml.aes_ctr128_crypt(
-        _ml.aes_key(_ml.sha1("".join((key1,left,key1)))[:AES_KEY_LEN]),
-        right, 0)
-    left = _ml.strxor(left,  _ml.sha1("".join((key2,right,key2))))
-    right = _ml.aes_ctr128_crypt(
-        _ml.aes_key(_ml.sha1("".join((key3,left,key3)))[:AES_KEY_LEN]),
-        right, 0)
-    left = _ml.strxor(left,  _ml.sha1("".join((key4,right,key4))))
-
-    # You could write the above as:
-    #   right = ctr_crypt(right, "".join((key1,left,key1))[:AES_KEY_LEN])
-    #   left = strxor(left, sha1("".join((key2,right,key2))))
-    #   right = ctr_crypt(right, "".join((key3,left,key3))[:AES_KEY_LEN])
-    #   left = strxor(left, sha1("".join((key4,right,key4))))
-    # but that would be slower by about 10%.  (Since LIONESS is in the
-    # critical path, we care.)
-
-    return left + right
-
-def lioness_decrypt(s,key):
-    """Given a 16-byte key decrypts s using the LIONESS super-pseudorandom permutation.
-    """
-
-    assert len(key) == AES_KEY_LEN
-    assert len(s) > DIGEST_LEN
-    z15 = "\x00"*15
-    key1 = key
-    key2 = _ml.strxor(key1, z15+"\x01")
-    key3 = _ml.strxor(key1, z15+"\x02")
-    key4 = _ml.strxor(key1, z15+"\x03")
-    
-    left = s[:DIGEST_LEN]
-    right = s[DIGEST_LEN:]
-    del s
-
-    # Slow, comprehensible version:
-    #left = strxor(left,  sha1("".join([key4,right,key4])))
-    #right = ctr_crypt(right, sha1("".join([key3,left,key3]))[:AES_KEY_LEN])
-    #left = strxor(left,  sha1("".join([key2,right,key2])))
-    #right = ctr_crypt(right, sha1("".join([key1,left,key1]))[:AES_KEY_LEN])
-
-    # Equivalent-but-faster version:
-    left = _ml.strxor(left, _ml.sha1("".join((key4,right,key4))))
-    right = _ml.aes_ctr128_crypt(
-        _ml.aes_key(_ml.sha1("".join((key3,left, key3)))[:AES_KEY_LEN]),
-        right, 0)
-    left = _ml.strxor(left, _ml.sha1("".join((key2,right,key2))))
-    right = _ml.aes_ctr128_crypt(
-        _ml.aes_key(_ml.sha1("".join((key1,left, key1)))[:AES_KEY_LEN]),
-        right, 0)
-
-    return left + right
-
-
-
-
 def nym_encrypt(data, key):
     n = nbBits(_cr.pk_get_modulus(key)) / 8
     assert n == 128 or n == 256
     dataC = compressData(data)
-    #we pad to a multiple of the size of the RSA key
-    paddingLen = len(dataC) - (len(dataC) / n) * n
+    paddingLen = len(dataC) - (len(dataC) / 128) * 128
     if paddingLen != 0:
-        paddingLen = n - paddingLen
+        paddingLen = 128 - paddingLen
     dataP = dataC + '0'*paddingLen
     k = ""
-    for i in range(0, 16):
+    for i in range(0, 20):
         k = k + chr(random.randint(0, 255))
-    dataE = lioness_encrypt(dataP, k)
+    K = _cr.Keyset(k)
+    dataE = _cr.lioness_encrypt(dataP, K.getLionessKeys(""))
     #42 : taille du padding introduit par OAEP
-    #16 : taille de k
-    rsaLen = n - 42 - 16
+    #20 : taille de k
+    rsaLen = n - OAEP_OVERHEAD - 20
     rsaPart = pk_encrypt(k + dataE[0:rsaLen],key)
     return rsaPart + dataEnc[rsaLen:]

Deleted: trunk/Main.py
===================================================================
--- trunk/Main.py	2004-08-18 15:52:49 UTC (rev 110)
+++ trunk/Main.py	2004-08-18 20:29:02 UTC (rev 111)
@@ -1,195 +0,0 @@
-#!/usr/bin/env python2.3
-# $Id$
-
-import sys
-import os
-import getopt
-import User
-import Config
-import Message
-import Common
-import Mail
-
-lifeCycle = Common.lifeCycle
-
-def processIncoming(localpart, msg):
-    try:
-	nymuser = User.User(localpart)
-    except User.NoSuchUser:
-	print "No such user"
-	sys.exit(73)
-    # TODO : we should honor the "Quota" sending policy.
-    if nymuser.usage() + len(msg) > nymuser.quota():
-	print "Quota exceeded."
-	print repr(nymuser.usage()) + " > " + repr(nymuser.quota())
-	sys.exit(75)
-    # Valid user, not over quota. Filtering policy can wait.
-    nymuser.store(msg)
-    sys.exit(0)
-
-def processMessage(msg):
-    """process incoming control message
-    - verifies signature
-    - parse the message into header + sequence on control commands
-    - run appropriate actions"""
-    #TODO prendre le numero de sequence pour pouvoir l'aquitter
-    
-    def MyException(Exception): pass
-    
-    sr = Message.StrReader(msg)
-    try:
-	h = sr.readHeader()
-        if(h.nym == ""):
-            comList = sr.readCommandCToSList()
-            try:
-                if(len(comList) != 3):
-                    raise MyException()
-	        #this may be an account setup message
-	        #we suppose there is a exactly 1 Create Command in the message, 1 Newpk, and 1 surb
-	        #more will raise an error
-
-                nymUser = None
-	        #phase 1 we look for the command create
-                for idx, com in enumerate(comList):
-                    if(com.ct() == 0):
-		        #the Create command
-                        for pnym in self.list:
-                            try:
-                                nymUser=User.User(pnym,1)
-                            except User.AlreadySuchUser:
-                                pass
-                            if(nymUser != None):
-                                break
-                        if(nymUser == None):
-                            #TODO send an Error message to the client when surbs become available?
-                            #for the time being just ignore
-                            print "All nyms proposed in the list were already attribuated"
-                            raise MyException()
-                        del(comList[idx])
-                        break
-                if(nymUser == None):
-                    #TODO send an Error message to the client when surbs become available?
-                    #for the time being just ignore
-                    print "No Create Command"
-                    raise MyException()
-                        
-	        #phase 2 we look for the command surb
-                for idx, com in enumerate(comList):
-                    if(com.ct()==2):
-                        nymUser.addSurbs(com.surbs)
-                        del(comList[idx])
-                        break
-                if(len(comList) != 1):
-                    nymUser.abort()
-                    raise MyException()
-	        #phase 3 the last command should be a Newpk
-                com = comList[0]
-                if(com.ct() != 3):
-                    nymUser.abort()
-                    raise MyException()
-                nymUser.setKeys(com.kid,com.kenc)
-                if(not nymUser.checkMessageSign(msg[Message.sigLength:],h.sig)):
-                   nymUser.abort()
-                   raise MyException()
-            except MyException:
-                   #if you come here something went wrong during the account
-                   #initialization
-                   print "Bad formed account creation message"
-                   sys.exit(2) #TODO smart error code
-        else:
-            try:
-                nymUser = User.user(h.nym)
-            except User.NoSuchUser:
-                print "No such user"
-                sys.exit(73) #TODO is it the smart error code
-            if(not nymUser.checkMessageSign(msg[Message.sigLength:],h.sig)):
-               return
-            comList = sr.readCommandCToSList()
-            for com in comList:
-                if (com.ct() == 0):
-		    #we ignore the Create command if it comes from the nymholder of an account, should we rise an error?
-                    pass
-                #if the account is not initialized, or if it is already up we ignore Create2 messages
-                elif (com.ct() == 1):
-                    if (nymUser.isInitialized() and (not nymUser.isUp())):
-                        if(nymUser.checkChallenge(com.cr)):
-                            nymUser.setUp()
-		#other commands are only taken into account if the account is up
-                elif (nymUser.isUp()):
-                    if (com.ct() == 2):
-                        if( len(com.surbs) == 0):
-                            nymUser.delSurbs()
-                        else:
-                            nymUser.addSurbs(com.surbs)
-                    elif (com.ct() == 3):
-                        nymUser.setKeys(com.kid,com.kenc)
-                    elif (com.ct() == 4):
-                        ec = Mail.relay(com.rt,com.ri,com.body)
-                        if (ec != 0):
-                            print "mixminion exited abnormally with error code %d" % ec
-                            sys.exit(2)
-                            
-                    elif (com.ct() == 5):
-                        msgList = []
-                        sendList = []
-                        for m in com.l:
-                            if nymUser.hasMail(m):
-                                msgCom = Msg()
-                                msgCom.fromData(m,nymUser.getMail(m))
-                                msgList.append(msgCom)
-                                sendList.append(m)
-                        ec = nymUser.send(Message.buildMessage(msgList))
-                        if (ec == 0):
-                            nymUser.markMid(sendList,lifeCycle['sent-in-full'])
-                            if(nymUser['HoldUntilAck'] == 'never'):
-                                map(nymUser.delete_msg,sendList)
-                            
-                        else:
-                            print "mixminion exited abnormally with error code %d" % ec
-                            sys.exit(2)
-                        
-                                
-                                
-                    elif (com.ct() == 6):
-                        comList = []
-                        sendList = nymUser.sendList(com.num, com.after)
-                        mList = []
-                        for (ml, bf, blob) in sendList:
-                            sumCom = Summary()
-                            sumCom.fromData(bf, blob)
-                            comList.append(sumCom)
-                            mList = mList + ml
-                        ec = nymUser.send(Message.buildMessage(comList))
-                        if (ec == 0):
-                            nymUser.markMid(mList, lifeCycle['synopsis-sent'])
-                        else:
-                            print "mixminion exited abnormally with error code %d" % ec
-                            sys.exit(2)
-
-                    elif (com.ct() == 7):
-                        for mid in com.l:
-                            nymUser.delete_msg(mid)
-                    elif (com.ct() == 8):
-                        if(com.opt in Common.userPolicy):
-                            nymUser[com.opt] = com.val
-                    else:
-                        pass
-    except Message.ParseError, inst:
-	print inst
-	sys.exit(2) #TODO error code                
-	      
-    
-if __name__ == '__main__':
-    optlist, pholder = getopt.getopt(sys.argv[1:], 'D:d:m')
-    for o, a in optlist:
-        if o == "-D":
-            Config.DEBUG = True
-        
-    for o, a in optlist:
-	if o == "-d": # mail delivery
-	    processIncoming(a, sys.stdin.read())
-	    sys.exit(0)
-	if o == "-m":
-	    processMessage(sys.stdin.read())
-	    sys.exit(0)
-    

Deleted: trunk/Makefile
===================================================================
--- trunk/Makefile	2004-08-18 15:52:49 UTC (rev 110)
+++ trunk/Makefile	2004-08-18 20:29:02 UTC (rev 111)
@@ -1,10 +0,0 @@
-
-all: message.cmi synopsis.cmi config.cmi main.cmi user.cmi
-
-%.cmi: %.ml
-	ocamlfind ocamlc -c -package missinglib $<
-
-clean:
-	rm *.cmi *.cmo
-
-.PHONY: all clean

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2004-08-18 15:52:49 UTC (rev 110)
+++ trunk/TODO	2004-08-18 20:29:02 UTC (rev 111)
@@ -10,6 +10,7 @@
 
 Notes:
  - In case something brake, remember it's emag's fault.
+ - Use clean_surbs after sending something through mixminion
  
 Message.py:
  - add the print method which prints the content of a command object in a user
@@ -23,10 +24,10 @@
  - periodically scans for emails that need to be relayed.
 
 JR:
- - look at the crypto module of mixminion
- - what is the format of the keys
- - implement encrypt a mail, a set of synopses
+ o look at the crypto module of mixminion
+ o what is the format of the keys
+ o implement encrypt a mail, a set of synopses
  - implement sign a control message
- - figure what the routing type and info (cf Command relay) are
- - check the size of an ASN.1 encoded key 
- - get a life :)
+ o figure what the routing type and info (cf Command relay) are
+ X check the size of an ASN.1 encoded key 
+ X get a life :)

Deleted: trunk/User.py
===================================================================
--- trunk/User.py	2004-08-18 15:52:49 UTC (rev 110)
+++ trunk/User.py	2004-08-18 20:29:02 UTC (rev 111)
@@ -1,489 +0,0 @@
-# $Id$
-
-import os
-import Config
-import Common
-import Mail
-import Crypto
-import pickle
-import string
-import time
-import mixminion.Common
-from Message import intToStrBE
-import mixminion.Crypto as _cr
-
-surb_len = Common.surbLength
-lifeCycle = Common.lifeCycle
-
-class NoSuchUser(Exception): pass
-
-class AlreadySuchUser(Exception): pass
-
-def binsearch(l, prop):
-    """Returns first index i of l for which l[i] is true,
-       assuming prop is increasing over l"""
-    min = 0
-    max = len(l) - 1
-    if not prop(l[max]): return IndexError
-    if prop(l[min]): return min
-
-    current = (max + min) / 2
-    while max - min > 1:
-	if prop(l[current]):
-	    max = current
-	    current = (max + min) / 2
-	else:
-	    min = current
-	    current = (max + min) / 2
-    return max
-
-class User:
-    """Hold user data"""
-    def __init__(self, username, create = 0):
-        """0 : load user data throw an error if the user doesn't exist
-        1 : create user data throw an error if the user exists
-        _ : load a user data, if it doesn't exist create a new user silently
-	"""
-        self.datafile = Config.path + os.sep + username + '.dat'
-	self.username = username
-	self.index = None
-	self.mbox = None
-	self.syn = None
-	self.data = None
-        self._abort = False
-	self._lock()
-	try:
-	    f = open(self.datafile, 'r')
-            if (create == 1):
-                f.close()
-                raise AlreadySuchUser
-	    self.data = pickle.load(f)
-	    f.close()
-	except IOError:
-	    if create == 0: raise NoSuchUser()
-	    self.data = Config.default_settings
-	    self.data['username'] = username
-    
-    def __del__(self):
-        if (not self._abort):
-            self._save_index()
-            self._save_synbox()
-            self._save_mbox()
-            self._save_data()
-        self._release()
-    
-    def __getitem__(self, key):
-	return self.data[key]
-
-    def __setitem__(self, key, value):
-	self.data[key] = value
-
-    def _lock(self):
-	"""Lock the user. For well behaved functions."""
-	self.lock = mixminion.Common.Lockfile(Config.path + os.sep + 
-					      self.username + '.lck')
-	self.lock.acquire()
-
-    def _release(self):
-	self.lock.release()
-
-    def abort(self):
-        """permit to destroy a User object without saving its data
-        Can only be used if the object is being created for the
-        first time. If username.dat exist, it is ignored
-        """
-        try:
-            os.stat(self.datafile)
-        except:
-            self._abort = True
-
-    def timecmp(self, a, b):
-        return cmp(self.index[a]['time'], self.index[b]['time'])
-
-    def quota(self):
-	return self.data['quota']
-
-    def usage(self):
-	sum = 0
-	try:
-	    sum = os.stat(self.surbfile())[6]
-	except: pass
-	try:
-	    sum = sum + os.stat(self.indexfile())[6]
-	except: pass
-	try:
-	    sum = sum + os.stat(self.synboxfile())[6]
-	except: pass
-	try:
-	    sum = sum + os.stat(self.mboxfile())[6]
-	except: pass
-	self.data['usage'] = sum
-	return sum
-
-    def idKey(self):
-        return self.data['idKey']
-
-    def encKey(self):
-        return self.data['encKey']
-
-    def blobify(self, l):
-        """encrypts a set of synopses
-        l is a list of pair (mid,synopsis) """
-        s = ""
-        m = []
-        for mid, syn in l:
-            m.append(mid)
-            s = s + mid + intToStrBE(len(syn), 2) + syn
-        return (m, 'encrypted', Crypto.nym_encrypt(s, self.encKey()))
-
-    def getSyn(self, mid):
-	"""Retrieve a blurb consisting of the synopsis of the
-	   requested synopsis mid. May contain unwanted synopsis
-	   too."""
-	self.load_synbox()
-	for i, (midlist, status, synblob) in enumerate(self.syn):
-	    if mid in midlist: return i, (midlist, status, synblob)
-	raise ValueError()
-
-    def getMail(self, mid):
-        """Retrieve an encrypted mail from the mbox
-        raise ValueError if the mail cannot be found"""
-        self.load_mbox()
-        try:
-            return self.mbox[mid]
-        except:
-            raise ValueError()
-        
-    def midAfter(self, mid):
-	"""Retrieve mids of messages that came after message `mid'
-        the elements of the output are ordered by ascending
-        order of arrival time"""
-	self.load_index()
-	midtime = self.index[mid]['time']
-
-	ret = []
-	if mid == oldestMid: ret = self.index.keys()
-	else:
-	    for msg in self.index.keys():
-		if self.index[msg]['time'] >= midtime: ret.append(msg)
-	ret.sort(self.timecmp)
-	return ret
-    
-    def _save_data(self):
-	if self.data == None: return
-	f = open(self.datafile, 'w')
-	pickle.dump(self.data, f)
-	f.close()
-
-    def surbfile(self):
-	return Config.path + os.sep + self.data['username'] + '.surbs'
-
-    def send(self, msg):
-        if Config.DEBUG:
-            print msg
-            return 0
-        else:
-            fname = Mail.tmpFileMsg(msg)
-            ec = os.system("mixminion send -R " + self.surbfile() + " -i " + fname)
-            os.unlink(fname)
-            return ec
-
-    def clean_surbs(self):
-	"Inspect the surbs and delete the used/outdated"
-	fname = self.surbfile()
-	f = open(fname, "r")
-	buffer = f.read()
-	f.close()
-	surbs = []
-	while len(buffer) > 0:
-	    surbs.append(buffer[:surb_len])
-	    buffer = buffer[surb_len:]
-
-	goods = []
-	for surb in surbs:
-	    fname = '/tmp/' + Mail.mid2filename(Mail.genMid())
-	    fname = string.strip(fname)
-	    f = open(fname, 'w')
-	    f.write(surb)
-	    f.close()
-	    ec = os.system("mixminion inspect-surb " + fname + 
-			   " |grep 'Used: no'")
-	    os.unlink(fname)
-	    if ec == 0: goods.append(surb)
-	self.data['nSurbs'] = 0
-	f = open(self.surbfile(), "w")
-	for surb in goods:
-	    f.write(surb)
-	    self.data['nSurbs'] = self.data['nSurbs'] + 1
-	f.close()
-
-    def addSurbs(self,surbs):
-	fname = self.surbfile()
-	f = open(fname, "a")
-	f.write(surbs)
-	f.close()
-	self.data['nSurbs'] = self.data['nSurbs'] + ( len(surbs) / surb_len)
-
-    def delSurbs(self):
-	fname = self.surbfile()
-        os.unlink(fname)
-	self.data['nSurbs'] = 0
-
-    def load_mbox(self):
-	if not self.mbox == None: return
-	mbox = self.mboxfile()
-	try:
-	    f = open(mbox, 'r')
-	    self.mbox = pickle.load(f)
-	    f.close()
-	except IOError:
-	    self.mbox = {}
-
-    def mboxfile(self):
-	return Config.path + os.sep + self.data['username'] + '.mbox'
-
-    def _save_mbox(self):
-	if self.mbox == None: return
-	mbox = self.mboxfile()
-	f = open(mbox, 'w')
-	pickle.dump(self.mbox, f)
-	f.close()
-
-    def synboxfile(self):
-	return Config.path + os.sep + self.data['username'] + '.syn'
-
-    def indexfile(self):
-	return Config.path + os.sep + self.data['username'] + '.idx'
-	
-    def load_synbox(self):
-	if not self.syn == None: return
-	synbox = self.synboxfile()
-	try:
-	    f = open(synbox, 'r')
-	    self.syn = pickle.load(f)
-	    f.close()
-	except IOError:
-	    self.syn = []
-
-    def _save_synbox(self):
-	if self.syn == None: return
-	synbox = self.synboxfile()
-	f = open(synbox, 'w')
-	pickle.dump(self.syn, f)
-	f.close()
-    
-    def load_index(self):
-	if not self.index == None: return
-	index = self.indexfile()
-	try:
-	    f = open(index, 'r')
-	    self.index = pickle.load(f)
-	    f.close()
-	except IOError:
-	    self.index = {}
-    
-    def _save_index(self):
-	if self.index == None: return
-	index = self.indexfile()
-	f = open(index, 'w')
-	pickle.dump(self.index, f)
-	f.close()
-        
-    def store(self, msg):
-	"Store an incoming message"
-	syn = Mail.synopsize(msg)
-	# Store the mail.
-	self.load_mbox()
-	self.load_index()
-	mid = Mail.genMid()
-	while self.index.has_key(mid): mid = Mail.genMid()
-	self.mbox[mid] = Crypto.nym_encrypt(msg,self.data['encKey']) 
-	# store the synopsis
-	self.load_synbox()
-	self.syn.append(([mid], 'clear', syn))
-
-	# create an index entry for the synopsis
-	self.index[mid] = {'time' : int(time.time()),
-			   'status' : lifeCycle['nothing-sent'] }
-
-    def delete_msg(self, mid):
-	"""Delete a stored message. Delete the synopsis if possible"""
-	self.load_index()
-
-	if not self.index.has_key(mid): return
-	self.load_mbox()
-	del self.mbox[mid]
-	self.index[mid]['status'] = lifeCycle['deleted']
-	self.load_synbox()
-
-	i, (sl, enc, blurb) = self.getSyn(mid)
-	candelete = True
-	for omid in sl:
-	    if not self.index[omid]['status'] == lifeCycle['deleted']:
-		candelete = False
-		break
-	    if candelete:
-		self.syn.remove((sl, enc, blurb))
-		for omid in sl: del self.index[omid]
-	    else: return
-
-    def setKeys(self, kid, kenc):
-        """given 2 modulus (int) set the public keys of the user"""
-	self.data['idKey'] = _cr.pk_from_modulus(kid)
-	self.data['encKey'] = _cr.pk_from_modulus(kenc)
-
-    def isInitialized(self):
-	"""True if the first 3 commands :
-	- a Create command
-	- a Newpk command
-	- a Surb command containing at least 3 surbs
-	have arrived"""
-	return (self.data['nSurbs'] > 2) and (self.data['idkey'] != None)
-
-    def isUp(self):
-	return self['up']
-
-    def setUp(self):
-	self['up'] = True
-
-    def checkMessageSign(self, m, s):
-        return (s == _cr.pk_check_signature(_cr.sha1(m), self.idKey()))
-	    
-    def checkChallenge(self, cr):
-        return (self['cr'] == cr)
-
-    def encryptSyn(self, i, j):
-        """Replace in the synbox the syn between i and j-1
-        by an encrypted blob. Initially the syn have to be in clear
-        raise an error if it is not the case"""
-        self.load_synbox()
-        self.syn[i:j] = [self.blobify(syn[i:j])]
-
-    def encOldSyn(self):
-	"""Encrypt synopsis we had in clear for too long"""
-	try:
-	    firstclear = binsearch(self.syn, lambda x: (x[1] == 'clear'))
-	except: return
-	
-	offset = firstclear
-	last = len(self.syn)
-	size = last - offset
-	lastchunk = size % maxSynPerBlob
-
-	while offset + maxSynPerBlob < last:
-	    self.encryptSyn(offset, offset + maxSynPerBlurb)
-	    offset = offset + 1
-	    last = last - maxSynPerBlurb
-	
-	if offset + 1 >= last: return
-	# See if among the few remaining synopses, some are considered
-	# too old
-	try:
-	    fyoung = binsearch(self.syn, lambda x: self.index[x[0][0]]['time'] <
-		time.time() - self['EncryptSummaryAfter'] * 30 * 60)
-	except: pass
-	if fyoung <= offset: return
-	self.encryptSyn(offset, fyoung)
-
-
-    def markMid(self,l,mark):
-        """the status of the mids in l which had a status
-        previous to mark in the lifeCycle are set to mark"""
-        self.load_index()
-        for e in l:
-            if (self.index[e]['status'] < mark):
-                self.index[e]['status'] = mark
-        
-    def hasMail(self,mid):
-        self.load_index()
-        try:
-            return self.index[mid]['status'] != lifeCycle['deleted']
-        except:
-            return False
-        
-    def sendList(self, num, after):
-        """returns a list of (ml, bf, synblob)
-        in the process of creating it ca modify the synbox,
-        doing some encryption"""
-        def lhasMail(midIdx, l):
-            return self.mbox.has_key(l[midIdx])
-        def addBlob(slist, mlist, ilist, blob):
-            """append to slist (mlist, BF, blob)
-            BF is the bitfield obtained from the elements e of ilist
-            which verifies : the mid mlist[e] has a mail"""
-            def test(midx):
-                lhasMail(midx, mlist)
-            slist.append(Mail.bf(filter(test, ilist)), blob)
-        #the list of the mid after "after"
-        midList = self.midAfter(after)
-        #load the structures
-        self.load_index()
-        self.load_synbox()
-        self.load_mbox()
-        #we just need the num first
-        midList = midList[:num]
-                    
-        #create a list of blobs containing the mid in midlist
-        clearListEmpty = True #is there any non encrypted synopses between bInf and the current i, or bSup that need to be sent?  
-        sendList = [] #result list
-        
-        try:
-            i, _ = self.getSyn(midList[0])
-        except:
-            #this should not happen
-            raise 'Bug'
-        #as long as midList isn't empty
-        while(midList):
-            #look for the synblob containing midList[0]
-            (ml, status, synblob) = self.syn[i]
-            if (status == 'clear'):
-                if (clearListEmpty):
-                    bInf = i
-                    clearListEmpty = False
-                if (i + 1 - bInf == 16):
-                    self.encryptSyn(bInf, i + 1)
-                    clearListEmpty = True
-                    (m, _, sy) = self.syn[bInf]
-                    addBlob(sendList, m, range(len(m)), sy)
-                else:
-                    bSup = i+1
-                del midList[0]
-            elif (status == 'encrypted'):
-                if (not clearListEmpty):
-                    self.encryptSyn(bInf, bSup)
-                    clearListEmpty = True
-                    (m,_,sy) = self.syn[bInf]
-                    addBlob(sendList, m, range(len(m)), sy)
-                #idxList=[ml.index(midList[0])]
-                def test(midx):
-                    return (self.timecmp(num, midx) < 0)
-                #idxList contains the mid in ml older than num
-                idxList = filter(test, ml)
-                #remove from the midList the mid from idxList
-                for j in idxList:
-                    try:
-                        midList.remove(j)
-                    except ValueError:
-                        pass
-                tlist = []
-                for j in idxList:
-                    tlist.append(ml.index(j))
-                addBlob(sendList, ml, tList, synblob)
-            else:
-                #this should not happen
-                raise 'Bug'
-            i = i + 1
-        #if clearList isn't empty
-        if (not clearListEmpty):
-            self.encryptSyn(bInf, bSup) 
-            (m, _, sy) = self.syn[bInf]
-            addBlob(sendList, m, range(len(m)), sy)
-        return sendList
-
-if __name__ == '__main__':
-    try:
-        a = User('laurent')
-    except NoSuchUser:
-        print "this user does not exist"
-    #ec = a.relay("NYM3 TEST : " + repr(time.time()))
-    #print "Errorcode is " + repr(ec)

Modified: trunk/doc/nym-spec.txt
===================================================================
--- trunk/doc/nym-spec.txt	2004-08-18 15:52:49 UTC (rev 110)
+++ trunk/doc/nym-spec.txt	2004-08-18 20:29:02 UTC (rev 111)
@@ -1,4 +1,4 @@
-$Id: nym-spec.txt,v 1.6 2004/02/20 21:58:50 nickm Exp $
+$Id: nym-spec.txt,v 1.8 2004/08/18 18:50:22 nickm Exp $
 
                                Mix3:Nym
     Underhill: A Proposed Type 3 Nymserver Protocol Specification
@@ -75,7 +75,7 @@
    4.4.1.   CREATED [0x00]
    4.4.2.   STATUS [0x01]
    4.4.3.   SUMMARY [0x02]
-   4.4.4.   MSG [0x03]
+   4.4.4.   MSGS [0x03]
    4.4.5.   DROPPED [0x04]
    4.4.6    ERROR [0x05]
    5.       Filtering and abuse prevention
@@ -344,11 +344,6 @@
             A time of receipt.
 
       - A set of SURBs
-   
-   Note : As it is described later in these specifications, we will need
-   to order the message identifiers according to their time of arrival.
-   We consider that Z(20) is a special message identifier, older than all
-   the others.
 
 2.2. Processing incoming emails
 
@@ -511,7 +506,7 @@
    To encrypt an octet sequence, the nymserver first compresses the
    octet sequence (as described in E2E-spec.txt).  Next, the nymserver
    pads the octet sequence to the nearest multiple of 128 octets in
-   length.  The nymserver then generates a random 128-bit key;
+   length.  The nymserver then generates a random 160-bit key;
    LIONESS-encrypts the padded compressed data with the key; and
    prepends to the encrypted data the RSA-encrypted key.  We use the
    same trick as minion-spec.txt to minimize wasted space.
@@ -523,12 +518,12 @@
            P -- The padding granularity -- either 1024 or 128.
 
      Let M_C = COMPRESS(M).
-     Let PADDING_LEN = CEIL(LEN(M_C)/P) - LEN(M_C).
-     Let M_P = M | Z(PADDING_LEN).
+     Let PADDING_LEN = CEIL(LEN(M_C)/P)*P - LEN(M_C).
+     Let M_P = M_C | Z(PADDING_LEN).
 
-     Let K = Rand(16).
+     Let K = Rand(20).
      Let M_Enc = SPRP_Encrypt(K, "", M_P)
-     Let RSA_LEN = Len(PK_nym) - PK_OVERHEAD_LEN - 16
+     Let RSA_LEN = Len(PK_nym) - PK_OVERHEAD_LEN - 20
      Let RSA_PART = PK_Encrypt(PK_nym, K | M_Enc[0:RSA_LEN])
 
      Return RSA_PART | M_Enc[RSA_LEN:Len(M_Enc)-RSA_LEN]
@@ -593,15 +588,15 @@
    of the size of the immediately following CD field.
 
    The following values for CT are recognized:
-        0x00 : CREATE    (Create a new nym)
-        0x01 : CREATE2   (Confirm a new nym)
-        0x02 : SURB      (Supply the nymserver with new set of SURBs)
-        0x03 : NEWPK     (Set or replace public keys)
-        0x04 : RELAY     (Send an email to a recipient)
-        0x05 : GET       (Retrieve a list of emails)
-        0x06 : SUMMARIZE (Retrieve a list of synopses)
-        0x07 : DELETE    (Expunge a list of emails from the nymserver)
-        0x08 : POLICY    (Adjust user settings)
+        0x00 : CREATE  (Create a new nym)
+        0x01 : CREATE2 (Confirm a new nym)
+        0x02 : SURB    (Supply the nymserver with new set of SURBs)
+        0x03 : NEWPK   (Set or replace public keys)
+        0x04 : RELAY   (Send an email to a recipient)
+        0x05 : GET     (Retrieve a list of emails)
+        0x06 : SUMMARY (Retrieve a list of synopses)
+        0x07 : DELETE  (Expunge a list of emails from the nymserver)
+        0x08 : POLICY  (Adjust user settings)
 
 4.3.1. CREATE [0x00]
 
@@ -699,6 +694,9 @@
    the AFTER field requests that only summaries newer than the
    message ID specified be returned.
 
+   For purposes of this command, the message identifier Z(20) is older than
+   all other message IDs.
+
 4.3.8. DELETE [0x07]
 
    A DELETE command tells the server to delete a number of specified
@@ -765,7 +763,7 @@
         0x00 : CREATED  (Acknowledge a new nym)
         0x01 : STATUS   (Acknowledge messages and describe status)
         0x02 : SUMMARY  (Describe pending emails)
-        0x03 : MSG     (Send emails to the client)
+        0x03 : MSGS     (Send emails to the client)
         0x04 : DROPPED  (Tell the client about dropped emails)
         0x05 : ERROR    (Tell the client about an error condition)