purepython-aes 0.1.0__tar.gz → 0.3.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.
Files changed (87) hide show
  1. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/.github/workflows/release.yml +0 -18
  2. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/PKG-INFO +1 -1
  3. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/__init__.py +4 -0
  4. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/__init__.py +9 -1
  5. purepython_aes-0.3.0/src/purepython_aes/aes/modes/__init__.py +4 -0
  6. purepython_aes-0.3.0/src/purepython_aes/aes/modes/block/__init__.py +6 -0
  7. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/modes/block/_base.py +4 -4
  8. purepython_aes-0.3.0/src/purepython_aes/aes/modes/block/cbc.py +35 -0
  9. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/modes/block/ecb.py +2 -2
  10. purepython_aes-0.3.0/src/purepython_aes/aes/modes/block/pcbc.py +35 -0
  11. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes.egg-info/PKG-INFO +1 -1
  12. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes.egg-info/SOURCES.txt +4 -0
  13. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes.egg-info/scm_file_list.json +4 -0
  14. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes.egg-info/scm_version.json +2 -2
  15. purepython_aes-0.3.0/tests/unit/aes/modes/block/test_cbc.py +67 -0
  16. purepython_aes-0.3.0/tests/unit/aes/modes/block/test_pcbc.py +70 -0
  17. purepython_aes-0.1.0/src/purepython_aes/aes/modes/__init__.py +0 -4
  18. purepython_aes-0.1.0/src/purepython_aes/aes/modes/block/__init__.py +0 -4
  19. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/.github/workflows/pre-commit.yml +0 -0
  20. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/.gitignore +0 -0
  21. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/.pre-commit-config.yaml +0 -0
  22. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/LISENCE.txt +0 -0
  23. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/README.md +0 -0
  24. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/pyproject.toml +0 -0
  25. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/scripts/check-test-marks.sh +0 -0
  26. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/setup.cfg +0 -0
  27. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/algorithms/__init__.py +0 -0
  28. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/algorithms/aes128.py +0 -0
  29. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/algorithms/aes192.py +0 -0
  30. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/algorithms/aes256.py +0 -0
  31. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/core/__init__.py +0 -0
  32. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/core/aes.py +0 -0
  33. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/core/expansion.py +0 -0
  34. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/core/operations.py +0 -0
  35. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/core/state.py +0 -0
  36. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/interface.py +0 -0
  37. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/modes/_base.py +0 -0
  38. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/modes/operations.py +0 -0
  39. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/padding/__init__.py +0 -0
  40. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/padding/_base.py +0 -0
  41. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/padding/ansix923.py +0 -0
  42. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/padding/iso10126.py +0 -0
  43. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/padding/iso7816.py +0 -0
  44. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/padding/no.py +0 -0
  45. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/padding/pkcs7.py +0 -0
  46. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/aes/padding/zero.py +0 -0
  47. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/const/__init__.py +0 -0
  48. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/const/aes.py +0 -0
  49. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/const/sbox.py +0 -0
  50. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/py.typed +0 -0
  51. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/types/__init__.py +0 -0
  52. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/types/finite/__init__.py +0 -0
  53. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes/types/finite/aliases.py +0 -0
  54. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes.egg-info/dependency_links.txt +0 -0
  55. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes.egg-info/requires.txt +0 -0
  56. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/src/purepython_aes.egg-info/top_level.txt +0 -0
  57. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/__init__.py +0 -0
  58. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/test_initial.py +0 -0
  59. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/__init__.py +0 -0
  60. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/__init__.py +0 -0
  61. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/algorithms/__init__.py +0 -0
  62. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/algorithms/conftest.py +0 -0
  63. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/algorithms/test_aes128.py +0 -0
  64. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/algorithms/test_aes192.py +0 -0
  65. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/algorithms/test_aes256.py +0 -0
  66. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/core/__init__.py +0 -0
  67. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/core/strategies.py +0 -0
  68. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/core/test_aes.py +0 -0
  69. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/core/test_expansion.py +0 -0
  70. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/core/test_operations.py +0 -0
  71. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/core/test_state.py +0 -0
  72. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/modes/__init__.py +0 -0
  73. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/modes/block/__init__.py +0 -0
  74. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/modes/block/test_ecb.py +0 -0
  75. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/modes/test_operations.py +0 -0
  76. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/__init__.py +0 -0
  77. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/conftest.py +0 -0
  78. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/strategies.py +0 -0
  79. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/test_ansix923.py +0 -0
  80. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/test_iso10126.py +0 -0
  81. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/test_iso7816.py +0 -0
  82. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/test_no.py +0 -0
  83. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/test_pkcs7.py +0 -0
  84. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/padding/test_zero.py +0 -0
  85. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/aes/strategies.py +0 -0
  86. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/const/__init__.py +0 -0
  87. {purepython_aes-0.1.0 → purepython_aes-0.3.0}/tests/unit/const/test_sbox.py +0 -0
@@ -50,28 +50,10 @@ jobs:
50
50
  run: python -m pip install --editable ".[dev, test]"
51
51
  - name: Run pre-commit hooks
52
52
  run: pre-commit run --all-files --show-diff-on-failure
53
- slow-tests:
54
- name: Run release-only tests
55
- needs:
56
- - validate
57
- runs-on: ubuntu-latest
58
- steps:
59
- - name: Check out tagged commit
60
- uses: actions/checkout@v4
61
- - name: Set up Python
62
- uses: actions/setup-python@v5
63
- with:
64
- python-version: "3.10"
65
- cache: pip
66
- - name: Install dependencies
67
- run: python -m pip install --editable ".[dev, test]"
68
- - name: Run slow tests
69
- run: python -m pytest -n 8 -m "slow and not quick"
70
53
  build:
71
54
  name: Build distributions
72
55
  needs:
73
56
  - pre-commit
74
- - slow-tests
75
57
  runs-on: ubuntu-latest
76
58
  steps:
77
59
  - name: Check out tagged commit
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: purepython-aes
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: Pure-Python implementation of AES encryption algorithm.
5
5
  Author-email: Emelianov Artem <penguin5726@proton.me>
6
6
  License-Expression: MIT
@@ -7,10 +7,12 @@ from purepython_aes.aes import (
7
7
  AnsiX923Padding,
8
8
  BasePadding,
9
9
  BlockCipherMode,
10
+ CbcMode,
10
11
  EcbMode,
11
12
  Iso7816Padding,
12
13
  Iso10126Padding,
13
14
  NoPadding,
15
+ PcbcMode,
14
16
  Pkcs7Padding,
15
17
  ZeroPadding,
16
18
  )
@@ -24,10 +26,12 @@ __all__: list[str] = [
24
26
  'AnsiX923Padding',
25
27
  'BasePadding',
26
28
  'BlockCipherMode',
29
+ 'CbcMode',
27
30
  'EcbMode',
28
31
  'Iso7816Padding',
29
32
  'Iso10126Padding',
30
33
  'NoPadding',
34
+ 'PcbcMode',
31
35
  'Pkcs7Padding',
32
36
  'ZeroPadding',
33
37
  ]
@@ -1,6 +1,12 @@
1
1
  from purepython_aes.aes.algorithms import Aes128, Aes192, Aes256
2
2
  from purepython_aes.aes.interface import Aes
3
- from purepython_aes.aes.modes import AesMode, BlockCipherMode, EcbMode
3
+ from purepython_aes.aes.modes import (
4
+ AesMode,
5
+ BlockCipherMode,
6
+ CbcMode,
7
+ EcbMode,
8
+ PcbcMode,
9
+ )
4
10
  from purepython_aes.aes.padding import (
5
11
  AnsiX923Padding,
6
12
  BasePadding,
@@ -18,7 +24,9 @@ __all__: list[str] = [
18
24
  'Aes',
19
25
  'AesMode',
20
26
  'BlockCipherMode',
27
+ 'CbcMode',
21
28
  'EcbMode',
29
+ 'PcbcMode',
22
30
  'AnsiX923Padding',
23
31
  'BasePadding',
24
32
  'Iso7816Padding',
@@ -0,0 +1,4 @@
1
+ from purepython_aes.aes.modes._base import AesMode
2
+ from purepython_aes.aes.modes.block import BlockCipherMode, CbcMode, EcbMode, PcbcMode
3
+
4
+ __all__: list[str] = ['AesMode', 'BlockCipherMode', 'CbcMode', 'EcbMode', 'PcbcMode']
@@ -0,0 +1,6 @@
1
+ from purepython_aes.aes.modes.block._base import BlockCipherMode
2
+ from purepython_aes.aes.modes.block.cbc import CbcMode
3
+ from purepython_aes.aes.modes.block.ecb import EcbMode
4
+ from purepython_aes.aes.modes.block.pcbc import PcbcMode
5
+
6
+ __all__: list[str] = ['BlockCipherMode', 'CbcMode', 'EcbMode', 'PcbcMode']
@@ -11,13 +11,13 @@ class BlockCipherMode(AesMode, ABC):
11
11
  padding: BasePadding
12
12
 
13
13
  @abstractmethod
14
- def encrypt_blocks(self, padded_plaintext: bytes) -> bytes:
14
+ def __encrypt_blocks__(self, padded_plaintext: bytes) -> bytes:
15
15
  """Encrypt plaintext containing complete blocks."""
16
16
 
17
17
  raise NotImplementedError
18
18
 
19
19
  @abstractmethod
20
- def decrypt_blocks(self, ciphertext: bytes) -> bytes:
20
+ def __decrypt_blocks__(self, ciphertext: bytes) -> bytes:
21
21
  """Decrypt ciphertext containing complete blocks."""
22
22
 
23
23
  raise NotImplementedError
@@ -25,11 +25,11 @@ class BlockCipherMode(AesMode, ABC):
25
25
  def encrypt(self, plaintext: bytes) -> bytes:
26
26
  """Pad and encrypt a byte string."""
27
27
 
28
- return self.encrypt_blocks(self.padding.pad(plaintext))
28
+ return self.__encrypt_blocks__(self.padding.pad(plaintext))
29
29
 
30
30
  def decrypt(self, ciphertext: bytes) -> bytes:
31
31
  """Decrypt and unpad a byte string."""
32
32
 
33
33
  if len(ciphertext) % AES_BLOCK_SIZE != 0:
34
34
  raise ValueError(f'len(ciphertext) % {AES_BLOCK_SIZE} must be 0')
35
- return self.padding.unpad(self.decrypt_blocks(ciphertext))
35
+ return self.padding.unpad(self.__decrypt_blocks__(ciphertext))
@@ -0,0 +1,35 @@
1
+ from dataclasses import dataclass
2
+ from secrets import token_bytes
3
+ from typing import final
4
+
5
+ from purepython_aes.aes.modes.block._base import BlockCipherMode
6
+ from purepython_aes.aes.modes.operations import split_into_blocks, xor
7
+ from purepython_aes.const import AES_BLOCK_SIZE
8
+
9
+
10
+ @final
11
+ @dataclass(slots=True)
12
+ class CbcMode(BlockCipherMode):
13
+ """Cipher Block Chaining mode of operation."""
14
+
15
+ def __encrypt_blocks__(self, padded_plaintext: bytes) -> bytes:
16
+ initialization_vector: bytes = token_bytes(AES_BLOCK_SIZE)
17
+ previous_ciphertext_block: bytes = initialization_vector
18
+ ciphertext_blocks: list[bytes] = [initialization_vector]
19
+ for block in split_into_blocks(padded_plaintext):
20
+ chained_block: bytes = xor(block, previous_ciphertext_block)
21
+ ciphertext_block: bytes = self.algorithm.encrypt_block(chained_block)
22
+ ciphertext_blocks.append(ciphertext_block)
23
+ previous_ciphertext_block = ciphertext_block
24
+ return bytes(0).join(ciphertext_blocks)
25
+
26
+ def __decrypt_blocks__(self, ciphertext: bytes) -> bytes:
27
+ initialization_vector, *ciphertext_blocks = split_into_blocks(ciphertext)
28
+ previous_ciphertext_block: bytes = initialization_vector
29
+ plaintext_blocks: list[bytes] = []
30
+ for block in ciphertext_blocks:
31
+ decrypted_block: bytes = self.algorithm.decrypt_block(block)
32
+ plaintext_block: bytes = xor(decrypted_block, previous_ciphertext_block)
33
+ plaintext_blocks.append(plaintext_block)
34
+ previous_ciphertext_block = block
35
+ return bytes(0).join(plaintext_blocks)
@@ -10,12 +10,12 @@ from purepython_aes.aes.modes.operations import split_into_blocks
10
10
  class EcbMode(BlockCipherMode):
11
11
  """Electronic Codebook mode of operation."""
12
12
 
13
- def encrypt_blocks(self, padded_plaintext: bytes) -> bytes:
13
+ def __encrypt_blocks__(self, padded_plaintext: bytes) -> bytes:
14
14
  return bytes(0).join(
15
15
  map(self.algorithm.encrypt_block, split_into_blocks(padded_plaintext))
16
16
  )
17
17
 
18
- def decrypt_blocks(self, ciphertext: bytes) -> bytes:
18
+ def __decrypt_blocks__(self, ciphertext: bytes) -> bytes:
19
19
  return bytes(0).join(
20
20
  map(self.algorithm.decrypt_block, split_into_blocks(ciphertext))
21
21
  )
@@ -0,0 +1,35 @@
1
+ from dataclasses import dataclass
2
+ from secrets import token_bytes
3
+ from typing import final
4
+
5
+ from purepython_aes.aes.modes.block._base import BlockCipherMode
6
+ from purepython_aes.aes.modes.operations import split_into_blocks, xor
7
+ from purepython_aes.const import AES_BLOCK_SIZE
8
+
9
+
10
+ @final
11
+ @dataclass(slots=True)
12
+ class PcbcMode(BlockCipherMode):
13
+ """Propagating Cipher Block Chaining mode of operation."""
14
+
15
+ def __encrypt_blocks__(self, padded_plaintext: bytes) -> bytes:
16
+ initialization_vector: bytes = token_bytes(AES_BLOCK_SIZE)
17
+ previous_ciphertext_block: bytes = initialization_vector
18
+ ciphertext_blocks: list[bytes] = [initialization_vector]
19
+ for block in split_into_blocks(padded_plaintext):
20
+ chained_block: bytes = xor(block, previous_ciphertext_block)
21
+ ciphertext_block: bytes = self.algorithm.encrypt_block(chained_block)
22
+ ciphertext_blocks.append(ciphertext_block)
23
+ previous_ciphertext_block = xor(block, ciphertext_block)
24
+ return bytes(0).join(ciphertext_blocks)
25
+
26
+ def __decrypt_blocks__(self, ciphertext: bytes) -> bytes:
27
+ initialization_vector, *ciphertext_blocks = split_into_blocks(ciphertext)
28
+ previous_ciphertext_block: bytes = initialization_vector
29
+ plaintext_blocks: list[bytes] = []
30
+ for block in ciphertext_blocks:
31
+ decrypted_block: bytes = self.algorithm.decrypt_block(block)
32
+ plaintext_block: bytes = xor(decrypted_block, previous_ciphertext_block)
33
+ plaintext_blocks.append(plaintext_block)
34
+ previous_ciphertext_block = xor(block, plaintext_block)
35
+ return bytes(0).join(plaintext_blocks)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: purepython-aes
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: Pure-Python implementation of AES encryption algorithm.
5
5
  Author-email: Emelianov Artem <penguin5726@proton.me>
6
6
  License-Expression: MIT
@@ -31,7 +31,9 @@ src/purepython_aes/aes/modes/_base.py
31
31
  src/purepython_aes/aes/modes/operations.py
32
32
  src/purepython_aes/aes/modes/block/__init__.py
33
33
  src/purepython_aes/aes/modes/block/_base.py
34
+ src/purepython_aes/aes/modes/block/cbc.py
34
35
  src/purepython_aes/aes/modes/block/ecb.py
36
+ src/purepython_aes/aes/modes/block/pcbc.py
35
37
  src/purepython_aes/aes/padding/__init__.py
36
38
  src/purepython_aes/aes/padding/_base.py
37
39
  src/purepython_aes/aes/padding/ansix923.py
@@ -65,7 +67,9 @@ tests/unit/aes/core/test_state.py
65
67
  tests/unit/aes/modes/__init__.py
66
68
  tests/unit/aes/modes/test_operations.py
67
69
  tests/unit/aes/modes/block/__init__.py
70
+ tests/unit/aes/modes/block/test_cbc.py
68
71
  tests/unit/aes/modes/block/test_ecb.py
72
+ tests/unit/aes/modes/block/test_pcbc.py
69
73
  tests/unit/aes/padding/__init__.py
70
74
  tests/unit/aes/padding/conftest.py
71
75
  tests/unit/aes/padding/strategies.py
@@ -34,6 +34,8 @@
34
34
  "src/purepython_aes/aes/modes/operations.py",
35
35
  "src/purepython_aes/aes/modes/block/_base.py",
36
36
  "src/purepython_aes/aes/modes/block/__init__.py",
37
+ "src/purepython_aes/aes/modes/block/cbc.py",
38
+ "src/purepython_aes/aes/modes/block/pcbc.py",
37
39
  "src/purepython_aes/aes/modes/block/ecb.py",
38
40
  "src/purepython_aes/aes/algorithms/aes128.py",
39
41
  "src/purepython_aes/aes/algorithms/__init__.py",
@@ -64,7 +66,9 @@
64
66
  "tests/unit/aes/modes/test_operations.py",
65
67
  "tests/unit/aes/modes/__init__.py",
66
68
  "tests/unit/aes/modes/block/__init__.py",
69
+ "tests/unit/aes/modes/block/test_pcbc.py",
67
70
  "tests/unit/aes/modes/block/test_ecb.py",
71
+ "tests/unit/aes/modes/block/test_cbc.py",
68
72
  "tests/unit/aes/algorithms/test_aes256.py",
69
73
  "tests/unit/aes/algorithms/__init__.py",
70
74
  "tests/unit/aes/algorithms/test_aes128.py",
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "0.1.0",
2
+ "tag": "0.3.0",
3
3
  "distance": 0,
4
- "node": "g18cff6ba62f4743b0f5af672a133edba13f2b244",
4
+ "node": "gd094c7acbd7291759ff4f81bfdab575e037f2200",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-07-13"
@@ -0,0 +1,67 @@
1
+ from itertools import product
2
+
3
+ from hypothesis import assume, 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
+ AnsiX923Padding,
13
+ BasePadding,
14
+ CbcMode,
15
+ Iso7816Padding,
16
+ Iso10126Padding,
17
+ NoPadding,
18
+ Pkcs7Padding,
19
+ ZeroPadding,
20
+ )
21
+ from tests.unit.aes.strategies import aes256key, aes_blocks
22
+
23
+
24
+ @mark.quick
25
+ class TestCbcMode:
26
+ @staticmethod
27
+ @mark.parametrize(
28
+ ['aes', 'padding'],
29
+ tuple(
30
+ product(
31
+ [Aes128, Aes192, Aes256],
32
+ [AnsiX923Padding, Iso10126Padding, Iso7816Padding, Pkcs7Padding],
33
+ ),
34
+ ),
35
+ )
36
+ @given(key=aes256key, data=binary())
37
+ def test_decrypt_inverts_encrypt(
38
+ aes: type[Aes],
39
+ padding: type[BasePadding],
40
+ key: bytes,
41
+ data: bytes,
42
+ ) -> None:
43
+ ecb: CbcMode = CbcMode(aes(key[:aes.__key_size__]), padding()) # fmt: skip
44
+ assert ecb.decrypt(ecb.encrypt(data)) == data
45
+
46
+ @staticmethod
47
+ @mark.parametrize(['aes'], [[Aes128], [Aes192], [Aes256]])
48
+ @given(key=aes256key, data=binary())
49
+ def test_decrypt_inverts_encrypt_zero_padding(
50
+ aes: type[Aes],
51
+ key: bytes,
52
+ data: bytes,
53
+ ) -> None:
54
+ assume(not data.endswith(bytes(1)))
55
+ ecb: CbcMode = CbcMode(aes(key[:aes.__key_size__]), ZeroPadding()) # fmt: skip
56
+ assert ecb.decrypt(ecb.encrypt(data)) == data
57
+
58
+ @staticmethod
59
+ @mark.parametrize(['aes'], [[Aes128], [Aes192], [Aes256]])
60
+ @given(key=aes256key, data=aes_blocks)
61
+ def test_decrypt_inverts_encrypt_no_padding(
62
+ aes: type[Aes],
63
+ key: bytes,
64
+ data: bytes,
65
+ ) -> None:
66
+ ecb: CbcMode = CbcMode(aes(key[:aes.__key_size__]), NoPadding()) # fmt: skip
67
+ assert ecb.decrypt(ecb.encrypt(data)) == data
@@ -0,0 +1,70 @@
1
+ from itertools import product
2
+
3
+ from hypothesis import assume, 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
+ AnsiX923Padding,
13
+ BasePadding,
14
+ Iso7816Padding,
15
+ Iso10126Padding,
16
+ NoPadding,
17
+ PcbcMode,
18
+ Pkcs7Padding,
19
+ ZeroPadding,
20
+ )
21
+ from tests.unit.aes.strategies import aes256key, aes_blocks
22
+
23
+
24
+ @mark.quick
25
+ class TestCbcMode:
26
+ @staticmethod
27
+ @mark.parametrize(
28
+ ['aes', 'padding'],
29
+ tuple(
30
+ product(
31
+ [Aes128, Aes192, Aes256],
32
+ [AnsiX923Padding, Iso10126Padding, Iso7816Padding, Pkcs7Padding],
33
+ ),
34
+ ),
35
+ )
36
+ @given(key=aes256key, data=binary())
37
+ def test_decrypt_inverts_encrypt(
38
+ aes: type[Aes],
39
+ padding: type[BasePadding],
40
+ key: bytes,
41
+ data: bytes,
42
+ ) -> None:
43
+ ecb: PcbcMode = PcbcMode(aes(key[:aes.__key_size__]), padding()) # fmt: skip
44
+ assert ecb.decrypt(ecb.encrypt(data)) == data
45
+
46
+ @staticmethod
47
+ @mark.parametrize(['aes'], [[Aes128], [Aes192], [Aes256]])
48
+ @given(key=aes256key, data=binary())
49
+ def test_decrypt_inverts_encrypt_zero_padding(
50
+ aes: type[Aes],
51
+ key: bytes,
52
+ data: bytes,
53
+ ) -> None:
54
+ assume(not data.endswith(bytes(1)))
55
+ ecb: PcbcMode = PcbcMode(
56
+ algorithm=aes(key[:aes.__key_size__]), # fmt: skip
57
+ padding=ZeroPadding(),
58
+ )
59
+ assert ecb.decrypt(ecb.encrypt(data)) == data
60
+
61
+ @staticmethod
62
+ @mark.parametrize(['aes'], [[Aes128], [Aes192], [Aes256]])
63
+ @given(key=aes256key, data=aes_blocks)
64
+ def test_decrypt_inverts_encrypt_no_padding(
65
+ aes: type[Aes],
66
+ key: bytes,
67
+ data: bytes,
68
+ ) -> None:
69
+ ecb: PcbcMode = PcbcMode(aes(key[:aes.__key_size__]), NoPadding()) # fmt: skip
70
+ assert ecb.decrypt(ecb.encrypt(data)) == data
@@ -1,4 +0,0 @@
1
- from purepython_aes.aes.modes._base import AesMode
2
- from purepython_aes.aes.modes.block import BlockCipherMode, EcbMode
3
-
4
- __all__: list[str] = ['AesMode', 'BlockCipherMode', 'EcbMode']
@@ -1,4 +0,0 @@
1
- from purepython_aes.aes.modes.block._base import BlockCipherMode
2
- from purepython_aes.aes.modes.block.ecb import EcbMode
3
-
4
- __all__: list[str] = ['BlockCipherMode', 'EcbMode']
File without changes
File without changes