acesecurity 2.0.0.7__py3-none-any.whl

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.
acecurity/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from . import passwords, rand
2
+ from ._direct import EAN, GenericLabeledEnum, RiskLevel, Security
acecurity/_cli.py ADDED
File without changes
acecurity/_direct.py ADDED
@@ -0,0 +1,112 @@
1
+ """TBA"""
2
+
3
+ from enum import Enum as _Enum
4
+
5
+
6
+ from typing_extensions import deprecated
7
+
8
+ # Standard typing imports for aps
9
+ import typing_extensions as _te
10
+ import collections.abc as _a
11
+ import typing as _ty
12
+
13
+ if _ty.TYPE_CHECKING:
14
+ import _typeshed as _tsh
15
+ import types as _ts
16
+
17
+ __all__ = ["GenericLabeledEnum", "EAN", "Security", "RiskLevel"]
18
+
19
+
20
+ class GenericLabeledEnum(_Enum):
21
+ value: _ty.Any
22
+ label: str
23
+
24
+ def __new__(cls, value: _ty.Any, label: str):
25
+ # Construct a base instance based on value type
26
+ obj = object.__new__(cls) # <-- FIXED: safe for nested or complex types
27
+ obj._value_ = value
28
+ obj.label = label
29
+ return obj
30
+
31
+ def __str__(self) -> str:
32
+ return self.label # printed or str() shows label
33
+
34
+ def __repr__(self) -> str:
35
+ return f"{self.__class__.__name__}.{self.name}({repr(self.value)}, {repr(self.label)})"
36
+
37
+ def __int__(self) -> int:
38
+ try:
39
+ return int(self.value)
40
+ except Exception as e:
41
+ raise TypeError("Cannot convert non-int value to int") from e
42
+
43
+ def __index__(self) -> int:
44
+ print(f"Converting {self, type(self)} to int")
45
+ return int(self)
46
+
47
+ def __eq__(self, other: _ty.Any) -> bool:
48
+ return self.value == other or super().__eq__(other)
49
+
50
+ def __hash__(self) -> int:
51
+ return hash(self.value)
52
+
53
+ def __getattr__(self, attr):
54
+ # 🔥 Here's the key: delegate missing attrs to `.value`
55
+ try:
56
+ return getattr(self.value, attr)
57
+ except AttributeError:
58
+ raise AttributeError(
59
+ f"{self.__class__.__name__} object has no attribute '{attr}'"
60
+ )
61
+
62
+
63
+ # @deprecated("Please use GenericLabeledEnum instead")
64
+ class EAN:
65
+ def __init__(self, value: _ty.Any, info: str) -> None:
66
+ self.value = value
67
+ self.info = info
68
+
69
+ def __repr__(self) -> str:
70
+ return self.info
71
+
72
+
73
+ class Security: # Changed to indices for easy selection from iterables
74
+ """Baseclass for different security levels"""
75
+
76
+ BASIC = EAN(
77
+ 0,
78
+ "An attacker can reverse whatever if they have enough info on you pretty easily",
79
+ )
80
+ AVERAGE = EAN(1, "A lot better than basic")
81
+ STRONG = EAN(2, "Practically impossible to reverse or crack")
82
+ SUPER_STRONG = EAN(
83
+ 3,
84
+ "Great security, but at the cost of comfort features like readability and efficiency",
85
+ )
86
+
87
+ check_not_available: bool = True
88
+
89
+
90
+ class RiskLevel(GenericLabeledEnum):
91
+ """Risk assessment for various parts of security"""
92
+
93
+ HARMLESS = (
94
+ None,
95
+ "Harmless: Considered secure, even with the threat of future quantum computers.",
96
+ )
97
+ NOT_RECOMMENDED = (
98
+ None,
99
+ "Not recommended: Generally secure but there are better or more modern alternatives.",
100
+ )
101
+ KNOWN_UNSAFE = (
102
+ None,
103
+ "Deprecated: Known vulnerabilities exist; should not be used.",
104
+ )
105
+ KNOWN_UNSAFE_NOT_RECOMMENDED = (
106
+ None,
107
+ "Deprecated, Not recommended: Combination of known issues and better alternatives.",
108
+ )
109
+ HIGHLY_DANGEROUS = (
110
+ None,
111
+ "Highly dangerous: Easily broken and should not be used under any circumstances.",
112
+ )
acecurity/main.py ADDED
@@ -0,0 +1,237 @@
1
+ import sys
2
+ from acecurity.crypto import PasswordManager, set_backend, Backend, PQPasswordManager, DataEncryptor, DigitalSigner
3
+ from acecurity import Security
4
+
5
+ set_backend([Backend.cryptography])
6
+
7
+ # ret: bytes = PasswordManager.hash_password("Test", strength=Security.SUPER_STRONG)
8
+ # print("RET", ret)
9
+ # print(PasswordManager.verify_password("Test", ret))
10
+
11
+ # ret: bytes = PQPasswordManager.hash_password("Test", strength=Security.STRONG)
12
+ # set_backend([Backend.argon2_cffi])
13
+ # print(PQPasswordManager.verify_password("Test", ret))
14
+
15
+ # ec = DataEncryptor.generate()
16
+ # print(ec.get_key())
17
+ # crypt: bytes = ec.encrypt_data(b"Test data")
18
+ # print(crypt)
19
+ # key: bytes = ec.get_key()
20
+ # new_ec = ec.from_key(key)
21
+ # print(new_ec.decrypt_data(crypt))
22
+
23
+ sign = DigitalSigner.generate()
24
+ print(sign.get_private_key())
25
+ signature: bytes = sign.sign_data(b"My data")
26
+ print("SIG", signature)
27
+ print(sign.verify_signature(b"My data", signature))
28
+
29
+ sys.exit(0)
30
+
31
+ from acecurity.tests.test_rand import test_random_generators, test_weighted_functions
32
+
33
+
34
+ test_random_generators()
35
+ # test_weighted_functions()
36
+
37
+ from acecurity.passwords import SecurePasswordGenerator
38
+
39
+ generator = SecurePasswordGenerator(security="super_strong")
40
+ pw_data = generator.passphrase()
41
+
42
+ print(pw_data["password"]) # Actual password
43
+ print(pw_data["extra_info"]) # Generation method metadata
44
+
45
+ generator.sentence() # Readable sentence
46
+ generator.pattern() # Format like Aa99##
47
+ generator.complex_pattern() # Pattern + random word mix
48
+ generator.complex() # High entropy, mixed format
49
+ generator.mnemonic() # Easy to remember
50
+
51
+ pw_data = generator.generate_secure_password(return_worst_case=True)
52
+ print(pw_data["worst_case"]) # e.g., "centuries"
53
+
54
+ from acecurity.crypto.algos import (
55
+ Sym,
56
+ Asym,
57
+ HashAlgorithm,
58
+ KeyDerivationFunction,
59
+ )
60
+ from acecurity.crypto.exceptions import NotSupportedError
61
+ from acecurity.crypto import set_backend, Backend
62
+ import os
63
+
64
+
65
+ set_backend() # Uses Backend.std_lib
66
+
67
+
68
+ # MD5
69
+ h = HashAlgorithm.MD5.hash(b"hello world")
70
+ print("MD5:", h.hex())
71
+ print("Verify:", HashAlgorithm.MD5.verify(b"hello world", h))
72
+ print("Std-Verify:", HashAlgorithm.std_verify(b"hello world", h))
73
+
74
+ # SHA1
75
+ h = HashAlgorithm.SHA1.hash(b"hello world")
76
+ print("SHA1:", h.hex())
77
+ print("Verify:", HashAlgorithm.SHA1.verify(b"hello world", h))
78
+ print("Std-Verify:", HashAlgorithm.std_verify(b"hello world", h))
79
+
80
+ # SHA256
81
+ h = HashAlgorithm.SHA2.SHA256.hash(b"hello world")
82
+ print("SHA256:", h.hex())
83
+ print("Verify:", HashAlgorithm.SHA2.SHA256.verify(b"hello world", h))
84
+ print("Std-Verify:", HashAlgorithm.std_verify(b"hello world", h))
85
+
86
+ # SHA3-256
87
+ h = HashAlgorithm.SHA3.SHA256.hash(b"hello world")
88
+ print("SHA3-256:", h.hex())
89
+ print("Verify:", HashAlgorithm.SHA3.SHA256.verify(b"hello world", h))
90
+ print("Std-Verify:", HashAlgorithm.std_verify(b"hello world", h))
91
+
92
+
93
+ # SHAKE128 (8 bytes)
94
+ h = HashAlgorithm.SHA3.SHAKE128.hash(b"hello", 8)
95
+ print("SHAKE128:", h.hex())
96
+ print("Verify:", HashAlgorithm.SHA3.SHAKE128.verify(b"hello", h))
97
+ print("Std-Verify:", HashAlgorithm.std_verify(b"hello", h))
98
+
99
+ # BLAKE2s (8 bytes)
100
+ h = HashAlgorithm.BLAKE2.BLAKE2s.hash(b"hello", 8)
101
+ print("BLAKE2s:", h.hex())
102
+ print("Verify:", HashAlgorithm.BLAKE2.BLAKE2s.verify(b"hello", h))
103
+ print("Std-Verify:", HashAlgorithm.std_verify(b"hello", h))
104
+
105
+
106
+ # RIPEMD160
107
+ try:
108
+ h = HashAlgorithm.RIPEMD160.hash(b"hello")
109
+ print("RIPEMD160:", h.hex())
110
+ print("Verify:", HashAlgorithm.RIPEMD160.verify(b"hello", h))
111
+ print("Std-Verify:", HashAlgorithm.std_verify(b"hello", h))
112
+ except Exception as e:
113
+ print("RIPEMD160 unsupported in std_lib:", e)
114
+
115
+
116
+ password = b"my-password"
117
+ salt = os.urandom(16)
118
+
119
+ print("PBKDF2HMAC:", KeyDerivationFunction.PBKDF2HMAC.derive(password, salt=salt).hex())
120
+ print("PBKDF1 :", KeyDerivationFunction.PBKDF1.derive(password, salt=salt, length=16).hex())
121
+ print("Scrypt :", KeyDerivationFunction.Scrypt.derive(password, salt=salt, length=16).hex())
122
+ print("HKDF :", KeyDerivationFunction.HKDF.derive(password, salt=salt).hex())
123
+ print("ConcatKDF :", KeyDerivationFunction.ConcatKDF.derive(password, otherinfo=b"my-info").hex())
124
+
125
+
126
+ set_backend(
127
+ [
128
+ Backend.argon2_cffi, # Required for Argon2; Argon2 is also supported by cryptography but not 100% so we put quantcrypt first
129
+ Backend.cryptography,
130
+ Backend.pycryptodomex,
131
+ Backend.quantcrypt, # To enable post-quantum cryptography
132
+ Backend.bcrypt, # Required for BCrypt
133
+ Backend.std_lib, # Fallback
134
+ ]
135
+ )
136
+
137
+
138
+ # Hash a password/message using Argon2
139
+ hashed = HashAlgorithm.ARGON2.hash(b"Ha", os.urandom(16))
140
+ print("\nArgon2 Hash:", hashed.decode())
141
+
142
+ # Verify the hash
143
+ is_valid = HashAlgorithm.ARGON2.verify(b"Ha", hashed)
144
+ print("Argon2 Valid:", is_valid)
145
+
146
+ try:
147
+ print(
148
+ "Std-Verify",
149
+ HashAlgorithm.std_verify(
150
+ b"Ha", hashed, fallback_algorithm="argon2", text_ids=False
151
+ ),
152
+ ) # Std-Verify can't decode special algos like argon2 or bcrypt
153
+ except NotSupportedError:
154
+ print("Std-Verify failed")
155
+
156
+
157
+ # Hash a password with BCrypt
158
+ bcrypt_hash = HashAlgorithm.BCRYPT.hash(b"my-secret-password")
159
+ print("BCrypt Hash:", bcrypt_hash.decode())
160
+
161
+ # Verify the password against the hash
162
+ is_valid = HashAlgorithm.BCRYPT.verify(b"my-secret-password", bcrypt_hash)
163
+ print("BCrypt Valid:", is_valid)
164
+
165
+
166
+ # Derive a key using Argon2 KDF
167
+ derived_key = KeyDerivationFunction.ARGON2.derive(b"my-password", salt=os.urandom(16))
168
+ print("Argon2 Derived Key:", derived_key.hex())
169
+
170
+ # Derive a key using BCrypt KDF
171
+ bcrypt_key = KeyDerivationFunction.BCRYPT.derive(b"my-password", salt=os.urandom(16))
172
+ print("BCrypt Derived Key:", bcrypt_key.hex())
173
+
174
+
175
+ # Recipient generates a keypair
176
+ recipient_key = Asym.Cipher.KYBER.keypair.new("kyber1024")
177
+
178
+ # Extract public key from recipient and share it with the sender
179
+ pub_key_bytes = recipient_key.encode_public_key()
180
+ # Keys can't be regenerated and try: except: takes more space;
181
+ # This can only happen if you do not pass one of the keys when using .decode( ... )
182
+ if pub_key_bytes is None:
183
+ raise ValueError("recipient_key has no public key")
184
+
185
+ # Sender receives the public key and creates a key object with only the public key
186
+ sender_key = Asym.Cipher.KYBER.keypair.decode("kyber1024", public_key=pub_key_bytes)
187
+ # Sender encapsulates a shared secret for the recipient
188
+ ciphertext, shared_secret_sender = sender_key.encapsulate()
189
+
190
+ # Recipient decapsulates to recover the shared secret
191
+ shared_secret_recipient = recipient_key.decapsulate(ciphertext)
192
+
193
+ print("\n=== Kyber KEM Flow ===")
194
+ print(f"Ciphertext : {ciphertext.hex()}")
195
+ print(f"Sender Shared Secret : {shared_secret_sender.hex()}")
196
+ print(f"Recipient Shared Secret: {shared_secret_recipient.hex()}")
197
+ assert shared_secret_sender == shared_secret_recipient, "Shared secrets do not match!"
198
+
199
+
200
+ # Generate the signing keypair (private + public)
201
+ sign_key = Asym.Cipher.DILITHIUM.keypair.new("dilithium5")
202
+
203
+ # Sign a message using the private key
204
+ message = b"Hello World"
205
+ signature = sign_key.sign(message)
206
+
207
+ # Extract and share only the public key
208
+ pub_key_bytes = sign_key.encode_public_key()
209
+ # Keys can't be regenerated and try: except: takes more space;
210
+ # This can only happen if you do not pass one of the keys when using .decode( ... )
211
+ if pub_key_bytes is None:
212
+ raise ValueError("sign_key has no public key")
213
+
214
+ # Create a new key object with only the public key for verification
215
+ verify_key = Asym.Cipher.DILITHIUM.keypair.decode(
216
+ "dilithium5", public_key=pub_key_bytes
217
+ )
218
+ # Verify the signature using the public key
219
+ is_valid = verify_key.sign_verify(message, signature)
220
+
221
+ print("\n=== Dilithium Signature Flow ===")
222
+ print(f"Signature : {signature.hex()}")
223
+ print(f"Signature Valid? {is_valid}")
224
+ assert is_valid, "Signature verification failed!"
225
+
226
+ set_backend(
227
+ [
228
+ Backend.cryptography,
229
+ ]
230
+ )
231
+
232
+ # AES test
233
+ crypt_key = Sym.Cipher.AES.key.new(128)
234
+ encrypted: bytes = crypt_key.encrypt(b"Hello World", Sym.Padding.PKCS7, Sym.Operation.GCM)
235
+ print(encrypted)
236
+ decrypted: bytes = crypt_key.decrypt(encrypted, Sym.Padding.PKCS7, Sym.Operation.GCM)
237
+ print(decrypted)