_serialization.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. from __future__ import annotations
  5. import abc
  6. from cryptography import utils
  7. from cryptography.hazmat.primitives.hashes import HashAlgorithm
  8. # This exists to break an import cycle. These classes are normally accessible
  9. # from the serialization module.
  10. class PBES(utils.Enum):
  11. PBESv1SHA1And3KeyTripleDESCBC = "PBESv1 using SHA1 and 3-Key TripleDES"
  12. PBESv2SHA256AndAES256CBC = "PBESv2 using SHA256 PBKDF2 and AES256 CBC"
  13. class Encoding(utils.Enum):
  14. PEM = "PEM"
  15. DER = "DER"
  16. OpenSSH = "OpenSSH"
  17. Raw = "Raw"
  18. X962 = "ANSI X9.62"
  19. SMIME = "S/MIME"
  20. class PrivateFormat(utils.Enum):
  21. PKCS8 = "PKCS8"
  22. TraditionalOpenSSL = "TraditionalOpenSSL"
  23. Raw = "Raw"
  24. OpenSSH = "OpenSSH"
  25. PKCS12 = "PKCS12"
  26. def encryption_builder(self) -> KeySerializationEncryptionBuilder:
  27. if self not in (PrivateFormat.OpenSSH, PrivateFormat.PKCS12):
  28. raise ValueError(
  29. "encryption_builder only supported with PrivateFormat.OpenSSH"
  30. " and PrivateFormat.PKCS12"
  31. )
  32. return KeySerializationEncryptionBuilder(self)
  33. class PublicFormat(utils.Enum):
  34. SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1"
  35. PKCS1 = "Raw PKCS#1"
  36. OpenSSH = "OpenSSH"
  37. Raw = "Raw"
  38. CompressedPoint = "X9.62 Compressed Point"
  39. UncompressedPoint = "X9.62 Uncompressed Point"
  40. class ParameterFormat(utils.Enum):
  41. PKCS3 = "PKCS3"
  42. class KeySerializationEncryption(metaclass=abc.ABCMeta):
  43. pass
  44. class BestAvailableEncryption(KeySerializationEncryption):
  45. def __init__(self, password: bytes):
  46. if not isinstance(password, bytes) or len(password) == 0:
  47. raise ValueError("Password must be 1 or more bytes.")
  48. self.password = password
  49. class NoEncryption(KeySerializationEncryption):
  50. pass
  51. class KeySerializationEncryptionBuilder:
  52. def __init__(
  53. self,
  54. format: PrivateFormat,
  55. *,
  56. _kdf_rounds: int | None = None,
  57. _hmac_hash: HashAlgorithm | None = None,
  58. _key_cert_algorithm: PBES | None = None,
  59. ) -> None:
  60. self._format = format
  61. self._kdf_rounds = _kdf_rounds
  62. self._hmac_hash = _hmac_hash
  63. self._key_cert_algorithm = _key_cert_algorithm
  64. def kdf_rounds(self, rounds: int) -> KeySerializationEncryptionBuilder:
  65. if self._kdf_rounds is not None:
  66. raise ValueError("kdf_rounds already set")
  67. if not isinstance(rounds, int):
  68. raise TypeError("kdf_rounds must be an integer")
  69. if rounds < 1:
  70. raise ValueError("kdf_rounds must be a positive integer")
  71. return KeySerializationEncryptionBuilder(
  72. self._format,
  73. _kdf_rounds=rounds,
  74. _hmac_hash=self._hmac_hash,
  75. _key_cert_algorithm=self._key_cert_algorithm,
  76. )
  77. def hmac_hash(
  78. self, algorithm: HashAlgorithm
  79. ) -> KeySerializationEncryptionBuilder:
  80. if self._format is not PrivateFormat.PKCS12:
  81. raise TypeError(
  82. "hmac_hash only supported with PrivateFormat.PKCS12"
  83. )
  84. if self._hmac_hash is not None:
  85. raise ValueError("hmac_hash already set")
  86. return KeySerializationEncryptionBuilder(
  87. self._format,
  88. _kdf_rounds=self._kdf_rounds,
  89. _hmac_hash=algorithm,
  90. _key_cert_algorithm=self._key_cert_algorithm,
  91. )
  92. def key_cert_algorithm(
  93. self, algorithm: PBES
  94. ) -> KeySerializationEncryptionBuilder:
  95. if self._format is not PrivateFormat.PKCS12:
  96. raise TypeError(
  97. "key_cert_algorithm only supported with "
  98. "PrivateFormat.PKCS12"
  99. )
  100. if self._key_cert_algorithm is not None:
  101. raise ValueError("key_cert_algorithm already set")
  102. return KeySerializationEncryptionBuilder(
  103. self._format,
  104. _kdf_rounds=self._kdf_rounds,
  105. _hmac_hash=self._hmac_hash,
  106. _key_cert_algorithm=algorithm,
  107. )
  108. def build(self, password: bytes) -> KeySerializationEncryption:
  109. if not isinstance(password, bytes) or len(password) == 0:
  110. raise ValueError("Password must be 1 or more bytes.")
  111. return _KeySerializationEncryption(
  112. self._format,
  113. password,
  114. kdf_rounds=self._kdf_rounds,
  115. hmac_hash=self._hmac_hash,
  116. key_cert_algorithm=self._key_cert_algorithm,
  117. )
  118. class _KeySerializationEncryption(KeySerializationEncryption):
  119. def __init__(
  120. self,
  121. format: PrivateFormat,
  122. password: bytes,
  123. *,
  124. kdf_rounds: int | None,
  125. hmac_hash: HashAlgorithm | None,
  126. key_cert_algorithm: PBES | None,
  127. ):
  128. self._format = format
  129. self.password = password
  130. self._kdf_rounds = kdf_rounds
  131. self._hmac_hash = hmac_hash
  132. self._key_cert_algorithm = key_cert_algorithm