Skip to content

Commit f0177b0

Browse files
committed
Enforce 192-bit key length for TripleDES
TripleDES now only accepts 24-byte (192-bit) keys. Users needing single DES (1-key) or two-key Triple DES compatibility must expand the key themselves: - Single DES (8 bytes): key + key + key - Two-key 3DES (16 bytes): key + key[:8] This change removes the automatic key expansion that was previously done in the TripleDES constructor, making the key length requirement explicit and preventing accidental use of weaker key configurations.
1 parent a3b0bd8 commit f0177b0

File tree

7 files changed

+46
-29
lines changed

7 files changed

+46
-29
lines changed

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ Changelog
2727
such keys are impossible to process in a constant-time manner. We do not
2828
believe keys with this problem are in wide use, however we may revert this
2929
change based on the feedback we receive.
30+
* **BACKWARDS INCOMPATIBLE:**
31+
:class:`~cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES` now
32+
requires 192-bit (24-byte) keys. Users needing single DES or two-key Triple
33+
DES compatibility must expand the key themselves (e.g., for single DES:
34+
``key + key + key``, for two-key: ``key + key[:8]``).
3035
* Updated the minimum supported Rust version (MSRV) to 1.83.0, from 1.74.0.
3136
* Added support for loading elliptic curve keys that contain explicit encodings
3237
of the curves ``secp256r1``, ``secp384r1``, and ``secp521r1``.

docs/hazmat/decrepit/ciphers.rst

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ object along with the appropriate :mod:`~cryptography.hazmat.primitives.ciphers.
5151
Nonetheless, Triple DES is not recommended for new applications because it
5252
is incredibly slow; old applications should consider moving away from it.
5353

54-
:param key: The secret key. This must be kept secret. Either ``64``,
55-
``128``, or ``192`` :term:`bits` long. DES only uses ``56``, ``112``,
56-
or ``168`` bits of the key as there is a parity byte in each component
57-
of the key. Some writing refers to there being up to three separate
58-
keys that are each ``56`` bits long, they can simply be concatenated
59-
to produce the full key.
54+
:param key: The secret key. This must be kept secret. ``192`` :term:`bits`
55+
long (24 bytes). DES only uses ``168`` bits of the key as there is a
56+
parity byte in each component of the key. Some writing refers to there
57+
being three separate keys that are each ``56`` bits long, they can
58+
simply be concatenated to produce the full key. If you need single DES
59+
or two-key Triple DES compatibility, you must expand the key yourself
60+
(e.g., for single DES: ``key + key + key``, for two-key:
61+
``key + key[:8]``).
6062
:type key: :term:`bytes-like`
6163

6264
.. class:: CAST5(key)

src/cryptography/hazmat/decrepit/ciphers/algorithms.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,9 @@ def key_size(self) -> int:
2626
class TripleDES(BlockCipherAlgorithm):
2727
name = "3DES"
2828
block_size = 64
29-
key_sizes = frozenset([64, 128, 192])
29+
key_sizes = frozenset([192])
3030

3131
def __init__(self, key: bytes):
32-
if len(key) == 8:
33-
key += key + key
34-
elif len(key) == 16:
35-
key += key[:8]
3632
self.key = _verify_key_size(self, key)
3733

3834
@property

tests/hazmat/primitives/decrepit/test_3des.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
@pytest.mark.supported(
2323
only_if=lambda backend: backend.cipher_supported(
24-
algorithms.TripleDES(b"\x00" * 8), modes.CBC(b"\x00" * 8)
24+
algorithms.TripleDES(b"\x00" * 24), modes.CBC(b"\x00" * 8)
2525
),
2626
skip_message="Does not support TripleDES CBC",
2727
)
@@ -36,7 +36,9 @@ class TestTripleDESModeCBC:
3636
"TCBCvarkey.rsp",
3737
"TCBCvartext.rsp",
3838
],
39-
lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
39+
lambda keys, **kwargs: algorithms.TripleDES(
40+
binascii.unhexlify(keys) * 3
41+
),
4042
lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
4143
)
4244

@@ -53,7 +55,7 @@ class TestTripleDESModeCBC:
5355

5456
@pytest.mark.supported(
5557
only_if=lambda backend: backend.cipher_supported(
56-
algorithms.TripleDES(b"\x00" * 8), OFB(b"\x00" * 8)
58+
algorithms.TripleDES(b"\x00" * 24), OFB(b"\x00" * 8)
5759
),
5860
skip_message="Does not support TripleDES OFB",
5961
)
@@ -68,7 +70,9 @@ class TestTripleDESModeOFB:
6870
"TOFBvartext.rsp",
6971
"TOFBinvperm.rsp",
7072
],
71-
lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
73+
lambda keys, **kwargs: algorithms.TripleDES(
74+
binascii.unhexlify(keys) * 3
75+
),
7276
lambda iv, **kwargs: OFB(binascii.unhexlify(iv)),
7377
)
7478

@@ -85,7 +89,7 @@ class TestTripleDESModeOFB:
8589

8690
@pytest.mark.supported(
8791
only_if=lambda backend: backend.cipher_supported(
88-
algorithms.TripleDES(b"\x00" * 8), CFB(b"\x00" * 8)
92+
algorithms.TripleDES(b"\x00" * 24), CFB(b"\x00" * 8)
8993
),
9094
skip_message="Does not support TripleDES CFB",
9195
)
@@ -100,7 +104,9 @@ class TestTripleDESModeCFB:
100104
"TCFB64varkey.rsp",
101105
"TCFB64vartext.rsp",
102106
],
103-
lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
107+
lambda keys, **kwargs: algorithms.TripleDES(
108+
binascii.unhexlify(keys) * 3
109+
),
104110
lambda iv, **kwargs: CFB(binascii.unhexlify(iv)),
105111
)
106112

@@ -117,7 +123,7 @@ class TestTripleDESModeCFB:
117123

118124
@pytest.mark.supported(
119125
only_if=lambda backend: backend.cipher_supported(
120-
algorithms.TripleDES(b"\x00" * 8), CFB8(b"\x00" * 8)
126+
algorithms.TripleDES(b"\x00" * 24), CFB8(b"\x00" * 8)
121127
),
122128
skip_message="Does not support TripleDES CFB8",
123129
)
@@ -132,7 +138,9 @@ class TestTripleDESModeCFB8:
132138
"TCFB8varkey.rsp",
133139
"TCFB8vartext.rsp",
134140
],
135-
lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
141+
lambda keys, **kwargs: algorithms.TripleDES(
142+
binascii.unhexlify(keys) * 3
143+
),
136144
lambda iv, **kwargs: CFB8(binascii.unhexlify(iv)),
137145
)
138146

@@ -149,7 +157,7 @@ class TestTripleDESModeCFB8:
149157

150158
@pytest.mark.supported(
151159
only_if=lambda backend: backend.cipher_supported(
152-
algorithms.TripleDES(b"\x00" * 8), modes.ECB()
160+
algorithms.TripleDES(b"\x00" * 24), modes.ECB()
153161
),
154162
skip_message="Does not support TripleDES ECB",
155163
)
@@ -164,7 +172,9 @@ class TestTripleDESModeECB:
164172
"TECBvarkey.rsp",
165173
"TECBvartext.rsp",
166174
],
167-
lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
175+
lambda keys, **kwargs: algorithms.TripleDES(
176+
binascii.unhexlify(keys) * 3
177+
),
168178
lambda **kwargs: modes.ECB(),
169179
)
170180

tests/hazmat/primitives/decrepit/test_algorithms.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ def test_invalid_mode_algorithm():
7272

7373

7474
class TestTripleDES:
75-
@pytest.mark.parametrize("key", [b"0" * 16, b"0" * 32, b"0" * 48])
76-
def test_key_size(self, key):
77-
cipher = TripleDES(binascii.unhexlify(key))
75+
def test_key_size(self):
76+
cipher = TripleDES(binascii.unhexlify(b"0" * 48))
7877
assert cipher.key_size == 192
7978

80-
def test_invalid_key_size(self):
79+
@pytest.mark.parametrize("key", [b"0" * 12, b"0" * 16, b"0" * 32])
80+
def test_invalid_key_size(self, key):
8181
with pytest.raises(ValueError):
82-
TripleDES(binascii.unhexlify(b"0" * 12))
82+
TripleDES(binascii.unhexlify(key))
8383

8484
def test_invalid_key_type(self):
8585
with pytest.raises(TypeError, match="key must be bytes"):

tests/hazmat/primitives/test_cmac.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def test_aes_verify(self, backend, params):
8181

8282
@pytest.mark.supported(
8383
only_if=lambda backend: backend.cmac_algorithm_supported(
84-
TripleDES(fake_key)
84+
TripleDES(b"\x00" * 24)
8585
),
8686
skip_message="Does not support CMAC.",
8787
)
@@ -102,7 +102,7 @@ def test_3des_generate(self, backend, params):
102102

103103
@pytest.mark.supported(
104104
only_if=lambda backend: backend.cmac_algorithm_supported(
105-
TripleDES(fake_key)
105+
TripleDES(b"\x00" * 24)
106106
),
107107
skip_message="Does not support CMAC.",
108108
)

tests/hazmat/primitives/utils.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,11 @@ def _kbkdf_cmac_counter_mode_test(backend, prf, ctr_loc, brk_loc, params):
448448
break_location=brk_loc,
449449
)
450450

451-
ko = ctrkdf.derive(binascii.unhexlify(params["ki"]))
451+
ki = binascii.unhexlify(params["ki"])
452+
# TripleDES requires 24-byte keys. Expand 16-byte (2-key) to 24-byte.
453+
if prf == "cmac_tdes2":
454+
ki = ki + ki[:8]
455+
ko = ctrkdf.derive(ki)
452456
assert binascii.hexlify(ko) == params["ko"]
453457

454458

0 commit comments

Comments
 (0)