Skip to content

Commit 7570fc5

Browse files
committed
update
1 parent 89fc194 commit 7570fc5

File tree

6 files changed

+91
-27
lines changed

6 files changed

+91
-27
lines changed

.idea/.gitignore

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/cngn-pyhon-library.iml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/material_theme_project_new.xml

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cngn_manager/AESCrypto.py

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,55 +4,78 @@
44
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
55
import os
66
import base64
7-
87
class AESCrypto:
98
ALGORITHM = algorithms.AES
109
IV_LENGTH = 16
1110
KEY_LENGTH = 32 # 256 bits
12-
11+
BLOCK_SIZE = 16 # AES block size
12+
class InvalidPaddingError(Exception):
13+
pass
1314
@staticmethod
1415
def prepare_key(key: str) -> bytes:
1516
# Hash the key using SHA-256 to ensure it's always the correct length (32 bytes)
1617
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
1718
digest.update(key.encode('utf-8'))
1819
return digest.finalize()
19-
20+
@staticmethod
21+
def pkcs7_pad(data: bytes) -> bytes:
22+
"""Apply PKCS7 padding to the data."""
23+
padding_length = AESCrypto.BLOCK_SIZE - (len(data) % AESCrypto.BLOCK_SIZE)
24+
padding = bytes([padding_length] * padding_length)
25+
return data + padding
26+
@staticmethod
27+
def pkcs7_unpad(data: bytes) -> bytes:
28+
"""
29+
Remove and validate PKCS7 padding.
30+
Raises InvalidPaddingError if padding is incorrect.
31+
"""
32+
if len(data) == 0:
33+
raise AESCrypto.InvalidPaddingError("Empty data")
34+
if len(data) % AESCrypto.BLOCK_SIZE != 0:
35+
raise AESCrypto.InvalidPaddingError("Data length not multiple of block size")
36+
padding_length = data[-1]
37+
if padding_length == 0 or padding_length > AESCrypto.BLOCK_SIZE:
38+
raise AESCrypto.InvalidPaddingError("Invalid padding length")
39+
if len(data) < padding_length:
40+
raise AESCrypto.InvalidPaddingError("Padding length larger than data")
41+
# Check all padding bytes are correct
42+
padding = data[-padding_length:]
43+
if not all(x == padding_length for x in padding):
44+
raise AESCrypto.InvalidPaddingError("Invalid padding values")
45+
return data[:-padding_length]
2046
@staticmethod
2147
def encrypt(data: str, key: str) -> dict:
2248
# Generate a random Initialization Vector (IV)
2349
iv = os.urandom(AESCrypto.IV_LENGTH)
2450
key_buffer = AESCrypto.prepare_key(key)
25-
2651
# Create cipher and encrypt the data
2752
cipher = Cipher(AESCrypto.ALGORITHM(key_buffer), modes.CBC(iv), backend=default_backend())
2853
encryptor = cipher.encryptor()
29-
30-
# Pad data to be multiple of 16 bytes (block size for AES)
31-
padding_length = 16 - (len(data) % 16)
32-
padded_data = data + chr(padding_length) * padding_length
33-
encrypted = encryptor.update(padded_data.encode('utf-8')) + encryptor.finalize()
34-
54+
# Properly pad data using PKCS7
55+
padded_data = AESCrypto.pkcs7_pad(data.encode('utf-8'))
56+
encrypted = encryptor.update(padded_data) + encryptor.finalize()
3557
# Return the encrypted content and the IV (both base64 encoded)
3658
return {
3759
'content': base64.b64encode(encrypted).decode('utf-8'),
3860
'iv': base64.b64encode(iv).decode('utf-8')
3961
}
40-
4162
@staticmethod
4263
def decrypt(encrypted_data: dict, key: str) -> str:
43-
# Decode the base64 encoded IV and content
44-
iv = base64.b64decode(encrypted_data['iv'])
45-
encrypted_content = base64.b64decode(encrypted_data['content'])
46-
key_buffer = AESCrypto.prepare_key(key)
47-
48-
# Create cipher and decrypt the data
49-
cipher = Cipher(AESCrypto.ALGORITHM(key_buffer), modes.CBC(iv), backend=default_backend())
50-
decryptor = cipher.decryptor()
51-
52-
decrypted = decryptor.update(encrypted_content) + decryptor.finalize()
53-
54-
# Remove padding
55-
padding_length = decrypted[-1]
56-
decrypted = decrypted[:-padding_length]
57-
58-
return decrypted.decode('utf-8')
64+
try:
65+
# Decode the base64 encoded IV and content
66+
iv = base64.b64decode(encrypted_data['iv'])
67+
encrypted_content = base64.b64decode(encrypted_data['content'])
68+
key_buffer = AESCrypto.prepare_key(key)
69+
# Create cipher and decrypt the data
70+
cipher = Cipher(AESCrypto.ALGORITHM(key_buffer), modes.CBC(iv), backend=default_backend())
71+
decryptor = cipher.decryptor()
72+
decrypted = decryptor.update(encrypted_content) + decryptor.finalize()
73+
# Remove padding with validation
74+
unpadded = AESCrypto.pkcs7_unpad(decrypted)
75+
return unpadded.decode('utf-8')
76+
except AESCrypto.InvalidPaddingError as e:
77+
# Handle padding errors uniformly to prevent timing attacks
78+
raise AESCrypto.InvalidPaddingError("Decryption failed")
79+
except Exception as e:
80+
# Handle all other errors uniformly
81+
raise AESCrypto.InvalidPaddingError("Decryption failed")

0 commit comments

Comments
 (0)