2008-10-16 09:43:29 -04:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
#
|
|
|
|
|
# PublicKey/DSA.py : DSA signature primitive
|
|
|
|
|
#
|
|
|
|
|
# Copyright (C) 2008 Dwayne C. Litzenberger <dlitz@dlitz.net>
|
|
|
|
|
#
|
|
|
|
|
# =======================================================================
|
|
|
|
|
# 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):
|
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:
|
|
|
|
|
|