ja4 0.1.0

A fast, pure-rust, no_std implementation of the JA4 TLS client fingerprinting algorithm.
Documentation
# ja4

[![Crates.io](https://img.shields.io/crates/v/ja4.svg)](https://crates.io/crates/ja4)
[![Docs.rs](https://docs.rs/ja4/badge.svg)](https://docs.rs/ja4)
[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](#license)
[![no_std](https://img.shields.io/badge/no__std-compatible-success.svg)](#no-std-support)
[![Safety](https://img.shields.io/badge/unsafe-forbidden-success.svg)](#security)

A high-performance, production-ready, `#![no_std]` Rust implementation of the **JA4 TLS Client Fingerprinting** algorithm.

JA4 is a modular, human-readable TLS client fingerprinting standard designed to replace the legacy JA3 method. It normalizes TLS GREASE values, sorts ciphers and extensions, and formats the output into three structured, searchable segments (`a_b_c`) representing:
- **Part a**: Connection characteristics (protocol, version, SNI, ciphers/extensions counts, first ALPN chars).
- **Part b**: A truncated hash of the sorted list of cipher suites.
- **Part c**: A truncated hash of the sorted list of extensions and signature algorithms.

## Features

- **Zero-Allocation**: No heap allocations (`std::vec`, `std::string`, etc.) on the parser's critical path.
- **Pure Rust**: 100% Rust implementation utilizing the pure-Rust `sha2` crate.
- **Unsafe-Free**: Enforces `#![forbid(unsafe_code)]` for high-assurance environments.
- **`no_std` Support**: Compiles out-of-the-box in bare-metal, embedded, and kernel-level (e.g., eBPF/Wasm) environments.
- **Robust & Safe**: Extensively bounds-checked and panic-free parser.

## Installation

Add the following to your `Cargo.toml`:

```toml
[dependencies]
ja4 = "0.1"
```

## Usage Example

### TCP (with TLS Record Header)

```rust
use ja4::parse_ja4;

fn main() {
    // A raw TLS ClientHello packet captured from a TCP stream
    let packet: &[u8] = &[
        0x16, 0x03, 0x01, 0x00, 0x2f, // TLS Record Header
        0x01, 0x00, 0x00, 0x2b,       // Handshake Header (ClientHello)
        0x03, 0x03,                   // Version TLS 1.2
        // ... (remaining payload / random / ciphers / extensions)
    ];

    match parse_ja4(packet, false) {
        Some(result) => {
            println!("JA4 Fingerprint: {}", result.as_str());
            // Outputs: t12i010000_8daaf6152771_000000000000 (example)
        }
        None => {
            eprintln!("Failed to parse ClientHello packet.");
        }
    }
}
```

### QUIC (No Record Header)

When analyzing QUIC-based TLS (e.g., HTTP/3), the TLS payload does not start with a 5-byte TCP TLS record header. Pass `true` for the `is_quic` parameter:

```rust
use ja4::parse_ja4;

fn parse_quic_payload(quic_tls_payload: &[u8]) {
    if let Some(result) = parse_ja4(quic_tls_payload, true) {
        println!("QUIC JA4 Fingerprint: {}", result);
    }
}
```

## Anatomy of a JA4 Fingerprint

A JA4 fingerprint consists of three parts separated by underscores (e.g., `t13d1516h2_8daaf6152771_e5627efa2ab1`):

### Part A: Connection Details (`t13d1516h2`)
- **Protocol** (`t` or `q`): `t` for TCP, `q` for QUIC.
- **Version** (`13`, `12`, etc.): The highest TLS version supported by the client.
- **SNI** (`d` or `i`): `d` if SNI (Server Name Indication) is present, `i` if not.
- **Ciphers Count** (2 digits): Number of cipher suites offered (capped at `99`).
- **Extensions Count** (2 digits): Number of TLS extensions offered (capped at `99`).
- **ALPN** (2 chars): First and last alphanumeric characters of the first ALPN protocol (e.g., `h2`), or `00` if not present.

### Part B: Ciphers Hash (`8daaf6152771`)
- The first 12 hex characters of the SHA-256 hash of the sorted list of cipher suites.

### Part C: Extensions & Signature Algorithms Hash (`e5627efa2ab1`)
- The first 12 hex characters of the SHA-256 hash of the sorted list of extensions, followed by the sorted signature algorithms list.

## Security & Safety

This crate is designed for use in critical traffic inspection infrastructures.
- **No Unsafe Code**: Enforced by `#![forbid(unsafe_code)]`.
- **Panic Protection**: Every index, slice, and offset lookup uses safe bounds-checking methods, avoiding out-of-bounds panics even on highly corrupted or malicious packets.

## License

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)

at your option.