2008-10-16 09:43:29 -04:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
#
|
|
|
|
|
# PublicKey/DSA.py : DSA signature primitive
|
|
|
|
|
#
|
2009-02-28 13:24:04 -05:00
|
|
|
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
2008-10-16 09:43:29 -04:00
|
|
|
#
|
2009-02-28 13:24:04 -05:00
|
|
|
# ===================================================================
|
|
|
|
|
# The contents of this file are dedicated to the public domain. To
|
|
|
|
|
# the extent that dedication to the public domain is not available,
|
|
|
|
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
|
|
|
|
# non-exclusive license to exercise all rights associated with the
|
|
|
|
|
# contents of this file for any purpose whatsoever.
|
|
|
|
|
# No rights are reserved.
|
2008-10-16 09:43:29 -04:00
|
|
|
#
|
2009-02-28 13:24:04 -05:00
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
# SOFTWARE.
|
|
|
|
|
# ===================================================================
|
2008-10-16 09:43:29 -04:00
|
|
|
|
|
|
|
|
"""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):
|
2008-10-18 18:29:00 -04:00
|
|
|
# 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):
|
2008-10-16 09:43:29 -04:00
|
|
|
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:
|
|
|
|
|
|