padding.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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.hazmat.primitives import hashes
  7. from cryptography.hazmat.primitives._asymmetric import (
  8. AsymmetricPadding as AsymmetricPadding,
  9. )
  10. from cryptography.hazmat.primitives.asymmetric import rsa
  11. class PKCS1v15(AsymmetricPadding):
  12. name = "EMSA-PKCS1-v1_5"
  13. def __eq__(self, other: object) -> bool:
  14. if not isinstance(other, PKCS1v15):
  15. return NotImplemented
  16. return True
  17. class _MaxLength:
  18. "Sentinel value for `MAX_LENGTH`."
  19. class _Auto:
  20. "Sentinel value for `AUTO`."
  21. class _DigestLength:
  22. "Sentinel value for `DIGEST_LENGTH`."
  23. class PSS(AsymmetricPadding):
  24. MAX_LENGTH = _MaxLength()
  25. AUTO = _Auto()
  26. DIGEST_LENGTH = _DigestLength()
  27. name = "EMSA-PSS"
  28. _salt_length: int | _MaxLength | _Auto | _DigestLength
  29. def __init__(
  30. self,
  31. mgf: MGF,
  32. salt_length: int | _MaxLength | _Auto | _DigestLength,
  33. ) -> None:
  34. self._mgf = mgf
  35. if not isinstance(
  36. salt_length, (int, _MaxLength, _Auto, _DigestLength)
  37. ):
  38. raise TypeError(
  39. "salt_length must be an integer, MAX_LENGTH, "
  40. "DIGEST_LENGTH, or AUTO"
  41. )
  42. if isinstance(salt_length, int) and salt_length < 0:
  43. raise ValueError("salt_length must be zero or greater.")
  44. self._salt_length = salt_length
  45. def __eq__(self, other: object) -> bool:
  46. if not isinstance(other, PSS):
  47. return NotImplemented
  48. return (
  49. self._mgf == other._mgf and self._salt_length == other._salt_length
  50. )
  51. @property
  52. def mgf(self) -> MGF:
  53. return self._mgf
  54. class OAEP(AsymmetricPadding):
  55. name = "EME-OAEP"
  56. def __init__(
  57. self,
  58. mgf: MGF,
  59. algorithm: hashes.HashAlgorithm,
  60. label: bytes | None,
  61. ):
  62. if not isinstance(algorithm, hashes.HashAlgorithm):
  63. raise TypeError("Expected instance of hashes.HashAlgorithm.")
  64. self._mgf = mgf
  65. self._algorithm = algorithm
  66. self._label = label
  67. def __eq__(self, other: object) -> bool:
  68. if not isinstance(other, OAEP):
  69. return NotImplemented
  70. return (
  71. self._mgf == other._mgf
  72. and self._algorithm == other._algorithm
  73. and self._label == other._label
  74. )
  75. @property
  76. def algorithm(self) -> hashes.HashAlgorithm:
  77. return self._algorithm
  78. @property
  79. def mgf(self) -> MGF:
  80. return self._mgf
  81. class MGF(metaclass=abc.ABCMeta):
  82. _algorithm: hashes.HashAlgorithm
  83. class MGF1(MGF):
  84. def __init__(self, algorithm: hashes.HashAlgorithm):
  85. if not isinstance(algorithm, hashes.HashAlgorithm):
  86. raise TypeError("Expected instance of hashes.HashAlgorithm.")
  87. self._algorithm = algorithm
  88. def __eq__(self, other: object) -> bool:
  89. if not isinstance(other, MGF1):
  90. return NotImplemented
  91. return self._algorithm == other._algorithm
  92. def calculate_max_pss_salt_length(
  93. key: rsa.RSAPrivateKey | rsa.RSAPublicKey,
  94. hash_algorithm: hashes.HashAlgorithm,
  95. ) -> int:
  96. if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)):
  97. raise TypeError("key must be an RSA public or private key")
  98. # bit length - 1 per RFC 3447
  99. emlen = (key.key_size + 6) // 8
  100. salt_length = emlen - hash_algorithm.digest_size - 2
  101. assert salt_length >= 0
  102. return salt_length