purepython-aes 0.3.1__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {purepython_aes-0.3.1/src/purepython_aes.egg-info → purepython_aes-0.5.0}/PKG-INFO +1 -1
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/__init__.py +8 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/__init__.py +8 -0
- purepython_aes-0.5.0/src/purepython_aes/aes/modes/__init__.py +15 -0
- purepython_aes-0.5.0/src/purepython_aes/aes/modes/_base.py +31 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/modes/block/_base.py +2 -6
- purepython_aes-0.5.0/src/purepython_aes/aes/modes/stream/__init__.py +5 -0
- purepython_aes-0.5.0/src/purepython_aes/aes/modes/stream/_base.py +40 -0
- purepython_aes-0.5.0/src/purepython_aes/aes/modes/stream/cfb.py +76 -0
- purepython_aes-0.5.0/src/purepython_aes/aes/modes/stream/ofb.py +45 -0
- purepython_aes-0.5.0/src/purepython_aes/types/__init__.py +9 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/types/finite/__init__.py +2 -1
- purepython_aes-0.5.0/src/purepython_aes/types/finite/literals.py +6 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0/src/purepython_aes.egg-info}/PKG-INFO +1 -1
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes.egg-info/SOURCES.txt +8 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes.egg-info/scm_file_list.json +8 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes.egg-info/scm_version.json +2 -2
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/test_keys.py +2 -2
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/test_expansion.py +5 -5
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/test_operations.py +6 -6
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/test_state.py +1 -1
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/modes/block/test_cbc.py +8 -8
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/modes/block/test_ecb.py +2 -2
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/modes/block/test_pcbc.py +9 -9
- purepython_aes-0.5.0/tests/unit/aes/modes/stream/test_cfb.py +48 -0
- purepython_aes-0.5.0/tests/unit/aes/modes/stream/test_ofb.py +28 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/modes/test_operations.py +2 -2
- purepython_aes-0.5.0/tests/unit/const/__init__.py +0 -0
- purepython_aes-0.3.1/src/purepython_aes/aes/modes/__init__.py +0 -4
- purepython_aes-0.3.1/src/purepython_aes/aes/modes/_base.py +0 -14
- purepython_aes-0.3.1/src/purepython_aes/types/__init__.py +0 -5
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/.github/workflows/pre-commit.yml +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/.github/workflows/release.yml +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/.gitignore +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/.pre-commit-config.yaml +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/LISENCE.txt +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/README.md +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/pyproject.toml +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/scripts/check-test-marks.sh +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/setup.cfg +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/algorithms/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/algorithms/aes128.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/algorithms/aes192.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/algorithms/aes256.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/expansion.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/keys.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/ttables.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/interface.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/algorithms/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/algorithms/aes128.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/algorithms/aes192.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/algorithms/aes256.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/expansion.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/operations.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/state.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/modes/block/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/modes/block/cbc.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/modes/block/ecb.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/modes/block/pcbc.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/modes/operations.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/padding/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/padding/_base.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/padding/ansix923.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/padding/iso10126.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/padding/iso7816.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/padding/no.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/padding/pkcs7.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/padding/zero.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/const/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/const/aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/const/sbox.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/py.typed +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/types/finite/aliases.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes.egg-info/dependency_links.txt +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes.egg-info/requires.txt +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes.egg-info/top_level.txt +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/test_initial.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/conftest.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/test_aes128.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/test_aes192.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/test_aes256.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/test_aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/test_expansion.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/test_ttables.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/algorithms/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/algorithms/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/algorithms/test_aes128.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/algorithms/test_aes192.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/algorithms/test_aes256.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/test_aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/modes/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/modes/block/__init__.py +0 -0
- {purepython_aes-0.3.1/tests/unit/aes/padding → purepython_aes-0.5.0/tests/unit/aes/modes/stream}/__init__.py +0 -0
- {purepython_aes-0.3.1/tests/unit/const → purepython_aes-0.5.0/tests/unit/aes/padding}/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/padding/conftest.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/padding/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/padding/test_ansix923.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/padding/test_iso10126.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/padding/test_iso7816.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/padding/test_no.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/padding/test_pkcs7.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/padding/test_zero.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/const/test_sbox.py +0 -0
|
@@ -8,15 +8,19 @@ from purepython_aes.aes import (
|
|
|
8
8
|
BasePadding,
|
|
9
9
|
BlockCipherMode,
|
|
10
10
|
CbcMode,
|
|
11
|
+
CfbMode,
|
|
12
|
+
CipherMode,
|
|
11
13
|
EcbMode,
|
|
12
14
|
Iso7816Padding,
|
|
13
15
|
Iso10126Padding,
|
|
14
16
|
NoPadding,
|
|
17
|
+
OfbMode,
|
|
15
18
|
PcbcMode,
|
|
16
19
|
Pkcs7Padding,
|
|
17
20
|
ReferenceAes128,
|
|
18
21
|
ReferenceAes192,
|
|
19
22
|
ReferenceAes256,
|
|
23
|
+
StreamCipherMode,
|
|
20
24
|
ZeroPadding,
|
|
21
25
|
)
|
|
22
26
|
|
|
@@ -30,14 +34,18 @@ __all__: list[str] = [
|
|
|
30
34
|
'BasePadding',
|
|
31
35
|
'BlockCipherMode',
|
|
32
36
|
'CbcMode',
|
|
37
|
+
'CfbMode',
|
|
38
|
+
'CipherMode',
|
|
33
39
|
'EcbMode',
|
|
34
40
|
'Iso7816Padding',
|
|
35
41
|
'Iso10126Padding',
|
|
36
42
|
'NoPadding',
|
|
43
|
+
'OfbMode',
|
|
37
44
|
'PcbcMode',
|
|
38
45
|
'Pkcs7Padding',
|
|
39
46
|
'ReferenceAes128',
|
|
40
47
|
'ReferenceAes192',
|
|
41
48
|
'ReferenceAes256',
|
|
49
|
+
'StreamCipherMode',
|
|
42
50
|
'ZeroPadding',
|
|
43
51
|
]
|
|
@@ -11,8 +11,12 @@ from purepython_aes.aes.modes import (
|
|
|
11
11
|
AesMode,
|
|
12
12
|
BlockCipherMode,
|
|
13
13
|
CbcMode,
|
|
14
|
+
CfbMode,
|
|
15
|
+
CipherMode,
|
|
14
16
|
EcbMode,
|
|
17
|
+
OfbMode,
|
|
15
18
|
PcbcMode,
|
|
19
|
+
StreamCipherMode,
|
|
16
20
|
)
|
|
17
21
|
from purepython_aes.aes.padding import (
|
|
18
22
|
AnsiX923Padding,
|
|
@@ -35,8 +39,12 @@ __all__: list[str] = [
|
|
|
35
39
|
'AesMode',
|
|
36
40
|
'BlockCipherMode',
|
|
37
41
|
'CbcMode',
|
|
42
|
+
'CfbMode',
|
|
43
|
+
'CipherMode',
|
|
38
44
|
'EcbMode',
|
|
45
|
+
'OfbMode',
|
|
39
46
|
'PcbcMode',
|
|
47
|
+
'StreamCipherMode',
|
|
40
48
|
'AnsiX923Padding',
|
|
41
49
|
'BasePadding',
|
|
42
50
|
'Iso7816Padding',
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from purepython_aes.aes.modes._base import AesMode, CipherMode
|
|
2
|
+
from purepython_aes.aes.modes.block import BlockCipherMode, CbcMode, EcbMode, PcbcMode
|
|
3
|
+
from purepython_aes.aes.modes.stream import CfbMode, OfbMode, StreamCipherMode
|
|
4
|
+
|
|
5
|
+
__all__: list[str] = [
|
|
6
|
+
'AesMode',
|
|
7
|
+
'CipherMode',
|
|
8
|
+
'BlockCipherMode',
|
|
9
|
+
'CbcMode',
|
|
10
|
+
'EcbMode',
|
|
11
|
+
'PcbcMode',
|
|
12
|
+
'CfbMode',
|
|
13
|
+
'OfbMode',
|
|
14
|
+
'StreamCipherMode',
|
|
15
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
from purepython_aes.aes.core.interface import Aes
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class AesMode(ABC):
|
|
11
|
+
"""Base class for all AES modes of operation."""
|
|
12
|
+
|
|
13
|
+
algorithm: Aes
|
|
14
|
+
"""Either AES-128, AES-192, or AES-256."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(slots=True)
|
|
18
|
+
class CipherMode(AesMode):
|
|
19
|
+
"""Base class for all AES Cipher modes of operation."""
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def encrypt(self, plaintext: bytes) -> bytes:
|
|
23
|
+
"""Encrypt a byte string."""
|
|
24
|
+
|
|
25
|
+
raise NotImplementedError
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def decrypt(self, ciphertext: bytes) -> bytes:
|
|
29
|
+
"""Decrypt a byte string."""
|
|
30
|
+
|
|
31
|
+
raise NotImplementedError
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
|
|
4
|
-
from purepython_aes.aes.modes._base import
|
|
4
|
+
from purepython_aes.aes.modes._base import CipherMode
|
|
5
5
|
from purepython_aes.aes.padding import BasePadding
|
|
6
6
|
from purepython_aes.const import AES_BLOCK_SIZE
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@dataclass(slots=True)
|
|
10
|
-
class BlockCipherMode(
|
|
10
|
+
class BlockCipherMode(CipherMode, ABC):
|
|
11
11
|
padding: BasePadding
|
|
12
12
|
|
|
13
13
|
@abstractmethod
|
|
@@ -23,13 +23,9 @@ class BlockCipherMode(AesMode, ABC):
|
|
|
23
23
|
raise NotImplementedError
|
|
24
24
|
|
|
25
25
|
def encrypt(self, plaintext: bytes) -> bytes:
|
|
26
|
-
"""Pad and encrypt a byte string."""
|
|
27
|
-
|
|
28
26
|
return self.__encrypt_blocks__(self.padding.pad(plaintext))
|
|
29
27
|
|
|
30
28
|
def decrypt(self, ciphertext: bytes) -> bytes:
|
|
31
|
-
"""Decrypt and unpad a byte string."""
|
|
32
|
-
|
|
33
29
|
if len(ciphertext) % AES_BLOCK_SIZE != 0:
|
|
34
30
|
raise ValueError(f'len(ciphertext) % {AES_BLOCK_SIZE} must be 0')
|
|
35
31
|
return self.padding.unpad(self.__decrypt_blocks__(ciphertext))
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from secrets import token_bytes
|
|
4
|
+
|
|
5
|
+
from purepython_aes.aes.modes._base import CipherMode
|
|
6
|
+
from purepython_aes.const import AES_BLOCK_SIZE
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(slots=True)
|
|
10
|
+
class StreamCipherMode(CipherMode, ABC):
|
|
11
|
+
def encrypt(self, plaintext: bytes) -> bytes:
|
|
12
|
+
iv: bytes = token_bytes(AES_BLOCK_SIZE)
|
|
13
|
+
ciphertext: bytes = self.__encrypt_stream__(iv, plaintext)
|
|
14
|
+
return iv + ciphertext
|
|
15
|
+
|
|
16
|
+
def decrypt(self, ciphertext: bytes) -> bytes:
|
|
17
|
+
return self.__decrypt_stream__(
|
|
18
|
+
initialization_value=ciphertext[:AES_BLOCK_SIZE],
|
|
19
|
+
ciphertext=ciphertext[AES_BLOCK_SIZE:],
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def __encrypt_stream__(
|
|
24
|
+
self,
|
|
25
|
+
initialization_value: bytes,
|
|
26
|
+
plaintext: bytes,
|
|
27
|
+
) -> bytes:
|
|
28
|
+
"""Transform plaintext into ciphertext."""
|
|
29
|
+
|
|
30
|
+
raise NotImplementedError
|
|
31
|
+
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def __decrypt_stream__(
|
|
34
|
+
self,
|
|
35
|
+
initialization_value: bytes,
|
|
36
|
+
ciphertext: bytes,
|
|
37
|
+
) -> bytes:
|
|
38
|
+
"""Transform ciphertext into plaintext."""
|
|
39
|
+
|
|
40
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import final
|
|
3
|
+
|
|
4
|
+
from purepython_aes.aes.modes.stream._base import StreamCipherMode
|
|
5
|
+
from purepython_aes.const import AES_BLOCK_SIZE
|
|
6
|
+
from purepython_aes.types import CfbSegmentSize
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@final
|
|
10
|
+
@dataclass(slots=True)
|
|
11
|
+
class CfbMode(StreamCipherMode):
|
|
12
|
+
"""Cipher FeedBack mode of operation."""
|
|
13
|
+
|
|
14
|
+
segment_size: CfbSegmentSize = AES_BLOCK_SIZE # type: ignore[assignment]
|
|
15
|
+
"""Feedback segment size in bytes."""
|
|
16
|
+
|
|
17
|
+
def __post_init__(self) -> None:
|
|
18
|
+
if self.segment_size < 1 or self.segment_size > AES_BLOCK_SIZE:
|
|
19
|
+
raise ValueError(
|
|
20
|
+
', '.join(
|
|
21
|
+
(
|
|
22
|
+
f'expected 1 <= segment_size <= {AES_BLOCK_SIZE}',
|
|
23
|
+
f'got {self.segment_size}',
|
|
24
|
+
)
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def __encrypt_stream__(
|
|
29
|
+
self,
|
|
30
|
+
initialization_value: bytes,
|
|
31
|
+
plaintext: bytes,
|
|
32
|
+
) -> bytes:
|
|
33
|
+
feedback_register: bytes = initialization_value
|
|
34
|
+
plaintext_size: int = len(plaintext)
|
|
35
|
+
ciphertext: bytearray = bytearray(plaintext_size)
|
|
36
|
+
for segment_start in range(0, plaintext_size, self.segment_size):
|
|
37
|
+
segment_end: int = min(segment_start + self.segment_size, plaintext_size)
|
|
38
|
+
segment_length: int = segment_end - segment_start
|
|
39
|
+
encrypted_register: bytes = self.algorithm.encrypt_block(feedback_register)
|
|
40
|
+
for segment_index in range(segment_length):
|
|
41
|
+
ciphertext[segment_start + segment_index] = (
|
|
42
|
+
plaintext[segment_start + segment_index]
|
|
43
|
+
^ encrypted_register[segment_index]
|
|
44
|
+
)
|
|
45
|
+
ciphertext_segment: bytes = bytes(ciphertext[segment_start:segment_end])
|
|
46
|
+
feedback_register = (
|
|
47
|
+
feedback_register[segment_length:] + bytes(ciphertext_segment)
|
|
48
|
+
if segment_length != AES_BLOCK_SIZE
|
|
49
|
+
else ciphertext_segment
|
|
50
|
+
)
|
|
51
|
+
return bytes(ciphertext)
|
|
52
|
+
|
|
53
|
+
def __decrypt_stream__(
|
|
54
|
+
self,
|
|
55
|
+
initialization_value: bytes,
|
|
56
|
+
ciphertext: bytes,
|
|
57
|
+
) -> bytes:
|
|
58
|
+
feedback_register: bytes = initialization_value
|
|
59
|
+
ciphertext_size: int = len(ciphertext)
|
|
60
|
+
plaintext: bytearray = bytearray(ciphertext_size)
|
|
61
|
+
for segment_start in range(0, ciphertext_size, self.segment_size):
|
|
62
|
+
segment_end: int = min(segment_start + self.segment_size, ciphertext_size)
|
|
63
|
+
segment_length: int = segment_end - segment_start
|
|
64
|
+
encrypted_register: bytes = self.algorithm.encrypt_block(feedback_register)
|
|
65
|
+
for segment_index in range(segment_length):
|
|
66
|
+
plaintext[segment_start + segment_index] = (
|
|
67
|
+
ciphertext[segment_start + segment_index]
|
|
68
|
+
^ encrypted_register[segment_index]
|
|
69
|
+
)
|
|
70
|
+
ciphertext_segment: bytes = ciphertext[segment_start:segment_end]
|
|
71
|
+
feedback_register = (
|
|
72
|
+
feedback_register[segment_length:] + ciphertext_segment
|
|
73
|
+
if segment_length != AES_BLOCK_SIZE
|
|
74
|
+
else ciphertext_segment
|
|
75
|
+
)
|
|
76
|
+
return bytes(plaintext)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import final
|
|
3
|
+
|
|
4
|
+
from purepython_aes.aes.modes.stream._base import StreamCipherMode
|
|
5
|
+
from purepython_aes.const import AES_BLOCK_SIZE
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@final
|
|
9
|
+
@dataclass(slots=True)
|
|
10
|
+
class OfbMode(StreamCipherMode):
|
|
11
|
+
"""Output FeedBack mode of operation."""
|
|
12
|
+
|
|
13
|
+
def __encrypt_stream__(
|
|
14
|
+
self,
|
|
15
|
+
initialization_value: bytes,
|
|
16
|
+
plaintext: bytes,
|
|
17
|
+
) -> bytes:
|
|
18
|
+
return self.__transform_stream__(initialization_value, plaintext)
|
|
19
|
+
|
|
20
|
+
def __decrypt_stream__(
|
|
21
|
+
self,
|
|
22
|
+
initialization_value: bytes,
|
|
23
|
+
ciphertext: bytes,
|
|
24
|
+
) -> bytes:
|
|
25
|
+
return self.__transform_stream__(initialization_value, ciphertext)
|
|
26
|
+
|
|
27
|
+
def __transform_stream__(
|
|
28
|
+
self,
|
|
29
|
+
initialization_value: bytes,
|
|
30
|
+
data: bytes,
|
|
31
|
+
) -> bytes:
|
|
32
|
+
"""XOR data with the OFB keystream."""
|
|
33
|
+
|
|
34
|
+
feedback_register: bytes = initialization_value
|
|
35
|
+
data_size: int = len(data)
|
|
36
|
+
transformed_data: bytearray = bytearray(data_size)
|
|
37
|
+
for block_start in range(0, data_size, AES_BLOCK_SIZE):
|
|
38
|
+
block_end: int = min(block_start + AES_BLOCK_SIZE, data_size)
|
|
39
|
+
block_length: int = block_end - block_start
|
|
40
|
+
feedback_register = self.algorithm.encrypt_block(feedback_register)
|
|
41
|
+
for block_index in range(block_length):
|
|
42
|
+
transformed_data[block_start + block_index] = (
|
|
43
|
+
data[block_start + block_index] ^ feedback_register[block_index]
|
|
44
|
+
)
|
|
45
|
+
return bytes(transformed_data)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
from purepython_aes.types.finite.aliases import IntLookupTable256, RoundKey, RoundKeys
|
|
2
|
+
from purepython_aes.types.finite.literals import CfbSegmentSize
|
|
2
3
|
|
|
3
|
-
__all__: list[str] = ['IntLookupTable256', 'RoundKey', 'RoundKeys']
|
|
4
|
+
__all__: list[str] = ['IntLookupTable256', 'RoundKey', 'RoundKeys', 'CfbSegmentSize']
|
|
@@ -44,6 +44,10 @@ src/purepython_aes/aes/modes/block/_base.py
|
|
|
44
44
|
src/purepython_aes/aes/modes/block/cbc.py
|
|
45
45
|
src/purepython_aes/aes/modes/block/ecb.py
|
|
46
46
|
src/purepython_aes/aes/modes/block/pcbc.py
|
|
47
|
+
src/purepython_aes/aes/modes/stream/__init__.py
|
|
48
|
+
src/purepython_aes/aes/modes/stream/_base.py
|
|
49
|
+
src/purepython_aes/aes/modes/stream/cfb.py
|
|
50
|
+
src/purepython_aes/aes/modes/stream/ofb.py
|
|
47
51
|
src/purepython_aes/aes/padding/__init__.py
|
|
48
52
|
src/purepython_aes/aes/padding/_base.py
|
|
49
53
|
src/purepython_aes/aes/padding/ansix923.py
|
|
@@ -58,6 +62,7 @@ src/purepython_aes/const/sbox.py
|
|
|
58
62
|
src/purepython_aes/types/__init__.py
|
|
59
63
|
src/purepython_aes/types/finite/__init__.py
|
|
60
64
|
src/purepython_aes/types/finite/aliases.py
|
|
65
|
+
src/purepython_aes/types/finite/literals.py
|
|
61
66
|
tests/__init__.py
|
|
62
67
|
tests/test_initial.py
|
|
63
68
|
tests/unit/__init__.py
|
|
@@ -92,6 +97,9 @@ tests/unit/aes/modes/block/__init__.py
|
|
|
92
97
|
tests/unit/aes/modes/block/test_cbc.py
|
|
93
98
|
tests/unit/aes/modes/block/test_ecb.py
|
|
94
99
|
tests/unit/aes/modes/block/test_pcbc.py
|
|
100
|
+
tests/unit/aes/modes/stream/__init__.py
|
|
101
|
+
tests/unit/aes/modes/stream/test_cfb.py
|
|
102
|
+
tests/unit/aes/modes/stream/test_ofb.py
|
|
95
103
|
tests/unit/aes/padding/__init__.py
|
|
96
104
|
tests/unit/aes/padding/conftest.py
|
|
97
105
|
tests/unit/aes/padding/strategies.py
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes.egg-info/scm_file_list.json
RENAMED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"src/purepython_aes/types/__init__.py",
|
|
12
12
|
"src/purepython_aes/types/finite/aliases.py",
|
|
13
13
|
"src/purepython_aes/types/finite/__init__.py",
|
|
14
|
+
"src/purepython_aes/types/finite/literals.py",
|
|
14
15
|
"src/purepython_aes/const/__init__.py",
|
|
15
16
|
"src/purepython_aes/const/aes.py",
|
|
16
17
|
"src/purepython_aes/const/sbox.py",
|
|
@@ -46,6 +47,10 @@
|
|
|
46
47
|
"src/purepython_aes/aes/modes/_base.py",
|
|
47
48
|
"src/purepython_aes/aes/modes/__init__.py",
|
|
48
49
|
"src/purepython_aes/aes/modes/operations.py",
|
|
50
|
+
"src/purepython_aes/aes/modes/stream/_base.py",
|
|
51
|
+
"src/purepython_aes/aes/modes/stream/cfb.py",
|
|
52
|
+
"src/purepython_aes/aes/modes/stream/__init__.py",
|
|
53
|
+
"src/purepython_aes/aes/modes/stream/ofb.py",
|
|
49
54
|
"src/purepython_aes/aes/modes/block/_base.py",
|
|
50
55
|
"src/purepython_aes/aes/modes/block/__init__.py",
|
|
51
56
|
"src/purepython_aes/aes/modes/block/cbc.py",
|
|
@@ -92,6 +97,9 @@
|
|
|
92
97
|
"tests/unit/aes/padding/test_no.py",
|
|
93
98
|
"tests/unit/aes/modes/test_operations.py",
|
|
94
99
|
"tests/unit/aes/modes/__init__.py",
|
|
100
|
+
"tests/unit/aes/modes/stream/test_cfb.py",
|
|
101
|
+
"tests/unit/aes/modes/stream/__init__.py",
|
|
102
|
+
"tests/unit/aes/modes/stream/test_ofb.py",
|
|
95
103
|
"tests/unit/aes/modes/block/__init__.py",
|
|
96
104
|
"tests/unit/aes/modes/block/test_pcbc.py",
|
|
97
105
|
"tests/unit/aes/modes/block/test_ecb.py",
|
|
@@ -19,11 +19,11 @@ from tests.unit.aes.strategies import aes128key, aes192key, aes256key
|
|
|
19
19
|
@mark.quick
|
|
20
20
|
@mark.parametrize(
|
|
21
21
|
'round_count',
|
|
22
|
-
|
|
22
|
+
[
|
|
23
23
|
AES_128_ROUND_COUNT,
|
|
24
24
|
AES_192_ROUND_COUNT,
|
|
25
25
|
AES_256_ROUND_COUNT,
|
|
26
|
-
|
|
26
|
+
],
|
|
27
27
|
)
|
|
28
28
|
def test_preserves_round_key_count(round_count: int) -> None:
|
|
29
29
|
encryption_round_keys: RoundKeys = [
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/test_expansion.py
RENAMED
|
@@ -13,15 +13,15 @@ from purepython_aes.const import (
|
|
|
13
13
|
AES_BLOCK_SIZE,
|
|
14
14
|
)
|
|
15
15
|
|
|
16
|
-
AES_CONFIGURATIONS: Final[
|
|
16
|
+
AES_CONFIGURATIONS: Final[list[tuple[int, int]]] = [
|
|
17
17
|
(AES_128_KEY_SIZE, AES_128_ROUND_COUNT),
|
|
18
18
|
(AES_192_KEY_SIZE, AES_192_ROUND_COUNT),
|
|
19
19
|
(AES_256_KEY_SIZE, AES_256_ROUND_COUNT),
|
|
20
|
-
|
|
20
|
+
]
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
@mark.quick
|
|
24
|
-
@mark.parametrize(
|
|
24
|
+
@mark.parametrize(['key_size', 'round_count'], AES_CONFIGURATIONS)
|
|
25
25
|
def test_expand_key_returns_corrent_number_of_keys(
|
|
26
26
|
key_size: int,
|
|
27
27
|
round_count: int,
|
|
@@ -31,14 +31,14 @@ def test_expand_key_returns_corrent_number_of_keys(
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@mark.quick
|
|
34
|
-
@mark.parametrize(
|
|
34
|
+
@mark.parametrize(['key_size', 'round_count'], AES_CONFIGURATIONS)
|
|
35
35
|
def test_expand_key_returns_16_byte_round_keys(key_size: int, round_count: int) -> None:
|
|
36
36
|
round_keys: tuple[bytes, ...] = expand_key(bytes(key_size), round_count)
|
|
37
37
|
assert all(len(round_key) == AES_BLOCK_SIZE for round_key in round_keys)
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
@mark.quick
|
|
41
|
-
@mark.parametrize(
|
|
41
|
+
@mark.parametrize(['key_size', 'round_count'], AES_CONFIGURATIONS)
|
|
42
42
|
def test_expanded_schedule_starts_with_original_key(
|
|
43
43
|
key_size: int,
|
|
44
44
|
round_count: int,
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/test_operations.py
RENAMED
|
@@ -29,8 +29,8 @@ def xor_columns(
|
|
|
29
29
|
|
|
30
30
|
@mark.quick
|
|
31
31
|
@mark.parametrize(
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
['left', 'right', 'expected'],
|
|
33
|
+
[
|
|
34
34
|
(0x00, 0x00, 0x00),
|
|
35
35
|
(0x00, 0x01, 0x00),
|
|
36
36
|
(0x01, 0x00, 0x00),
|
|
@@ -45,7 +45,7 @@ def xor_columns(
|
|
|
45
45
|
(0xFF, 0xFF, 0x13),
|
|
46
46
|
(0x80, 0x02, 0x1B),
|
|
47
47
|
(0x80, 0x80, 0x9A),
|
|
48
|
-
|
|
48
|
+
],
|
|
49
49
|
)
|
|
50
50
|
def test_galois256_multiply_known_values(left: int, right: int, expected: int) -> None:
|
|
51
51
|
assert galois256_multiply(left, right) == expected
|
|
@@ -107,8 +107,8 @@ def test_galois256_multiply_right_distributes_over_xor() -> None:
|
|
|
107
107
|
|
|
108
108
|
@mark.quick
|
|
109
109
|
@mark.parametrize(
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
['values', 'expected'],
|
|
111
|
+
[
|
|
112
112
|
((), 0x00),
|
|
113
113
|
((0x00,), 0x00),
|
|
114
114
|
((0x57,), 0x57),
|
|
@@ -117,7 +117,7 @@ def test_galois256_multiply_right_distributes_over_xor() -> None:
|
|
|
117
117
|
((0xFF, 0x0F, 0xF0), 0x00),
|
|
118
118
|
((0x01, 0x02, 0x04, 0x08), 0x0F),
|
|
119
119
|
((0xDE, 0xAD, 0xBE, 0xEF), 0x22),
|
|
120
|
-
|
|
120
|
+
],
|
|
121
121
|
)
|
|
122
122
|
def test_xor_bytes_known_values(values: tuple[int, ...], expected: int) -> None:
|
|
123
123
|
assert xor_bytes(*values) == expected
|
|
@@ -17,7 +17,7 @@ class TestAesState:
|
|
|
17
17
|
assert state.to_bytes() == block
|
|
18
18
|
|
|
19
19
|
@staticmethod
|
|
20
|
-
@mark.parametrize('block',
|
|
20
|
+
@mark.parametrize('block', [bytes(), bytes(1), bytes(15), bytes(17), bytes(32)])
|
|
21
21
|
def test_from_bytes_rejects_invalid_block_lengths(block: bytes) -> None:
|
|
22
22
|
with raises(
|
|
23
23
|
expected_exception=ValueError,
|
|
@@ -50,11 +50,11 @@ class TestCbcMode:
|
|
|
50
50
|
key: bytes,
|
|
51
51
|
data: bytes,
|
|
52
52
|
) -> None:
|
|
53
|
-
|
|
54
|
-
assert
|
|
53
|
+
cbc: CbcMode = CbcMode(aes(key[:aes.__key_size__]), padding()) # fmt: skip
|
|
54
|
+
assert cbc.decrypt(cbc.encrypt(data)) == data
|
|
55
55
|
|
|
56
56
|
@staticmethod
|
|
57
|
-
@mark.parametrize(
|
|
57
|
+
@mark.parametrize('aes', [Aes128, Aes192, Aes256])
|
|
58
58
|
@given(key=aes256key, data=binary())
|
|
59
59
|
def test_decrypt_inverts_encrypt_zero_padding(
|
|
60
60
|
aes: type[Aes],
|
|
@@ -62,16 +62,16 @@ class TestCbcMode:
|
|
|
62
62
|
data: bytes,
|
|
63
63
|
) -> None:
|
|
64
64
|
assume(not data.endswith(bytes(1)))
|
|
65
|
-
|
|
66
|
-
assert
|
|
65
|
+
cbc: CbcMode = CbcMode(aes(key[:aes.__key_size__]), ZeroPadding()) # fmt: skip
|
|
66
|
+
assert cbc.decrypt(cbc.encrypt(data)) == data
|
|
67
67
|
|
|
68
68
|
@staticmethod
|
|
69
|
-
@mark.parametrize(
|
|
69
|
+
@mark.parametrize('aes', [Aes128, Aes192, Aes256])
|
|
70
70
|
@given(key=aes256key, data=aes_blocks)
|
|
71
71
|
def test_decrypt_inverts_encrypt_no_padding(
|
|
72
72
|
aes: type[Aes],
|
|
73
73
|
key: bytes,
|
|
74
74
|
data: bytes,
|
|
75
75
|
) -> None:
|
|
76
|
-
|
|
77
|
-
assert
|
|
76
|
+
cbc: CbcMode = CbcMode(aes(key[:aes.__key_size__]), NoPadding()) # fmt: skip
|
|
77
|
+
assert cbc.decrypt(cbc.encrypt(data)) == data
|
|
@@ -54,7 +54,7 @@ class TestEcbMode:
|
|
|
54
54
|
assert ecb.decrypt(ecb.encrypt(data)) == data
|
|
55
55
|
|
|
56
56
|
@staticmethod
|
|
57
|
-
@mark.parametrize(
|
|
57
|
+
@mark.parametrize('aes', [Aes128, Aes192, Aes256])
|
|
58
58
|
@given(key=aes256key, data=binary())
|
|
59
59
|
def test_decrypt_inverts_encrypt_zero_padding(
|
|
60
60
|
aes: type[Aes],
|
|
@@ -66,7 +66,7 @@ class TestEcbMode:
|
|
|
66
66
|
assert ecb.decrypt(ecb.encrypt(data)) == data
|
|
67
67
|
|
|
68
68
|
@staticmethod
|
|
69
|
-
@mark.parametrize(
|
|
69
|
+
@mark.parametrize('aes', [Aes128, Aes192, Aes256])
|
|
70
70
|
@given(key=aes256key, data=aes_blocks)
|
|
71
71
|
def test_decrypt_inverts_encrypt_no_padding(
|
|
72
72
|
aes: type[Aes],
|
|
@@ -25,7 +25,7 @@ from tests.unit.aes.strategies import aes256key, aes_blocks
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
@mark.quick
|
|
28
|
-
class
|
|
28
|
+
class TestPcbcMode:
|
|
29
29
|
@staticmethod
|
|
30
30
|
@mark.parametrize(
|
|
31
31
|
['aes', 'padding'],
|
|
@@ -50,11 +50,11 @@ class TestCbcMode:
|
|
|
50
50
|
key: bytes,
|
|
51
51
|
data: bytes,
|
|
52
52
|
) -> None:
|
|
53
|
-
|
|
54
|
-
assert
|
|
53
|
+
pcbc: PcbcMode = PcbcMode(aes(key[:aes.__key_size__]), padding()) # fmt: skip
|
|
54
|
+
assert pcbc.decrypt(pcbc.encrypt(data)) == data
|
|
55
55
|
|
|
56
56
|
@staticmethod
|
|
57
|
-
@mark.parametrize(
|
|
57
|
+
@mark.parametrize('aes', [Aes128, Aes192, Aes256])
|
|
58
58
|
@given(key=aes256key, data=binary())
|
|
59
59
|
def test_decrypt_inverts_encrypt_zero_padding(
|
|
60
60
|
aes: type[Aes],
|
|
@@ -62,19 +62,19 @@ class TestCbcMode:
|
|
|
62
62
|
data: bytes,
|
|
63
63
|
) -> None:
|
|
64
64
|
assume(not data.endswith(bytes(1)))
|
|
65
|
-
|
|
65
|
+
pcbc: PcbcMode = PcbcMode(
|
|
66
66
|
algorithm=aes(key[:aes.__key_size__]), # fmt: skip
|
|
67
67
|
padding=ZeroPadding(),
|
|
68
68
|
)
|
|
69
|
-
assert
|
|
69
|
+
assert pcbc.decrypt(pcbc.encrypt(data)) == data
|
|
70
70
|
|
|
71
71
|
@staticmethod
|
|
72
|
-
@mark.parametrize(
|
|
72
|
+
@mark.parametrize('aes', [Aes128, Aes192, Aes256])
|
|
73
73
|
@given(key=aes256key, data=aes_blocks)
|
|
74
74
|
def test_decrypt_inverts_encrypt_no_padding(
|
|
75
75
|
aes: type[Aes],
|
|
76
76
|
key: bytes,
|
|
77
77
|
data: bytes,
|
|
78
78
|
) -> None:
|
|
79
|
-
|
|
80
|
-
assert
|
|
79
|
+
pcbc: PcbcMode = PcbcMode(aes(key[:aes.__key_size__]), NoPadding()) # fmt: skip
|
|
80
|
+
assert pcbc.decrypt(pcbc.encrypt(data)) == data
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from itertools import product
|
|
2
|
+
|
|
3
|
+
from hypothesis import given
|
|
4
|
+
from hypothesis.strategies import binary
|
|
5
|
+
from pytest import mark
|
|
6
|
+
|
|
7
|
+
from purepython_aes import (
|
|
8
|
+
Aes,
|
|
9
|
+
Aes128,
|
|
10
|
+
Aes192,
|
|
11
|
+
Aes256,
|
|
12
|
+
CfbMode,
|
|
13
|
+
ReferenceAes128,
|
|
14
|
+
ReferenceAes192,
|
|
15
|
+
ReferenceAes256,
|
|
16
|
+
)
|
|
17
|
+
from purepython_aes.types import CfbSegmentSize
|
|
18
|
+
from tests.unit.aes.strategies import aes256key
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@mark.quick
|
|
22
|
+
class TestCfbMode:
|
|
23
|
+
@staticmethod
|
|
24
|
+
@mark.parametrize(
|
|
25
|
+
['aes', 'segment_size'],
|
|
26
|
+
tuple(
|
|
27
|
+
product(
|
|
28
|
+
[
|
|
29
|
+
Aes128,
|
|
30
|
+
Aes192,
|
|
31
|
+
Aes256,
|
|
32
|
+
ReferenceAes128,
|
|
33
|
+
ReferenceAes192,
|
|
34
|
+
ReferenceAes256,
|
|
35
|
+
],
|
|
36
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
|
|
37
|
+
),
|
|
38
|
+
),
|
|
39
|
+
)
|
|
40
|
+
@given(key=aes256key, data=binary())
|
|
41
|
+
def test_decrypt_inverts_encrypt(
|
|
42
|
+
aes: type[Aes],
|
|
43
|
+
segment_size: CfbSegmentSize,
|
|
44
|
+
key: bytes,
|
|
45
|
+
data: bytes,
|
|
46
|
+
) -> None:
|
|
47
|
+
cfb: CfbMode = CfbMode(aes(key[:aes.__key_size__]), segment_size) # fmt: skip
|
|
48
|
+
assert cfb.decrypt(cfb.encrypt(data)) == data
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from hypothesis import given
|
|
2
|
+
from hypothesis.strategies import binary
|
|
3
|
+
from pytest import mark
|
|
4
|
+
|
|
5
|
+
from purepython_aes import (
|
|
6
|
+
Aes,
|
|
7
|
+
Aes128,
|
|
8
|
+
Aes192,
|
|
9
|
+
Aes256,
|
|
10
|
+
OfbMode,
|
|
11
|
+
ReferenceAes128,
|
|
12
|
+
ReferenceAes192,
|
|
13
|
+
ReferenceAes256,
|
|
14
|
+
)
|
|
15
|
+
from tests.unit.aes.strategies import aes256key
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@mark.quick
|
|
19
|
+
class TestOfbMode:
|
|
20
|
+
@staticmethod
|
|
21
|
+
@mark.parametrize(
|
|
22
|
+
'aes',
|
|
23
|
+
[Aes128, Aes192, Aes256, ReferenceAes128, ReferenceAes192, ReferenceAes256],
|
|
24
|
+
)
|
|
25
|
+
@given(key=aes256key, data=binary())
|
|
26
|
+
def test_decrypt_inverts_encrypt(aes: type[Aes], key: bytes, data: bytes) -> None:
|
|
27
|
+
ofb: OfbMode = OfbMode(aes(key[:aes.__key_size__])) # fmt: skip
|
|
28
|
+
assert ofb.decrypt(ofb.encrypt(data)) == data
|
|
@@ -13,7 +13,7 @@ def test_xor_empty_inputs() -> None:
|
|
|
13
13
|
|
|
14
14
|
@mark.quick
|
|
15
15
|
@mark.parametrize(
|
|
16
|
-
|
|
16
|
+
['left', 'right', 'expected'],
|
|
17
17
|
[
|
|
18
18
|
(b'\x00', b'\x00', b'\x00'),
|
|
19
19
|
(b'\x00', b'\xff', b'\xff'),
|
|
@@ -45,7 +45,7 @@ def test_xor_known_values(left: bytes, right: bytes, expected: bytes) -> None:
|
|
|
45
45
|
|
|
46
46
|
@mark.quick
|
|
47
47
|
@mark.parametrize(
|
|
48
|
-
|
|
48
|
+
['left', 'right'],
|
|
49
49
|
[
|
|
50
50
|
(b'\x00', bytes(0)),
|
|
51
51
|
(bytes(0), b'\x00'),
|
|
File without changes
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from abc import ABC
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
|
|
6
|
-
from purepython_aes.aes.core.interface import Aes
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@dataclass
|
|
10
|
-
class AesMode(ABC):
|
|
11
|
-
"""Base class for all AES modes of operation."""
|
|
12
|
-
|
|
13
|
-
algorithm: Aes
|
|
14
|
-
"""Either AES-128, AES-192, or AES-256."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/algorithms/aes128.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/algorithms/aes192.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/fast/algorithms/aes256.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/expansion.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/operations.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/core/reference/state.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes/aes/modes/block/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/src/purepython_aes.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/__init__.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/strategies.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/test_aes128.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/test_aes192.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/fast/algorithms/test_aes256.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/algorithms/__init__.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.5.0}/tests/unit/aes/core/reference/algorithms/strategies.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{purepython_aes-0.3.1/tests/unit/const → purepython_aes-0.5.0/tests/unit/aes/padding}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|