broadfield-dev commited on
Commit
d2e44a8
Β·
verified Β·
1 Parent(s): 56b9b2c

Update server/app.py

Browse files
Files changed (1) hide show
  1. server/app.py +35 -20
server/app.py CHANGED
@@ -12,19 +12,15 @@ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
12
  from cryptography.hazmat.primitives import hashes
13
  from cryptography.hazmat.primitives import serialization
14
  from cryptography.hazmat.primitives.asymmetric import padding
15
- # Import 'rsa' for the key generation utility
16
  from cryptography.hazmat.primitives.asymmetric import rsa
17
  from cryptography.exceptions import InvalidTag
18
 
19
- # --- Constants ---
20
  HEADER_BITS = 32
21
  AES_GCM_NONCE_SIZE = 12
22
 
23
- # --- Configure Logging ---
24
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
25
  logger = logging.getLogger(__name__)
26
 
27
- # --- Load Keys and Config ---
28
  KEYLOCK_PRIV_KEY = os.environ.get('KEYLOCK_PRIV_KEY')
29
  KEYLOCK_STATUS_MESSAGE = ""
30
 
@@ -53,9 +49,7 @@ except Exception as e:
53
  logger.error(f"Error loading public key: {e}")
54
  PUBLIC_KEY_PEM_STRING = f"Error loading public key: {e}"
55
 
56
- # --- Key Generation Utility ---
57
  def generate_rsa_keys():
58
- """Generates a new 2048-bit RSA private and public key pair."""
59
  private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
60
  private_pem = private_key.private_bytes(
61
  encoding=serialization.Encoding.PEM,
@@ -68,9 +62,7 @@ def generate_rsa_keys():
68
  ).decode('utf-8')
69
  return private_pem, public_pem
70
 
71
- # --- Core Decryption Function ---
72
  def decode_data(image_base64_string: str) -> dict:
73
- """Decrypts a payload hidden in a PNG image via LSB steganography and hybrid encryption."""
74
  if not KEYLOCK_PRIV_KEY:
75
  error_msg = "Server Error: The API is not configured with a private key."
76
  raise gr.Error(error_msg)
@@ -122,27 +114,51 @@ def decode_data(image_base64_string: str) -> dict:
122
  except Exception as e:
123
  raise gr.Error(f"An unexpected server error occurred. Details: {e}")
124
 
125
- # ==============================================================================
126
- # GRADIO INTERFACE
127
- # ==============================================================================
128
  with gr.Blocks(title="Secure Decoder API", theme=gr.themes.Soft()) as demo:
129
  gr.Markdown("# πŸ” Secure KeyLock Decoder API")
130
  gr.Markdown("This application provides a secure API endpoint to decrypt and extract JSON data hidden within PNG images.")
131
 
132
  with gr.Tabs():
133
  with gr.TabItem("πŸš€ Quick Start & Documentation"):
134
- # This tab remains unchanged, showing clients how to use the API
135
  gr.Markdown("## How to Use This API")
136
  gr.Markdown("### Step 1: Get the Server's Public Key")
137
- gr.Code(value=PUBLIC_KEY_PEM_STRING, language="python", label="Server Public Key")
138
- # ... (The rest of the extensive documentation from your original file)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  with gr.TabItem("βš™οΈ Server Status & Error Guide"):
141
  gr.Markdown("## Server Status")
142
  gr.Textbox(label="Private Key Status", value=KEYLOCK_STATUS_MESSAGE, interactive=False, lines=3)
143
  gr.Markdown("---")
144
 
145
- # --- NEW: Key Generation Utility ---
146
  with gr.Accordion("πŸ”‘ Admin: Key Pair Generator", open=False):
147
  gr.Markdown(
148
  "**For Administrators Only.** Use this tool to generate a new RSA key pair for the server. "
@@ -177,14 +193,13 @@ with gr.Blocks(title="Secure Decoder API", theme=gr.themes.Soft()) as demo:
177
  gr.Markdown("## Error Handling Guide")
178
  gr.Markdown(
179
  """
180
- - **`"Decryption failed. ... InvalidTag"`**: The most common error. The image was encrypted with a **different public key** or the image file was corrupted.
181
- - **`"Decryption failed. ... Key mismatch"`**: The RSA key size used to encrypt the data does not match the server's key size.
182
- - **`"Image data corrupt or truncated..."`**: The image file is incomplete or damaged.
183
- - **`"Server Error: ... not configured"`**: The administrator has not set the `KEYLOCK_PRIV_KEY` secret correctly.
184
  """
185
  )
186
 
187
- # --- Hidden component for the API endpoint ---
188
  with gr.Row(visible=False):
189
  api_input = gr.Textbox()
190
  api_output = gr.JSON()
 
12
  from cryptography.hazmat.primitives import hashes
13
  from cryptography.hazmat.primitives import serialization
14
  from cryptography.hazmat.primitives.asymmetric import padding
 
15
  from cryptography.hazmat.primitives.asymmetric import rsa
16
  from cryptography.exceptions import InvalidTag
17
 
 
18
  HEADER_BITS = 32
19
  AES_GCM_NONCE_SIZE = 12
20
 
 
21
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
22
  logger = logging.getLogger(__name__)
23
 
 
24
  KEYLOCK_PRIV_KEY = os.environ.get('KEYLOCK_PRIV_KEY')
25
  KEYLOCK_STATUS_MESSAGE = ""
26
 
 
49
  logger.error(f"Error loading public key: {e}")
50
  PUBLIC_KEY_PEM_STRING = f"Error loading public key: {e}"
51
 
 
52
  def generate_rsa_keys():
 
53
  private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
54
  private_pem = private_key.private_bytes(
55
  encoding=serialization.Encoding.PEM,
 
62
  ).decode('utf-8')
63
  return private_pem, public_pem
64
 
 
65
  def decode_data(image_base64_string: str) -> dict:
 
66
  if not KEYLOCK_PRIV_KEY:
67
  error_msg = "Server Error: The API is not configured with a private key."
68
  raise gr.Error(error_msg)
 
114
  except Exception as e:
115
  raise gr.Error(f"An unexpected server error occurred. Details: {e}")
116
 
 
 
 
117
  with gr.Blocks(title="Secure Decoder API", theme=gr.themes.Soft()) as demo:
118
  gr.Markdown("# πŸ” Secure KeyLock Decoder API")
119
  gr.Markdown("This application provides a secure API endpoint to decrypt and extract JSON data hidden within PNG images.")
120
 
121
  with gr.Tabs():
122
  with gr.TabItem("πŸš€ Quick Start & Documentation"):
 
123
  gr.Markdown("## How to Use This API")
124
  gr.Markdown("### Step 1: Get the Server's Public Key")
125
+ gr.Code(value=PUBLIC_KEY_PEM_STRING, language="pem", label="Server Public Key")
126
+ with gr.Accordion("Step 2: Create the Encrypted Image (Client-Side Python Example)", open=False):
127
+ gr.Markdown("Use the following Python code in your client application to create a KeyLock image.")
128
+ gr.Code(
129
+ language="python",
130
+ label="Client-Side Image Creation Script",
131
+ value="""
132
+ import json; import os; import struct; from PIL import Image; import numpy as np
133
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
134
+ from cryptography.hazmat.primitives import hashes, serialization
135
+ from cryptography.hazmat.primitives.asymmetric import padding
136
+ def create_keylock_image(public_key_pem: str, json_data: dict, template_image_path: str, output_path: str):
137
+ public_key = serialization.load_pem_public_key(public_key_pem.encode())
138
+ data_to_encrypt = json.dumps(json_data).encode('utf-8')
139
+ aes_key = AESGCM.generate_key(bit_length=256)
140
+ nonce = os.urandom(12)
141
+ ciphertext_with_tag = AESGCM(aes_key).encrypt(nonce, data_to_encrypt, None)
142
+ encrypted_aes_key = public_key.encrypt(aes_key, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None))
143
+ crypto_payload = struct.pack('>I', len(encrypted_aes_key)) + encrypted_aes_key + nonce + ciphertext_with_tag
144
+ header = struct.pack('>I', len(crypto_payload))
145
+ full_binary_string = ''.join(f'{byte:08b}' for byte in header + crypto_payload)
146
+ img = Image.open(template_image_path).convert("RGB")
147
+ pixel_data = np.array(img)
148
+ if len(full_binary_string) > pixel_data.size:
149
+ raise ValueError("Data is too large for the image.")
150
+ flat_pixels = pixel_data.ravel()
151
+ for i in range(len(full_binary_string)):
152
+ flat_pixels[i] = (flat_pixels[i] & 0b11111110) | int(full_binary_string[i])
153
+ Image.fromarray(pixel_data).save(output_path, "PNG")
154
+ """
155
+ )
156
 
157
  with gr.TabItem("βš™οΈ Server Status & Error Guide"):
158
  gr.Markdown("## Server Status")
159
  gr.Textbox(label="Private Key Status", value=KEYLOCK_STATUS_MESSAGE, interactive=False, lines=3)
160
  gr.Markdown("---")
161
 
 
162
  with gr.Accordion("πŸ”‘ Admin: Key Pair Generator", open=False):
163
  gr.Markdown(
164
  "**For Administrators Only.** Use this tool to generate a new RSA key pair for the server. "
 
193
  gr.Markdown("## Error Handling Guide")
194
  gr.Markdown(
195
  """
196
+ - **`"Decryption failed. ... InvalidTag"`**: The most common error. The image was encrypted with a **different public key** or the image file was corrupted.
197
+ - **`"Decryption failed. ... Key mismatch"`**: The RSA key size used to encrypt the data does not match the server's key size.
198
+ - **`"Image data corrupt or truncated..."`**: The image file is incomplete or damaged.
199
+ - **`"Server Error: ... not configured"`**: The administrator has not set the `KEYLOCK_PRIV_KEY` secret correctly.
200
  """
201
  )
202
 
 
203
  with gr.Row(visible=False):
204
  api_input = gr.Textbox()
205
  api_output = gr.JSON()