broadfield-dev commited on
Commit
e160fa0
·
verified ·
1 Parent(s): 19a90e7

Create core.py

Browse files
Files changed (1) hide show
  1. core.py +109 -0
core.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import json
3
+ import os
4
+ import struct
5
+ import logging
6
+
7
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
8
+ from cryptography.hazmat.primitives import hashes
9
+ from cryptography.hazmat.primitives import serialization
10
+ from cryptography.hazmat.primitives.asymmetric import rsa, padding
11
+ from PIL import Image, ImageDraw, ImageFont
12
+ import numpy as np
13
+
14
+ # --- Configure Logging ---
15
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
16
+ logger = logging.getLogger(__name__)
17
+
18
+ # --- Constants ---
19
+ AES_KEY_SIZE_CRYPTO = 32
20
+ AES_GCM_NONCE_SIZE_CRYPTO = 12
21
+ LENGTH_HEADER_SIZE = 4
22
+
23
+ def parse_kv_string_to_dict(kv_str: str) -> dict:
24
+ """Parses a string of key:value or key=value pairs into a dictionary."""
25
+ data_dict = {}
26
+ for line in kv_str.splitlines():
27
+ line = line.strip()
28
+ if not line or line.startswith('#'):
29
+ continue
30
+ if '=' in line:
31
+ key, value = line.split('=', 1)
32
+ elif ':' in line:
33
+ key, value = line.split(':', 1)
34
+ else:
35
+ raise ValueError(f"Invalid format on line: '{line}'. Use 'key: value' or 'key = value'.")
36
+ data_dict[key.strip()] = value.strip().strip("'\"")
37
+ return data_dict
38
+
39
+ def encrypt_data_hybrid(data: bytes, public_key_pem: str) -> bytes:
40
+ """Encrypts data using RSA-OAEP + AES-GCM hybrid encryption."""
41
+ public_key = serialization.load_pem_public_key(public_key_pem.encode('utf-8'))
42
+ aes_key = os.urandom(AES_KEY_SIZE_CRYPTO)
43
+ nonce = os.urandom(AES_GCM_NONCE_SIZE_CRYPTO)
44
+
45
+ ciphertext_with_tag = AESGCM(aes_key).encrypt(nonce, data, None)
46
+
47
+ rsa_encrypted_aes_key = public_key.encrypt(
48
+ aes_key,
49
+ padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)
50
+ )
51
+
52
+ encrypted_aes_key_len_bytes = struct.pack('>I', len(rsa_encrypted_aes_key))
53
+ return encrypted_aes_key_len_bytes + rsa_encrypted_aes_key + nonce + ciphertext_with_tag
54
+
55
+ def embed_data_in_image(img_obj: Image.Image, data: bytes) -> Image.Image:
56
+ """Embeds data into the LSB of an image."""
57
+ img_rgb = img_obj.convert("RGB")
58
+ pixel_data = np.array(img_rgb).ravel()
59
+
60
+ data_length_header = struct.pack('>I', len(data))
61
+ binary_payload = ''.join(format(byte, '08b') for byte in data_length_header + data)
62
+
63
+ if len(binary_payload) > pixel_data.size:
64
+ raise ValueError(f"Data too large for image capacity. Needs {len(binary_payload)} bits, image has {pixel_data.size}.")
65
+
66
+ for i in range(len(binary_payload)):
67
+ pixel_data[i] = (pixel_data[i] & 0xFE) | int(binary_payload[i])
68
+
69
+ stego_pixels = pixel_data.reshape(img_rgb.size[1], img_rgb.size[0], 3)
70
+ return Image.fromarray(stego_pixels, 'RGB')
71
+
72
+ def create_carrier_image(width=800, height=600) -> Image.Image:
73
+ """Generates a simple carrier image."""
74
+ img = Image.new('RGB', (width, height), color = (73, 109, 137))
75
+ d = ImageDraw.Draw(img)
76
+ try:
77
+ font = ImageFont.truetype("DejaVuSans.ttf", 40)
78
+ except IOError:
79
+ font = ImageFont.load_default()
80
+ d.text((width/2, height/2), "KeyLock Encrypted Data", fill=(255,255,0), font=font, anchor="ms")
81
+ return img
82
+
83
+ def create_encrypted_image(secret_data_str: str, public_key_pem: str) -> Image.Image:
84
+ """
85
+ High-level orchestrator function to create the final encrypted image.
86
+ """
87
+ logger.info("Starting image creation process...")
88
+
89
+ # 1. Parse and validate secret data
90
+ if not secret_data_str.strip():
91
+ raise ValueError("Secret data cannot be empty.")
92
+ secret_dict = parse_kv_string_to_dict(secret_data_str)
93
+ if not secret_dict:
94
+ raise ValueError("No valid key-value pairs found in secret data.")
95
+
96
+ # 2. Serialize data to JSON bytes
97
+ json_bytes = json.dumps(secret_dict).encode('utf-8')
98
+ logger.info(f"Serialized {len(json_bytes)} bytes of data.")
99
+
100
+ # 3. Encrypt the data
101
+ encrypted_payload = encrypt_data_hybrid(json_bytes, public_key_pem)
102
+ logger.info(f"Encrypted payload created with size: {len(encrypted_payload)} bytes.")
103
+
104
+ # 4. Create a carrier image and embed the data
105
+ carrier_image = create_carrier_image()
106
+ stego_image = embed_data_in_image(carrier_image, encrypted_payload)
107
+ logger.info("Data successfully embedded into carrier image.")
108
+
109
+ return stego_image