[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[minion-cvs] Changed base-64 encoding to wrap at 64-characters inste...



Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv4265/lib/mixminion

Modified Files:
	Common.py Crypto.py Packet.py test.py 
Log Message:
Changed base-64 encoding to wrap at 64-characters instead of 76.

Why was this necessary?  Because Outlook breaks up long lines, you see.

But it isn't as simple as that.  If Outlook simply turned "ABC\n" into 
"AB\nC\n", we'd be fine.  Instead, Outlook searches for a plus sign, and
turns "A+BC\n" into "A+B\nA+C\n", thus **corrupting** the data.

I hope those responsible for this feature -- which they doubtlessly
thought was very clever indeed -- are deeply, deeply ashamed of
themselves.  

Clippy helpfully says: "You seem to be corrupting user data.  Do you
want me to teach you about transport layers?"



Index: Common.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Common.py,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -d -r1.61 -r1.62
--- Common.py	13 Feb 2003 07:03:49 -0000	1.61
+++ Common.py	16 Feb 2003 04:50:55 -0000	1.62
@@ -7,13 +7,14 @@
 
 __all__ = [ 'IntervalSet', 'Lockfile', 'LOG', 'LogStream', 'MixError',
             'MixFatalError', 'MixProtocolError', 'UIError', 'UsageError',
-            'ceilDiv', 'checkPrivateDir', 'createPrivateDir', 'floorDiv',
+            'ceilDiv', 'checkPrivateDir', 'createPrivateDir',
+            'encodeBase64', 'floorDiv',
             'formatBase64', 'formatDate', 'formatFnameTime', 'formatTime',
             'installSIGCHLDHandler', 'isSMTPMailbox', 'openUnique',
             'previousMidnight', 'readPossiblyGzippedFile', 'secureDelete',
             'stringContains', 'succeedingMidnight', 'waitForChildren' ]
 
-import base64
+import binascii
 import bisect
 import calendar
 import fcntl
@@ -121,8 +122,21 @@
 
 def formatBase64(s):
     """Convert 's' to a one-line base-64 representation."""
-    return base64.encodestring(s).replace("\n", "")
+    return binascii.b2a_base64(s).strip()
 
+def encodeBase64(s, lineWidth=64):
+    """Convert 's' to a multiline base-64 representation.  Improves upon
+       base64.encodestring by having a variable line width.  Implementation
+       is based upon that function.
+    """
+    # XXXX003 test me
+    pieces = []
+    bytesPerLine = floorDiv(lineWidth, 4) * 3
+    for i in xrange(0, len(s), bytesPerLine):
+        chunk = s[i:i+bytesPerLine]
+        pieces.append(binascii.b2a_base64(chunk))
+    return "".join(pieces)
+    
 #----------------------------------------------------------------------
 def createPrivateDir(d, nocreate=0):
     """Create a directory, and all parent directories, checking permissions

Index: Crypto.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Crypto.py,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- Crypto.py	11 Feb 2003 22:18:10 -0000	1.40
+++ Crypto.py	16 Feb 2003 04:50:55 -0000	1.41
@@ -8,7 +8,6 @@
    the functions in mixminion.Crypto, and not call _minionlib's crypto
    functionality themselves."""
 
-import base64
 import binascii
 import copy_reg
 import errno
@@ -580,7 +579,7 @@
             mode = "wb"
         while 1:
             bytes = self.getBytes(6)
-            base = base64.encodestring(bytes).strip().replace("/","-")
+            base = binascii.b2a_base64(bytes).strip().replace("/","-")
             fname = os.path.join(dir, "%s%s"%(prefix,base))
             try:
                 fd = os.open(fname, flags, 0600)

Index: Packet.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Packet.py,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- Packet.py	13 Feb 2003 10:56:40 -0000	1.33
+++ Packet.py	16 Feb 2003 04:50:55 -0000	1.34
@@ -24,15 +24,14 @@
             'parseTextEncodedMessage', 'parseTextReplyBlocks', 'uncompressData'
             ]
 
-import base64
 import binascii
 import re
 import struct
 import sys
 import zlib
 from socket import inet_ntoa, inet_aton
-from mixminion.Common import MixError, MixFatalError, floorDiv, formatTime, \
-     isSMTPMailbox, LOG
+from mixminion.Common import MixError, MixFatalError, encodeBase64, \
+     floorDiv, formatTime, isSMTPMailbox, LOG
 from mixminion.Crypto import sha1
 
 if sys.version_info[:3] < (2,2,0):
@@ -520,7 +519,7 @@
 
     def packAsText(self):
         """Returns the external text representation of this reply block"""
-        text = base64.encodestring(self.pack())
+        text = encodeBase64(self.pack())
         if not text.endswith("\n"):
             text += "\n"
         return "%s\nVersion: 0.1\n%s%s\n"%(RB_TEXT_START,text,RB_TEXT_END)
@@ -733,7 +732,7 @@
         preNL = postNL = ""
 
         if self.messageType != 'TXT':
-            c = base64.encodestring(c)
+            c = encodeBase64(c)
         else:
             #XXXX004 disable "decoding handle" format
             if (c.startswith("Decoding-handle:") or

Index: test.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/test.py,v
retrieving revision 1.90
retrieving revision 1.91
diff -u -d -r1.90 -r1.91
--- test.py	14 Feb 2003 17:51:57 -0000	1.90
+++ test.py	16 Feb 2003 04:50:55 -0000	1.91
@@ -1223,12 +1223,12 @@
         eq(mt3.pack(), start+"\nDecoding-handle: gotcha!\nFoobar\n"+end)
         # Text generation: binary case
         v = hexread("00D1E50FED1F1CE5")*12
-        v64 = base64.encodestring(v)
+        v64 = encodeBase64(v)
         mb1 = tem(v, "BIN")
         eq(mb1.pack(), start+"""\
 Message-type: binary
-ANHlD+0fHOUA0eUP7R8c5QDR5Q/tHxzlANHlD+0fHOUA0eUP7R8c5QDR5Q/tHxzlANHlD+0fHOUA
-0eUP7R8c5QDR5Q/tHxzlANHlD+0fHOUA0eUP7R8c5QDR5Q/tHxzl
+ANHlD+0fHOUA0eUP7R8c5QDR5Q/tHxzlANHlD+0fHOUA0eUP7R8c5QDR5Q/tHxzl
+ANHlD+0fHOUA0eUP7R8c5QDR5Q/tHxzlANHlD+0fHOUA0eUP7R8c5QDR5Q/tHxzl
 """+end)
         eq(mb1.pack(), start+"Message-type: binary\n"+v64+end)
         # Overcompressed
@@ -2250,7 +2250,7 @@
         self.assertEquals(pbin, pkt.getContents())
         self.assert_(pkt.isPlaintext())
         self.failIf(pkt.isPrintingAscii())
-        self.assertEquals(base64.encodestring(pkt.getContents()),
+        self.assertEquals(encodeBase64(pkt.getContents()),
                           pkt.getAsciiContents())
         # with an overcompressed content
         pcomp = "          "*4096
@@ -2265,7 +2265,7 @@
         self.assert_(not pkt.isPlaintext())
         self.assert_(pkt.isOvercompressed())
         self.assert_(pkt.getAsciiContents(),
-             base64.encodestring(compressData(pcomp)))
+             encodeBase64(compressData(pcomp)))
 
         m = befm(p, SMTP_TYPE, "nobody@invalid", [self.server1],
                  [self.server3], getRSAKey(0,1024))
@@ -2278,7 +2278,7 @@
         self.assert_(pkt.isEncrypted())
         self.assert_(not pkt.isPrintingAscii())
         self.assertEquals(len(pkt.getContents()), 28*1024)
-        self.assertEquals(base64.encodestring(pkt.getContents()),
+        self.assertEquals(encodeBase64(pkt.getContents()),
                           pkt.getAsciiContents())
         
     def test_rejected(self):
@@ -4079,11 +4079,11 @@
         # Tests escapeMessageForEmail
         self.assert_(stringContains(eme(FDPFast('plain',message)), message))
         expect = "BEGINS =======\nMessage-type: binary\n"+\
-                 base64.encodestring(binmessage)+"====="
+                 encodeBase64(binmessage)+"====="
         self.assert_(stringContains(eme(FDPFast('plain',binmessage)), expect))
         expect = "BEGINS =======\nDecoding-handle: "+\
                  base64.encodestring(tag)+\
-                 base64.encodestring(binmessage)+"====="
+                 encodeBase64(binmessage)+"====="
         self.assert_(stringContains(eme(FDPFast('enc',binmessage,tag)),
                                         expect))
 
@@ -4113,9 +4113,10 @@
 
 ======= TYPE III ANONYMOUS MESSAGE BEGINS =======
 Decoding-handle: eHh4eHh4eHh4eHh4eHh4eHh4eHg=
-7/rOqx76yt7v+s6rHvrK3u/6zqse+sre7/rOqx76yt7v+s6rHvrK3u/6zqse+sre7/rOqx76yt7v
-+s6rHvrK3u/6zqse+sre7/rOqx76yt7v+s6rHvrK3u/6zqse+sre7/rOqx76yt7v+s6rHvrK3u/6
-zqse+sre7/rOqx76yt7v+s6rHvrK3u/6zqse+sre7/rOqx76yt7v+s6rHvrK3g==
+7/rOqx76yt7v+s6rHvrK3u/6zqse+sre7/rOqx76yt7v+s6rHvrK3u/6zqse+sre
+7/rOqx76yt7v+s6rHvrK3u/6zqse+sre7/rOqx76yt7v+s6rHvrK3u/6zqse+sre
+7/rOqx76yt7v+s6rHvrK3u/6zqse+sre7/rOqx76yt7v+s6rHvrK3u/6zqse+sre
+7/rOqx76yt7v+s6rHvrK3g==
 ======== TYPE III ANONYMOUS MESSAGE ENDS ========
 """