purepython-aes 0.1.0__tar.gz → 0.2.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 (84) hide show
  1. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/PKG-INFO +1 -1
  2. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/__init__.py +2 -0
  3. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/__init__.py +2 -1
  4. purepython_aes-0.2.0/src/purepython_aes/aes/modes/__init__.py +4 -0
  5. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/modes/block/__init__.py +2 -1
  6. purepython_aes-0.2.0/src/purepython_aes/aes/modes/block/cbc.py +35 -0
  7. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes.egg-info/PKG-INFO +1 -1
  8. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes.egg-info/SOURCES.txt +2 -0
  9. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes.egg-info/scm_file_list.json +2 -0
  10. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes.egg-info/scm_version.json +2 -2
  11. purepython_aes-0.2.0/tests/unit/aes/modes/block/test_cbc.py +67 -0
  12. purepython_aes-0.1.0/src/purepython_aes/aes/modes/__init__.py +0 -4
  13. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/.github/workflows/pre-commit.yml +0 -0
  14. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/.github/workflows/release.yml +0 -0
  15. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/.gitignore +0 -0
  16. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/.pre-commit-config.yaml +0 -0
  17. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/LISENCE.txt +0 -0
  18. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/README.md +0 -0
  19. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/pyproject.toml +0 -0
  20. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/scripts/check-test-marks.sh +0 -0
  21. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/setup.cfg +0 -0
  22. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/algorithms/__init__.py +0 -0
  23. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/algorithms/aes128.py +0 -0
  24. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/algorithms/aes192.py +0 -0
  25. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/algorithms/aes256.py +0 -0
  26. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/core/__init__.py +0 -0
  27. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/core/aes.py +0 -0
  28. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/core/expansion.py +0 -0
  29. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/core/operations.py +0 -0
  30. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/core/state.py +0 -0
  31. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/interface.py +0 -0
  32. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/modes/_base.py +0 -0
  33. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/modes/block/_base.py +0 -0
  34. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/modes/block/ecb.py +0 -0
  35. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/modes/operations.py +0 -0
  36. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/padding/__init__.py +0 -0
  37. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/padding/_base.py +0 -0
  38. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/padding/ansix923.py +0 -0
  39. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/padding/iso10126.py +0 -0
  40. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/padding/iso7816.py +0 -0
  41. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/padding/no.py +0 -0
  42. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/padding/pkcs7.py +0 -0
  43. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/aes/padding/zero.py +0 -0
  44. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/const/__init__.py +0 -0
  45. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/const/aes.py +0 -0
  46. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/const/sbox.py +0 -0
  47. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/py.typed +0 -0
  48. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/types/__init__.py +0 -0
  49. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/types/finite/__init__.py +0 -0
  50. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes/types/finite/aliases.py +0 -0
  51. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes.egg-info/dependency_links.txt +0 -0
  52. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes.egg-info/requires.txt +0 -0
  53. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/src/purepython_aes.egg-info/top_level.txt +0 -0
  54. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/__init__.py +0 -0
  55. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/test_initial.py +0 -0
  56. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/__init__.py +0 -0
  57. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/__init__.py +0 -0
  58. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/algorithms/__init__.py +0 -0
  59. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/algorithms/conftest.py +0 -0
  60. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/algorithms/test_aes128.py +0 -0
  61. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/algorithms/test_aes192.py +0 -0
  62. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/algorithms/test_aes256.py +0 -0
  63. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/core/__init__.py +0 -0
  64. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/core/strategies.py +0 -0
  65. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/core/test_aes.py +0 -0
  66. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/core/test_expansion.py +0 -0
  67. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/core/test_operations.py +0 -0
  68. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/core/test_state.py +0 -0
  69. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/modes/__init__.py +0 -0
  70. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/modes/block/__init__.py +0 -0
  71. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/modes/block/test_ecb.py +0 -0
  72. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/modes/test_operations.py +0 -0
  73. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/__init__.py +0 -0
  74. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/conftest.py +0 -0
  75. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/strategies.py +0 -0
  76. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/test_ansix923.py +0 -0
  77. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/test_iso10126.py +0 -0
  78. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/test_iso7816.py +0 -0
  79. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/test_no.py +0 -0
  80. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/test_pkcs7.py +0 -0
  81. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/padding/test_zero.py +0 -0
  82. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/aes/strategies.py +0 -0
  83. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/const/__init__.py +0 -0
  84. {purepython_aes-0.1.0 → purepython_aes-0.2.0}/tests/unit/const/test_sbox.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: purepython-aes
3
- Version: 0.1.0
3
+ Version: 0.2.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,6 +7,7 @@ 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,
@@ -24,6 +25,7 @@ __all__: list[str] = [
24
25
  'AnsiX923Padding',
25
26
  'BasePadding',
26
27
  'BlockCipherMode',
28
+ 'CbcMode',
27
29
  'EcbMode',
28
30
  'Iso7816Padding',
29
31
  'Iso10126Padding',
@@ -1,6 +1,6 @@
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 AesMode, BlockCipherMode, CbcMode, EcbMode
4
4
  from purepython_aes.aes.padding import (
5
5
  AnsiX923Padding,
6
6
  BasePadding,
@@ -18,6 +18,7 @@ __all__: list[str] = [
18
18
  'Aes',
19
19
  'AesMode',
20
20
  'BlockCipherMode',
21
+ 'CbcMode',
21
22
  'EcbMode',
22
23
  'AnsiX923Padding',
23
24
  'BasePadding',
@@ -0,0 +1,4 @@
1
+ from purepython_aes.aes.modes._base import AesMode
2
+ from purepython_aes.aes.modes.block import BlockCipherMode, CbcMode, EcbMode
3
+
4
+ __all__: list[str] = ['AesMode', 'BlockCipherMode', 'CbcMode', 'EcbMode']
@@ -1,4 +1,5 @@
1
1
  from purepython_aes.aes.modes.block._base import BlockCipherMode
2
+ from purepython_aes.aes.modes.block.cbc import CbcMode
2
3
  from purepython_aes.aes.modes.block.ecb import EcbMode
3
4
 
4
- __all__: list[str] = ['BlockCipherMode', 'EcbMode']
5
+ __all__: list[str] = ['BlockCipherMode', 'CbcMode', 'EcbMode']
@@ -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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: purepython-aes
3
- Version: 0.1.0
3
+ Version: 0.2.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,6 +31,7 @@ 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
35
36
  src/purepython_aes/aes/padding/__init__.py
36
37
  src/purepython_aes/aes/padding/_base.py
@@ -65,6 +66,7 @@ tests/unit/aes/core/test_state.py
65
66
  tests/unit/aes/modes/__init__.py
66
67
  tests/unit/aes/modes/test_operations.py
67
68
  tests/unit/aes/modes/block/__init__.py
69
+ tests/unit/aes/modes/block/test_cbc.py
68
70
  tests/unit/aes/modes/block/test_ecb.py
69
71
  tests/unit/aes/padding/__init__.py
70
72
  tests/unit/aes/padding/conftest.py
@@ -34,6 +34,7 @@
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",
37
38
  "src/purepython_aes/aes/modes/block/ecb.py",
38
39
  "src/purepython_aes/aes/algorithms/aes128.py",
39
40
  "src/purepython_aes/aes/algorithms/__init__.py",
@@ -65,6 +66,7 @@
65
66
  "tests/unit/aes/modes/__init__.py",
66
67
  "tests/unit/aes/modes/block/__init__.py",
67
68
  "tests/unit/aes/modes/block/test_ecb.py",
69
+ "tests/unit/aes/modes/block/test_cbc.py",
68
70
  "tests/unit/aes/algorithms/test_aes256.py",
69
71
  "tests/unit/aes/algorithms/__init__.py",
70
72
  "tests/unit/aes/algorithms/test_aes128.py",
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "0.1.0",
2
+ "tag": "0.2.0",
3
3
  "distance": 0,
4
- "node": "g18cff6ba62f4743b0f5af672a133edba13f2b244",
4
+ "node": "g6499740a96c2f3a034500f56fa2b3813839c4ba5",
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
@@ -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']
File without changes
File without changes