Telegram Desktop
tdata Structure
Overview
The tdata/ directory is the local data store for Telegram Desktop on macOS. It contains all persistent state written to disk: authentication credentials, application settings, secret chat key exchange residue, and the cached media subdirectories. Every file that holds user-specific configuration or credentials uses the TDF$ binary format, which encrypts the payload with a key derived from the user's account credentials.
The directory is not a database. There are no SQL tables, no plist files, and no standard macOS data formats. Each file is an opaque binary blob. The only readable portions without decryption are the 8-byte TDF$ header at the start of each file and the filesystem metadata (name, size, timestamps) of each entry.
For forensic purposes, the tdata/ directory manifest — the complete enumeration of every file with its size, modification timestamp, and TDF$ status — is itself a meaningful artifact even without decryption. File presence proves account activity; timestamps establish timeline; file sizes can indicate specific configuration states.
File Locations
| Distribution | tdata Path | Notes |
|---|---|---|
| Standalone | ~/Library/Application Support/Telegram Desktop/tdata/ | Direct write, no sandbox |
| App Store | ~/Library/Containers/ru.keepcoder.Telegram/Data/Library/Application Support/Telegram Desktop/tdata/ | Sandboxed container |
Both paths use an identical internal directory structure. The difference is only the root path.
TDF$ Header Format
Every TDF$ file starts with an 8-byte unencrypted header:
| Offset | Length | Field | Type | Notes |
|---|---|---|---|---|
| 0 | 4 bytes | Magic | [4]byte | 0x54 0x44 0x46 0x24 ("TDF$") |
| 4 | 4 bytes | Version | uint32 (little-endian) | Telegram Desktop format version |
| 8 | variable | Encrypted payload | bytes | AES-IGE encrypted |
The version field is an incremented integer that reflects the Telegram Desktop storage format version, not the application's user-visible version number. It can help correlate a tdata/ directory with a specific era of the Telegram Desktop application.
Detecting TDF$ files:
Check first 4 bytes for: 0x54 0x44 0x46 0x24
If match → TDF$ encrypted file
Read bytes 4-7 as little-endian uint32 → version number
Remainder → encrypted payload (cannot be read without key material)
Files in the user_data/cache/ and user_data/media_cache/ subdirectories do not typically carry TDF$ headers — they are the downloaded media files themselves, stored in their native format.
Key Files and Their Purposes
usertag
| Property | Value |
|---|---|
| Path | tdata/usertag |
| Format | TDF$ encrypted |
| Contents (encrypted) | Telegram user identifier, possibly phone number or user ID |
| Forensic value | Confirms account presence; creation timestamp = first login on this device |
The usertag file is the primary account identifier artifact. Its creation timestamp records approximately when the Telegram account was first authenticated on this macOS device. When multiple accounts are present, each account directory (tdata/#2/, etc.) has its own usertag with independent timestamps.
key_data and key_datas
| Property | key_data | key_datas |
|---|---|---|
| Path | tdata/key_data | tdata/key_datas |
| Format | TDF$ encrypted | TDF$ encrypted |
| Contents (encrypted) | Session authentication keys | Renewed session keys |
| Forensic value | Active session indicator | Session renewal indicator |
Session status can be inferred from file presence:
| Files Present | Session Status | Interpretation |
|---|---|---|
key_data only | Active | Session established, not recently renewed |
key_data + key_datas | Renewed | Session was recently renewed (new device login, security event) |
| Neither | None | No active session; account may have been logged out |
The key_datas suffix (with s) is the Telegram convention for a "safe" or secondary copy written during renewal. When both exist, the modification timestamp of key_datas records the most recent session renewal event.
settings0 and settings1
| Property | Value |
|---|---|
| Paths | tdata/settings0, tdata/settings1, tdata/settingss |
| Format | TDF$ encrypted |
| Contents (encrypted) | Application settings, preferences, UI state |
| Forensic value | Installation age indicator from creation timestamps |
Telegram Desktop writes settings in a dual-copy pattern (settings0/settings1) for crash safety. The settingss variant is an intermediate write buffer. Their combined presence indicates a fully initialized Telegram Desktop installation.
2fa_config and lockconfig
| Property | Value |
|---|---|
| Paths | tdata/2fa_config, tdata/lockconfig |
| Format | TDF$ encrypted |
| Forensic value | Presence confirms two-factor authentication or screen lock was configured |
These files will not always be present. Their presence is an indicator, not a guarantee of active 2FA, but it confirms the user interacted with Telegram's security settings.
Hex-named Directories
Directories with names like D877F783D5D3EF8C/ are session-specific containers. The name is derived from the account's authorization key hash. Multiple such directories within a single account's tdata indicate multiple sessions (devices) that have been authorized.
Multi-Account Structure
Telegram Desktop supports up to six simultaneous accounts. The directory structure is:
| Account | Path | Notes |
|---|---|---|
| Account 1 (primary) | tdata/ root | Uses tdata/usertag, tdata/key_data, etc. directly |
| Account 2 | tdata/#2/ | Contains its own usertag, key_data, etc. |
| Account 3 | tdata/#3/ | Same structure |
| Account 4 | tdata/#4/ | Same structure |
| Account 5 | tdata/#5/ | Same structure |
| Account 6 | tdata/#6/ | Same structure |
Each numbered subdirectory is a complete, independent account data store. A user with three accounts will have tdata/, tdata/#2/, and tdata/#3/, each with its own usertag, key_data, and settings files.
tdata Manifest Records
macfor collects a complete file-level manifest of the tdata/ directory hierarchy without attempting decryption. Each file produces a record with the following fields:
| Field | Type | Description |
|---|---|---|
type | string | Always "telegram_tdata_manifest" |
relative_path | string | Path relative to the tdata root |
absolute_path | string | Full path on the source system |
size | integer | File size in bytes |
mod_time | string | Modification timestamp (RFC 3339) |
is_tdf_encrypted | boolean | Whether the file begins with TDF$ magic bytes |
tdf_version | integer (optional) | TDF$ version number from header bytes 4-7 |
sha256 | string (optional) | SHA-256 hash, populated during raw collection only |
user | string | macOS username |
variant | string | "standalone" or "appstore" |
Example record:
{
"type": "telegram_tdata_manifest",
"relative_path": "usertag",
"absolute_path": "/Users/alice/Library/Application Support/Telegram Desktop/tdata/usertag",
"size": 572,
"mod_time": "2025-11-14T09:23:11Z",
"is_tdf_encrypted": true,
"tdf_version": 2008012,
"user": "alice",
"variant": "standalone"
}
Raw tdata Collection
The IncludeRawTdata collection option copies every file from the tdata/ hierarchy into the evidence container. This is an opt-in operation because tdata directories can be large, and the encrypted files require offline tooling to analyze.
When raw collection is enabled:
- Every file is copied with stream-based I/O (suitable for large files)
- A SHA-256 hash is computed during copy and recorded in the manifest record
- The Telegram application binary is also collected (
/Applications/Telegram.app/Contents/MacOS/Telegram) to support offline decryption analysis - Permission errors on individual files are logged and do not stop collection
macfor-pro collect --plugin messaging.telegram \
--option include_raw_tdata=true \
--output ./evidence.zip
Raw collection and large files
A populated tdata directory with media cache can exceed several gigabytes. Use include_raw_tdata=true only when offline decryption analysis is planned. For media evidence alone, the media cache collection option is more targeted.
SHA-256 Integrity
All files collected during raw mode have a SHA-256 hash computed at collection time and stored in the manifest. This provides:
- Evidence integrity verification
- Detection of file modifications between collection events
- Chain of custody documentation
Forensic Analysis Notes
- File creation time as first-login indicator: The
usertagfile is created when Telegram Desktop first authenticates an account on the device. Its birth time (on APFS volumes, where birth times are reliable) approximates the date of first use on this specific macOS installation. - Absent files indicate logout: If
key_dataandkey_datasare both absent but thetdata/directory exists (withsettings*files present), the account was explicitly logged out. Telegram removes the session key files on logout but leaves settings in place. - Version correlation: The TDF$ version field across files should be consistent. A mixed-version tdata directory (different version numbers across files) could indicate partial file recovery from an earlier backup or a version downgrade scenario.
- Dump files for crash timeline: Files in
tdata/dumps/are crash dumps written by Telegram Desktop when it crashes. Their filenames typically include a timestamp, providing a record of application crashes independent of system logs.
macfor Collection
This artifact is collected by the messaging.telegram plugin as part of the default collection.
# Default collection (accounts + tdata manifest + media cache + sessions)
macfor-pro collect --plugin messaging.telegram --output ./evidence.zip
# Include raw tdata files for offline decryption
macfor-pro collect --plugin messaging.telegram \
--option include_raw_tdata=true \
--output ./evidence.zip
# Manifest only (skip media, sessions, secret chat traces)
macfor-pro collect --plugin messaging.telegram \
--option skip_media_cache=true \
--option skip_sessions=true \
--option skip_secret_chat_traces=true \
--output ./evidence.zip