*.py: Add explicit conversions between binary and text strings.
authorMark Wooding <mdw@distorted.org.uk>
Mon, 21 Oct 2019 17:04:58 +0000 (18:04 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 11 Apr 2020 11:44:21 +0000 (12:44 +0100)
This doesn't do anything right now, but it'll be an important hook for
porting to Python 3.

catacomb/__init__.py
catacomb/pwsafe.py
pwsafe

index 80b6095..bbbe74b 100644 (file)
@@ -77,6 +77,9 @@ def default_lostexchook(why, ty, val, tb):
   _sys.stderr.write("\n")
 lostexchook = default_lostexchook
 
   _sys.stderr.write("\n")
 lostexchook = default_lostexchook
 
+## Text/binary conversions.
+def _bin(s): return s
+
 ## How to fix a name back into the right identifier.  Alas, the rules are not
 ## consistent.
 def _fixname(name):
 ## How to fix a name back into the right identifier.  Alas, the rules are not
 ## consistent.
 def _fixname(name):
@@ -256,7 +259,7 @@ class _ShakeBase (_HashBase):
 
   ## Python gets really confused if I try to augment `__new__' on native
   ## classes, so wrap and delegate.  Sorry.
 
   ## Python gets really confused if I try to augment `__new__' on native
   ## classes, so wrap and delegate.  Sorry.
-  def __init__(me, perso = '', *args, **kw):
+  def __init__(me, perso = _bin(''), *args, **kw):
     super(_ShakeBase, me).__init__(*args, **kw)
     me._h = me._SHAKE(perso = perso, func = me._FUNC)
 
     super(_ShakeBase, me).__init__(*args, **kw)
     me._h = me._SHAKE(perso = perso, func = me._FUNC)
 
@@ -304,7 +307,7 @@ _augment(_ShakeBase, _tmp)
 Shake._Z = _ShakeBase._Z = ByteString.zero(200)
 
 class KMAC (_ShakeBase):
 Shake._Z = _ShakeBase._Z = ByteString.zero(200)
 
 class KMAC (_ShakeBase):
-  _FUNC = 'KMAC'
+  _FUNC = _bin('KMAC')
   def __init__(me, k, *arg, **kw):
     super(KMAC, me).__init__(*arg, **kw)
     with me.bytepad(): me.stringenc(k)
   def __init__(me, k, *arg, **kw):
     super(KMAC, me).__init__(*arg, **kw)
     with me.bytepad(): me.stringenc(k)
@@ -316,7 +319,7 @@ class KMAC (_ShakeBase):
     me.rightenc(0)
     return super(KMAC, me).xof()
   @classmethod
     me.rightenc(0)
     return super(KMAC, me).xof()
   @classmethod
-  def _bare_new(cls): return cls("")
+  def _bare_new(cls): return cls(_bin(""))
 
 class KMAC128 (KMAC): _SHAKE = Shake128; _TAGSZ = 16
 class KMAC256 (KMAC): _SHAKE = Shake256; _TAGSZ = 32
 
 class KMAC128 (KMAC): _SHAKE = Shake128; _TAGSZ = 16
 class KMAC256 (KMAC): _SHAKE = Shake256; _TAGSZ = 32
@@ -783,7 +786,7 @@ _augment(GE, _tmp)
 ### RSA encoding techniques.
 
 class PKCS1Crypt (object):
 ### RSA encoding techniques.
 
 class PKCS1Crypt (object):
-  def __init__(me, ep = '', rng = rand):
+  def __init__(me, ep = _bin(''), rng = rand):
     me.ep = ep
     me.rng = rng
   def encode(me, msg, nbits):
     me.ep = ep
     me.rng = rng
   def encode(me, msg, nbits):
@@ -792,7 +795,7 @@ class PKCS1Crypt (object):
     return _base._p1crypt_decode(ct, nbits, me.ep, me.rng)
 
 class PKCS1Sig (object):
     return _base._p1crypt_decode(ct, nbits, me.ep, me.rng)
 
 class PKCS1Sig (object):
-  def __init__(me, ep = '', rng = rand):
+  def __init__(me, ep = _bin(''), rng = rand):
     me.ep = ep
     me.rng = rng
   def encode(me, msg, nbits):
     me.ep = ep
     me.rng = rng
   def encode(me, msg, nbits):
@@ -801,7 +804,7 @@ class PKCS1Sig (object):
     return _base._p1sig_decode(msg, sig, nbits, me.ep, me.rng)
 
 class OAEP (object):
     return _base._p1sig_decode(msg, sig, nbits, me.ep, me.rng)
 
 class OAEP (object):
-  def __init__(me, mgf = sha_mgf, hash = sha, ep = '', rng = rand):
+  def __init__(me, mgf = sha_mgf, hash = sha, ep = _bin(''), rng = rand):
     me.mgf = mgf
     me.hash = hash
     me.ep = ep
     me.mgf = mgf
     me.hash = hash
     me.ep = ep
index 7a5cda0..6d949c5 100644 (file)
@@ -37,6 +37,13 @@ import catacomb as _C
 ###--------------------------------------------------------------------------
 ### Python version portability.
 
 ###--------------------------------------------------------------------------
 ### Python version portability.
 
+def _bin(text): return text
+def _text(bin): return bin
+
+_NUL = _bin('\0')
+_CIPHER = _bin('cipher:')
+_MAC = _bin('mac:')
+
 def _excval(): return _SYS.exc_info()[1]
 
 ###--------------------------------------------------------------------------
 def _excval(): return _SYS.exc_info()[1]
 
 ###--------------------------------------------------------------------------
@@ -188,10 +195,10 @@ class PPK (Crypto):
     keys, indicating that a salt should be chosen randomly.
     """
     if not salt: salt = _C.rand.block(h.hashsz)
     keys, indicating that a salt should be chosen randomly.
     """
     if not salt: salt = _C.rand.block(h.hashsz)
-    tag = '%s\0%s' % (pp, salt)
+    tag = pp + _NUL + salt
     Crypto.__init__(me, c, h, m,
     Crypto.__init__(me, c, h, m,
-                    h().hash('cipher:' + tag).done(),
-                    h().hash('mac:' + tag).done())
+                    h().hash(_CIPHER).hash(tag).done(),
+                    h().hash(_MAC).hash(tag).done())
     me.salt = salt
 
 ###--------------------------------------------------------------------------
     me.salt = salt
 
 ###--------------------------------------------------------------------------
diff --git a/pwsafe b/pwsafe
index 205df23..e622e53 100644 (file)
--- a/pwsafe
+++ b/pwsafe
@@ -41,6 +41,9 @@ from catacomb.pwsafe import *
 ###--------------------------------------------------------------------------
 ### Python version portability.
 
 ###--------------------------------------------------------------------------
 ### Python version portability.
 
+def _text(bin): return bin
+def _bin(text): return text
+
 def _excval(): return SYS.exc_info()[1]
 
 ###--------------------------------------------------------------------------
 def _excval(): return SYS.exc_info()[1]
 
 ###--------------------------------------------------------------------------
@@ -99,7 +102,7 @@ def cmd_changepp(av):
 def cmd_find(av):
   if len(av) != 1: return 1
   with PW(file) as pw:
 def cmd_find(av):
   if len(av) != 1: return 1
   with PW(file) as pw:
-    try: print(pw[av[0]])
+    try: print(_text(pw[_bin(av[0])]))
     except KeyError: die("Password `%s' not found" % _excval().args[0])
 
 def cmd_store(av):
     except KeyError: die("Password `%s' not found" % _excval().args[0])
 
 def cmd_store(av):
@@ -111,10 +114,10 @@ def cmd_store(av):
       vpp = C.getpass("Confirm passphrase `%s': " % tag)
       if pp != vpp: die("passphrases don't match")
     elif av[1] == '-':
       vpp = C.getpass("Confirm passphrase `%s': " % tag)
       if pp != vpp: die("passphrases don't match")
     elif av[1] == '-':
-      pp = stdin.readline().rstrip('\n')
+      pp = _bin(stdin.readline().rstrip('\n'))
     else:
     else:
-      pp = av[1]
-    pw[av[0]] = pp
+      pp = _bin(av[1])
+    pw[_bin(av[0])] = pp
 
 def cmd_copy(av):
   if len(av) < 1 or len(av) > 2: return 1
 
 def cmd_copy(av):
   if len(av) < 1 or len(av) > 2: return 1
@@ -123,7 +126,8 @@ def cmd_copy(av):
       if len(av) >= 3: pat = av[1]
       else: pat = None
       for k in pw_in:
       if len(av) >= 3: pat = av[1]
       else: pat = None
       for k in pw_in:
-        if pat is None or fnmatch(k, pat): pw_out[k] = pw_in[k]
+        ktext = _text(k)
+        if pat is None or fnmatch(ktext, pat): pw_out[k] = pw_in[k]
 
 def cmd_list(av):
   if len(av) > 1: return 1
 
 def cmd_list(av):
   if len(av) > 1: return 1
@@ -131,16 +135,17 @@ def cmd_list(av):
     if len(av) >= 1: pat = av[0]
     else: pat = None
     for k in pw:
     if len(av) >= 1: pat = av[0]
     else: pat = None
     for k in pw:
-      if pat is None or fnmatch(k, pat): print(k)
+      ktext = _text(k)
+      if pat is None or fnmatch(ktext, pat): print(ktext)
 
 def cmd_topixie(av):
   if len(av) > 2: return 1
   with PW(file) as pw:
     pix = C.Pixie()
     if len(av) == 0:
 
 def cmd_topixie(av):
   if len(av) > 2: return 1
   with PW(file) as pw:
     pix = C.Pixie()
     if len(av) == 0:
-      for tag in pw: pix.set(tag, pw[tag])
+      for tag in pw: pix.set(tag, pw[_bin(tag)])
     else:
     else:
-      tag = av[0]
+      tag = _bin(av[0])
       if len(av) >= 2: pptag = av[1]
       else: pptag = av[0]
       pix.set(pptag, pw[tag])
       if len(av) >= 2: pptag = av[1]
       else: pptag = av[0]
       pix.set(pptag, pw[tag])
@@ -148,7 +153,7 @@ def cmd_topixie(av):
 def cmd_del(av):
   if len(av) != 1: return 1
   with PW(file, writep = True) as pw:
 def cmd_del(av):
   if len(av) != 1: return 1
   with PW(file, writep = True) as pw:
-    tag = av[0]
+    tag = _bin(av[0])
     try: del pw[tag]
     except KeyError: die("Password `%s' not found" % _excval().args[0])
 
     try: del pw[tag]
     except KeyError: die("Password `%s' not found" % _excval().args[0])