purepython-aes 0.3.1__tar.gz → 0.4.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.4.0}/PKG-INFO +1 -1
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/__init__.py +6 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/__init__.py +6 -0
- purepython_aes-0.4.0/src/purepython_aes/aes/modes/__init__.py +14 -0
- purepython_aes-0.4.0/src/purepython_aes/aes/modes/_base.py +31 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/modes/block/_base.py +2 -6
- purepython_aes-0.4.0/src/purepython_aes/aes/modes/stream/__init__.py +4 -0
- purepython_aes-0.4.0/src/purepython_aes/aes/modes/stream/_base.py +40 -0
- purepython_aes-0.4.0/src/purepython_aes/aes/modes/stream/cfb.py +76 -0
- purepython_aes-0.4.0/src/purepython_aes/types/__init__.py +9 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/types/finite/__init__.py +2 -1
- purepython_aes-0.4.0/src/purepython_aes/types/finite/literals.py +6 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0/src/purepython_aes.egg-info}/PKG-INFO +1 -1
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes.egg-info/SOURCES.txt +6 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes.egg-info/scm_file_list.json +6 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes.egg-info/scm_version.json +2 -2
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/modes/block/test_pcbc.py +1 -1
- purepython_aes-0.4.0/tests/unit/aes/modes/stream/test_cfb.py +48 -0
- purepython_aes-0.4.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.4.0}/.github/workflows/pre-commit.yml +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/.github/workflows/release.yml +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/.gitignore +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/.pre-commit-config.yaml +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/LISENCE.txt +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/README.md +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/pyproject.toml +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/scripts/check-test-marks.sh +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/setup.cfg +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/algorithms/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/algorithms/aes128.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/algorithms/aes192.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/algorithms/aes256.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/expansion.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/keys.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/ttables.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/interface.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/algorithms/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/algorithms/aes128.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/algorithms/aes192.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/algorithms/aes256.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/expansion.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/operations.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/state.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/modes/block/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/modes/block/cbc.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/modes/block/ecb.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/modes/block/pcbc.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/modes/operations.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/padding/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/padding/_base.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/padding/ansix923.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/padding/iso10126.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/padding/iso7816.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/padding/no.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/padding/pkcs7.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/padding/zero.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/const/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/const/aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/const/sbox.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/py.typed +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/types/finite/aliases.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes.egg-info/dependency_links.txt +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes.egg-info/requires.txt +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes.egg-info/top_level.txt +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/test_initial.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/conftest.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/algorithms/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/algorithms/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/algorithms/test_aes128.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/algorithms/test_aes192.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/algorithms/test_aes256.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/test_aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/test_expansion.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/test_keys.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/test_ttables.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/algorithms/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/algorithms/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/algorithms/test_aes128.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/algorithms/test_aes192.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/algorithms/test_aes256.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/test_aes.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/test_expansion.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/test_operations.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/test_state.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/modes/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/modes/block/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/modes/block/test_cbc.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/modes/block/test_ecb.py +0 -0
- {purepython_aes-0.3.1/tests/unit/aes/padding → purepython_aes-0.4.0/tests/unit/aes/modes/stream}/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/modes/test_operations.py +0 -0
- {purepython_aes-0.3.1/tests/unit/const → purepython_aes-0.4.0/tests/unit/aes/padding}/__init__.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/padding/conftest.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/padding/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/padding/test_ansix923.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/padding/test_iso10126.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/padding/test_iso7816.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/padding/test_no.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/padding/test_pkcs7.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/padding/test_zero.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/strategies.py +0 -0
- {purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/const/test_sbox.py +0 -0
|
@@ -8,6 +8,8 @@ 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,
|
|
@@ -17,6 +19,7 @@ from purepython_aes.aes import (
|
|
|
17
19
|
ReferenceAes128,
|
|
18
20
|
ReferenceAes192,
|
|
19
21
|
ReferenceAes256,
|
|
22
|
+
StreamCipherMode,
|
|
20
23
|
ZeroPadding,
|
|
21
24
|
)
|
|
22
25
|
|
|
@@ -30,6 +33,8 @@ __all__: list[str] = [
|
|
|
30
33
|
'BasePadding',
|
|
31
34
|
'BlockCipherMode',
|
|
32
35
|
'CbcMode',
|
|
36
|
+
'CfbMode',
|
|
37
|
+
'CipherMode',
|
|
33
38
|
'EcbMode',
|
|
34
39
|
'Iso7816Padding',
|
|
35
40
|
'Iso10126Padding',
|
|
@@ -39,5 +44,6 @@ __all__: list[str] = [
|
|
|
39
44
|
'ReferenceAes128',
|
|
40
45
|
'ReferenceAes192',
|
|
41
46
|
'ReferenceAes256',
|
|
47
|
+
'StreamCipherMode',
|
|
42
48
|
'ZeroPadding',
|
|
43
49
|
]
|
|
@@ -11,8 +11,11 @@ from purepython_aes.aes.modes import (
|
|
|
11
11
|
AesMode,
|
|
12
12
|
BlockCipherMode,
|
|
13
13
|
CbcMode,
|
|
14
|
+
CfbMode,
|
|
15
|
+
CipherMode,
|
|
14
16
|
EcbMode,
|
|
15
17
|
PcbcMode,
|
|
18
|
+
StreamCipherMode,
|
|
16
19
|
)
|
|
17
20
|
from purepython_aes.aes.padding import (
|
|
18
21
|
AnsiX923Padding,
|
|
@@ -35,8 +38,11 @@ __all__: list[str] = [
|
|
|
35
38
|
'AesMode',
|
|
36
39
|
'BlockCipherMode',
|
|
37
40
|
'CbcMode',
|
|
41
|
+
'CfbMode',
|
|
42
|
+
'CipherMode',
|
|
38
43
|
'EcbMode',
|
|
39
44
|
'PcbcMode',
|
|
45
|
+
'StreamCipherMode',
|
|
40
46
|
'AnsiX923Padding',
|
|
41
47
|
'BasePadding',
|
|
42
48
|
'Iso7816Padding',
|
|
@@ -0,0 +1,14 @@
|
|
|
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, StreamCipherMode
|
|
4
|
+
|
|
5
|
+
__all__: list[str] = [
|
|
6
|
+
'AesMode',
|
|
7
|
+
'CipherMode',
|
|
8
|
+
'BlockCipherMode',
|
|
9
|
+
'CbcMode',
|
|
10
|
+
'EcbMode',
|
|
11
|
+
'PcbcMode',
|
|
12
|
+
'CfbMode',
|
|
13
|
+
'StreamCipherMode',
|
|
14
|
+
]
|
|
@@ -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.transform_for_encryption(iv, plaintext)
|
|
14
|
+
return iv + ciphertext
|
|
15
|
+
|
|
16
|
+
def decrypt(self, ciphertext: bytes) -> bytes:
|
|
17
|
+
return self.transform_for_decryption(
|
|
18
|
+
initialization_value=ciphertext[:AES_BLOCK_SIZE],
|
|
19
|
+
ciphertext=ciphertext[AES_BLOCK_SIZE:],
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def transform_for_encryption(
|
|
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 transform_for_decryption(
|
|
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 transform_for_encryption(
|
|
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 transform_for_decryption(
|
|
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)
|
|
@@ -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,9 @@ 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
|
|
47
50
|
src/purepython_aes/aes/padding/__init__.py
|
|
48
51
|
src/purepython_aes/aes/padding/_base.py
|
|
49
52
|
src/purepython_aes/aes/padding/ansix923.py
|
|
@@ -58,6 +61,7 @@ src/purepython_aes/const/sbox.py
|
|
|
58
61
|
src/purepython_aes/types/__init__.py
|
|
59
62
|
src/purepython_aes/types/finite/__init__.py
|
|
60
63
|
src/purepython_aes/types/finite/aliases.py
|
|
64
|
+
src/purepython_aes/types/finite/literals.py
|
|
61
65
|
tests/__init__.py
|
|
62
66
|
tests/test_initial.py
|
|
63
67
|
tests/unit/__init__.py
|
|
@@ -92,6 +96,8 @@ tests/unit/aes/modes/block/__init__.py
|
|
|
92
96
|
tests/unit/aes/modes/block/test_cbc.py
|
|
93
97
|
tests/unit/aes/modes/block/test_ecb.py
|
|
94
98
|
tests/unit/aes/modes/block/test_pcbc.py
|
|
99
|
+
tests/unit/aes/modes/stream/__init__.py
|
|
100
|
+
tests/unit/aes/modes/stream/test_cfb.py
|
|
95
101
|
tests/unit/aes/padding/__init__.py
|
|
96
102
|
tests/unit/aes/padding/conftest.py
|
|
97
103
|
tests/unit/aes/padding/strategies.py
|
{purepython_aes-0.3.1 → purepython_aes-0.4.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,9 @@
|
|
|
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",
|
|
49
53
|
"src/purepython_aes/aes/modes/block/_base.py",
|
|
50
54
|
"src/purepython_aes/aes/modes/block/__init__.py",
|
|
51
55
|
"src/purepython_aes/aes/modes/block/cbc.py",
|
|
@@ -92,6 +96,8 @@
|
|
|
92
96
|
"tests/unit/aes/padding/test_no.py",
|
|
93
97
|
"tests/unit/aes/modes/test_operations.py",
|
|
94
98
|
"tests/unit/aes/modes/__init__.py",
|
|
99
|
+
"tests/unit/aes/modes/stream/test_cfb.py",
|
|
100
|
+
"tests/unit/aes/modes/stream/__init__.py",
|
|
95
101
|
"tests/unit/aes/modes/block/__init__.py",
|
|
96
102
|
"tests/unit/aes/modes/block/test_pcbc.py",
|
|
97
103
|
"tests/unit/aes/modes/block/test_ecb.py",
|
|
@@ -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
|
+
ecb: CfbMode = CfbMode(aes(key[:aes.__key_size__]), segment_size) # fmt: skip
|
|
48
|
+
assert ecb.decrypt(ecb.encrypt(data)) == data
|
|
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.4.0}/src/purepython_aes/aes/core/fast/algorithms/aes128.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/fast/algorithms/aes192.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.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.4.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.4.0}/src/purepython_aes/aes/core/reference/expansion.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/operations.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/src/purepython_aes/aes/core/reference/state.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.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.4.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.4.0}/tests/unit/aes/core/fast/algorithms/__init__.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/algorithms/strategies.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/algorithms/test_aes128.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/fast/algorithms/test_aes192.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.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
|
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/algorithms/__init__.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.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
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/test_expansion.py
RENAMED
|
File without changes
|
{purepython_aes-0.3.1 → purepython_aes-0.4.0}/tests/unit/aes/core/reference/test_operations.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.4.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
|