DH.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. from Crypto.Util.number import long_to_bytes
  2. from Crypto.PublicKey.ECC import (EccKey,
  3. construct,
  4. _import_curve25519_public_key,
  5. _import_curve448_public_key)
  6. def _compute_ecdh(key_priv, key_pub):
  7. pointP = key_pub.pointQ * key_priv.d
  8. if pointP.is_point_at_infinity():
  9. raise ValueError("Invalid ECDH point")
  10. if key_priv.curve == "Curve25519":
  11. z = bytearray(pointP.x.to_bytes(32, byteorder='little'))
  12. elif key_priv.curve == "Curve448":
  13. z = bytearray(pointP.x.to_bytes(56, byteorder='little'))
  14. else:
  15. # See Section 5.7.1.2 in NIST SP 800-56Ar3
  16. z = long_to_bytes(pointP.x, pointP.size_in_bytes())
  17. return z
  18. def import_x25519_public_key(encoded):
  19. """Create a new X25519 public key object,
  20. starting from the key encoded as raw ``bytes``,
  21. in the format described in RFC7748.
  22. Args:
  23. encoded (bytes):
  24. The x25519 public key to import.
  25. It must be 32 bytes.
  26. Returns:
  27. :class:`Crypto.PublicKey.EccKey` : a new ECC key object.
  28. Raises:
  29. ValueError: when the given key cannot be parsed.
  30. """
  31. x = _import_curve25519_public_key(encoded)
  32. return construct(curve='Curve25519', point_x=x)
  33. def import_x25519_private_key(encoded):
  34. """Create a new X25519 private key object,
  35. starting from the key encoded as raw ``bytes``,
  36. in the format described in RFC7748.
  37. Args:
  38. encoded (bytes):
  39. The X25519 private key to import.
  40. It must be 32 bytes.
  41. Returns:
  42. :class:`Crypto.PublicKey.EccKey` : a new ECC key object.
  43. Raises:
  44. ValueError: when the given key cannot be parsed.
  45. """
  46. return construct(seed=encoded, curve="Curve25519")
  47. def import_x448_public_key(encoded):
  48. """Create a new X448 public key object,
  49. starting from the key encoded as raw ``bytes``,
  50. in the format described in RFC7748.
  51. Args:
  52. encoded (bytes):
  53. The x448 public key to import.
  54. It must be 56 bytes.
  55. Returns:
  56. :class:`Crypto.PublicKey.EccKey` : a new ECC key object.
  57. Raises:
  58. ValueError: when the given key cannot be parsed.
  59. """
  60. x = _import_curve448_public_key(encoded)
  61. return construct(curve='Curve448', point_x=x)
  62. def import_x448_private_key(encoded):
  63. """Create a new X448 private key object,
  64. starting from the key encoded as raw ``bytes``,
  65. in the format described in RFC7748.
  66. Args:
  67. encoded (bytes):
  68. The X448 private key to import.
  69. It must be 56 bytes.
  70. Returns:
  71. :class:`Crypto.PublicKey.EccKey` : a new ECC key object.
  72. Raises:
  73. ValueError: when the given key cannot be parsed.
  74. """
  75. return construct(seed=encoded, curve="Curve448")
  76. def key_agreement(**kwargs):
  77. """Perform a Diffie-Hellman key agreement.
  78. Keywords:
  79. kdf (callable):
  80. A key derivation function that accepts ``bytes`` as input and returns
  81. ``bytes``.
  82. static_priv (EccKey):
  83. The local static private key. Optional.
  84. static_pub (EccKey):
  85. The static public key that belongs to the peer. Optional.
  86. eph_priv (EccKey):
  87. The local ephemeral private key, generated for this session. Optional.
  88. eph_pub (EccKey):
  89. The ephemeral public key, received from the peer for this session. Optional.
  90. At least two keys must be passed, of which one is a private key and one
  91. a public key.
  92. Returns (bytes):
  93. The derived secret key material.
  94. """
  95. static_priv = kwargs.get('static_priv', None)
  96. static_pub = kwargs.get('static_pub', None)
  97. eph_priv = kwargs.get('eph_priv', None)
  98. eph_pub = kwargs.get('eph_pub', None)
  99. kdf = kwargs.get('kdf', None)
  100. if kdf is None:
  101. raise ValueError("'kdf' is mandatory")
  102. count_priv = 0
  103. count_pub = 0
  104. curve = None
  105. def check_curve(curve, key, name, private):
  106. if not isinstance(key, EccKey):
  107. raise TypeError("'%s' must be an ECC key" % name)
  108. if private and not key.has_private():
  109. raise TypeError("'%s' must be a private ECC key" % name)
  110. if curve is None:
  111. curve = key.curve
  112. elif curve != key.curve:
  113. raise TypeError("'%s' is defined on an incompatible curve" % name)
  114. return curve
  115. if static_priv is not None:
  116. curve = check_curve(curve, static_priv, 'static_priv', True)
  117. count_priv += 1
  118. if static_pub is not None:
  119. curve = check_curve(curve, static_pub, 'static_pub', False)
  120. count_pub += 1
  121. if eph_priv is not None:
  122. curve = check_curve(curve, eph_priv, 'eph_priv', True)
  123. count_priv += 1
  124. if eph_pub is not None:
  125. curve = check_curve(curve, eph_pub, 'eph_pub', False)
  126. count_pub += 1
  127. if (count_priv + count_pub) < 2 or count_priv == 0 or count_pub == 0:
  128. raise ValueError("Too few keys for the ECDH key agreement")
  129. Zs = b''
  130. Ze = b''
  131. if static_priv and static_pub:
  132. # C(*, 2s)
  133. Zs = _compute_ecdh(static_priv, static_pub)
  134. if eph_priv and eph_pub:
  135. # C(2e, 0s) or C(2e, 2s)
  136. if bool(static_priv) != bool(static_pub):
  137. raise ValueError("DH mode C(2e, 1s) is not supported")
  138. Ze = _compute_ecdh(eph_priv, eph_pub)
  139. elif eph_priv and static_pub:
  140. # C(1e, 2s) or C(1e, 1s)
  141. Ze = _compute_ecdh(eph_priv, static_pub)
  142. elif eph_pub and static_priv:
  143. # C(1e, 2s) or C(1e, 1s)
  144. Ze = _compute_ecdh(static_priv, eph_pub)
  145. Z = Ze + Zs
  146. return kdf(Z)