Newbie Spellweaver
- Joined
- Jul 11, 2026
- Messages
- 8
- Reaction score
- 15
sharing this enc/dec decoder i built for editing files without need to open dec and decrypt again
it's using default xor, if needed change it on line 15
XOR_KEY = 0x57676592
View attachment 305596
it's using default xor, if needed change it on line 15
XOR_KEY = 0x57676592
View attachment 305596
Python:
#!/usr/bin/env python3
"""
CABAL Online .enc Editor v2.1
Visual editor for CABAL Online .enc files.
Open, edit, and save .enc files using XOR + zlib encryption.
"""
import struct
import zlib
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
XOR_KEY = 0x57676592
CHUNK_SIZE = 16384
XOR_BYTES = [(XOR_KEY >> (8 * i)) & 0xFF for i in range(4)]
def decrypt_enc(data: bytes) -> bytes:
if len(data) < 4:
raise ValueError("File is too small")
compressed = bytearray()
pos = 4
first = True
while pos < len(data):
chunk = bytearray(data[pos:pos + CHUNK_SIZE])
if first:
for i in range(min(4, len(chunk))):
chunk[i] ^= XOR_BYTES[i]
first = False
compressed.extend(chunk)
pos += len(chunk)
errors = []
for wbits in [-zlib.MAX_WBITS, zlib.MAX_WBITS, -11, 11, -9, 9]:
try:
return zlib.decompress(bytes(compressed), wbits)
except zlib.error as e:
errors.append("wbits=%d: %s" % (wbits, e))
raise ValueError("Failed to decompress. Attempts:\n" + "\n".join(errors))
def encrypt_enc(data: bytes, level: int = 9) -> bytes:
compressor = zlib.compressobj(level, zlib.DEFLATED, -zlib.MAX_WBITS)
compressed = compressor.compress(data) + compressor.flush()
result = bytearray()
result.extend(struct.pack('<I', len(data)))
first = True
pos = 0
while pos < len(compressed):
chunk = bytearray(compressed[pos:pos + CHUNK_SIZE])
if first:
for i in range(min(4, len(chunk))):
chunk[i] ^= XOR_BYTES[i]
first = False
result.extend(chunk)
pos += len(chunk)
return bytes(result)
class EncEditor(tk.Tk):
def __init__(self):
super().__init__()
self.title("CABAL .enc Editor")
self.geometry("900x650")
self._filepath = None
self._original_size = 0
self._current_data = None
self._setup_ui()
def _setup_ui(self):
menubar = tk.Menu(self)
self.config(menu=menubar)
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="Open .enc...", command=self._open_file, accelerator="Ctrl+O")
file_menu.add_command(label="Save (.enc)", command=self._save_file, accelerator="Ctrl+S")
file_menu.add_command(label="Save As...", command=self._save_as)
file_menu.add_separator()
file_menu.add_command(label="Export (.txt)", command=self._export_txt)
file_menu.add_command(label="Exit", command=self.destroy)
menubar.add_cascade(label="File", menu=file_menu)
self.bind_all("<Control-o>", lambda e: self._open_file())
self.bind_all("<Control-s>", lambda e: self._save_file())
self.bind_all("<Control-e>", lambda e: self._export_txt())
self.bind_all("<Control-f>", lambda e: self._show_find())
self.bind_all("<Control-z>", lambda e: self._text.edit_undo() if hasattr(self, '_text') else None)
self.bind_all("<Control-y>", lambda e: self._text.edit_redo() if hasattr(self, '_text') else None)
main_frame = ttk.Frame(self, padding=5)
main_frame.pack(fill=tk.BOTH, expand=True)
self._info_label = ttk.Label(main_frame, text="No file opened")
self._info_label.pack(fill=tk.X)
text_frame = ttk.Frame(main_frame)
text_frame.pack(fill=tk.BOTH, expand=True)
self._text = tk.Text(
text_frame,
wrap=tk.NONE,
font=("Consolas", 11),
bg="#1E1E1E",
fg="#D4D4D4",
insertbackground="white",
padx=5,
pady=5,
undo=True
)
self._text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self._text.bind("<Control-f>", lambda e: self._show_find())
scroll_y = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, command=self._text.yview)
scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
self._text.configure(yscrollcommand=scroll_y.set)
scroll_x = ttk.Scrollbar(main_frame, orient=tk.HORIZONTAL, command=self._text.xview)
scroll_x.pack(fill=tk.X)
self._text.configure(xscrollcommand=scroll_x.set)
status_frame = ttk.Frame(main_frame)
status_frame.pack(fill=tk.X, pady=(5, 0))
self._status_label = ttk.Label(status_frame, text="")
self._status_label.pack(side=tk.LEFT)
def _show_find(self):
if hasattr(self, '_find_bar') and self._find_bar.winfo_ismapped():
self._find_bar.destroy()
return
self._find_bar = ttk.Frame(self._text.master)
ttk.Label(self._find_bar, text="Find:").pack(side=tk.LEFT, padx=(0, 5))
entry = ttk.Entry(self._find_bar, width=30)
entry.pack(side=tk.LEFT)
entry.bind("<Return>", lambda e: self._do_find(entry.get()))
entry.bind("<Escape>", lambda e: self._find_bar.destroy())
ttk.Button(
self._find_bar,
text="Next",
command=lambda: self._do_find(entry.get())
).pack(side=tk.LEFT, padx=5)
ttk.Label(self._find_bar, text="").pack(side=tk.LEFT)
self._find_bar.pack(fill=tk.X, before=self._text)
entry.focus_set()
self._find_result = None
def _do_find(self, text):
if not text:
return
self._text.tag_remove("find", 1.0, tk.END)
start = self._text.index(tk.INSERT) if self._find_result else "1.0"
pos = self._text.search(text, start, tk.END, nocase=True)
if pos:
self._text.tag_add("find", pos, "%s+%dc" % (pos, len(text)))
self._text.tag_config("find", background="#264F78")
self._text.see(pos)
self._text.mark_set(tk.INSERT, pos)
self._find_result = pos
else:
self._find_result = None
def _open_file(self, event=None):
path = filedialog.askopenfilename(
title="Open .enc file",
filetypes=[
("ENC files", "*.enc"),
("All files", "*.*")
]
)
if not path:
return
try:
with open(path, 'rb') as f:
raw = f.read()
self._filepath = path
self._original_size = len(raw)
data = decrypt_enc(raw)
self._current_data = data
self._text.delete(1.0, tk.END)
text = data.decode("utf-8", errors="replace")
self._text.insert(1.0, text)
fname = os.path.basename(path)
self._info_label.config(
text="%s (%d -> %d bytes)" % (fname, len(raw), len(data))
)
self._status_label.config(text="OK")
except Exception as e:
messagebox.showerror("Error", "Failed to open file:\n%s" % e)
def _save_file(self, event=None):
if not self._filepath:
self._save_as()
return
self._do_save(self._filepath)
def _save_as(self):
path = filedialog.asksaveasfilename(
title="Save as .enc",
defaultextension=".enc",
filetypes=[
("ENC files", "*.enc"),
("All files", "*.*")
]
)
if path:
self._do_save(path)
self._filepath = path
def _do_save(self, path):
try:
text = self._text.get(1.0, tk.END)
if text.endswith("\n"):
text = text[:-1]
raw_data = text.encode("utf-8")
enc = encrypt_enc(raw_data)
with open(path, "wb") as f:
f.write(enc)
ratio = len(enc) / len(raw_data) if raw_data else 0
self._status_label.config(
text="Saved: %d bytes (ratio %.2fx)" % (len(enc), ratio)
)
messagebox.showinfo("Success", "File saved!")
except Exception as e:
messagebox.showerror("Error", "%s" % e)
def _export_txt(self):
path = filedialog.asksaveasfilename(
title="Export as .txt",
defaultextension=".txt",
filetypes=[
("Text files", "*.txt")
]
)
if not path:
return
try:
text = self._text.get(1.0, tk.END)
with open(path, "w", encoding="utf-8") as f:
f.write(text)
messagebox.showinfo("Success", "File exported!")
except Exception as e:
messagebox.showerror("Error", "%s" % e)
if __name__ == "__main__":
app = EncEditor()
app.mainloop()

