fastcrypter 2.3.0__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.
@@ -0,0 +1,568 @@
1
+ """
2
+ Secure Compressor - High-level interface for compression and encryption.
3
+
4
+ This module provides a simple, secure interface that combines compression
5
+ and encryption in a single operation for maximum security and efficiency.
6
+ """
7
+
8
+ from typing import Union, Optional, Dict, Any
9
+ from .core.compressor import Compressor, CompressionAlgorithmType, CompressionLevel
10
+ from .core.encryptor import Encryptor, EncryptionAlgorithmType
11
+ from .core.key_manager import KeyManager
12
+ from .core.custom_encoder import CustomEncoder
13
+ from .exceptions import EncrypterError, ValidationError, ErrorCodes
14
+
15
+ # Try to import C/C++ extensions for speed
16
+ try:
17
+ from .core import fast_crypto
18
+ FAST_CRYPTO_AVAILABLE = True
19
+ except ImportError:
20
+ FAST_CRYPTO_AVAILABLE = False
21
+
22
+ try:
23
+ from .core import fast_compression
24
+ FAST_COMPRESSION_AVAILABLE = True
25
+ except ImportError:
26
+ FAST_COMPRESSION_AVAILABLE = False
27
+
28
+
29
+ class SecureCompressor:
30
+ """
31
+ High-level secure compressor that combines compression and encryption.
32
+
33
+ This class provides a simple interface for securely compressing and
34
+ encrypting data in a single operation, with automatic algorithm selection
35
+ and key management. Now includes custom encoding for specified character sets.
36
+ """
37
+
38
+ def __init__(self,
39
+ password: str,
40
+ compression_algorithm: Union[CompressionAlgorithmType, str] = CompressionAlgorithmType.ZLIB,
41
+ compression_level: Union[CompressionLevel, int] = CompressionLevel.BALANCED,
42
+ encryption_algorithm: Union[EncryptionAlgorithmType, str] = EncryptionAlgorithmType.AES_256_GCM,
43
+ auto_select_compression: bool = True,
44
+ kdf_algorithm: str = 'pbkdf2',
45
+ kdf_iterations: int = 100000,
46
+ custom_charset: Optional[str] = None,
47
+ use_fast_extensions: bool = True):
48
+ """
49
+ Initialize the SecureCompressor.
50
+
51
+ Args:
52
+ password (str): Password for encryption key derivation.
53
+ compression_algorithm: Compression algorithm to use.
54
+ compression_level: Compression level (1-9).
55
+ encryption_algorithm: Encryption algorithm to use.
56
+ auto_select_compression (bool): Auto-select best compression algorithm.
57
+ kdf_algorithm (str): Key derivation function algorithm.
58
+ kdf_iterations (int): Number of KDF iterations.
59
+ custom_charset (str, optional): Custom character set for encoding output.
60
+ use_fast_extensions (bool): Use C/C++ extensions if available.
61
+
62
+ Raises:
63
+ ValidationError: If parameters are invalid.
64
+ """
65
+ # Validate password
66
+ if not password or len(password) < 8:
67
+ raise ValidationError(
68
+ "Password must be at least 8 characters long",
69
+ ErrorCodes.KEY_TOO_WEAK
70
+ )
71
+
72
+ self.password = password
73
+ self.use_fast_extensions = use_fast_extensions and (FAST_CRYPTO_AVAILABLE or FAST_COMPRESSION_AVAILABLE)
74
+
75
+ # Initialize components
76
+ self.compressor = Compressor(
77
+ algorithm=compression_algorithm,
78
+ level=compression_level,
79
+ auto_select=auto_select_compression
80
+ )
81
+
82
+ self.encryptor = Encryptor(
83
+ algorithm=encryption_algorithm,
84
+ derive_key=True
85
+ )
86
+
87
+ self.key_manager = KeyManager(
88
+ kdf_algorithm=kdf_algorithm,
89
+ iterations=kdf_iterations
90
+ )
91
+
92
+ # Initialize custom encoder if charset provided
93
+ self.custom_encoder = None
94
+ if custom_charset:
95
+ self.custom_encoder = CustomEncoder(charset=custom_charset)
96
+
97
+ # Store configuration
98
+ self.config = {
99
+ 'compression_algorithm': compression_algorithm,
100
+ 'compression_level': compression_level,
101
+ 'encryption_algorithm': encryption_algorithm,
102
+ 'auto_select_compression': auto_select_compression,
103
+ 'kdf_algorithm': kdf_algorithm,
104
+ 'kdf_iterations': kdf_iterations,
105
+ 'custom_charset': custom_charset,
106
+ 'use_fast_extensions': self.use_fast_extensions,
107
+ }
108
+
109
+ def compress_and_encrypt(self, data: Union[str, bytes],
110
+ output_format: str = 'binary') -> Union[bytes, str]:
111
+ """
112
+ Compress and encrypt data in a single operation.
113
+
114
+ The process follows these steps:
115
+ 1. Compress the data using the configured compression algorithm
116
+ 2. Encrypt the compressed data using the configured encryption algorithm
117
+ 3. Optionally encode to custom character set
118
+
119
+ Args:
120
+ data: Data to compress and encrypt (string or bytes).
121
+ output_format: Output format ('binary', 'custom', 'steganographic').
122
+
123
+ Returns:
124
+ Union[bytes, str]: Encrypted compressed data.
125
+
126
+ Raises:
127
+ EncrypterError: If compression or encryption fails.
128
+ ValidationError: If input data is invalid.
129
+ """
130
+ try:
131
+ # Step 1: Compress data (with fast extension if available)
132
+ if self.use_fast_extensions and FAST_COMPRESSION_AVAILABLE:
133
+ if isinstance(data, str):
134
+ data = data.encode('utf-8')
135
+ compressed_data = fast_compression.fast_compress(data)
136
+ else:
137
+ compressed_data = self.compressor.compress(data)
138
+
139
+ # Step 2: Encrypt compressed data
140
+ encrypted_data = self.encryptor.encrypt(compressed_data, self.password)
141
+
142
+ # Step 3: Apply custom encoding if requested
143
+ if output_format == 'binary':
144
+ return encrypted_data
145
+ elif output_format == 'custom' and self.custom_encoder:
146
+ return self.custom_encoder.encode(encrypted_data)
147
+ elif output_format == 'steganographic' and self.custom_encoder:
148
+ return self.custom_encoder.create_steganographic_text(encrypted_data)
149
+ else:
150
+ return encrypted_data
151
+
152
+ except Exception as e:
153
+ raise EncrypterError(
154
+ f"Secure compression failed: {str(e)}",
155
+ details={"operation": "compress_and_encrypt", "error": str(e)}
156
+ )
157
+
158
+ def decrypt_and_decompress(self, data: Union[bytes, str],
159
+ input_format: str = 'binary') -> bytes:
160
+ """
161
+ Decrypt and decompress data in a single operation.
162
+
163
+ The process follows these steps:
164
+ 1. Decode from custom format if necessary
165
+ 2. Decrypt the data using the configured encryption algorithm
166
+ 3. Decompress the decrypted data using the appropriate compression algorithm
167
+ 4. Return the original data
168
+
169
+ Args:
170
+ data: Encrypted compressed data to decrypt and decompress.
171
+ input_format: Input format ('binary', 'custom', 'steganographic').
172
+
173
+ Returns:
174
+ bytes: Original decompressed data.
175
+
176
+ Raises:
177
+ EncrypterError: If decryption or decompression fails.
178
+ ValidationError: If input data is invalid.
179
+ """
180
+ try:
181
+ # Step 1: Decode from custom format if necessary
182
+ if input_format == 'custom' and self.custom_encoder and isinstance(data, str):
183
+ encrypted_data = self.custom_encoder.decode(data)
184
+ elif input_format == 'binary':
185
+ encrypted_data = data
186
+ else:
187
+ encrypted_data = data
188
+
189
+ # Step 2: Decrypt data
190
+ decrypted_data = self.encryptor.decrypt(encrypted_data, self.password)
191
+
192
+ # Step 3: Decompress decrypted data (with fast extension if available)
193
+ if self.use_fast_extensions and FAST_COMPRESSION_AVAILABLE:
194
+ decompressed_data = fast_compression.fast_decompress(decrypted_data)
195
+ else:
196
+ decompressed_data = self.compressor.decompress(decrypted_data)
197
+
198
+ return decompressed_data
199
+
200
+ except Exception as e:
201
+ raise EncrypterError(
202
+ f"Secure decompression failed: {str(e)}",
203
+ details={"operation": "decrypt_and_decompress", "error": str(e)}
204
+ )
205
+
206
+ def compress_and_encrypt_to_custom(self, data: Union[str, bytes],
207
+ charset: str = "abcdef98Xvbvii") -> str:
208
+ """
209
+ Compress, encrypt, and encode to custom character set.
210
+
211
+ Args:
212
+ data: Data to process.
213
+ charset: Custom character set to use.
214
+
215
+ Returns:
216
+ str: Encoded string using only specified characters.
217
+ """
218
+ # Create temporary encoder if different charset
219
+ if not self.custom_encoder or self.custom_encoder.charset != charset:
220
+ temp_encoder = CustomEncoder(charset=charset)
221
+ else:
222
+ temp_encoder = self.custom_encoder
223
+
224
+ # Compress and encrypt
225
+ encrypted_data = self.compress_and_encrypt(data, output_format='binary')
226
+
227
+ # Encode to custom charset
228
+ return temp_encoder.encode(encrypted_data)
229
+
230
+ def decrypt_and_decompress_from_custom(self, encoded_data: str,
231
+ charset: str = "abcdef98Xvbvii") -> bytes:
232
+ """
233
+ Decode from custom character set, decrypt, and decompress.
234
+
235
+ Args:
236
+ encoded_data: Data encoded with custom charset.
237
+ charset: Custom character set used for encoding.
238
+
239
+ Returns:
240
+ bytes: Original data.
241
+ """
242
+ # Create temporary encoder if different charset
243
+ if not self.custom_encoder or self.custom_encoder.charset != charset:
244
+ temp_encoder = CustomEncoder(charset=charset)
245
+ else:
246
+ temp_encoder = self.custom_encoder
247
+
248
+ # Decode from custom charset
249
+ encrypted_data = temp_encoder.decode(encoded_data)
250
+
251
+ # Decrypt and decompress
252
+ return self.decrypt_and_decompress(encrypted_data, input_format='binary')
253
+
254
+ def compress_and_encrypt_string(self, text: str,
255
+ output_format: str = 'binary') -> Union[bytes, str]:
256
+ """
257
+ Compress and encrypt a string, returning encrypted data.
258
+
259
+ Args:
260
+ text (str): Text to compress and encrypt.
261
+ output_format: Output format ('binary', 'custom', 'steganographic').
262
+
263
+ Returns:
264
+ Union[bytes, str]: Encrypted compressed data.
265
+ """
266
+ return self.compress_and_encrypt(text, output_format)
267
+
268
+ def decrypt_and_decompress_to_string(self, data: Union[bytes, str],
269
+ input_format: str = 'binary',
270
+ encoding: str = 'utf-8') -> str:
271
+ """
272
+ Decrypt and decompress data, returning a string.
273
+
274
+ Args:
275
+ data: Encrypted compressed data.
276
+ input_format: Input format ('binary', 'custom', 'steganographic').
277
+ encoding (str): Text encoding to use for decoding.
278
+
279
+ Returns:
280
+ str: Original text.
281
+
282
+ Raises:
283
+ UnicodeDecodeError: If data cannot be decoded as text.
284
+ """
285
+ decompressed_data = self.decrypt_and_decompress(data, input_format)
286
+ return decompressed_data.decode(encoding)
287
+
288
+ def get_compression_ratio(self, original_data: Union[str, bytes],
289
+ compressed_encrypted_data: Union[bytes, str]) -> float:
290
+ """
291
+ Calculate the overall compression ratio (including encryption overhead).
292
+
293
+ Args:
294
+ original_data: Original uncompressed data.
295
+ compressed_encrypted_data: Final encrypted compressed data.
296
+
297
+ Returns:
298
+ float: Compression ratio (final_size / original_size).
299
+ """
300
+ if isinstance(original_data, str):
301
+ original_data = original_data.encode('utf-8')
302
+
303
+ if len(original_data) == 0:
304
+ return 0.0
305
+
306
+ if isinstance(compressed_encrypted_data, str):
307
+ final_size = len(compressed_encrypted_data.encode('utf-8'))
308
+ else:
309
+ final_size = len(compressed_encrypted_data)
310
+
311
+ return final_size / len(original_data)
312
+
313
+ def estimate_output_size(self, input_size: int, output_format: str = 'binary') -> Dict[str, int]:
314
+ """
315
+ Estimate the output size for given input size.
316
+
317
+ Args:
318
+ input_size (int): Size of input data in bytes.
319
+ output_format: Output format to estimate for.
320
+
321
+ Returns:
322
+ Dict[str, int]: Estimated sizes for different stages.
323
+ """
324
+ # Rough estimates based on typical compression ratios and encryption overhead
325
+ compression_ratios = {
326
+ CompressionAlgorithmType.ZLIB: 0.6,
327
+ CompressionAlgorithmType.LZMA: 0.4,
328
+ CompressionAlgorithmType.BROTLI: 0.5,
329
+ }
330
+
331
+ # Get compression ratio estimate
332
+ comp_ratio = compression_ratios.get(self.compressor.algorithm, 0.6)
333
+ compressed_size = int(input_size * comp_ratio) + 8 # Add header overhead
334
+
335
+ # Encryption adds overhead (headers, IV, tag, etc.)
336
+ encryption_overhead = 64 # Conservative estimate
337
+ encrypted_size = compressed_size + encryption_overhead
338
+
339
+ # Custom encoding overhead
340
+ if output_format == 'custom' and self.custom_encoder:
341
+ # Base conversion typically increases size
342
+ custom_size = int(encrypted_size * 1.4) # Rough estimate
343
+ else:
344
+ custom_size = encrypted_size
345
+
346
+ return {
347
+ 'original_size': input_size,
348
+ 'estimated_compressed_size': compressed_size,
349
+ 'estimated_encrypted_size': encrypted_size,
350
+ 'estimated_final_size': custom_size,
351
+ 'estimated_compression_ratio': comp_ratio,
352
+ 'estimated_total_ratio': custom_size / input_size if input_size > 0 else 0,
353
+ }
354
+
355
+ def change_password(self, new_password: str) -> None:
356
+ """
357
+ Change the password used for encryption.
358
+
359
+ Args:
360
+ new_password (str): New password to use.
361
+
362
+ Raises:
363
+ ValidationError: If new password is too weak.
364
+ """
365
+ if not new_password or len(new_password) < 8:
366
+ raise ValidationError(
367
+ "New password must be at least 8 characters long",
368
+ ErrorCodes.KEY_TOO_WEAK
369
+ )
370
+
371
+ self.password = new_password
372
+
373
+ def set_custom_charset(self, charset: str) -> None:
374
+ """
375
+ Set or change the custom character set for encoding.
376
+
377
+ Args:
378
+ charset (str): New character set to use.
379
+ """
380
+ self.custom_encoder = CustomEncoder(charset=charset)
381
+ self.config['custom_charset'] = charset
382
+
383
+ def validate_password_strength(self, password: Optional[str] = None) -> Dict[str, Any]:
384
+ """
385
+ Validate password strength.
386
+
387
+ Args:
388
+ password (str, optional): Password to validate. Uses current password if None.
389
+
390
+ Returns:
391
+ Dict[str, Any]: Password strength analysis.
392
+ """
393
+ pwd = password or self.password
394
+
395
+ # Basic strength checks
396
+ length_ok = len(pwd) >= 8
397
+ has_upper = any(c.isupper() for c in pwd)
398
+ has_lower = any(c.islower() for c in pwd)
399
+ has_digit = any(c.isdigit() for c in pwd)
400
+ has_special = any(not c.isalnum() for c in pwd)
401
+
402
+ # Calculate strength score
403
+ score = 0
404
+ if length_ok:
405
+ score += 1
406
+ if len(pwd) >= 12:
407
+ score += 1
408
+ if has_upper:
409
+ score += 1
410
+ if has_lower:
411
+ score += 1
412
+ if has_digit:
413
+ score += 1
414
+ if has_special:
415
+ score += 1
416
+
417
+ # Determine strength level
418
+ if score >= 5:
419
+ strength = "Strong"
420
+ elif score >= 3:
421
+ strength = "Medium"
422
+ else:
423
+ strength = "Weak"
424
+
425
+ return {
426
+ 'strength': strength,
427
+ 'score': score,
428
+ 'max_score': 6,
429
+ 'checks': {
430
+ 'length_ok': length_ok,
431
+ 'has_uppercase': has_upper,
432
+ 'has_lowercase': has_lower,
433
+ 'has_digits': has_digit,
434
+ 'has_special_chars': has_special,
435
+ },
436
+ 'recommendations': self._get_password_recommendations(pwd)
437
+ }
438
+
439
+ def _get_password_recommendations(self, password: str) -> list:
440
+ """Get password improvement recommendations."""
441
+ recommendations = []
442
+
443
+ if len(password) < 8:
444
+ recommendations.append("Use at least 8 characters")
445
+ elif len(password) < 12:
446
+ recommendations.append("Consider using 12+ characters for better security")
447
+
448
+ if not any(c.isupper() for c in password):
449
+ recommendations.append("Add uppercase letters")
450
+
451
+ if not any(c.islower() for c in password):
452
+ recommendations.append("Add lowercase letters")
453
+
454
+ if not any(c.isdigit() for c in password):
455
+ recommendations.append("Add numbers")
456
+
457
+ if not any(not c.isalnum() for c in password):
458
+ recommendations.append("Add special characters (!@#$%^&*)")
459
+
460
+ if not recommendations:
461
+ recommendations.append("Password strength is good!")
462
+
463
+ return recommendations
464
+
465
+ def get_info(self) -> Dict[str, Any]:
466
+ """
467
+ Get comprehensive information about the SecureCompressor configuration.
468
+
469
+ Returns:
470
+ Dict[str, Any]: Configuration and status information.
471
+ """
472
+ info = {
473
+ 'version': '1.0.0',
474
+ 'configuration': self.config,
475
+ 'compressor_info': self.compressor.get_info(),
476
+ 'encryptor_info': self.encryptor.get_info(),
477
+ 'key_manager_info': self.key_manager.get_info(),
478
+ 'password_strength': self.validate_password_strength(),
479
+ 'fast_extensions': {
480
+ 'crypto_available': FAST_CRYPTO_AVAILABLE,
481
+ 'compression_available': FAST_COMPRESSION_AVAILABLE,
482
+ 'enabled': self.use_fast_extensions,
483
+ }
484
+ }
485
+
486
+ if self.custom_encoder:
487
+ info['custom_encoder_info'] = self.custom_encoder.get_charset_info()
488
+
489
+ return info
490
+
491
+ def benchmark_performance(self, data_size: int = 1024) -> Dict[str, Any]:
492
+ """
493
+ Benchmark the performance of different operations.
494
+
495
+ Args:
496
+ data_size: Size of test data in bytes.
497
+
498
+ Returns:
499
+ Dict[str, Any]: Benchmark results.
500
+ """
501
+ import time
502
+ import secrets
503
+
504
+ # Generate test data
505
+ test_data = secrets.token_bytes(data_size)
506
+
507
+ results = {}
508
+
509
+ # Benchmark binary format
510
+ start_time = time.time()
511
+ encrypted = self.compress_and_encrypt(test_data, 'binary')
512
+ encrypt_time = time.time() - start_time
513
+
514
+ start_time = time.time()
515
+ decrypted = self.decrypt_and_decompress(encrypted, 'binary')
516
+ decrypt_time = time.time() - start_time
517
+
518
+ results['binary'] = {
519
+ 'encrypt_time': encrypt_time,
520
+ 'decrypt_time': decrypt_time,
521
+ 'total_time': encrypt_time + decrypt_time,
522
+ 'throughput_mbps': (data_size / (1024 * 1024)) / (encrypt_time + decrypt_time),
523
+ 'compression_ratio': len(encrypted) / data_size,
524
+ 'correctness': test_data == decrypted
525
+ }
526
+
527
+ # Benchmark custom encoding if available
528
+ if self.custom_encoder:
529
+ start_time = time.time()
530
+ custom_encrypted = self.compress_and_encrypt(test_data, 'custom')
531
+ custom_encrypt_time = time.time() - start_time
532
+
533
+ start_time = time.time()
534
+ custom_decrypted = self.decrypt_and_decompress(custom_encrypted, 'custom')
535
+ custom_decrypt_time = time.time() - start_time
536
+
537
+ results['custom'] = {
538
+ 'encrypt_time': custom_encrypt_time,
539
+ 'decrypt_time': custom_decrypt_time,
540
+ 'total_time': custom_encrypt_time + custom_decrypt_time,
541
+ 'throughput_mbps': (data_size / (1024 * 1024)) / (custom_encrypt_time + custom_decrypt_time),
542
+ 'expansion_ratio': len(custom_encrypted.encode('utf-8')) / data_size,
543
+ 'correctness': test_data == custom_decrypted
544
+ }
545
+
546
+ return results
547
+
548
+ def __repr__(self) -> str:
549
+ """String representation of the SecureCompressor."""
550
+ charset_info = f", charset={self.custom_encoder.charset}" if self.custom_encoder else ""
551
+ return (f"SecureCompressor("
552
+ f"compression={self.compressor.algorithm.value}, "
553
+ f"encryption={self.encryptor.algorithm.value}, "
554
+ f"kdf={self.key_manager.kdf_algorithm}"
555
+ f"{charset_info})")
556
+
557
+ def __str__(self) -> str:
558
+ """Human-readable string representation."""
559
+ base_str = (f"Secure Compressor with {self.compressor.algorithm.value.upper()} compression "
560
+ f"and {self.encryptor.algorithm.value.upper()} encryption")
561
+
562
+ if self.custom_encoder:
563
+ base_str += f" using custom charset '{self.custom_encoder.charset}'"
564
+
565
+ if self.use_fast_extensions:
566
+ base_str += " (fast extensions enabled)"
567
+
568
+ return base_str
@@ -0,0 +1,17 @@
1
+ """
2
+ Utility modules for the Encrypter package.
3
+
4
+ This package contains helper functions, validators,
5
+ and other utility components.
6
+ """
7
+
8
+ # Import will be added when utility files are created
9
+ # from .validators import validate_input, validate_key
10
+ # from .helpers import secure_random, clear_memory
11
+
12
+ __all__ = [
13
+ # "validate_input",
14
+ # "validate_key",
15
+ # "secure_random",
16
+ # "clear_memory",
17
+ ]