Skip to content

Commit 738d2be

Browse files
committed
Convert symmetric ciphers to Rust
1 parent 722a639 commit 738d2be

File tree

16 files changed

+901
-685
lines changed

16 files changed

+901
-685
lines changed

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

Lines changed: 4 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,12 @@
66

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

1211
from cryptography import utils, x509
1312
from cryptography.exceptions import UnsupportedAlgorithm
14-
from cryptography.hazmat.backends.openssl.ciphers import _CipherContext
1513
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
1614
from cryptography.hazmat.bindings.openssl import binding
17-
from cryptography.hazmat.decrepit.ciphers.algorithms import (
18-
ARC4,
19-
CAST5,
20-
IDEA,
21-
SEED,
22-
Blowfish,
23-
TripleDES,
24-
)
2515
from cryptography.hazmat.primitives import hashes, serialization
2616
from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding
2717
from cryptography.hazmat.primitives.asymmetric import ec
@@ -40,21 +30,9 @@
4030
)
4131
from cryptography.hazmat.primitives.ciphers.algorithms import (
4232
AES,
43-
AES128,
44-
AES256,
45-
SM4,
46-
Camellia,
47-
ChaCha20,
4833
)
4934
from cryptography.hazmat.primitives.ciphers.modes import (
5035
CBC,
51-
CFB,
52-
CFB8,
53-
CTR,
54-
ECB,
55-
GCM,
56-
OFB,
57-
XTS,
5836
Mode,
5937
)
6038
from cryptography.hazmat.primitives.serialization.pkcs12 import (
@@ -70,7 +48,7 @@
7048

7149
# Not actually supported, just used as a marker for some serialization tests.
7250
class _RC2:
73-
pass
51+
key_size = 128
7452

7553

7654
class Backend:
@@ -117,25 +95,15 @@ def __init__(self) -> None:
11795
self._lib = self._binding.lib
11896
self._fips_enabled = rust_openssl.is_fips_enabled()
11997

120-
self._cipher_registry: dict[
121-
tuple[type[CipherAlgorithm], type[Mode]],
122-
typing.Callable,
123-
] = {}
124-
self._register_default_ciphers()
125-
12698
def __repr__(self) -> str:
12799
return "<OpenSSLBackend(version: {}, FIPS: {}, Legacy: {})>".format(
128100
self.openssl_version_text(),
129101
self._fips_enabled,
130102
self._binding._legacy_provider_loaded,
131103
)
132104

133-
def openssl_assert(
134-
self,
135-
ok: bool,
136-
errors: list[rust_openssl.OpenSSLError] | None = None,
137-
) -> None:
138-
return binding._openssl_assert(ok, errors=errors)
105+
def openssl_assert(self, ok: bool) -> None:
106+
return binding._openssl_assert(ok)
139107

140108
def _enable_fips(self) -> None:
141109
# This function enables FIPS mode for OpenSSL 3.0.0 on installs that
@@ -210,103 +178,7 @@ def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool:
210178
if not isinstance(cipher, self._fips_ciphers):
211179
return False
212180

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

311183
def pbkdf2_hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool:
312184
return self.hmac_supported(algorithm)
@@ -841,34 +713,4 @@ def pkcs7_supported(self) -> bool:
841713
return not self._lib.CRYPTOGRAPHY_IS_BORINGSSL
842714

843715

844-
class GetCipherByName:
845-
def __init__(self, fmt: str):
846-
self._fmt = fmt
847-
848-
def __call__(self, backend: Backend, cipher: CipherAlgorithm, mode: Mode):
849-
cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower()
850-
evp_cipher = backend._lib.EVP_get_cipherbyname(
851-
cipher_name.encode("ascii")
852-
)
853-
854-
# try EVP_CIPHER_fetch if present
855-
if (
856-
evp_cipher == backend._ffi.NULL
857-
and backend._lib.Cryptography_HAS_300_EVP_CIPHER
858-
):
859-
evp_cipher = backend._lib.EVP_CIPHER_fetch(
860-
backend._ffi.NULL,
861-
cipher_name.encode("ascii"),
862-
backend._ffi.NULL,
863-
)
864-
865-
backend._consume_errors()
866-
return evp_cipher
867-
868-
869-
def _get_xts_cipher(backend: Backend, cipher: AES, mode):
870-
cipher_name = f"aes-{cipher.key_size // 2}-xts"
871-
return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
872-
873-
874716
backend = Backend()

0 commit comments

Comments
 (0)