PageRenderTime 36ms CodeModel.GetById 11ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/gdata/Crypto/PublicKey/DSA.py

http://radioappz.googlecode.com/
Python | 238 lines | 218 code | 7 blank | 13 comment | 9 complexity | da684ba5019f44e61a05f79af8089e9e MD5 | raw file
  1
  2#
  3#   DSA.py : Digital Signature Algorithm
  4#
  5#  Part of the Python Cryptography Toolkit
  6#
  7# Distribute and use freely; there are no restrictions on further
  8# dissemination and usage except those imposed by the laws of your
  9# country of residence.  This software is provided "as is" without
 10# warranty of fitness for use or suitability for any purpose, express
 11# or implied. Use at your own risk or not at all.
 12#
 13
 14__revision__ = "$Id: DSA.py,v 1.16 2004/05/06 12:52:54 akuchling Exp $"
 15
 16from Crypto.PublicKey.pubkey import *
 17from Crypto.Util import number
 18from Crypto.Util.number import bytes_to_long, long_to_bytes
 19from Crypto.Hash import SHA
 20
 21try:
 22    from Crypto.PublicKey import _fastmath
 23except ImportError:
 24    _fastmath = None
 25
 26class error (Exception):
 27    pass
 28
 29def generateQ(randfunc):
 30    S=randfunc(20)
 31    hash1=SHA.new(S).digest()
 32    hash2=SHA.new(long_to_bytes(bytes_to_long(S)+1)).digest()
 33    q = bignum(0)
 34    for i in range(0,20):
 35        c=ord(hash1[i])^ord(hash2[i])
 36        if i==0:
 37            c=c | 128
 38        if i==19:
 39            c= c | 1
 40        q=q*256+c
 41    while (not isPrime(q)):
 42        q=q+2
 43    if pow(2,159L) < q < pow(2,160L):
 44        return S, q
 45    raise error, 'Bad q value generated'
 46
 47def generate(bits, randfunc, progress_func=None):
 48    """generate(bits:int, randfunc:callable, progress_func:callable)
 49
 50    Generate a DSA key of length 'bits', using 'randfunc' to get
 51    random data and 'progress_func', if present, to display
 52    the progress of the key generation.
 53    """
 54
 55    if bits<160:
 56        raise error, 'Key length <160 bits'
 57    obj=DSAobj()
 58    # Generate string S and prime q
 59    if progress_func:
 60        progress_func('p,q\n')
 61    while (1):
 62        S, obj.q = generateQ(randfunc)
 63        n=(bits-1)/160
 64        C, N, V = 0, 2, {}
 65        b=(obj.q >> 5) & 15
 66        powb=pow(bignum(2), b)
 67        powL1=pow(bignum(2), bits-1)
 68        while C<4096:
 69            for k in range(0, n+1):
 70                V[k]=bytes_to_long(SHA.new(S+str(N)+str(k)).digest())
 71            W=V[n] % powb
 72            for k in range(n-1, -1, -1):
 73                W=(W<<160L)+V[k]
 74            X=W+powL1
 75            p=X-(X%(2*obj.q)-1)
 76            if powL1<=p and isPrime(p):
 77                break
 78            C, N = C+1, N+n+1
 79        if C<4096:
 80            break
 81        if progress_func:
 82            progress_func('4096 multiples failed\n')
 83
 84    obj.p = p
 85    power=(p-1)/obj.q
 86    if progress_func:
 87        progress_func('h,g\n')
 88    while (1):
 89        h=bytes_to_long(randfunc(bits)) % (p-1)
 90        g=pow(h, power, p)
 91        if 1<h<p-1 and g>1:
 92            break
 93    obj.g=g
 94    if progress_func:
 95        progress_func('x,y\n')
 96    while (1):
 97        x=bytes_to_long(randfunc(20))
 98        if 0 < x < obj.q:
 99            break
100    obj.x, obj.y = x, pow(g, x, p)
101    return obj
102
103def construct(tuple):
104    """construct(tuple:(long,long,long,long)|(long,long,long,long,long)):DSAobj
105    Construct a DSA object from a 4- or 5-tuple of numbers.
106    """
107    obj=DSAobj()
108    if len(tuple) not in [4,5]:
109        raise error, 'argument for construct() wrong length'
110    for i in range(len(tuple)):
111        field = obj.keydata[i]
112        setattr(obj, field, tuple[i])
113    return obj
114
115class DSAobj(pubkey):
116    keydata=['y', 'g', 'p', 'q', 'x']
117
118    def _encrypt(self, s, Kstr):
119        raise error, 'DSA algorithm cannot encrypt data'
120
121    def _decrypt(self, s):
122        raise error, 'DSA algorithm cannot decrypt data'
123
124    def _sign(self, M, K):
125        if (K<2 or self.q<=K):
126            raise error, 'K is not between 2 and q'
127        r=pow(self.g, K, self.p) % self.q
128        s=(inverse(K, self.q)*(M+self.x*r)) % self.q
129        return (r,s)
130
131    def _verify(self, M, sig):
132        r, s = sig
133        if r<=0 or r>=self.q or s<=0 or s>=self.q:
134            return 0
135        w=inverse(s, self.q)
136        u1, u2 = (M*w) % self.q, (r*w) % self.q
137        v1 = pow(self.g, u1, self.p)
138        v2 = pow(self.y, u2, self.p)
139        v = ((v1*v2) % self.p)
140        v = v % self.q
141        if v==r:
142            return 1
143        return 0
144
145    def size(self):
146        "Return the maximum number of bits that can be handled by this key."
147        return number.size(self.p) - 1
148
149    def has_private(self):
150        """Return a Boolean denoting whether the object contains
151        private components."""
152        if hasattr(self, 'x'):
153            return 1
154        else:
155            return 0
156
157    def can_sign(self):
158        """Return a Boolean value recording whether this algorithm can generate signatures."""
159        return 1
160
161    def can_encrypt(self):
162        """Return a Boolean value recording whether this algorithm can encrypt data."""
163        return 0
164
165    def publickey(self):
166        """Return a new key object containing only the public information."""
167        return construct((self.y, self.g, self.p, self.q))
168
169object=DSAobj
170
171generate_py = generate
172construct_py = construct
173
174class DSAobj_c(pubkey):
175    keydata = ['y', 'g', 'p', 'q', 'x']
176
177    def __init__(self, key):
178        self.key = key
179
180    def __getattr__(self, attr):
181        if attr in self.keydata:
182            return getattr(self.key, attr)
183        else:
184            if self.__dict__.has_key(attr):
185                self.__dict__[attr]
186            else:
187                raise AttributeError, '%s instance has no attribute %s' % (self.__class__, attr)
188
189    def __getstate__(self):
190        d = {}
191        for k in self.keydata:
192            if hasattr(self.key, k):
193                d[k]=getattr(self.key, k)
194        return d
195
196    def __setstate__(self, state):
197        y,g,p,q = state['y'], state['g'], state['p'], state['q']
198        if not state.has_key('x'):
199            self.key = _fastmath.dsa_construct(y,g,p,q)
200        else:
201            x = state['x']
202            self.key = _fastmath.dsa_construct(y,g,p,q,x)
203
204    def _sign(self, M, K):
205        return self.key._sign(M, K)
206
207    def _verify(self, M, (r, s)):
208        return self.key._verify(M, r, s)
209
210    def size(self):
211        return self.key.size()
212
213    def has_private(self):
214        return self.key.has_private()
215
216    def publickey(self):
217        return construct_c((self.key.y, self.key.g, self.key.p, self.key.q))
218
219    def can_sign(self):
220        return 1
221
222    def can_encrypt(self):
223        return 0
224
225def generate_c(bits, randfunc, progress_func=None):
226    obj = generate_py(bits, randfunc, progress_func)
227    y,g,p,q,x = obj.y, obj.g, obj.p, obj.q, obj.x
228    return construct_c((y,g,p,q,x))
229
230def construct_c(tuple):
231    key = apply(_fastmath.dsa_construct, tuple)
232    return DSAobj_c(key)
233
234if _fastmath:
235    #print "using C version of DSA"
236    generate = generate_c
237    construct = construct_c
238    error = _fastmath.error