# -*- coding: utf-8 -*- # # PublicKey/DSA.py : DSA signature primitive # # Copyright (C) 2008 Dwayne C. Litzenberger # # ======================================================================= # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ======================================================================= """DSA public-key signature algorithm.""" __revision__ = "$Id$" __all__ = ['generate', 'construct', 'error'] from Crypto.Util.python_compat import * from Crypto.PublicKey import _DSA, _slowmath, pubkey from Crypto import Random try: from Crypto.PublicKey import _fastmath except ImportError: _fastmath = None class _DSAobj(pubkey.pubkey): keydata = ['y', 'g', 'p', 'q', 'x'] def __init__(self, implementation, key): self.implementation = implementation self.key = key def __getattr__(self, attrname): if attrname in self.keydata: # For backward compatibility, allow the user to get (not set) the # DSA key parameters directly from this object. return getattr(self.key, attrname) else: raise AttributeError("%s object has no %r attribute" % (self.__class__.__name__, attrname,)) def _encrypt(self, c, K): raise error("DSA cannot encrypt") def _decrypt(self, c): raise error("DSA cannot decrypt") def _blind(self, m, r): raise error("DSA cannot blind") def _unblind(self, m, r): raise error("DSA cannot unblind") def _sign(self, m, k): return self.key._sign(m, k) def _verify(self, m, sig): (r, s) = sig return self.key._verify(m, r, s) def has_private(self): return self.key.has_private() def size(self): return self.key.size() def can_blind(self): return False def can_encrypt(self): return False def can_sign(self): return True def publickey(self): return self.implementation.construct((self.key.y, self.key.g, self.key.p, self.key.q)) def __getstate__(self): d = {} for k in self.keydata: try: d[k] = getattr(self.key, k) except AttributeError: pass return d def __setstate__(self, d): if not hasattr(self, 'implementation'): self.implementation = DSAImplementation() t = [] for k in self.keydata: if not d.has_key(k): break t.append(d[k]) self.key = self.implementation._math.dsa_construct(*tuple(t)) def __repr__(self): attrs = [] for k in self.keydata: if k == 'p': attrs.append("p(%d)" % (self.size()+1,)) elif hasattr(self.key, k): attrs.append(k) if self.has_private(): attrs.append("private") return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs)) class DSAImplementation(object): def __init__(self, **kwargs): # 'use_fast_math' parameter: # None (default) - Use fast math if available; Use slow math if not. # True - Use fast math, and raise RuntimeError if it's not available. # False - Use slow math. use_fast_math = kwargs.get('use_fast_math', None) if use_fast_math is None: # Automatic if _fastmath is not None: self._math = _fastmath else: self._math = _slowmath elif use_fast_math: # Explicitly select fast math if _fastmath is not None: self._math = _fastmath else: raise RuntimeError("fast math module not available") else: # Explicitly select slow math self._math = _slowmath self.error = self._math.error # 'default_randfunc' parameter: # None (default) - use Random.new().read # not None - use the specified function self._default_randfunc = kwargs.get('default_randfunc', None) self._current_randfunc = None def _get_randfunc(self, randfunc): if randfunc is not None: return randfunc elif self._current_randfunc is None: self._current_randfunc = Random.new().read return self._current_randfunc def generate(self, bits, randfunc=None, progress_func=None): # Check against FIPS 186-2, which says that the size of the prime p # must be a multiple of 64 bits between 512 and 1024 for i in (0, 1, 2, 3, 4, 5, 6, 7, 8): if bits == 512 + 64*i: return self._generate(bits, randfunc, progress_func) # The March 2006 draft of FIPS 186-3 also allows 2048 and 3072-bit # primes, but only with longer q values. Since the current DSA # implementation only supports a 160-bit q, we don't support larger # values. raise ValueError("Number of bits in p must be a multiple of 64 between 512 and 1024, not %d bits" % (bits,)) def _generate(self, bits, randfunc=None, progress_func=None): rf = self._get_randfunc(randfunc) obj = _DSA.generate_py(bits, rf, progress_func) # TODO: Don't use legacy _DSA module key = self._math.dsa_construct(obj.y, obj.g, obj.p, obj.q, obj.x) return _DSAobj(self, key) def construct(self, tup): key = self._math.dsa_construct(*tup) return _DSAobj(self, key) _impl = DSAImplementation() generate = _impl.generate construct = _impl.construct error = _impl.error # vim:set ts=4 sw=4 sts=4 expandtab: