X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-python/blobdiff_plain/6bd22b53a63463d18ee6b1bd4d0ca0f02a8f5b99..614c3bbf3c1c6fede55feae44370b0fe6d3fb5f0:/catacomb/__init__.py diff --git a/catacomb/__init__.py b/catacomb/__init__.py index 7ea8d57..ff771b9 100644 --- a/catacomb/__init__.py +++ b/catacomb/__init__.py @@ -25,18 +25,57 @@ from __future__ import with_statement -import _base -import types as _types from binascii import hexlify as _hexify, unhexlify as _unhexify from contextlib import contextmanager as _ctxmgr -from sys import argv as _argv +try: import DLFCN as _dlfcn +except ImportError: _dlfcn = None +import os as _os from struct import pack as _pack +import sys as _sys +import types as _types + +###-------------------------------------------------------------------------- +### Import the main C extension module. + +try: + _dlflags = _odlflags = _sys.getdlopenflags() +except AttributeError: + _dlflags = _odlflags = -1 + +## Set the `deep binding' flag. Python has its own different MD5 +## implementation, and some distributions export `md5_init' and friends so +## they override our versions, which doesn't end well. Figure out how to +## turn this flag on so we don't have the problem. +if _dlflags >= 0: + try: _dlflags |= _dlfcn.RTLD_DEEPBIND + except AttributeError: + try: _dlflags |= _os.RTLD_DEEPBIND + except AttributeError: + if _os.uname()[0] == 'Linux': _dlflags |= 8 # magic knowledge + else: pass # can't do this. + _sys.setdlopenflags(_dlflags) + +import _base + +if _odlflags >= 0: + _sys.setdlopenflags(_odlflags) + +del _dlflags, _odlflags ###-------------------------------------------------------------------------- ### Basic stuff. -## For the benefit of the default keyreporter, we need the program na,e. -_base._ego(_argv[0]) +## For the benefit of the default keyreporter, we need the program name. +_base._ego(_sys.argv[0]) + +## Register our module. +_base._set_home_module(_sys.modules[__name__]) +def default_lostexchook(why, ty, val, tb): + """`catacomb.lostexchook(WHY, TY, VAL, TB)' reports lost exceptions.""" + _sys.stderr.write("\n\n!!! LOST EXCEPTION: %s\n" % why) + _sys.excepthook(ty, val, tb) + _sys.stderr.write("\n") +lostexchook = default_lostexchook ## How to fix a name back into the right identifier. Alas, the rules are not ## consistent. @@ -46,7 +85,7 @@ def _fixname(name): name = name.replace('-', '_') ## But slashes might become underscores or just vanish. - if name.startswith('salsa20'): name = name.translate(None, '/') + if name.startswith('salsa20'): name = name.replace('/', '') else: name = name.replace('/', '_') ## Done. @@ -199,7 +238,7 @@ class _ShakeBase (_HashBase): ## Delegate methods... def copy(me): new = me.__class__(); new._copy(me) - def _copy(me, other): me._h = other._h + def _copy(me, other): me._h = other._h.copy() def hash(me, m): me._h.hash(m); return me def xof(me): me._h.xof(); return me def get(me, n): return me._h.get(n) @@ -312,15 +351,18 @@ class BaseRat (object): def __mul__(me, you): n, d = _split_rat(you) return type(me)(me._n*n, me._d*d) - def __div__(me, you): + __rmul__ = __mul__ + def __truediv__(me, you): n, d = _split_rat(you) return type(me)(me._n*d, me._d*n) - def __rdiv__(me, you): + def __rtruediv__(me, you): n, d = _split_rat(you) return type(me)(me._d*n, me._n*d) + __div__ = __truediv__ + __rdiv__ = __rtruediv__ def __cmp__(me, you): n, d = _split_rat(you) - return type(me)(me._n*d, n*me._d) + return cmp(me._n*d, n*me._d) def __rcmp__(me, you): n, d = _split_rat(you) return cmp(n*me._d, me._n*d) @@ -340,8 +382,10 @@ class _tmp: def mont(x): return MPMont(x) def barrett(x): return MPBarrett(x) def reduce(x): return MPReduce(x) - def __div__(me, you): return IntRat(me, you) - def __rdiv__(me, you): return IntRat(you, me) + def __truediv__(me, you): return IntRat(me, you) + def __rtruediv__(me, you): return IntRat(you, me) + __div__ = __truediv__ + __rdiv__ = __rtruediv__ _repr_pretty_ = _pp_str _augment(MP, _tmp) @@ -352,8 +396,10 @@ class _tmp: def halftrace(x, y): return x.reduce().halftrace(y) def modsqrt(x, y): return x.reduce().sqrt(y) def quadsolve(x, y): return x.reduce().quadsolve(y) - def __div__(me, you): return GFRat(me, you) - def __rdiv__(me, you): return GFRat(you, me) + def __truediv__(me, you): return GFRat(me, you) + def __rtruediv__(me, you): return GFRat(you, me) + __div__ = __truediv__ + __rdiv__ = __rtruediv__ _repr_pretty_ = _pp_str _augment(GF, _tmp) @@ -835,77 +881,92 @@ X448_BASE = MP(5).storel(56) Z128 = ByteString.zero(16) -class _BoxyPub (object): +class _BasePub (object): def __init__(me, pub, *args, **kw): - if len(pub) != me._PUBSZ: raise ValueError, 'bad public key' - super(_BoxyPub, me).__init__(*args, **kw) + if not me._PUBSZ.check(len(pub)): raise ValueError, 'bad public key' + super(_BasePub, me).__init__(*args, **kw) me.pub = pub def __repr__(me): return '%s(pub = %r)' % (_clsname(me), me.pub) + def _pp(me, pp): _pp_kv(pp, 'pub', me.pub) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) - if cyclep: - pp.text('...') - else: - _pp_kv(pp, 'pub', me.pub) + if cyclep: pp.text('...') + else: me._pp(pp) pp.end_group(ind, ')') -class _BoxyPriv (_BoxyPub): +class _BasePriv (object): def __init__(me, priv, pub = None, *args, **kw): - if len(priv) != me._KEYSZ: raise ValueError, 'bad private key' - if pub is None: pub = me._op(priv, me._BASE) - super(_BoxyPriv, me).__init__(pub = pub, *args, **kw) + if not me._KEYSZ.check(len(priv)): raise ValueError, 'bad private key' + if pub is None: pub = me._pubkey(priv) + super(_BasePriv, me).__init__(pub = pub, *args, **kw) me.priv = priv + @classmethod + def generate(cls, rng = rand): + return cls(rng.block(cls._KEYSZ.default)) + def __repr__(me): + return '%s(priv = %d, pub = %r)' % \ + (_clsname(me), _repr_secret(me.priv), me.pub) + def _pp(me, pp): + _pp_kv(pp, 'priv', me.priv, secretp = True); pp.text(','); pp.breakable() + super(_BasePriv, me)._pp(pp) + +class _XDHPub (_BasePub): pass + +class _XDHPriv (_BasePriv): + def _pubkey(me, priv): return me._op(priv, me._BASE) def agree(me, you): return me._op(me.priv, you.pub) - def boxkey(me, recip): - return me._hashkey(me.agree(recip)) - def box(me, recip, n, m): - return secret_box(me.boxkey(recip), n, m) - def unbox(me, recip, n, c): - return secret_unbox(me.boxkey(recip), n, c) - def __repr__(me): return '%s(priv = %s, pub = %r)' % \ - (_clsname(me), _repr_secret(me.priv), me.pub) - def _repr_pretty_(me, pp, cyclep): - ind = _pp_bgroup_tyname(pp, me) - if cyclep: - pp.text('...') - else: - _pp_kv(pp, 'priv', me.priv, True); pp.text(','); pp.breakable() - _pp_kv(pp, 'pub', me.pub) - pp.end_group(ind, ')') + def boxkey(me, recip): return me._hashkey(me.agree(recip)) + def box(me, recip, n, m): return secret_box(me.boxkey(recip), n, m) + def unbox(me, recip, n, c): return secret_unbox(me.boxkey(recip), n, c) -class X25519Pub (_BoxyPub): - _PUBSZ = X25519_PUBSZ +class X25519Pub (_XDHPub): + _PUBSZ = KeySZSet(X25519_PUBSZ) _BASE = X25519_BASE -class X25519Priv (_BoxyPriv, X25519Pub): - _KEYSZ = X25519_KEYSZ +class X25519Priv (_XDHPriv, X25519Pub): + _KEYSZ = KeySZSet(X25519_KEYSZ) def _op(me, k, X): return x25519(k, X) def _hashkey(me, z): return hsalsa20_prf(z, Z128) -class X448Pub (_BoxyPub): - _PUBSZ = X448_PUBSZ +class X448Pub (_XDHPub): + _PUBSZ = KeySZSet(X448_PUBSZ) _BASE = X448_BASE -class X448Priv (_BoxyPriv, X448Pub): - _KEYSZ = X448_KEYSZ +class X448Priv (_XDHPriv, X448Pub): + _KEYSZ = KeySZSet(X448_KEYSZ) def _op(me, k, X): return x448(k, X) - ##def _hashkey(me, z): return ??? - -class Ed25519Pub (object): - def __init__(me, pub): - me.pub = pub - def verify(me, msg, sig): - return ed25519_verify(me.pub, msg, sig) - -class Ed25519Priv (Ed25519Pub): - def __init__(me, priv): - me.priv = priv - Ed25519Pub.__init__(me, ed25519_pubkey(priv)) - def sign(me, msg): - return ed25519_sign(me.priv, msg, pub = me.pub) - @classmethod - def generate(cls, rng = rand): - return cls(rng.block(ED25519_KEYSZ)) + def _hashkey(me, z): return Shake256().hash(z).done(salsa20.keysz.default) + +class _EdDSAPub (_BasePub): + def beginhash(me): return me._HASH() + def endhash(me, h): return h.done() + +class _EdDSAPriv (_BasePriv, _EdDSAPub): + pass + +class Ed25519Pub (_EdDSAPub): + _PUBSZ = KeySZSet(ED25519_PUBSZ) + _HASH = sha512 + def verify(me, msg, sig, **kw): + return ed25519_verify(me.pub, msg, sig, **kw) + +class Ed25519Priv (_EdDSAPriv, Ed25519Pub): + _KEYSZ = KeySZAny(ED25519_KEYSZ) + def _pubkey(me, priv): return ed25519_pubkey(priv) + def sign(me, msg, **kw): + return ed25519_sign(me.priv, msg, pub = me.pub, **kw) + +class Ed448Pub (_EdDSAPub): + _PUBSZ = KeySZSet(ED448_PUBSZ) + _HASH = shake256 + def verify(me, msg, sig, **kw): + return ed448_verify(me.pub, msg, sig, **kw) + +class Ed448Priv (_EdDSAPriv, Ed448Pub): + _KEYSZ = KeySZAny(ED448_KEYSZ) + def _pubkey(me, priv): return ed448_pubkey(priv) + def sign(me, msg, **kw): + return ed448_sign(me.priv, msg, pub = me.pub, **kw) ###-------------------------------------------------------------------------- ### Built-in named curves and prime groups.