dh.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. import abc
  5. import typing
  6. from cryptography.hazmat.primitives import _serialization
  7. _MIN_MODULUS_SIZE = 512
  8. def generate_parameters(
  9. generator: int, key_size: int, backend: typing.Any = None
  10. ) -> "DHParameters":
  11. from cryptography.hazmat.backends.openssl.backend import backend as ossl
  12. return ossl.generate_dh_parameters(generator, key_size)
  13. class DHParameterNumbers:
  14. def __init__(self, p: int, g: int, q: typing.Optional[int] = None) -> None:
  15. if not isinstance(p, int) or not isinstance(g, int):
  16. raise TypeError("p and g must be integers")
  17. if q is not None and not isinstance(q, int):
  18. raise TypeError("q must be integer or None")
  19. if g < 2:
  20. raise ValueError("DH generator must be 2 or greater")
  21. if p.bit_length() < _MIN_MODULUS_SIZE:
  22. raise ValueError(
  23. "p (modulus) must be at least {}-bit".format(_MIN_MODULUS_SIZE)
  24. )
  25. self._p = p
  26. self._g = g
  27. self._q = q
  28. def __eq__(self, other: object) -> bool:
  29. if not isinstance(other, DHParameterNumbers):
  30. return NotImplemented
  31. return (
  32. self._p == other._p and self._g == other._g and self._q == other._q
  33. )
  34. def parameters(self, backend: typing.Any = None) -> "DHParameters":
  35. from cryptography.hazmat.backends.openssl.backend import (
  36. backend as ossl,
  37. )
  38. return ossl.load_dh_parameter_numbers(self)
  39. @property
  40. def p(self) -> int:
  41. return self._p
  42. @property
  43. def g(self) -> int:
  44. return self._g
  45. @property
  46. def q(self) -> typing.Optional[int]:
  47. return self._q
  48. class DHPublicNumbers:
  49. def __init__(self, y: int, parameter_numbers: DHParameterNumbers) -> None:
  50. if not isinstance(y, int):
  51. raise TypeError("y must be an integer.")
  52. if not isinstance(parameter_numbers, DHParameterNumbers):
  53. raise TypeError(
  54. "parameters must be an instance of DHParameterNumbers."
  55. )
  56. self._y = y
  57. self._parameter_numbers = parameter_numbers
  58. def __eq__(self, other: object) -> bool:
  59. if not isinstance(other, DHPublicNumbers):
  60. return NotImplemented
  61. return (
  62. self._y == other._y
  63. and self._parameter_numbers == other._parameter_numbers
  64. )
  65. def public_key(self, backend: typing.Any = None) -> "DHPublicKey":
  66. from cryptography.hazmat.backends.openssl.backend import (
  67. backend as ossl,
  68. )
  69. return ossl.load_dh_public_numbers(self)
  70. @property
  71. def y(self) -> int:
  72. return self._y
  73. @property
  74. def parameter_numbers(self) -> DHParameterNumbers:
  75. return self._parameter_numbers
  76. class DHPrivateNumbers:
  77. def __init__(self, x: int, public_numbers: DHPublicNumbers) -> None:
  78. if not isinstance(x, int):
  79. raise TypeError("x must be an integer.")
  80. if not isinstance(public_numbers, DHPublicNumbers):
  81. raise TypeError(
  82. "public_numbers must be an instance of " "DHPublicNumbers."
  83. )
  84. self._x = x
  85. self._public_numbers = public_numbers
  86. def __eq__(self, other: object) -> bool:
  87. if not isinstance(other, DHPrivateNumbers):
  88. return NotImplemented
  89. return (
  90. self._x == other._x
  91. and self._public_numbers == other._public_numbers
  92. )
  93. def private_key(self, backend: typing.Any = None) -> "DHPrivateKey":
  94. from cryptography.hazmat.backends.openssl.backend import (
  95. backend as ossl,
  96. )
  97. return ossl.load_dh_private_numbers(self)
  98. @property
  99. def public_numbers(self) -> DHPublicNumbers:
  100. return self._public_numbers
  101. @property
  102. def x(self) -> int:
  103. return self._x
  104. class DHParameters(metaclass=abc.ABCMeta):
  105. @abc.abstractmethod
  106. def generate_private_key(self) -> "DHPrivateKey":
  107. """
  108. Generates and returns a DHPrivateKey.
  109. """
  110. @abc.abstractmethod
  111. def parameter_bytes(
  112. self,
  113. encoding: _serialization.Encoding,
  114. format: _serialization.ParameterFormat,
  115. ) -> bytes:
  116. """
  117. Returns the parameters serialized as bytes.
  118. """
  119. @abc.abstractmethod
  120. def parameter_numbers(self) -> DHParameterNumbers:
  121. """
  122. Returns a DHParameterNumbers.
  123. """
  124. DHParametersWithSerialization = DHParameters
  125. class DHPublicKey(metaclass=abc.ABCMeta):
  126. @abc.abstractproperty
  127. def key_size(self) -> int:
  128. """
  129. The bit length of the prime modulus.
  130. """
  131. @abc.abstractmethod
  132. def parameters(self) -> DHParameters:
  133. """
  134. The DHParameters object associated with this public key.
  135. """
  136. @abc.abstractmethod
  137. def public_numbers(self) -> DHPublicNumbers:
  138. """
  139. Returns a DHPublicNumbers.
  140. """
  141. @abc.abstractmethod
  142. def public_bytes(
  143. self,
  144. encoding: _serialization.Encoding,
  145. format: _serialization.PublicFormat,
  146. ) -> bytes:
  147. """
  148. Returns the key serialized as bytes.
  149. """
  150. DHPublicKeyWithSerialization = DHPublicKey
  151. class DHPrivateKey(metaclass=abc.ABCMeta):
  152. @abc.abstractproperty
  153. def key_size(self) -> int:
  154. """
  155. The bit length of the prime modulus.
  156. """
  157. @abc.abstractmethod
  158. def public_key(self) -> DHPublicKey:
  159. """
  160. The DHPublicKey associated with this private key.
  161. """
  162. @abc.abstractmethod
  163. def parameters(self) -> DHParameters:
  164. """
  165. The DHParameters object associated with this private key.
  166. """
  167. @abc.abstractmethod
  168. def exchange(self, peer_public_key: DHPublicKey) -> bytes:
  169. """
  170. Given peer's DHPublicKey, carry out the key exchange and
  171. return shared key as bytes.
  172. """
  173. @abc.abstractmethod
  174. def private_numbers(self) -> DHPrivateNumbers:
  175. """
  176. Returns a DHPrivateNumbers.
  177. """
  178. @abc.abstractmethod
  179. def private_bytes(
  180. self,
  181. encoding: _serialization.Encoding,
  182. format: _serialization.PrivateFormat,
  183. encryption_algorithm: _serialization.KeySerializationEncryption,
  184. ) -> bytes:
  185. """
  186. Returns the key serialized as bytes.
  187. """
  188. DHPrivateKeyWithSerialization = DHPrivateKey