[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)