Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: third_party/google-endpoints/Crypto/PublicKey/ElGamal.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #
2 # ElGamal.py : ElGamal encryption/decryption and signatures
3 #
4 # Part of the Python Cryptography Toolkit
5 #
6 # Originally written by: A.M. Kuchling
7 #
8 # ===================================================================
9 # The contents of this file are dedicated to the public domain. To
10 # the extent that dedication to the public domain is not available,
11 # everyone is granted a worldwide, perpetual, royalty-free,
12 # non-exclusive license to exercise all rights associated with the
13 # contents of this file for any purpose whatsoever.
14 # No rights are reserved.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 # SOFTWARE.
24 # ===================================================================
25
26 """ElGamal public-key algorithm (randomized encryption and signature).
27
28 Signature algorithm
29 -------------------
30 The security of the ElGamal signature scheme is based (like DSA) on the discrete
31 logarithm problem (DLP_). Given a cyclic group, a generator *g*,
32 and an element *h*, it is hard to find an integer *x* such that *g^x = h*.
33
34 The group is the largest multiplicative sub-group of the integers modulo *p*,
35 with *p* prime.
36 The signer holds a value *x* (*0<x<p-1*) as private key, and its public
37 key (*y* where *y=g^x mod p*) is distributed.
38
39 The ElGamal signature is twice as big as *p*.
40
41 Encryption algorithm
42 --------------------
43 The security of the ElGamal encryption scheme is based on the computational
44 Diffie-Hellman problem (CDH_). Given a cyclic group, a generator *g*,
45 and two integers *a* and *b*, it is difficult to find
46 the element *g^{ab}* when only *g^a* and *g^b* are known, and not *a* and *b*.
47
48 As before, the group is the largest multiplicative sub-group of the integers
49 modulo *p*, with *p* prime.
50 The receiver holds a value *a* (*0<a<p-1*) as private key, and its public key
51 (*b* where *b*=g^a*) is given to the sender.
52
53 The ElGamal ciphertext is twice as big as *p*.
54
55 Domain parameters
56 -----------------
57 For both signature and encryption schemes, the values *(p,g)* are called
58 *domain parameters*.
59 They are not sensitive but must be distributed to all parties (senders and
60 receivers).
61 Different signers can share the same domain parameters, as can
62 different recipients of encrypted messages.
63
64 Security
65 --------
66 Both DLP and CDH problem are believed to be difficult, and they have been proved
67 such (and therefore secure) for more than 30 years.
68
69 The cryptographic strength is linked to the magnitude of *p*.
70 In 2012, a sufficient size for *p* is deemed to be 2048 bits.
71 For more information, see the most recent ECRYPT_ report.
72
73 Even though ElGamal algorithms are in theory reasonably secure for new designs,
74 in practice there are no real good reasons for using them.
75 The signature is four times larger than the equivalent DSA, and the ciphertext
76 is two times larger than the equivalent RSA.
77
78 Functionality
79 -------------
80 This module provides facilities for generating new ElGamal keys and for construc ting
81 them from known components. ElGamal keys allows you to perform basic signing,
82 verification, encryption, and decryption.
83
84 >>> from Crypto import Random
85 >>> from Crypto.Random import random
86 >>> from Crypto.PublicKey import ElGamal
87 >>> from Crypto.Util.number import GCD
88 >>> from Crypto.Hash import SHA
89 >>>
90 >>> message = "Hello"
91 >>> key = ElGamal.generate(1024, Random.new().read)
92 >>> h = SHA.new(message).digest()
93 >>> while 1:
94 >>> k = random.StrongRandom().randint(1,key.p-1)
95 >>> if GCD(k,key.p-1)==1: break
96 >>> sig = key.sign(h,k)
97 >>> ...
98 >>> if key.verify(h,sig):
99 >>> print "OK"
100 >>> else:
101 >>> print "Incorrect signature"
102
103 .. _DLP: http://www.cosic.esat.kuleuven.be/publications/talk-78.pdf
104 .. _CDH: http://en.wikipedia.org/wiki/Computational_Diffie%E2%80%93Hellman_assum ption
105 .. _ECRYPT: http://www.ecrypt.eu.org/documents/D.SPA.17.pdf
106 """
107
108 __revision__ = "$Id$"
109
110 __all__ = ['generate', 'construct', 'error', 'ElGamalobj']
111
112 from Crypto.PublicKey.pubkey import *
113 from Crypto.Util import number
114
115 class error (Exception):
116 pass
117
118 # Generate an ElGamal key with N bits
119 def generate(bits, randfunc, progress_func=None):
120 """Randomly generate a fresh, new ElGamal key.
121
122 The key will be safe for use for both encryption and signature
123 (although it should be used for **only one** purpose).
124
125 :Parameters:
126 bits : int
127 Key length, or size (in bits) of the modulus *p*.
128 Recommended value is 2048.
129 randfunc : callable
130 Random number generation function; it should accept
131 a single integer N and return a string of random data
132 N bytes long.
133 progress_func : callable
134 Optional function that will be called with a short string
135 containing the key parameter currently being generated;
136 it's useful for interactive applications where a user is
137 waiting for a key to be generated.
138
139 :attention: You should always use a cryptographically secure random number g enerator,
140 such as the one defined in the ``Crypto.Random`` module; **don't** just use the
141 current time and the ``random`` module.
142
143 :Return: An ElGamal key object (`ElGamalobj`).
144 """
145 obj=ElGamalobj()
146 # Generate a safe prime p
147 # See Algorithm 4.86 in Handbook of Applied Cryptography
148 if progress_func:
149 progress_func('p\n')
150 while 1:
151 q = bignum(getPrime(bits-1, randfunc))
152 obj.p = 2*q+1
153 if number.isPrime(obj.p, randfunc=randfunc):
154 break
155 # Generate generator g
156 # See Algorithm 4.80 in Handbook of Applied Cryptography
157 # Note that the order of the group is n=p-1=2q, where q is prime
158 if progress_func:
159 progress_func('g\n')
160 while 1:
161 # We must avoid g=2 because of Bleichenbacher's attack described
162 # in "Generating ElGamal signatures without knowning the secret key",
163 # 1996
164 #
165 obj.g = number.getRandomRange(3, obj.p, randfunc)
166 safe = 1
167 if pow(obj.g, 2, obj.p)==1:
168 safe=0
169 if safe and pow(obj.g, q, obj.p)==1:
170 safe=0
171 # Discard g if it divides p-1 because of the attack described
172 # in Note 11.67 (iii) in HAC
173 if safe and divmod(obj.p-1, obj.g)[1]==0:
174 safe=0
175 # g^{-1} must not divide p-1 because of Khadir's attack
176 # described in "Conditions of the generator for forging ElGamal
177 # signature", 2011
178 ginv = number.inverse(obj.g, obj.p)
179 if safe and divmod(obj.p-1, ginv)[1]==0:
180 safe=0
181 if safe:
182 break
183 # Generate private key x
184 if progress_func:
185 progress_func('x\n')
186 obj.x=number.getRandomRange(2, obj.p-1, randfunc)
187 # Generate public key y
188 if progress_func:
189 progress_func('y\n')
190 obj.y = pow(obj.g, obj.x, obj.p)
191 return obj
192
193 def construct(tup):
194 """Construct an ElGamal key from a tuple of valid ElGamal components.
195
196 The modulus *p* must be a prime.
197
198 The following conditions must apply:
199
200 - 1 < g < p-1
201 - g^{p-1} = 1 mod p
202 - 1 < x < p-1
203 - g^x = y mod p
204
205 :Parameters:
206 tup : tuple
207 A tuple of long integers, with 3 or 4 items
208 in the following order:
209
210 1. Modulus (*p*).
211 2. Generator (*g*).
212 3. Public key (*y*).
213 4. Private key (*x*). Optional.
214
215 :Return: An ElGamal key object (`ElGamalobj`).
216 """
217
218 obj=ElGamalobj()
219 if len(tup) not in [3,4]:
220 raise ValueError('argument for construct() wrong length')
221 for i in range(len(tup)):
222 field = obj.keydata[i]
223 setattr(obj, field, tup[i])
224 return obj
225
226 class ElGamalobj(pubkey):
227 """Class defining an ElGamal key.
228
229 :undocumented: __getstate__, __setstate__, __repr__, __getattr__
230 """
231
232 #: Dictionary of ElGamal parameters.
233 #:
234 #: A public key will only have the following entries:
235 #:
236 #: - **y**, the public key.
237 #: - **g**, the generator.
238 #: - **p**, the modulus.
239 #:
240 #: A private key will also have:
241 #:
242 #: - **x**, the private key.
243 keydata=['p', 'g', 'y', 'x']
244
245 def encrypt(self, plaintext, K):
246 """Encrypt a piece of data with ElGamal.
247
248 :Parameter plaintext: The piece of data to encrypt with ElGamal.
249 It must be numerically smaller than the module (*p*).
250 :Type plaintext: byte string or long
251
252 :Parameter K: A secret number, chosen randomly in the closed
253 range *[1,p-2]*.
254 :Type K: long (recommended) or byte string (not recommended)
255
256 :Return: A tuple with two items. Each item is of the same type as the
257 plaintext (string or long).
258
259 :attention: selection of *K* is crucial for security. Generating a
260 random number larger than *p-1* and taking the modulus by *p-1* is
261 **not** secure, since smaller values will occur more frequently.
262 Generating a random number systematically smaller than *p-1*
263 (e.g. *floor((p-1)/8)* random bytes) is also **not** secure.
264 In general, it shall not be possible for an attacker to know
265 the value of any bit of K.
266
267 :attention: The number *K* shall not be reused for any other
268 operation and shall be discarded immediately.
269 """
270 return pubkey.encrypt(self, plaintext, K)
271
272 def decrypt(self, ciphertext):
273 """Decrypt a piece of data with ElGamal.
274
275 :Parameter ciphertext: The piece of data to decrypt with ElGamal.
276 :Type ciphertext: byte string, long or a 2-item tuple as returned
277 by `encrypt`
278
279 :Return: A byte string if ciphertext was a byte string or a tuple
280 of byte strings. A long otherwise.
281 """
282 return pubkey.decrypt(self, ciphertext)
283
284 def sign(self, M, K):
285 """Sign a piece of data with ElGamal.
286
287 :Parameter M: The piece of data to sign with ElGamal. It may
288 not be longer in bit size than *p-1*.
289 :Type M: byte string or long
290
291 :Parameter K: A secret number, chosen randomly in the closed
292 range *[1,p-2]* and such that *gcd(k,p-1)=1*.
293 :Type K: long (recommended) or byte string (not recommended)
294
295 :attention: selection of *K* is crucial for security. Generating a
296 random number larger than *p-1* and taking the modulus by *p-1* is
297 **not** secure, since smaller values will occur more frequently.
298 Generating a random number systematically smaller than *p-1*
299 (e.g. *floor((p-1)/8)* random bytes) is also **not** secure.
300 In general, it shall not be possible for an attacker to know
301 the value of any bit of K.
302
303 :attention: The number *K* shall not be reused for any other
304 operation and shall be discarded immediately.
305
306 :attention: M must be be a cryptographic hash, otherwise an
307 attacker may mount an existential forgery attack.
308
309 :Return: A tuple with 2 longs.
310 """
311 return pubkey.sign(self, M, K)
312
313 def verify(self, M, signature):
314 """Verify the validity of an ElGamal signature.
315
316 :Parameter M: The expected message.
317 :Type M: byte string or long
318
319 :Parameter signature: The ElGamal signature to verify.
320 :Type signature: A tuple with 2 longs as return by `sign`
321
322 :Return: True if the signature is correct, False otherwise.
323 """
324 return pubkey.verify(self, M, signature)
325
326 def _encrypt(self, M, K):
327 a=pow(self.g, K, self.p)
328 b=( M*pow(self.y, K, self.p) ) % self.p
329 return ( a,b )
330
331 def _decrypt(self, M):
332 if (not hasattr(self, 'x')):
333 raise TypeError('Private key not available in this object')
334 ax=pow(M[0], self.x, self.p)
335 plaintext=(M[1] * inverse(ax, self.p ) ) % self.p
336 return plaintext
337
338 def _sign(self, M, K):
339 if (not hasattr(self, 'x')):
340 raise TypeError('Private key not available in this object')
341 p1=self.p-1
342 if (GCD(K, p1)!=1):
343 raise ValueError('Bad K value: GCD(K,p-1)!=1')
344 a=pow(self.g, K, self.p)
345 t=(M-self.x*a) % p1
346 while t<0: t=t+p1
347 b=(t*inverse(K, p1)) % p1
348 return (a, b)
349
350 def _verify(self, M, sig):
351 if sig[0]<1 or sig[0]>self.p-1:
352 return 0
353 v1=pow(self.y, sig[0], self.p)
354 v1=(v1*pow(sig[0], sig[1], self.p)) % self.p
355 v2=pow(self.g, M, self.p)
356 if v1==v2:
357 return 1
358 return 0
359
360 def size(self):
361 return number.size(self.p) - 1
362
363 def has_private(self):
364 if hasattr(self, 'x'):
365 return 1
366 else:
367 return 0
368
369 def publickey(self):
370 return construct((self.p, self.g, self.y))
371
372
373 object=ElGamalobj
OLDNEW
« no previous file with comments | « third_party/google-endpoints/Crypto/PublicKey/DSA.py ('k') | third_party/google-endpoints/Crypto/PublicKey/RSA.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698