ecdsa.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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, deterministic_signing=deterministic
  50. )
  51. der_signature = self.key.sign(data, algorithm)
  52. dsa_r, dsa_s = utils.decode_dss_signature(der_signature)
  53. signature = int.to_bytes(
  54. dsa_r, length=self.public_cls.octets, byteorder="big"
  55. ) + int.to_bytes(dsa_s, length=self.public_cls.octets, byteorder="big")
  56. if verify:
  57. self.public_key().verify(signature, data)
  58. return signature
  59. @classmethod
  60. def generate(cls) -> "PrivateECDSA":
  61. return cls(
  62. key=ec.generate_private_key(
  63. curve=cls.public_cls.curve, backend=default_backend()
  64. ),
  65. )
  66. class PublicECDSAP256SHA256(PublicECDSA):
  67. algorithm = Algorithm.ECDSAP256SHA256
  68. chosen_hash = hashes.SHA256()
  69. curve = ec.SECP256R1()
  70. octets = 32
  71. class PrivateECDSAP256SHA256(PrivateECDSA):
  72. public_cls = PublicECDSAP256SHA256
  73. class PublicECDSAP384SHA384(PublicECDSA):
  74. algorithm = Algorithm.ECDSAP384SHA384
  75. chosen_hash = hashes.SHA384()
  76. curve = ec.SECP384R1()
  77. octets = 48
  78. class PrivateECDSAP384SHA384(PrivateECDSA):
  79. public_cls = PublicECDSAP384SHA384