ElGamal.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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. """ElGamal public-key algorithm (randomized encryption and signature).
  26. Signature algorithm
  27. -------------------
  28. The security of the ElGamal signature scheme is based (like DSA) on the discrete
  29. logarithm problem (DLP_). Given a cyclic group, a generator *g*,
  30. and an element *h*, it is hard to find an integer *x* such that *g^x = h*.
  31. The group is the largest multiplicative sub-group of the integers modulo *p*,
  32. with *p* prime.
  33. The signer holds a value *x* (*0<x<p-1*) as private key, and its public
  34. key (*y* where *y=g^x mod p*) is distributed.
  35. The ElGamal signature is twice as big as *p*.
  36. Encryption algorithm
  37. --------------------
  38. The security of the ElGamal encryption scheme is based on the computational
  39. Diffie-Hellman problem (CDH_). Given a cyclic group, a generator *g*,
  40. and two integers *a* and *b*, it is difficult to find
  41. the element *g^{ab}* when only *g^a* and *g^b* are known, and not *a* and *b*.
  42. As before, the group is the largest multiplicative sub-group of the integers
  43. modulo *p*, with *p* prime.
  44. The receiver holds a value *a* (*0<a<p-1*) as private key, and its public key
  45. (*b* where *b*=g^a*) is given to the sender.
  46. The ElGamal ciphertext is twice as big as *p*.
  47. Domain parameters
  48. -----------------
  49. For both signature and encryption schemes, the values *(p,g)* are called
  50. *domain parameters*.
  51. They are not sensitive but must be distributed to all parties (senders and
  52. receivers).
  53. Different signers can share the same domain parameters, as can
  54. different recipients of encrypted messages.
  55. Security
  56. --------
  57. Both DLP and CDH problem are believed to be difficult, and they have been proved
  58. such (and therefore secure) for more than 30 years.
  59. The cryptographic strength is linked to the magnitude of *p*.
  60. In 2012, a sufficient size for *p* is deemed to be 2048 bits.
  61. For more information, see the most recent ECRYPT_ report.
  62. Even though ElGamal algorithms are in theory reasonably secure for new designs,
  63. in practice there are no real good reasons for using them.
  64. The signature is four times larger than the equivalent DSA, and the ciphertext
  65. is two times larger than the equivalent RSA.
  66. Functionality
  67. -------------
  68. This module provides facilities for generating new ElGamal keys and for constructing
  69. them from known components. ElGamal keys allows you to perform basic signing,
  70. verification, encryption, and decryption.
  71. >>> from Crypto import Random
  72. >>> from Crypto.Random import random
  73. >>> from Crypto.PublicKey import ElGamal
  74. >>> from Crypto.Util.number import GCD
  75. >>> from Crypto.Hash import SHA
  76. >>>
  77. >>> message = "Hello"
  78. >>> key = ElGamal.generate(1024, Random.new().read)
  79. >>> h = SHA.new(message).digest()
  80. >>> while 1:
  81. >>> k = random.StrongRandom().randint(1,key.p-1)
  82. >>> if GCD(k,key.p-1)==1: break
  83. >>> sig = key.sign(h,k)
  84. >>> ...
  85. >>> if key.verify(h,sig):
  86. >>> print "OK"
  87. >>> else:
  88. >>> print "Incorrect signature"
  89. .. _DLP: http://www.cosic.esat.kuleuven.be/publications/talk-78.pdf
  90. .. _CDH: http://en.wikipedia.org/wiki/Computational_Diffie%E2%80%93Hellman_assumption
  91. .. _ECRYPT: http://www.ecrypt.eu.org/documents/D.SPA.17.pdf
  92. """
  93. __revision__ = "$Id$"
  94. __all__ = ['generate', 'construct', 'error', 'ElGamalobj']
  95. from Crypto.PublicKey.pubkey import *
  96. from Crypto.Util import number
  97. class error (Exception):
  98. pass
  99. # Generate an ElGamal key with N bits
  100. def generate(bits, randfunc, progress_func=None):
  101. """Randomly generate a fresh, new ElGamal key.
  102. The key will be safe for use for both encryption and signature
  103. (although it should be used for **only one** purpose).
  104. :Parameters:
  105. bits : int
  106. Key length, or size (in bits) of the modulus *p*.
  107. Recommended value is 2048.
  108. randfunc : callable
  109. Random number generation function; it should accept
  110. a single integer N and return a string of random data
  111. N bytes long.
  112. progress_func : callable
  113. Optional function that will be called with a short string
  114. containing the key parameter currently being generated;
  115. it's useful for interactive applications where a user is
  116. waiting for a key to be generated.
  117. :attention: You should always use a cryptographically secure random number generator,
  118. such as the one defined in the ``Crypto.Random`` module; **don't** just use the
  119. current time and the ``random`` module.
  120. :Return: An ElGamal key object (`ElGamalobj`).
  121. """
  122. obj=ElGamalobj()
  123. # Generate a safe prime p
  124. # See Algorithm 4.86 in Handbook of Applied Cryptography
  125. if progress_func:
  126. progress_func('p\n')
  127. while 1:
  128. q = bignum(getPrime(bits-1, randfunc))
  129. obj.p = 2*q+1
  130. if number.isPrime(obj.p, randfunc=randfunc):
  131. break
  132. # Generate generator g
  133. # See Algorithm 4.80 in Handbook of Applied Cryptography
  134. # Note that the order of the group is n=p-1=2q, where q is prime
  135. if progress_func:
  136. progress_func('g\n')
  137. while 1:
  138. # We must avoid g=2 because of Bleichenbacher's attack described
  139. # in "Generating ElGamal signatures without knowning the secret key",
  140. # 1996
  141. #
  142. obj.g = number.getRandomRange(3, obj.p, randfunc)
  143. safe = 1
  144. if pow(obj.g, 2, obj.p)==1:
  145. safe=0
  146. if safe and pow(obj.g, q, obj.p)==1:
  147. safe=0
  148. # Discard g if it divides p-1 because of the attack described
  149. # in Note 11.67 (iii) in HAC
  150. if safe and divmod(obj.p-1, obj.g)[1]==0:
  151. safe=0
  152. # g^{-1} must not divide p-1 because of Khadir's attack
  153. # described in "Conditions of the generator for forging ElGamal
  154. # signature", 2011
  155. ginv = number.inverse(obj.g, obj.p)
  156. if safe and divmod(obj.p-1, ginv)[1]==0:
  157. safe=0
  158. if safe:
  159. break
  160. # Generate private key x
  161. if progress_func:
  162. progress_func('x\n')
  163. obj.x=number.getRandomRange(2, obj.p-1, randfunc)
  164. # Generate public key y
  165. if progress_func:
  166. progress_func('y\n')
  167. obj.y = pow(obj.g, obj.x, obj.p)
  168. return obj
  169. def construct(tup):
  170. """Construct an ElGamal key from a tuple of valid ElGamal components.
  171. The modulus *p* must be a prime.
  172. The following conditions must apply:
  173. - 1 < g < p-1
  174. - g^{p-1} = 1 mod p
  175. - 1 < x < p-1
  176. - g^x = y mod p
  177. :Parameters:
  178. tup : tuple
  179. A tuple of long integers, with 3 or 4 items
  180. in the following order:
  181. 1. Modulus (*p*).
  182. 2. Generator (*g*).
  183. 3. Public key (*y*).
  184. 4. Private key (*x*). Optional.
  185. :Return: An ElGamal key object (`ElGamalobj`).
  186. """
  187. obj=ElGamalobj()
  188. if len(tup) not in [3,4]:
  189. raise ValueError('argument for construct() wrong length')
  190. for i in range(len(tup)):
  191. field = obj.keydata[i]
  192. setattr(obj, field, tup[i])
  193. return obj
  194. class ElGamalobj(pubkey):
  195. """Class defining an ElGamal key.
  196. :undocumented: __getstate__, __setstate__, __repr__, __getattr__
  197. """
  198. #: Dictionary of ElGamal parameters.
  199. #:
  200. #: A public key will only have the following entries:
  201. #:
  202. #: - **y**, the public key.
  203. #: - **g**, the generator.
  204. #: - **p**, the modulus.
  205. #:
  206. #: A private key will also have:
  207. #:
  208. #: - **x**, the private key.
  209. keydata=['p', 'g', 'y', 'x']
  210. def encrypt(self, plaintext, K):
  211. """Encrypt a piece of data with ElGamal.
  212. :Parameter plaintext: The piece of data to encrypt with ElGamal.
  213. It must be numerically smaller than the module (*p*).
  214. :Type plaintext: byte string or long
  215. :Parameter K: A secret number, chosen randomly in the closed
  216. range *[1,p-2]*.
  217. :Type K: long (recommended) or byte string (not recommended)
  218. :Return: A tuple with two items. Each item is of the same type as the
  219. plaintext (string or long).
  220. :attention: selection of *K* is crucial for security. Generating a
  221. random number larger than *p-1* and taking the modulus by *p-1* is
  222. **not** secure, since smaller values will occur more frequently.
  223. Generating a random number systematically smaller than *p-1*
  224. (e.g. *floor((p-1)/8)* random bytes) is also **not** secure.
  225. In general, it shall not be possible for an attacker to know
  226. the value of any bit of K.
  227. :attention: The number *K* shall not be reused for any other
  228. operation and shall be discarded immediately.
  229. """
  230. return pubkey.encrypt(self, plaintext, K)
  231. def decrypt(self, ciphertext):
  232. """Decrypt a piece of data with ElGamal.
  233. :Parameter ciphertext: The piece of data to decrypt with ElGamal.
  234. :Type ciphertext: byte string, long or a 2-item tuple as returned
  235. by `encrypt`
  236. :Return: A byte string if ciphertext was a byte string or a tuple
  237. of byte strings. A long otherwise.
  238. """
  239. return pubkey.decrypt(self, ciphertext)
  240. def sign(self, M, K):
  241. """Sign a piece of data with ElGamal.
  242. :Parameter M: The piece of data to sign with ElGamal. It may
  243. not be longer in bit size than *p-1*.
  244. :Type M: byte string or long
  245. :Parameter K: A secret number, chosen randomly in the closed
  246. range *[1,p-2]* and such that *gcd(k,p-1)=1*.
  247. :Type K: long (recommended) or byte string (not recommended)
  248. :attention: selection of *K* is crucial for security. Generating a
  249. random number larger than *p-1* and taking the modulus by *p-1* is
  250. **not** secure, since smaller values will occur more frequently.
  251. Generating a random number systematically smaller than *p-1*
  252. (e.g. *floor((p-1)/8)* random bytes) is also **not** secure.
  253. In general, it shall not be possible for an attacker to know
  254. the value of any bit of K.
  255. :attention: The number *K* shall not be reused for any other
  256. operation and shall be discarded immediately.
  257. :attention: M must be be a cryptographic hash, otherwise an
  258. attacker may mount an existential forgery attack.
  259. :Return: A tuple with 2 longs.
  260. """
  261. return pubkey.sign(self, M, K)
  262. def verify(self, M, signature):
  263. """Verify the validity of an ElGamal signature.
  264. :Parameter M: The expected message.
  265. :Type M: byte string or long
  266. :Parameter signature: The ElGamal signature to verify.
  267. :Type signature: A tuple with 2 longs as return by `sign`
  268. :Return: True if the signature is correct, False otherwise.
  269. """
  270. return pubkey.verify(self, M, signature)
  271. def _encrypt(self, M, K):
  272. a=pow(self.g, K, self.p)
  273. b=( M*pow(self.y, K, self.p) ) % self.p
  274. return ( a,b )
  275. def _decrypt(self, M):
  276. if (not hasattr(self, 'x')):
  277. raise TypeError('Private key not available in this object')
  278. ax=pow(M[0], self.x, self.p)
  279. plaintext=(M[1] * inverse(ax, self.p ) ) % self.p
  280. return plaintext
  281. def _sign(self, M, K):
  282. if (not hasattr(self, 'x')):
  283. raise TypeError('Private key not available in this object')
  284. p1=self.p-1
  285. if (GCD(K, p1)!=1):
  286. raise ValueError('Bad K value: GCD(K,p-1)!=1')
  287. a=pow(self.g, K, self.p)
  288. t=(M-self.x*a) % p1
  289. while t<0: t=t+p1
  290. b=(t*inverse(K, p1)) % p1
  291. return (a, b)
  292. def _verify(self, M, sig):
  293. if sig[0]<1 or sig[0]>self.p-1:
  294. return 0
  295. v1=pow(self.y, sig[0], self.p)
  296. v1=(v1*pow(sig[0], sig[1], self.p)) % self.p
  297. v2=pow(self.g, M, self.p)
  298. if v1==v2:
  299. return 1
  300. return 0
  301. def size(self):
  302. return number.size(self.p) - 1
  303. def has_private(self):
  304. if hasattr(self, 'x'):
  305. return 1
  306. else:
  307. return 0
  308. def publickey(self):
  309. return construct((self.p, self.g, self.y))
  310. object=ElGamalobj