https://github.com/traceflight/tls-decryptor
A Rust TLS decryption library (with private key) supporting TLS 1.2 and TLS 1.3 Application Data record decryption.
https://github.com/traceflight/tls-decryptor
Last synced: 3 months ago
JSON representation
A Rust TLS decryption library (with private key) supporting TLS 1.2 and TLS 1.3 Application Data record decryption.
- Host: GitHub
- URL: https://github.com/traceflight/tls-decryptor
- Owner: traceflight
- License: apache-2.0
- Created: 2026-03-22T13:32:22.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-03-22T15:01:07.000Z (3 months ago)
- Last Synced: 2026-03-23T05:28:46.609Z (3 months ago)
- Language: Rust
- Homepage:
- Size: 46.9 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE-APACHE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# TLS Decryptor
A Rust TLS decryption library (with private key) supporting TLS 1.2 and TLS 1.3 Application Data record decryption.
## Prerequisites
**Important:** This library requires access to the private key to derive session keys and decrypt TLS traffic. Specifically:
- **TLS 1.2 with RSA key exchange**: Requires the server's RSA private key to decrypt the Pre-Master Secret from the ClientKeyExchange message
- **TLS 1.2 with ECDHE key exchange**: Requires the ECDHE private key to compute the shared secret
- **TLS 1.3**: Requires the ECDHE private key to compute the shared secret
Without the corresponding private key, this library cannot derive the session keys needed for decryption.
## Features
- 🔐 Derive TLS session keys from private keys and handshake parameters
- 📦 Decrypt individual TLS Application Data records using session keys
- 🔧 Support for multiple cipher suites (AES-GCM, ChaCha20-Poly1305)
- 🧩 Extensible cipher suite architecture
- ✅ Comprehensive test coverage with test data verified by Python scripts
## Dependencies
This project is built upon:
- **[RustCrypto](https://github.com/rustcrypto/)** - Provides cryptographic algorithms used throughout the library
- **[tls-parser](https://crates.io/crates/tls-parser) ([GitHub](https://github.com/rusticata/tls-parser))** - Provides TLS record parsing capabilities
## Supported Cipher Suites
### TLS 1.2
| Cipher Suite Name | ID | Key Exchange | Encryption |
|------------------|-----|--------------|------------|
| TLS_RSA_WITH_AES_128_GCM_SHA256 | 0x009C | RSA | AES-128-GCM |
| TLS_RSA_WITH_AES_256_GCM_SHA384 | 0x009D | RSA | AES-256-GCM |
| TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 | 0xCCA8 | ECDHE | ChaCha20-Poly1305 |
### TLS 1.3
| Cipher Suite Name | ID | Encryption |
|------------------|-----|------------|
| TLS13_AES_128_GCM_SHA256 | 0x1301 | AES-128-GCM |
| TLS13_AES_256_GCM_SHA384 | 0x1302 | AES-256-GCM |
| TLS13_CHACHA20_POLY1305_SHA256 | 0x1303 | ChaCha20-Poly1305 |
## Installation
Add the dependency to your `Cargo.toml`:
```toml
[dependencies]
tls-decryptor = "0.1.0"
```
## Quick Start
### TLS 1.2 RSA Key Exchange
```rust
use tls_decryptor::{
TlsDecrypter, SessionKey, Direction,
key_derivation::derive_keys_tls12,
types::CipherSuite,
};
fn main() -> Result<(), tls_decryptor::DecryptError> {
// 1. Decrypt Pre-Master Secret using private key
// Note: This requires an external RSA library (e.g., rsa crate)
// let private_key_pem = std::fs::read_to_string("server_key.pem")?;
// let encrypted_pms = /* extracted from ClientKeyExchange message */;
// let pre_master_secret = /* decrypt using RSA private key */;
let pre_master_secret = /* Pre-Master Secret obtained from RSA decryption */;
// 2. Derive session keys
let client_random = /* extracted from ClientHello (32 bytes) */;
let server_random = /* extracted from ServerHello (32 bytes) */;
let cipher_suite = CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256;
let session_key = derive_keys_tls12(
&client_random,
&server_random,
&pre_master_secret,
cipher_suite,
)?;
// 3. Create decrypter and decrypt
let mut decrypter = TlsDecrypter::new(session_key)?;
let encrypted_record = /* TLS Application Data record */;
let plaintext = decrypter.decrypt_application_data(
&encrypted_record,
Direction::ServerToClient,
)?;
println!("Decrypted: {:?}", String::from_utf8_lossy(&plaintext));
Ok(())
}
```
### TLS 1.3 ECDHE Key Exchange
```rust
use tls_decryptor::{
TlsDecrypter, Direction,
key_derivation::derive_keys_tls13,
types::CipherSuite,
};
fn main() -> Result<(), tls_decryptor::DecryptError> {
// 1. Compute ECDHE shared secret
// Use util::compute_shared_secret_tls13 or compute manually
let shared_secret = /* ECDHE shared secret */;
// 2. Derive session keys
let cipher_suite = CipherSuite::TLS13_AES_128_GCM_SHA256;
let handshake_hash = /* hash of handshake messages */;
let session_key = derive_keys_tls13(
&shared_secret,
cipher_suite,
&handshake_hash,
)?;
// 3. Create decrypter and decrypt
let mut decrypter = TlsDecrypter::new(session_key)?;
let encrypted_record = /* TLS Application Data record */;
let plaintext = decrypter.decrypt_application_data(
&encrypted_record,
Direction::ClientToServer,
)?;
println!("Decrypted: {:?}", String::from_utf8_lossy(&plaintext));
Ok(())
}
```
### Decrypt with Known Session Keys
If you already have the session keys (e.g., exported from Wireshark or other tools), you can directly create a `SessionKey`:
```rust
use tls_decryptor::{TlsDecrypter, SessionKey, Direction};
use tls_decryptor::types::TlsVersion;
use rustls::CipherSuite;
fn main() -> Result<(), tls_decryptor::DecryptError> {
// Directly create session key
let session_key = SessionKey::new(
TlsVersion::Tls13,
CipherSuite::TLS13_AES_128_GCM_SHA256,
vec![0u8; 16], // client_write_key
vec![0u8; 16], // server_write_key
vec![0u8; 12], // client_write_iv
vec![0u8; 12], // server_write_iv
);
let mut decrypter = TlsDecrypter::new(session_key)?;
// Decrypt data
let encrypted_record = hex::decode("170303002c...")?;
let plaintext = decrypter.decrypt_application_data(
&encrypted_record,
Direction::ServerToClient,
)?;
Ok(())
}
```
## API Reference
### Core Types
#### `TlsDecrypter`
TLS record decrypter responsible for decrypting TLS Application Data records.
```rust
// Create decrypter
let decrypter = TlsDecrypter::new(session_key)?;
// Create decrypter with initial sequence numbers
let decrypter = TlsDecrypter::with_sequence_numbers(
session_key,
client_to_server_seq,
server_to_client_seq,
)?;
// Decrypt Application Data record
let plaintext = decrypter.decrypt_application_data(&encrypted_record, direction)?;
// Manage sequence numbers
decrypter.set_sequence_number(Direction::ClientToServer, 100);
decrypter.reset_sequence_numbers();
```
#### `SessionKey`
Session key material containing all keys required to decrypt TLS records.
```rust
let session_key = SessionKey::new(
version, // TlsVersion
cipher_suite, // CipherSuite
client_write_key,
server_write_key,
client_write_iv,
server_write_iv,
);
```
#### `Direction`
Data flow direction enum.
```rust
enum Direction {
ClientToServer, // Client to server
ServerToClient, // Server to client
}
```
### Key Derivation Functions
#### `derive_keys_tls12`
TLS 1.2 key derivation function using PRF (Pseudo-Random Function).
```rust
use tls_decryptor::types::CipherSuite;
pub fn derive_keys_tls12(
client_random: &[u8; 32],
server_random: &[u8; 32],
pre_master_secret: &[u8],
cipher_suite: CipherSuite,
) -> Result
```
#### `derive_keys_tls13`
TLS 1.3 key derivation function using HKDF (HMAC-based Key Derivation Function).
```rust
use tls_decryptor::types::CipherSuite;
pub fn derive_keys_tls13(
shared_secret: &[u8],
cipher_suite: CipherSuite,
handshake_hash: &[u8],
) -> Result
```
## Architecture
### Cipher Suite Architecture
The library uses an extensible cipher suite architecture:
1. **[`CipherContext`](src/cipher/trait_def.rs)** - Trait defining the cipher suite interface
2. **[`CipherRegistry`](src/cipher/registry.rs)** - Global registry (singleton pattern)
3. **[`suites/`](src/cipher/suites/)** - Concrete suite implementations
Adding a new cipher suite:
1. Create a new file in `src/cipher/suites/`
2. Implement the `CipherContext` trait
3. Add `pub mod` declaration in [`cipher/suites/mod.rs`](src/cipher/suites/mod.rs)
4. Register in [`cipher/registry.rs`](src/cipher/registry.rs) `register_builtins()`
## Technical Details
### TLS 1.2 Key Derivation
```
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
key_block = PRF(master_secret, "key expansion",
ServerHello.random + ClientHello.random)
key_block = client_write_key | server_write_key |
client_write_IV | server_write_IV
```
### TLS 1.3 Key Derivation
```
handshake_secret = HKDF-Extract(0, shared_secret)
master_secret = HKDF-Extract(0, handshake_secret)
client_application_traffic_secret =
HKDF-Expand-Label(master_secret, "c ap traffic", handshake_hash)
key = HKDF-Expand-Label(traffic_secret, "key", "", key_length)
iv = HKDF-Expand-Label(traffic_secret, "iv", "", iv_length)
```
### AEAD Additional Data
The Additional Authenticated Data (AAD) used for AEAD decryption must be the 5-byte TLS record header:
```
AAD = content_type (1) || version (2) || length (2)
```
### Sequence Number Management
- `TlsDecrypter` maintains sequence numbers for both directions internally
- Each direction counts independently
- Wraps around to 0 on overflow
## Contributing
Issues and Pull Requests are welcome!
## Related Links
- [RFC 5246 - TLS 1.2](https://tools.ietf.org/html/rfc5246)
- [RFC 8446 - TLS 1.3](https://tools.ietf.org/html/rfc8446)
- [rustls](https://github.com/rustls/rustls)
## License
This project is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
http://opensource.org/licenses/MIT)