OLD | NEW |
(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 |
OLD | NEW |