dsa.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import struct
  2. from cryptography.hazmat.backends import default_backend
  3. from cryptography.hazmat.primitives import hashes
  4. from cryptography.hazmat.primitives.asymmetric import dsa, utils
  5. from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey
  6. from dns.dnssectypes import Algorithm
  7. from dns.rdtypes.ANY.DNSKEY import DNSKEY
  8. class PublicDSA(CryptographyPublicKey):
  9. key: dsa.DSAPublicKey
  10. key_cls = dsa.DSAPublicKey
  11. algorithm = Algorithm.DSA
  12. chosen_hash = hashes.SHA1()
  13. def verify(self, signature: bytes, data: bytes) -> None:
  14. sig_r = signature[1:21]
  15. sig_s = signature[21:]
  16. sig = utils.encode_dss_signature(
  17. int.from_bytes(sig_r, "big"), int.from_bytes(sig_s, "big")
  18. )
  19. self.key.verify(sig, data, self.chosen_hash)
  20. def encode_key_bytes(self) -> bytes:
  21. """Encode a public key per RFC 2536, section 2."""
  22. pn = self.key.public_numbers()
  23. dsa_t = (self.key.key_size // 8 - 64) // 8
  24. if dsa_t > 8:
  25. raise ValueError("unsupported DSA key size")
  26. octets = 64 + dsa_t * 8
  27. res = struct.pack("!B", dsa_t)
  28. res += pn.parameter_numbers.q.to_bytes(20, "big")
  29. res += pn.parameter_numbers.p.to_bytes(octets, "big")
  30. res += pn.parameter_numbers.g.to_bytes(octets, "big")
  31. res += pn.y.to_bytes(octets, "big")
  32. return res
  33. @classmethod
  34. def from_dnskey(cls, key: DNSKEY) -> "PublicDSA":
  35. cls._ensure_algorithm_key_combination(key)
  36. keyptr = key.key
  37. (t,) = struct.unpack("!B", keyptr[0:1])
  38. keyptr = keyptr[1:]
  39. octets = 64 + t * 8
  40. dsa_q = keyptr[0:20]
  41. keyptr = keyptr[20:]
  42. dsa_p = keyptr[0:octets]
  43. keyptr = keyptr[octets:]
  44. dsa_g = keyptr[0:octets]
  45. keyptr = keyptr[octets:]
  46. dsa_y = keyptr[0:octets]
  47. return cls(
  48. key=dsa.DSAPublicNumbers( # type: ignore
  49. int.from_bytes(dsa_y, "big"),
  50. dsa.DSAParameterNumbers(
  51. int.from_bytes(dsa_p, "big"),
  52. int.from_bytes(dsa_q, "big"),
  53. int.from_bytes(dsa_g, "big"),
  54. ),
  55. ).public_key(default_backend()),
  56. )
  57. class PrivateDSA(CryptographyPrivateKey):
  58. key: dsa.DSAPrivateKey
  59. key_cls = dsa.DSAPrivateKey
  60. public_cls = PublicDSA
  61. def sign(
  62. self,
  63. data: bytes,
  64. verify: bool = False,
  65. deterministic: bool = True,
  66. ) -> bytes:
  67. """Sign using a private key per RFC 2536, section 3."""
  68. public_dsa_key = self.key.public_key()
  69. if public_dsa_key.key_size > 1024:
  70. raise ValueError("DSA key size overflow")
  71. der_signature = self.key.sign(
  72. data, self.public_cls.chosen_hash # pyright: ignore
  73. )
  74. dsa_r, dsa_s = utils.decode_dss_signature(der_signature)
  75. dsa_t = (public_dsa_key.key_size // 8 - 64) // 8
  76. octets = 20
  77. signature = (
  78. struct.pack("!B", dsa_t)
  79. + int.to_bytes(dsa_r, length=octets, byteorder="big")
  80. + int.to_bytes(dsa_s, length=octets, byteorder="big")
  81. )
  82. if verify:
  83. self.public_key().verify(signature, data)
  84. return signature
  85. @classmethod
  86. def generate(cls, key_size: int) -> "PrivateDSA":
  87. return cls(
  88. key=dsa.generate_private_key(key_size=key_size),
  89. )
  90. class PublicDSANSEC3SHA1(PublicDSA):
  91. algorithm = Algorithm.DSANSEC3SHA1
  92. class PrivateDSANSEC3SHA1(PrivateDSA):
  93. public_cls = PublicDSANSEC3SHA1