dp.exe — KiTTY Password Decryptor


KiTTY Password Decryptor

**Version 1.0.0** — Modern C++23 Win32 utility for decrypting KiTTY session passwords *Standalone Win32 utility that reads KiTTY `Sessions` directories, decrypts stored passwords using KiTTY's custom Blowfish/nbcrypt algorithm, and displays results in a sortable, filterable GUI.* *Operates in two modes: a full Win32 dialog interface with dark-mode and MICA support, and a headless CLI mode for scripting. Exports to CSV or JSON. Zero external dependencies — pure Win32, statically linked, no VC++ Redistributable required.*

📚 Table of Contents


Feature Overview

This is a standalone Win32 utility written in modern C++23 that provides comprehensive KiTTY password decryption capabilities:

Core Capabilities

  • Password decryption — KiTTY custom base64 + Fisher-Yates scramble seeded by ciphertext prefix; two key derivation modes tried automatically
  • Session scanning — Recursive directory walker (max depth 4) searches for Sessions folders; percent-decodes filenames; skips Default Settings
  • GUI — Win32 dialog, sortable/filterable SysListView32, double-click / right-click clipboard copy
  • CLI — Headless single-password decrypt; two argument orderings; attaches to parent console for pipeline use
  • Export CSV — RFC 4180, semicolon-separated, double-quote escaping, UTF-8 no BOM
  • Export JSON — Pretty-printed JSON array, full Unicode escape for control characters, UTF-8 no BOM
  • Dark mode — Auto-detects Windows dark/light theme; MICA backdrop on Win11 (build ≥ 22000); rounded corners via DWM; reacts to WM_SETTINGCHANGE live
  • DPI — Per-Monitor DPI v2 (manifest); Segoe UI Variable on Win11, Segoe UI fallback; font scaled via GetDpiForWindow
  • No dependencies — Pure Win32; no external DLLs; no VC++ Redistributable; statically linked CRT (/MT)

Design Priorities

  1. Zero external dependencies — pure Win32 API surface
  2. Modern C++23 architecture with RAII and std::format
  3. Deterministic behavior with fail-fast crypto fallback
  4. Native Windows UX with dark mode, MICA, and DPI awareness

Architecture

Layered Structure

flowchart TD A[wmain Entry Point] --> B[dp::app::Run] B --> C{CLI Args?} C -->|Yes| D[CLI Mode] C -->|No| E[GUI Mode] D --> F[dp::core::DecryptPassword] E --> G[dp::ui::MainDialog] F --> H[KittyDecryptBase64] G --> I[OnScan] G --> J[OnExportCsv] G --> K[OnExportJson] I --> L[dp::core::LoadSessionsFromRoot] L --> M[ScanDir Walker] L --> N[ReadKeyValues Parser] L --> O[BuildSession] O --> H J --> P[dp::core::ExportCsv] K --> Q[dp::core::ExportJson]
wmain (dp.cpp)
  ↓
dp::app::Run (App.cpp)
  ├─ CLI path  ──► dp::core::DecryptPassword ──► KittyDecryptBase64
  │                                               └─ KiTTY base64 engine
  └─ GUI path  ──► dp::ui::MainDialog::Show
                        ├─ OnScan ──► dp::core::LoadSessionsFromRoot
                        │             ├─ ScanDir (recursive walker)
                        │             ├─ ReadKeyValues (kv parser)
                        │             └─ BuildSession ──► DecryptPassword
                        ├─ OnExportCsv  ──► dp::core::ExportCsv
                        ├─ OnExportJson ──► dp::core::ExportJson
                        └─ ApplyTheme ──► DWM + uxtheme dark-mode stack

Namespace Map

Namespace Directory Responsibility
dp::app src/app/ CLI/GUI dispatch, COM init, console attach
dp::core src/core/ Crypto, scan, export, string utilities
dp::ui src/ui/ Win32 dialog, dark mode, ListView
dp::ui::dark src/ui/DarkMode.h Undocumented uxtheme wrappers

Usage

GUI Mode

Launch dp.exe with no arguments. The main dialog opens:

  1. Click Browse… to select a root folder (e.g. your KiTTY Portable directory or %APPDATA%\KiTTY).
  2. Click Scan — the tool recursively finds all Sessions subdirectories and decrypts every stored password.
  3. Use the Filter box to search across session name, host, user, terminal type and password simultaneously (case-insensitive).
  4. Click any column header to sort; click again to reverse.
  5. Double-click a row or right-click → Copy selected to copy tab-separated fields to the clipboard.
  6. Export CSV / Export JSON — save the currently shown (filtered) set via a standard Save dialog.

Rows with a failed decrypt are rendered in red. The status bar shows total / shown / decrypted counts.

CLI Mode

dp.exe <password> <host> <term> [0|1]
dp.exe <0|1>      <host> <term> <password>

Two argument orderings are accepted — mode flag first or password first. The mode flag is optional; when omitted the engine tries both key derivation modes automatically.

Example (from build.ps1 smoke test):

dp.exe 1633bGXSgBnT4I wesmar.wp.pl xterm 0
Expected output: bc107!+

On success the plaintext is written to stdout followed by a newline and the process exits with code 0. On failure ERR:DECRYPT is printed and the exit code is 1. When launched from a terminal the process auto-attaches to the parent console and sets UTF-8 output.

Help:

dp.exe --help
dp.exe -h
dp.exe /?

Crypto Engine

KiTTY stores passwords as a custom base64-encoded ciphertext. The decryption algorithm implemented in KittyBcrypt.cpp works as follows:

Base Alphabet

A shuffled 64-character set distinct from standard Base64:

AZERTYUIOPQSDFGHJKLMWXCVBNazertyuiopqsdfghjklmwxcvbn0123456789+/

Key Derivation

Two modes, both attempted automatically:

Mode Key
0 (default) host + term + "KiTTY"
1 (portable) "KiTTY" (password-only variant)

Decryption Steps

[mermaid]
flowchart LR
A[Ciphertext] --> B[Seed Alphabet
≤5 bytes]
B --> C[Advance Past
Seed Prefix]
C --> D{Marker Byte?}
D -->|Yes| E[Accumulate Offset
Re-scramble Alphabet]
D -->|No| F[Locate in Alphabet]
E --> G[Output
offset + index]
F --> G
G --> H{Every pattern.size()?}
H -->|Yes| I[Key Re-scramble]
H -->|No| J{More Bytes?}
I --> J
J -->|Yes| D
J -->|No| K[Plaintext Output]


1. **Seed the alphabet** with the first ≤ 5 bytes of the ciphertext (Fisher-Yates scramble driven by ciphertext bytes).
2. **Advance past** the 5-byte seed prefix.
3. **For each remaining ciphertext byte:**
   - Detect **marker bytes** (equal to the last character of the current alphabet)
   - Each marker accumulates an offset and re-scrambles the alphabet using the key
4. **Locate the non-marker byte** in the current alphabet; output `offset + index` as the plaintext byte.
5. **Every `pattern.size()` decoded bytes** trigger another key-driven re-scramble.
6. **Skip silently:** embedded newlines and characters absent from the current alphabet.

`DecryptPassword` tries mode 0 first; falls back to mode 1 if mode 0 yields no output.

---

## Session Scanner {#session-scanner}

`Scan.cpp` — `LoadSessionsFromRoot(root, out)`

### Scanning Process

[mermaid]
flowchart TD
    A[Root Directory] --> B[Recursive Walk<br/>Max Depth 4]
    B --> C{Directory =<br/>'Sessions'?}
    C -->|No| B
    C -->|Yes| D[Read All Files<br/>in Sessions]
    D --> E[Parse Key-Value<br/>KeyName\Value\n]
    E --> F[Percent-Decode<br/>Filename]
    F --> G{Default Settings?}
    G -->|Yes| H[Skip]
    G -->|No| I[Extract Fields]
    I --> J[Decrypt Password]
    J --> K[Build Session Struct]
    K --> L[Add to Output]

Scanner Characteristics

  • Recursively walks subdirectories up to depth 4
  • When a directory named Sessions (case-insensitive) is found, all files inside it are treated as session files
  • Subdirectories of Sessions are not descended
  • Each session file is parsed as KeyName\Value\n key-value pairs (KiTTY's native storage format)
  • The filename is percent-decoded (%XX → byte) and widened to UTF-16 for the session name
  • Default Settings (and its percent-encoded form) is silently skipped

Fields Extracted Per Session

Field Registry key
Session name filename (percent-decoded)
Host HostName
User UserName
Terminal TerminalType (default: xterm)
Port PortNumber
Encrypted password Password
  • Files are read in a single ReadFile call (capped at 64 MiB)
  • Zero-copy string_view slicing is used for line parsing

Export

Both exporters build the entire output in a std::string buffer before writing in a single fwrite call (RAII unique_ptr<FILE>).

CSV Export (ExportCsv)

  • Semicolon-separated, UTF-8 no BOM
  • RFC 4180 double-quote escaping
  • Columns: Session;Host;User;Port;Term;Password;Source

JSON Export (ExportJson)

  • Pretty-printed JSON array, one object per line
  • std::format used for field serialisation
  • All control characters (< 0x20) emitted as \uXXXX
  • Special characters (", \, \n, \r, \t) escaped per JSON spec

UI and Dark Mode

MainDialog is a single modal Win32 dialog (DIALOGEX, resource IDD_MAIN). All Windows API surface uses Unicode (W variants). The dialog owns one SysListView32 with full-row select, double-buffer, and grid lines.

Dark Mode Detection

Reads HKCU\...\Themes\Personalize\AppsUseLightTheme. Theme is applied on WM_INITDIALOG and refreshed live on WM_SETTINGCHANGE / ImmersiveColorSet.

DWM Attributes Applied at Runtime

Attribute Effect
DWMWA_USE_IMMERSIVE_DARK_MODE (20) Dark title bar
DWMWA_SYSTEMBACKDROP_TYPE (38) = DWMSBT_MAINWINDOW MICA backdrop (Win11 only)
DWMWA_WINDOW_CORNER_PREFERENCE (33) = DWMWCP_ROUND Rounded window corners

Undocumented uxtheme.dll Ordinals

Loaded dynamically; all calls are no-ops on older Windows:

Ordinal Function Purpose
133 AllowDarkModeForWindow Opts a specific HWND into dark rendering
135 SetPreferredAppMode(1) Allows dark menus and scrollbars process-wide
136 FlushMenuThemes Forces menu renderer to pick up dark preference
137 RefreshImmersiveColorPolicyState Tells DWM color system to re-read user preference

ListView Styling

SetWindowTheme(list_, L"DarkMode_Explorer", nullptr) applied to the SysListView32 and its header in dark mode. The NM_CUSTOMDRAW handler:

  • Colours failed-decrypt rows red
  • Highlights filtered rows with a tinted background

Font

Segoe UI Variable (Win11) / Segoe UI (Win10), height scaled with GetDpiForWindow and MulDiv(9, dpi, 72), CLEARTYPE_QUALITY.


Module Map (for Maintainers)

File Purpose
src/dp.cpp wmain — Unicode entry point
src/app/App.cpp Run() — argument parsing, CLI decrypt, GUI bootstrap
src/app/App.h Run() declaration
src/core/Crypto.cpp DecryptPassword — tries both key derivation modes
src/core/Crypto.h Public decrypt API
src/core/KittyBcrypt.cpp KittyDecryptBase64 — full KiTTY nbcrypt algorithm
src/core/KittyBcrypt.h Decrypt function declaration
src/core/Scan.cpp LoadSessionsFromRoot — walker, parser, session builder
src/core/Scan.h Scanner API
src/core/Export.cpp ExportCsv, ExportJson
src/core/Export.h Export API
src/core/Session.h Session struct (name, host, user, term, port, password, source)
src/core/StringUtil.cpp WidenUtf8Fallback, NarrowUtf8, BaseName, PercentDecode, IEquals, ContainsInsensitive
src/core/StringUtil.h String utility declarations
src/ui/MainDialog.cpp Win32 dialog — all message handling, theming, ListView, export
src/ui/MainDialog.h MainDialog class declaration
src/ui/DarkMode.h Inline dark-mode wrappers over undocumented uxtheme ordinals
src/WinCommon.h Windows targeting macros, lean headers
src/Resource.h Dialog and control resource IDs
src/LinkerDeps.cpp #pragma comment(lib, …) for comctl32, dwmapi, ole32, shell32, uxtheme
src/dp.manifest Per-Monitor DPI v2, long-path aware, CC v6, Win10/11 compat
src/dp.rc Dialog template and version resource
dp.vcxproj MSBuild project — Debug/Release × Win32/x64, C++23, /MT release
build.ps1 PowerShell build script — clean, build both arches, strip intermediates, reproducible timestamps

Source Tree (Local Repo)

Current local layout:

dp/
├─ src/
│   ├─ dp.cpp                  wmain
│   ├─ WinCommon.h             Windows targeting + lean headers
│   ├─ Resource.h              Control and dialog IDs
│   ├─ LinkerDeps.cpp          Pragma-lib dependencies
│   ├─ dp.manifest             DPI v2 / CC v6 / Win11 compat manifest
│   ├─ dp.rc                   Dialog template + version resource
│   ├─ app/
│   │   ├─ App.cpp             CLI/GUI dispatch
│   │   └─ App.h
│   ├─ core/
│   │   ├─ Session.h           Session data struct
│   │   ├─ Crypto.cpp/h        DecryptPassword (dual-mode key derivation)
│   │   ├─ KittyBcrypt.cpp/h   KittyDecryptBase64 (nbcrypt engine)
│   │   ├─ Scan.cpp/h          Session directory walker and parser
│   │   ├─ Export.cpp/h        CSV and JSON export
│   │   └─ StringUtil.cpp/h    UTF-8/wide conversions, percent-decode, search
│   └─ ui/
│       ├─ DarkMode.h          Uxtheme ordinal wrappers (header-only)
│       ├─ MainDialog.cpp      Full Win32 dialog implementation
│       └─ MainDialog.h
├─ dp.vcxproj                  MSBuild project
├─ dp.vcxproj.filters          Solution Explorer filter layout
├─ dp.slnx                     Solution file
└─ build.ps1                   Build + clean + smoke test script

Build output:

bin/
├─ x86/dp.exe
└─ x64/dp.exe

Build System

Requirements: Visual Studio 2026 with C++ Desktop workload (MSVC v145 toolset).

.\build.ps1

The script performs the following steps:

  1. Locate VS 2026 via vswhere.exe
  2. Kill any running dp.exe from the repo directory (avoids file-lock on clean)
  3. Remove bin\ and obj\ directories
  4. Build Release|Win32 and Release|x64 via MSBuild
  5. Strip all intermediates (obj\ and everything in bin\ except dp.exe)
  6. Stamp both binaries with a reproducible timestamp of 2030-01-01

Compiler Flags (Release)

Flag Purpose
/std:c++latest C++23 features (std::format, std::ranges, designated initialisers)
/utf-8 Source and execution charset = UTF-8
/W4 /permissive- /sdl High warning level, strict conformance, security checks
/Zc:__cplusplus /Zc:preprocessor Correct __cplusplus value, conformant preprocessor
/MT Static CRT — no VC++ Redistributable on target
/O2 /GL /LTCG Max speed, whole-program optimisation, link-time code generation
/BREPRO Reproducible builds

Linker Entry Point

wmainCRTStartup — Unicode wide-char wmain; no narrow-string codec risk for path arguments.

Smoke Test

Printed by build.ps1 on completion:

cd test
..\bin\x86\dp.exe 1633bGXSgBnT4I wesmar.wp.pl xterm 0
# Expected: bc107!+

System Requirements

Component Requirement
Operating System Windows 10 or later (Windows 11 recommended for MICA and rounded corners)
Architecture x64 (bin\x64\dp.exe) and x86 (bin\x86\dp.exe)
Compiler (build) Visual Studio 2026, MSVC v145 toolset, C++23
Runtime dependencies None — static CRT (/MT), pure Win32; no VC++ Redistributable required
Windows APIs comctl32, dwmapi, ole32 (IFileDialog), shell32, uxtheme

dp.exe v1.0.0 — KiTTY Password Decryptor — Modern C++23 Win32 implementation.

wesmar (Marek Wesolowski) | kvc.pl