Expand description
DVB SimulCrypt — head-end CA message framing (ETSI TS 103 197 V1.5.1).
The DVB SimulCrypt head-end carries control/response messages between its conditional-access components over TCP. This crate is a codec for those messages — it does not open sockets. It implements the generic message structure and the two CA-bearing interfaces:
SimulcryptMessage— the genericgeneric_message(TS 103 197 §4.4.1, Table 1b): a 5-byte header (protocol_version+message_type+message_length, big-endian) followed by an ordered list of TLVParameters (parameter_type+parameter_length+ value).message_lengthand everyparameter_lengthare recomputed on serialize from the typed fields — there is no raw passthrough.- ECMG ⇔ SCS (clause 5):
EcmgScsMessageType(channel/stream setup, test, status, close, error, plusCW_provision0x0201andECM_response0x0202) and the Table 5EcmgScsParameterTyperegistry (Super_CAS_id0x0001…ECM_id0x0019,error_status0x7000,error_information0x7001) +EcmgErrorStatus(Table 6). - EMMG/PDG ⇔ MUX (clause 6):
EmmgMuxMessageType(channel/stream messages,stream_BW_request/allocation,data_provision0x0211) and the Table 7EmmgMuxParameterTyperegistry +EmmgErrorStatus(Table 8), plus theDataType(§6.2.3) andSectionTspktFlagvalue tables. - C(P)SIG ⇔ (P)SIG (clause 8):
CpSigMessageType(channel/stream messages, trigger/table/descriptor/PID‑provision messages0x0301–0x0321) and the Table 36CpSigParameterTyperegistry (bouquet_id0x0100…flow_stream_type0x012C,error_status0x7000,error_information0x7001).
§Interface scoping
The 16-bit message_type/parameter_type spaces are interface-scoped:
the same value means different things on different interfaces, and the
interface is not on the wire — it is fixed by which TCP connection the
message arrived on (analogous to a resource scope). So
SimulcryptMessage::parse_on takes an Interface hint and decodes the
raw values into the matching interface-tagged MessageType /
ParameterType enums.
§Signalling only — no crypto
The control words in CP_CW_combination/CW_encryption, the ECMs in
ECM_datagram, and the EMM/private data in datagram are carried as
opaque borrowed bytes. This crate frames and parses them; it never
decrypts or interprets them. The non-implemented interfaces (C(P)SIG⇔(P)SIG,
EIS⇔SCS, (P)SIG⇔MUX, ACG⇔EIS, SIMCOMP⇔MUXCONFIG) share the same framing but
are not modelled.
#![no_std] + alloc; depends only on dvb-common.
§Examples
Build an ECMG⇔SCS channel_setup from typed fields and round-trip it:
use dvb_simulcrypt::{
EcmgScsMessageType, EcmgScsParameterType, Interface, MessageType, Parameter,
ParameterType, SimulcryptMessage,
};
use dvb_common::traits::{Parse, Serialize};
let ecm_channel_id = [0x00, 0x2A]; // 0x002A
let super_cas_id = [0x00, 0x01, 0x00, 0x02]; // CA_system_id | subsystem_id
let msg = SimulcryptMessage::new(
Interface::EcmgScs.protocol_version(),
MessageType::EcmgScs(EcmgScsMessageType::ChannelSetup),
vec![
Parameter::new(
ParameterType::EcmgScs(EcmgScsParameterType::EcmChannelId),
&ecm_channel_id,
),
Parameter::new(
ParameterType::EcmgScs(EcmgScsParameterType::SuperCasId),
&super_cas_id,
),
],
);
let mut buf = vec![0u8; msg.serialized_len()];
msg.serialize_into(&mut buf).unwrap();
assert_eq!(SimulcryptMessage::parse_on(Interface::EcmgScs, &buf).unwrap(), msg);§Runnable examples
Run with cargo run -p dvb-simulcrypt --example <name>.
§build_channel_setup
/// Build an ECMG⇔SCS `channel_setup` message from typed fields, serialize it
/// (recomputing message_length + each parameter_length), and dump the wire
/// bytes.
///
/// ```sh
/// cargo run -p dvb-simulcrypt --example build_channel_setup
/// ```
use dvb_common::traits::{Parse, Serialize};
use dvb_simulcrypt::{
EcmgScsMessageType, EcmgScsParameterType, Interface, MessageType, Parameter, ParameterType,
SimulcryptMessage,
};
fn main() {
// channel_setup (Table, §5.4.1): ECM_channel_id (1) + Super_CAS_id (1).
let ecm_channel_id = [0x00u8, 0x2A]; // ECM_channel_id = 0x002A
let super_cas_id = [0x00u8, 0x01, 0x00, 0x02]; // CA_system_id | CA_subsystem_id
let msg = SimulcryptMessage::new(
Interface::EcmgScs.protocol_version(),
MessageType::EcmgScs(EcmgScsMessageType::ChannelSetup),
vec![
Parameter::new(
ParameterType::EcmgScs(EcmgScsParameterType::EcmChannelId),
&ecm_channel_id,
),
Parameter::new(
ParameterType::EcmgScs(EcmgScsParameterType::SuperCasId),
&super_cas_id,
),
],
);
let mut bytes = vec![0u8; msg.serialized_len()];
let n = msg.serialize_into(&mut bytes).unwrap();
println!("interface: {}", msg.interface());
println!(
"message_type: {} (0x{:04X})",
msg.message_type,
msg.message_type.to_u16()
);
println!("protocol_version: 0x{:02X}", msg.protocol_version);
println!("message_length (body): {}", msg.body_len());
println!("parameters: {}", msg.parameters.len());
for p in &msg.parameters {
print!(" {} (0x{:04X}) =", p.ptype, p.ptype.to_u16());
for b in p.value {
print!(" {b:02X}");
}
println!();
}
print!("wire bytes ({n}):");
for b in &bytes {
print!(" {b:02X}");
}
println!();
// Round-trip: parse against the same interface, expect equality.
assert_eq!(
SimulcryptMessage::parse_on(Interface::EcmgScs, &bytes).unwrap(),
msg
);
// The default `Parse` impl also targets ECMG⇔SCS.
assert_eq!(SimulcryptMessage::parse(&bytes).unwrap(), msg);
println!("round-trip: OK");
}§parse_cw_provision
/// Read the committed `cw_provision.bin` fixture (an ECMG⇔SCS `CW_provision`
/// message), parse it against the ECMG⇔SCS interface, walk its parameters
/// (treating the CW inside `CP_CW_combination` as opaque), and byte-exact
/// round-trip it.
///
/// ```sh
/// cargo run -p dvb-simulcrypt --example parse_cw_provision
/// ```
use std::fs;
use dvb_common::traits::Serialize;
use dvb_simulcrypt::{
EcmgScsParameterType, Interface, MessageType, ParameterType, SimulcryptMessage,
};
fn main() {
let path = concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/cw_provision.bin"
);
let bytes = match fs::read(path) {
Ok(d) => d,
Err(e) => {
eprintln!("fixture not available ({e}); nothing to do");
return;
}
};
let msg = SimulcryptMessage::parse_on(Interface::EcmgScs, &bytes)
.expect("CW_provision fixture must parse");
println!("interface: {}", msg.interface());
println!(
"message_type: {} (0x{:04X})",
msg.message_type,
msg.message_type.to_u16()
);
assert!(matches!(
msg.message_type,
MessageType::EcmgScs(dvb_simulcrypt::EcmgScsMessageType::CwProvision)
));
for p in &msg.parameters {
print!(
" {} (0x{:04X}), {} bytes:",
p.ptype,
p.ptype.to_u16(),
p.value.len()
);
for b in p.value {
print!(" {b:02X}");
}
println!();
}
// The CP_CW_combination's CW is opaque — we only locate the parameter.
// Guard: the parameter must carry at least 2 bytes for the CP number.
if let Some(cpcw) = msg.find(ParameterType::EcmgScs(
EcmgScsParameterType::CpCwCombination,
)) {
if let Some(cp_bytes) = cpcw.value.get(0..2) {
let cp = u16::from_be_bytes([cp_bytes[0], cp_bytes[1]]);
println!(
"CP_CW_combination: CP={cp}, CW={} opaque bytes",
cpcw.value.len() - 2
);
} else {
println!(
"CP_CW_combination: value too short ({} bytes, need ≥2)",
cpcw.value.len()
);
}
}
// Byte-exact round-trip.
let mut out = vec![0u8; msg.serialized_len()];
let n = msg.serialize_into(&mut out).unwrap();
assert_eq!(n, bytes.len());
assert_eq!(
out, bytes,
"serialize must reproduce the fixture byte-for-byte"
);
println!("byte-exact round-trip: OK");
}Structs§
- Parameter
- One TLV parameter of a
SimulcryptMessage(Table 1b): a typedparameter_typeplus a borrowed, opaqueparameter_value. - Simulcrypt
Message - A generic SimulCrypt message (TS 103 197 Table 1b): the 5-byte header plus
an ordered list of TLV
Parameters.
Enums§
- CpSig
Message Type - C(P)SIG⇔(P)SIG
message_typevalues (TS 103 197 Table 3, §4.4.1 / §8). - CpSig
Parameter Type - C(P)SIG⇔(P)SIG
parameter_typevalues (TS 103 197 Table 36, §8). - Data
Type data_typevalues (TS 103 197 §6.2.3 p. 42) — what adatagramcarries.- Ecmg
Error Status - ECMG⇔SCS
error_statusvalues (TS 103 197 Table 6, §5.6 p. 39). - Ecmg
ScsMessage Type - ECMG⇔SCS
message_typevalues (TS 103 197 Table 3, §4.4.1 pp. 27-28). - Ecmg
ScsParameter Type - ECMG⇔SCS
parameter_typevalues (TS 103 197 Table 5, §5.2 p. 31). - Emmg
Error Status - EMMG/PDG⇔MUX
error_statusvalues (TS 103 197 Table 8, §6.2.6 p. 47). - Emmg
MuxMessage Type - EMMG/PDG⇔MUX
message_typevalues (TS 103 197 Table 3, §4.4.1 pp. 27-28). - Emmg
MuxParameter Type - EMMG/PDG⇔MUX
parameter_typevalues (TS 103 197 Table 7, §6.2.2 p. 42). - Error
- A SimulCrypt parse / serialize error.
- Interface
- The SimulCrypt connection-oriented interface a message belongs to.
- Message
Type - Interface-tagged
message_type: decode a raw value once theInterfaceis known. - Parameter
Type - Interface-tagged
parameter_type: decode a raw value once theInterfaceis known. - Section
Tspkt Flag section_TSpkt_flagvalues (TS 103 197 §6.2.3 p. 43) — the datagram framing indatagramparameters. (The same flag, with the same meaning, is carried on the ECMG⇔SCS interface forECM_datagram.)
Constants§
- HEADER_
LEN - Bytes of the fixed
generic_messageheader: protocol_version (1) + message_type (2) + message_length (2). - PARAMETER_
HEADER_ LEN - Bytes of a parameter TLV’s fixed prefix: parameter_type (2) + parameter_length (2).
Type Aliases§
- Result
- Result alias for SimulCrypt parsing.