diff options
Diffstat (limited to 'Lib/dos-8x3/dsa.py')
-rw-r--r-- | Lib/dos-8x3/dsa.py | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/Lib/dos-8x3/dsa.py b/Lib/dos-8x3/dsa.py new file mode 100644 index 0000000..4bd26bc --- /dev/null +++ b/Lib/dos-8x3/dsa.py @@ -0,0 +1,221 @@ +# +# DSA.py : Stupid name. Should really be called qNEW.py or something. +# Suggestions for a better name would be welcome. +# +# Maintained by A.M. Kuchling (amk@magnet.com) +# Date: 1997/09/03 +# +# Distribute and use freely; there are no restrictions on further +# dissemination and usage except those imposed by the laws of your +# country of residence. +# + +# TODO : +# Change the name +# Add more comments and docstrings +# Write documentation +# Add better RNG (?) + +import types, md5 + +error = 'DSA module error' + +def RandomNumber(N, randfunc): + "Get an N-bit random number" + str=randfunc(N/8) + char=ord(randfunc(1))>>(8-(N%8)) + return Str2Int(chr(char)+str) + +def Int2Str(n): + "Convert an integer to a string form" + s='' + while n>0: + s=chr(n & 255)+s + n=n>>8 + return s + +def Str2Int(s): + "Convert a string to a long integer" + if type(s)!=types.StringType: return s # Integers will be left alone + return reduce(lambda x,y : x*256+ord(y), s, 0L) + + +def getPrime(N, randfunc): + "Find a prime number measuring N bits" + number=RandomNumber(N, randfunc) | 1 + while (not isPrime(number)): + number=number+2 + return number + +sieve=[2,3,5,7,11,13,17,19,23,29,31,37,41] +def isPrime(N): + """Test if a number N is prime, using a simple sieve check, + followed by a more elaborate Rabin-Miller test.""" + for i in sieve: + if (N % i)==0: return 0 + N1=N - 1L ; n=1L + while (n<N): n=n<<1L # Compute number of bits in N + for j in sieve: + a=long(j) ; d=1L ; t=n + while (t): # Iterate over the bits in N1 + x=(d*d) % N + if x==1L and d!=1L and d!=N1: return 0 # Square root of 1 found + if N1 & t: d=(x*a) % N + else: d=x + t=t>>1L + if d!=1L: return 0 + return 1 + +class DSAobj: + def size(self): + "Return the max. number of bits that can be handled by this key" + bits, power = 0,1L + while (power<self.p): bits, power = bits+1, power<<1 + return bits-1 + + def hasprivate(self): + """Return a Boolean denoting whether the object contains private components""" + if hasattr(self, 'x'): return 1 + else: return 0 + + def cansign(self): + return self.hasprivate() + def canencrypt(self): + return 0 + + def publickey(self): + new=DSAobj() + for i in 'pqgy': setattr(new, i, getattr(self, i)) + return new + + def _sign(self, M, K): + if (self.q<=K): + raise error, 'K is greater than q' + r=pow(self.g, K, self.p) % self.q + s=(K- (r*M*self.x % self.q)) % self.q + return (r,s) + def _verify(self, M, sig): + r, s = sig + if r<=0 or r>=self.q or s<=0 or s>=self.q: return 0 + v1=pow(self.g, s, self.p) + v2=pow(self.y, M*r, self.p) + v=((v1*v2) % self.p) + v=v % self.q + if v==r: return 1 + return 0 + + def sign(self, M, K): + if (not self.hasprivate()): + raise error, 'Private key not available in this object' + if type(M)==types.StringType: M=Str2Int(M) + if type(K)==types.StringType: K=Str2Int(K) + return self._sign(M, K) + def verify(self, M, signature): + if type(M)==types.StringType: M=Str2Int(M) + return self._verify(M, signature) + validate=verify + + def generate(self, L, randfunc, progress_func=None): + """Generate a private key with L bits""" + HASHBITS=128 # Number of bits in the hashing algorithm used + # (128 for MD5; change to 160 for SHA) + + if L<512: raise error, 'Key length <512 bits' + # Generate string S and prime q + if progress_func: apply(progress_func, ('p,q\n',)) + while (1): + self.q = getPrime(160, randfunc) + S = Int2Str(self.q) + n=(L-1)/HASHBITS + C, N, V = 0, 2, {} +# b=(self.q >> 5) & 15 + b= (L-1) % HASHBITS + powb=pow(long(2), b) + powL1=pow(long(2), L-1) + while C<4096: + for k in range(0, n+1): + V[k]=Str2Int(md5.new(S+str(N)+str(k)).digest()) + W=V[n] % powb + for k in range(n-1, -1, -1): + W=(W<< long(HASHBITS) )+V[k] + X=W+powL1 + p=X-(X%(2*self.q)-1) + if powL1<=p and isPrime(p): break + C, N = C+1, N+n+1 + if C<4096: break + if progress_func: apply(progress_func, ('4096 multiples failed\n',) ) + self.p = p + power=(p-1)/self.q + if progress_func: apply(progress_func, ('h,g\n',)) + while (1): + h=Str2Int(randfunc(L)) % (p-1) + g=pow(h, power, p) + if 1<h<p-1 and g>1: break + self.g=g + if progress_func: apply(progress_func, ('x,y\n',)) + while (1): + x=Str2Int(randfunc(20)) + if 0<x<self.q: break + self.x, self.y=x, pow(g, x, p) + return self + +object=DSAobj + +# XXX this random number generation function sucks, since it isn't +# cryptographically strong! But it'll do for this first release... + +def randfunc(N): + import os, string + if string.lower(os.uname()[0])=='linux': + # On Linux, use /dev/urandom + f=open('/dev/urandom', 'r') + return f.read(N) + else: + import time + s="" + while len(s)<N: + rand=md5.new(str(time.time())).digest() + s=s+rand + return s[0:N] + +if __name__=='__main__': + import sys, string + BITS=512 + if len(sys.argv)>1: + BITS=string.atoi(sys.argv[1]) + print ' Generating', BITS, 'bit key' + key=DSAobj() + key.generate(BITS, randfunc, sys.stdout.write) + print ' Key data: (the private key is x)' + for i in 'xygqp': print '\t', i, ':', hex(getattr(key, i)) + plaintext="Hello" + + if key.cansign(): + print ' Signature test' + print "Plaintext:", plaintext + K=getPrime(30, randfunc) + signature=key.sign(plaintext, K) + print "Signature:", signature + result=key.verify(plaintext, signature) + if not result: + print " Sig. verification failed when it should have succeeded" + else: print 'Signature verified' + + # Test on a mangled plaintext + result=key.verify(plaintext[:-1], signature) + if result: + print " Sig. verification succeeded when it should have failed" + + # Change a single bit in the plaintext + badtext=plaintext[:-3]+chr( 1 ^ ord(plaintext[-3]) )+plaintext[-3:] + result=key.verify(badtext, signature) + if result: + print " Sig. verification succeeded when it should have failed" + + print 'Removing private key data' + pubonly=key.publickey() + result=pubonly.verify(plaintext, signature) + if not result: + print " Sig. verification failed when it should have succeeded" + else: + print 'Signature verified' |