dsa.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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(data, self.public_cls.chosen_hash)
  72. dsa_r, dsa_s = utils.decode_dss_signature(der_signature)
  73. dsa_t = (public_dsa_key.key_size // 8 - 64) // 8
  74. octets = 20
  75. signature = (
  76. struct.pack("!B", dsa_t)
  77. + int.to_bytes(dsa_r, length=octets, byteorder="big")
  78. + int.to_bytes(dsa_s, length=octets, byteorder="big")
  79. )
  80. if verify:
  81. self.public_key().verify(signature, data)
  82. return signature
  83. @classmethod
  84. def generate(cls, key_size: int) -> "PrivateDSA":
  85. return cls(
  86. key=dsa.generate_private_key(key_size=key_size),
  87. )
  88. class PublicDSANSEC3SHA1(PublicDSA):
  89. algorithm = Algorithm.DSANSEC3SHA1
  90. class PrivateDSANSEC3SHA1(PrivateDSA):
  91. public_cls = PublicDSANSEC3SHA1