ecdsa.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. from cryptography.hazmat.backends import default_backend
  2. from cryptography.hazmat.primitives import hashes
  3. from cryptography.hazmat.primitives.asymmetric import ec, utils
  4. from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey
  5. from dns.dnssectypes import Algorithm
  6. from dns.rdtypes.ANY.DNSKEY import DNSKEY
  7. class PublicECDSA(CryptographyPublicKey):
  8. key: ec.EllipticCurvePublicKey
  9. key_cls = ec.EllipticCurvePublicKey
  10. algorithm: Algorithm
  11. chosen_hash: hashes.HashAlgorithm
  12. curve: ec.EllipticCurve
  13. octets: int
  14. def verify(self, signature: bytes, data: bytes) -> None:
  15. sig_r = signature[0 : self.octets]
  16. sig_s = signature[self.octets :]
  17. sig = utils.encode_dss_signature(
  18. int.from_bytes(sig_r, "big"), int.from_bytes(sig_s, "big")
  19. )
  20. self.key.verify(sig, data, ec.ECDSA(self.chosen_hash))
  21. def encode_key_bytes(self) -> bytes:
  22. """Encode a public key per RFC 6605, section 4."""
  23. pn = self.key.public_numbers()
  24. return pn.x.to_bytes(self.octets, "big") + pn.y.to_bytes(self.octets, "big")
  25. @classmethod
  26. def from_dnskey(cls, key: DNSKEY) -> "PublicECDSA":
  27. cls._ensure_algorithm_key_combination(key)
  28. ecdsa_x = key.key[0 : cls.octets]
  29. ecdsa_y = key.key[cls.octets : cls.octets * 2]
  30. return cls(
  31. key=ec.EllipticCurvePublicNumbers(
  32. curve=cls.curve,
  33. x=int.from_bytes(ecdsa_x, "big"),
  34. y=int.from_bytes(ecdsa_y, "big"),
  35. ).public_key(default_backend()),
  36. )
  37. class PrivateECDSA(CryptographyPrivateKey):
  38. key: ec.EllipticCurvePrivateKey
  39. key_cls = ec.EllipticCurvePrivateKey
  40. public_cls = PublicECDSA
  41. def sign(
  42. self,
  43. data: bytes,
  44. verify: bool = False,
  45. deterministic: bool = True,
  46. ) -> bytes:
  47. """Sign using a private key per RFC 6605, section 4."""
  48. algorithm = ec.ECDSA(
  49. self.public_cls.chosen_hash, # pyright: ignore
  50. deterministic_signing=deterministic,
  51. )
  52. der_signature = self.key.sign(data, algorithm)
  53. dsa_r, dsa_s = utils.decode_dss_signature(der_signature)
  54. signature = int.to_bytes(
  55. dsa_r, length=self.public_cls.octets, byteorder="big" # pyright: ignore
  56. ) + int.to_bytes(
  57. dsa_s, length=self.public_cls.octets, byteorder="big" # pyright: ignore
  58. )
  59. if verify:
  60. self.public_key().verify(signature, data)
  61. return signature
  62. @classmethod
  63. def generate(cls) -> "PrivateECDSA":
  64. return cls(
  65. key=ec.generate_private_key(
  66. curve=cls.public_cls.curve, backend=default_backend() # pyright: ignore
  67. ),
  68. )
  69. class PublicECDSAP256SHA256(PublicECDSA):
  70. algorithm = Algorithm.ECDSAP256SHA256
  71. chosen_hash = hashes.SHA256()
  72. curve = ec.SECP256R1()
  73. octets = 32
  74. class PrivateECDSAP256SHA256(PrivateECDSA):
  75. public_cls = PublicECDSAP256SHA256
  76. class PublicECDSAP384SHA384(PublicECDSA):
  77. algorithm = Algorithm.ECDSAP384SHA384
  78. chosen_hash = hashes.SHA384()
  79. curve = ec.SECP384R1()
  80. octets = 48
  81. class PrivateECDSAP384SHA384(PrivateECDSA):
  82. public_cls = PublicECDSAP384SHA384