File: elgamal-keygen.patch

package info (click to toggle)
python-crypto 2.1.0-2%2Bsqueeze2
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 1,584 kB
  • ctags: 2,188
  • sloc: ansic: 10,073; python: 6,026; makefile: 32; sh: 10
file content (120 lines) | stat: -rw-r--r-- 4,286 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
Description: Fix insecure ElGamal key generation.
Author: Legrandin <gooksankoo@hoiptorrow.mailexpire.com>
Origin:
 https://github.com/dlitz/pycrypto/commit/9f912f13,
 https://github.com/dlitz/pycrypto/commit/c575de4f
Last-Update: 2012-05-25

Index: python-crypto-2.1.0/lib/Crypto/PublicKey/ElGamal.py
===================================================================
--- python-crypto-2.1.0.orig/lib/Crypto/PublicKey/ElGamal.py	2012-05-25 01:25:55.000000000 +0200
+++ python-crypto-2.1.0/lib/Crypto/PublicKey/ElGamal.py	2012-05-25 14:59:35.000000000 +0200
@@ -40,37 +40,48 @@
     the progress of the key generation.
     """
     obj=ElGamalobj()
-    # Generate prime p
+    # Generate a safe prime p
+    # See Algorithm 4.86 in Handbook of Applied Cryptography
     if progress_func:
         progress_func('p\n')
-    obj.p=bignum(getPrime(bits, randfunc))
-    # Generate random number g
+    while 1:
+        q = bignum(getPrime(bits-1, randfunc))
+        obj.p = 2*q+1
+        if number.isPrime(obj.p, randfunc=randfunc):
+            break
+    # Generate generator g
+    # See Algorithm 4.80 in Handbook of Applied Cryptography
+    # Note that the order of the group is n=p-1=2q, where q is prime
     if progress_func:
         progress_func('g\n')
-    size=bits-1-(ord(randfunc(1)) & 63) # g will be from 1--64 bits smaller than p
-    if size<1:
-        size=bits-1
-    while (1):
-        obj.g=bignum(getPrime(size, randfunc))
-        if obj.g < obj.p:
+    while 1:
+        # We must avoid g=2 because of Bleichenbacher's attack described
+        # in "Generating ElGamal signatures without knowning the secret key",
+        # 1996
+        #
+        obj.g = number.getRandomRange(3, obj.p, randfunc)
+        safe = 1
+        if pow(obj.g, 2, obj.p)==1:
+            safe=0
+        if safe and pow(obj.g, q, obj.p)==1:
+            safe=0
+        # Discard g if it divides p-1 because of the attack described
+        # in Note 11.67 (iii) in HAC
+        if safe and divmod(obj.p-1, obj.g)[1]==0:
+            safe=0
+        # g^{-1} must not divide p-1 because of Khadir's attack
+        # described in "Conditions of the generator for forging ElGamal
+        # signature", 2011
+        ginv = number.inverse(obj.g, obj.p)
+        if safe and divmod(obj.p-1, ginv)[1]==0:
+            safe=0
+        if safe:
             break
-        size=(size+1) % bits
-        if size==0:
-            size=4
-    # Generate random number x
+    # Generate private key x
     if progress_func:
         progress_func('x\n')
-    while (1):
-        size=bits-1-ord(randfunc(1)) # x will be from 1 to 256 bits smaller than p
-        if size>2:
-            break
-    while (1):
-        obj.x=bignum(getPrime(size, randfunc))
-        if obj.x < obj.p:
-            break
-        size = (size+1) % bits
-        if size==0:
-            size=4
+    obj.x=number.getRandomRange(2, obj.p-1, randfunc)
+    # Generate public key y
     if progress_func:
         progress_func('y\n')
     obj.y = pow(obj.g, obj.x, obj.p)
@@ -118,6 +129,8 @@
         return (a, b)
 
     def _verify(self, M, sig):
+        if sig[0]<1 or sig[0]>self.p-1:
+            return 0
         v1=pow(self.y, sig[0], self.p)
         v1=(v1*pow(sig[0], sig[1], self.p)) % self.p
         v2=pow(self.g, M, self.p)
Index: python-crypto-2.1.0/lib/Crypto/Util/number.py
===================================================================
--- python-crypto-2.1.0.orig/lib/Crypto/Util/number.py	2012-05-25 01:25:55.000000000 +0200
+++ python-crypto-2.1.0/lib/Crypto/Util/number.py	2012-05-25 01:25:57.000000000 +0200
@@ -84,6 +84,22 @@
     assert size(value) >= N
     return value
 
+def getRandomRange(a, b, randfunc=None):
+    """getRandomRange(a:int, b:int, randfunc:callable):long
+    Return a random number n so that a <= n < b.
+
+    If randfunc is omitted, then Random.new().read is used.
+
+    This function is for internal use only and may be renamed or removed in
+    the future.
+    """
+    range_ = b - a - 1
+    bits = size(range_)
+    value = getRandomNumber(bits, randfunc)
+    while value > range_:
+        value = getRandomNumber(bits, randfunc)
+    return a + value
+
 def GCD(x,y):
     """GCD(x:long, y:long): long
     Return the GCD of x and y.