Skip to content

Commit 53fb74b

Browse files
committed
Remove old impl of registery
1 parent 61d4c0a commit 53fb74b

File tree

7 files changed

+68
-180
lines changed

7 files changed

+68
-180
lines changed

src/cryptography/hazmat/backends/openssl/backend.py

Lines changed: 2 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import collections
88
import contextlib
9-
import itertools
109
import typing
1110

1211
from cryptography import utils, x509
@@ -33,27 +32,9 @@
3332
)
3433
from cryptography.hazmat.primitives.ciphers.algorithms import (
3534
AES,
36-
AES128,
37-
AES256,
38-
ARC4,
39-
SM4,
40-
Camellia,
41-
ChaCha20,
42-
TripleDES,
43-
_BlowfishInternal,
44-
_CAST5Internal,
45-
_IDEAInternal,
46-
_SEEDInternal,
4735
)
4836
from cryptography.hazmat.primitives.ciphers.modes import (
4937
CBC,
50-
CFB,
51-
CFB8,
52-
CTR,
53-
ECB,
54-
GCM,
55-
OFB,
56-
XTS,
5738
Mode,
5839
)
5940
from cryptography.hazmat.primitives.serialization.pkcs12 import (
@@ -69,7 +50,7 @@
6950

7051
# Not actually supported, just used as a marker for some serialization tests.
7152
class _RC2:
72-
pass
53+
key_size = 128
7354

7455

7556
class Backend:
@@ -128,12 +109,6 @@ def __init__(self) -> None:
128109
self._lib = self._binding.lib
129110
self._fips_enabled = rust_openssl.is_fips_enabled()
130111

131-
self._cipher_registry: dict[
132-
tuple[type[CipherAlgorithm], type[Mode]],
133-
typing.Callable,
134-
] = {}
135-
self._register_default_ciphers()
136-
137112
def __repr__(self) -> str:
138113
return "<OpenSSLBackend(version: {}, FIPS: {}, Legacy: {})>".format(
139114
self.openssl_version_text(),
@@ -217,93 +192,7 @@ def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool:
217192
if not isinstance(cipher, self._fips_ciphers):
218193
return False
219194

220-
try:
221-
adapter = self._cipher_registry[type(cipher), type(mode)]
222-
except KeyError:
223-
return False
224-
evp_cipher = adapter(self, cipher, mode)
225-
return self._ffi.NULL != evp_cipher
226-
227-
def register_cipher_adapter(self, cipher_cls, mode_cls, adapter) -> None:
228-
if (cipher_cls, mode_cls) in self._cipher_registry:
229-
raise ValueError(
230-
f"Duplicate registration for: {cipher_cls} {mode_cls}."
231-
)
232-
self._cipher_registry[cipher_cls, mode_cls] = adapter
233-
234-
def _register_default_ciphers(self) -> None:
235-
for cipher_cls in [AES, AES128, AES256]:
236-
for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8, GCM]:
237-
self.register_cipher_adapter(
238-
cipher_cls,
239-
mode_cls,
240-
GetCipherByName(
241-
"{cipher.name}-{cipher.key_size}-{mode.name}"
242-
),
243-
)
244-
for mode_cls in [CBC, CTR, ECB, OFB, CFB]:
245-
self.register_cipher_adapter(
246-
Camellia,
247-
mode_cls,
248-
GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"),
249-
)
250-
for mode_cls in [CBC, CFB, CFB8, OFB]:
251-
self.register_cipher_adapter(
252-
TripleDES, mode_cls, GetCipherByName("des-ede3-{mode.name}")
253-
)
254-
self.register_cipher_adapter(
255-
TripleDES, ECB, GetCipherByName("des-ede3")
256-
)
257-
# ChaCha20 uses the Long Name "chacha20" in OpenSSL, but in LibreSSL
258-
# it uses "chacha"
259-
self.register_cipher_adapter(
260-
ChaCha20,
261-
type(None),
262-
GetCipherByName(
263-
"chacha" if self._lib.CRYPTOGRAPHY_IS_LIBRESSL else "chacha20"
264-
),
265-
)
266-
self.register_cipher_adapter(AES, XTS, _get_xts_cipher)
267-
for mode_cls in [ECB, CBC, OFB, CFB, CTR, GCM]:
268-
self.register_cipher_adapter(
269-
SM4, mode_cls, GetCipherByName("sm4-{mode.name}")
270-
)
271-
# Don't register legacy ciphers if they're unavailable. Hypothetically
272-
# this wouldn't be necessary because we test availability by seeing if
273-
# we get an EVP_CIPHER * in the _CipherContext __init__, but OpenSSL 3
274-
# will return a valid pointer even though the cipher is unavailable.
275-
if (
276-
self._binding._legacy_provider_loaded
277-
or not self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER
278-
):
279-
for mode_cls in [CBC, CFB, OFB, ECB]:
280-
self.register_cipher_adapter(
281-
_BlowfishInternal,
282-
mode_cls,
283-
GetCipherByName("bf-{mode.name}"),
284-
)
285-
for mode_cls in [CBC, CFB, OFB, ECB]:
286-
self.register_cipher_adapter(
287-
_SEEDInternal,
288-
mode_cls,
289-
GetCipherByName("seed-{mode.name}"),
290-
)
291-
for cipher_cls, mode_cls in itertools.product(
292-
[_CAST5Internal, _IDEAInternal],
293-
[CBC, OFB, CFB, ECB],
294-
):
295-
self.register_cipher_adapter(
296-
cipher_cls,
297-
mode_cls,
298-
GetCipherByName("{cipher.name}-{mode.name}"),
299-
)
300-
self.register_cipher_adapter(
301-
ARC4, type(None), GetCipherByName("rc4")
302-
)
303-
# We don't actually support RC2, this is just used by some tests.
304-
self.register_cipher_adapter(
305-
_RC2, type(None), GetCipherByName("rc2")
306-
)
195+
return rust_openssl.ciphers.cipher_supported(cipher, mode)
307196

308197
def pbkdf2_hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool:
309198
return self.hmac_supported(algorithm)
@@ -1119,34 +1008,4 @@ def _load_pkcs7_certificates(self, p7) -> list[x509.Certificate]:
11191008
return certs
11201009

11211010

1122-
class GetCipherByName:
1123-
def __init__(self, fmt: str):
1124-
self._fmt = fmt
1125-
1126-
def __call__(self, backend: Backend, cipher: CipherAlgorithm, mode: Mode):
1127-
cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower()
1128-
evp_cipher = backend._lib.EVP_get_cipherbyname(
1129-
cipher_name.encode("ascii")
1130-
)
1131-
1132-
# try EVP_CIPHER_fetch if present
1133-
if (
1134-
evp_cipher == backend._ffi.NULL
1135-
and backend._lib.Cryptography_HAS_300_EVP_CIPHER
1136-
):
1137-
evp_cipher = backend._lib.EVP_CIPHER_fetch(
1138-
backend._ffi.NULL,
1139-
cipher_name.encode("ascii"),
1140-
backend._ffi.NULL,
1141-
)
1142-
1143-
backend._consume_errors()
1144-
return evp_cipher
1145-
1146-
1147-
def _get_xts_cipher(backend: Backend, cipher: AES, mode):
1148-
cipher_name = f"aes-{cipher.key_size // 2}-xts"
1149-
return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
1150-
1151-
11521011
backend = Backend()

src/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ def create_decryption_ctx(
2323
def create_decryption_ctx(
2424
algorithm: ciphers.CipherAlgorithm, mode: modes.Mode
2525
) -> ciphers.CipherContext: ...
26+
def cipher_supported(
27+
algorithm: ciphers.CipherAlgorithm, mode: modes.Mode
28+
) -> bool: ...
2629
def _advance(
2730
ctx: ciphers.AEADEncryptionContext | ciphers.AEADDecryptionContext, n: int
2831
) -> None: ...

src/rust/src/backend/cipher_registry.rs

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ fn get_cipher_registry(
129129
let seed = types::SEED.get(py)?;
130130
let arc4 = types::ARC4.get(py)?;
131131
let chacha20 = types::CHACHA20.get(py)?;
132+
let rc2 = types::RC2.get(py)?;
132133

133134
let cbc = types::CBC.get(py)?;
134135
let cfb = types::CFB.get(py)?;
@@ -245,42 +246,53 @@ fn get_cipher_registry(
245246
}
246247
}
247248

248-
#[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_SEED"))]
249-
{
250-
m.add(seed, cbc, Some(128), Cipher::seed_cbc())?;
251-
m.add(seed, cfb, Some(128), Cipher::seed_cfb128())?;
252-
m.add(seed, ofb, Some(128), Cipher::seed_ofb())?;
253-
m.add(seed, ecb, Some(128), Cipher::seed_ecb())?;
254-
}
249+
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))]
250+
m.add(chacha20, none_type, None, Cipher::chacha20())?;
255251

256-
#[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_BF"))]
252+
// Don't register legacy ciphers if they're unavailable. In theory
253+
// this should't be necessary but OpenSSL 3 will return an EVP_CIPHER
254+
// even when the cipher is unavailable.
255+
if cfg!(not(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER))
256+
|| types::LEGACY_PROVIDER_LOADED.get(py)?.is_true()?
257257
{
258-
m.add(blowfish, cbc, None, Cipher::bf_cbc())?;
259-
m.add(blowfish, cfb, None, Cipher::bf_cfb64())?;
260-
m.add(blowfish, ofb, None, Cipher::bf_ofb())?;
261-
m.add(blowfish, ecb, None, Cipher::bf_ecb())?;
262-
}
258+
#[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_BF"))]
259+
{
260+
m.add(blowfish, cbc, None, Cipher::bf_cbc())?;
261+
m.add(blowfish, cfb, None, Cipher::bf_cfb64())?;
262+
m.add(blowfish, ofb, None, Cipher::bf_ofb())?;
263+
m.add(blowfish, ecb, None, Cipher::bf_ecb())?;
264+
}
265+
#[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_SEED"))]
266+
{
267+
m.add(seed, cbc, Some(128), Cipher::seed_cbc())?;
268+
m.add(seed, cfb, Some(128), Cipher::seed_cfb128())?;
269+
m.add(seed, ofb, Some(128), Cipher::seed_ofb())?;
270+
m.add(seed, ecb, Some(128), Cipher::seed_ecb())?;
271+
}
263272

264-
#[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_CAST"))]
265-
{
266-
m.add(cast5, cbc, None, Cipher::cast5_cbc())?;
267-
m.add(cast5, ecb, None, Cipher::cast5_ecb())?;
268-
m.add(cast5, ofb, None, Cipher::cast5_ofb())?;
269-
m.add(cast5, cfb, None, Cipher::cast5_cfb64())?;
270-
}
273+
#[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_CAST"))]
274+
{
275+
m.add(cast5, cbc, None, Cipher::cast5_cbc())?;
276+
m.add(cast5, ecb, None, Cipher::cast5_ecb())?;
277+
m.add(cast5, ofb, None, Cipher::cast5_ofb())?;
278+
m.add(cast5, cfb, None, Cipher::cast5_cfb64())?;
279+
}
271280

272-
#[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_IDEA"))]
273-
{
274-
m.add(idea, cbc, Some(128), Cipher::idea_cbc())?;
275-
m.add(idea, ecb, Some(128), Cipher::idea_ecb())?;
276-
m.add(idea, ofb, Some(128), Cipher::idea_ofb())?;
277-
m.add(idea, cfb, Some(128), Cipher::idea_cfb64())?;
278-
}
281+
#[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_IDEA"))]
282+
{
283+
m.add(idea, cbc, Some(128), Cipher::idea_cbc())?;
284+
m.add(idea, ecb, Some(128), Cipher::idea_ecb())?;
285+
m.add(idea, ofb, Some(128), Cipher::idea_ofb())?;
286+
m.add(idea, cfb, Some(128), Cipher::idea_cfb64())?;
287+
}
279288

280-
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))]
281-
m.add(chacha20, none_type, None, Cipher::chacha20())?;
289+
m.add(arc4, none_type, None, Cipher::rc4())?;
282290

283-
m.add(arc4, none_type, None, Cipher::rc4())?;
291+
// We don't actually support RC2, this is just used by some tests.
292+
if let Some(rc2_cbc) = Cipher::from_nid(openssl::nid::Nid::RC2_CBC) {
293+
m.add(rc2, cbc, None, rc2_cbc)?;
294+
}
295+
}
284296

285297
Ok(m.build())
286298
})

src/rust/src/backend/ciphers.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,15 @@ fn create_decryption_ctx(
523523
}
524524
}
525525

526+
#[pyo3::prelude::pyfunction]
527+
fn cipher_supported(
528+
py: pyo3::Python<'_>,
529+
algorithm: &pyo3::PyAny,
530+
mode: &pyo3::PyAny,
531+
) -> CryptographyResult<bool> {
532+
Ok(cipher_registry::get_cipher(py, algorithm, mode.get_type())?.is_some())
533+
}
534+
526535
#[pyo3::prelude::pyfunction]
527536
fn _advance(ctx: &pyo3::PyAny, n: u64) {
528537
if let Ok(c) = ctx.downcast::<pyo3::PyCell<PyAEADEncryptionContext>>() {
@@ -545,6 +554,7 @@ pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelu
545554
let m = pyo3::prelude::PyModule::new(py, "ciphers")?;
546555
m.add_function(pyo3::wrap_pyfunction!(create_encryption_ctx, m)?)?;
547556
m.add_function(pyo3::wrap_pyfunction!(create_decryption_ctx, m)?)?;
557+
m.add_function(pyo3::wrap_pyfunction!(cipher_supported, m)?)?;
548558

549559
m.add_function(pyo3::wrap_pyfunction!(_advance, m)?)?;
550560
m.add_function(pyo3::wrap_pyfunction!(_advance_aad, m)?)?;

src/rust/src/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,8 @@ pub static ARC4: LazyPyImport = LazyPyImport::new(
538538
"cryptography.hazmat.primitives.ciphers.algorithms",
539539
&["ARC4"],
540540
);
541+
pub static RC2: LazyPyImport =
542+
LazyPyImport::new("cryptography.hazmat.backends.openssl.backend", &["_RC2"]);
541543

542544
pub static MODE_WITH_INITIALIZATION_VECTOR: LazyPyImport = LazyPyImport::new(
543545
"cryptography.hazmat.primitives.ciphers.modes",
@@ -572,6 +574,11 @@ pub static GCM: LazyPyImport =
572574
pub static XTS: LazyPyImport =
573575
LazyPyImport::new("cryptography.hazmat.primitives.ciphers.modes", &["XTS"]);
574576

577+
pub static LEGACY_PROVIDER_LOADED: LazyPyImport = LazyPyImport::new(
578+
"cryptography.hazmat.bindings.openssl.binding",
579+
&["Binding", "_legacy_provider_loaded"],
580+
);
581+
575582
#[cfg(test)]
576583
mod tests {
577584
use super::LazyPyImport;

tests/hazmat/backends/test_openssl.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
from cryptography.hazmat.backends.openssl.backend import backend
1414
from cryptography.hazmat.primitives import hashes, serialization
1515
from cryptography.hazmat.primitives.asymmetric import padding
16-
from cryptography.hazmat.primitives.ciphers.algorithms import AES
17-
from cryptography.hazmat.primitives.ciphers.modes import CBC
1816

1917
from ...doubles import (
2018
DummyAsymmetricPadding,
@@ -92,10 +90,6 @@ def test_supports_cipher(self):
9290
is False
9391
)
9492

95-
def test_register_duplicate_cipher_adapter(self):
96-
with pytest.raises(ValueError):
97-
backend.register_cipher_adapter(AES, CBC, None)
98-
9993
def test_openssl_assert(self):
10094
backend.openssl_assert(True)
10195
with pytest.raises(InternalError):

tests/hazmat/primitives/test_pkcs12.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
ed25519,
2020
rsa,
2121
)
22+
from cryptography.hazmat.primitives.ciphers import modes
2223
from cryptography.hazmat.primitives.serialization import (
2324
Encoding,
2425
PublicFormat,
@@ -81,7 +82,9 @@ def test_load_pkcs12_ec_keys(self, filename, password, backend):
8182
],
8283
)
8384
@pytest.mark.supported(
84-
only_if=lambda backend: backend.cipher_supported(_RC2(), None),
85+
only_if=lambda backend: backend.cipher_supported(
86+
_RC2(), modes.CBC(initialization_vector=b"\x00" * 16)
87+
),
8588
skip_message="Does not support RC2",
8689
)
8790
def test_load_pkcs12_ec_keys_rc2(self, filename, password, backend):

0 commit comments

Comments
 (0)