Support key_derivation_rate and fix update_session_keys only working by accident
parent
febcc71ac8
commit
0b5229d36f
109
src/rfc3711.rs
109
src/rfc3711.rs
|
@ -40,6 +40,9 @@ pub struct SrtpContext {
|
||||||
// TODO: support other fields
|
// TODO: support other fields
|
||||||
pub master_key: Vec<u8>,
|
pub master_key: Vec<u8>,
|
||||||
pub master_salt: Vec<u8>,
|
pub master_salt: Vec<u8>,
|
||||||
|
// Since actual kdr is a power of two, this only stores the power (+1).
|
||||||
|
// i.e. actual kdr is 2^(key_derivation_rate-1) (or 0 in case of 0)
|
||||||
|
pub key_derivation_rate: u8,
|
||||||
pub rollover_counter: u32,
|
pub rollover_counter: u32,
|
||||||
pub highest_recv_seq_num: u16,
|
pub highest_recv_seq_num: u16,
|
||||||
pub encryption: EncryptionAlgorithm,
|
pub encryption: EncryptionAlgorithm,
|
||||||
|
@ -56,6 +59,7 @@ impl SrtpContext {
|
||||||
SrtpContext {
|
SrtpContext {
|
||||||
master_key: Vec::from(master_key),
|
master_key: Vec::from(master_key),
|
||||||
master_salt: Vec::from(master_salt),
|
master_salt: Vec::from(master_salt),
|
||||||
|
key_derivation_rate: 0,
|
||||||
rollover_counter: 0,
|
rollover_counter: 0,
|
||||||
highest_recv_seq_num: 0,
|
highest_recv_seq_num: 0,
|
||||||
encryption: EncryptionAlgorithm::default(),
|
encryption: EncryptionAlgorithm::default(),
|
||||||
|
@ -67,8 +71,16 @@ impl SrtpContext {
|
||||||
auth_tag_len: 80 / 8,
|
auth_tag_len: 80 / 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn update_session_keys(&mut self) {
|
pub fn update_session_keys(&mut self, index: u64) {
|
||||||
let index = ((self.rollover_counter as u64) << 16) + self.highest_recv_seq_num as u64;
|
let index = if self.key_derivation_rate == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
index >> (self.key_derivation_rate - 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: only recalculate if index changed, probably also cache surrounding indices
|
||||||
|
// but make sure the initial updates happens
|
||||||
|
|
||||||
let index = BigUint::from(index);
|
let index = BigUint::from(index);
|
||||||
|
|
||||||
let enc_key_id = BigUint::from_bytes_be(&[0, 0, 0, 0, 0, 0, 0]) + index.clone();
|
let enc_key_id = BigUint::from_bytes_be(&[0, 0, 0, 0, 0, 0, 0]) + index.clone();
|
||||||
|
@ -154,6 +166,45 @@ impl SrtpContext {
|
||||||
};
|
};
|
||||||
(probable_roc, ((probable_roc as PacketIndex) << 16) + seq_num as PacketIndex)
|
(probable_roc, ((probable_roc as PacketIndex) << 16) + seq_num as PacketIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://tools.ietf.org/html/rfc3711#section-3.3
|
||||||
|
pub fn process_incoming(&mut self, packet: &[u8]) -> Result<Vec<u8>> {
|
||||||
|
// Step 1: determining the correct context (has already happened at this point)
|
||||||
|
|
||||||
|
// Step 2: Determine index of the SRTP packet
|
||||||
|
let reader = &mut &packet[..];
|
||||||
|
let header = track_try!(rfc3550::RtpFixedHeader::read_from(reader));
|
||||||
|
let seq_num = header.seq_num;
|
||||||
|
let (rollover_counter, index) = self.estimate_packet_index(seq_num);
|
||||||
|
|
||||||
|
// Step 3: Determine master key and salt
|
||||||
|
// TODO: support re-keying
|
||||||
|
// TODO: support MKI
|
||||||
|
|
||||||
|
// Step 4: Determine session keys and salt
|
||||||
|
self.update_session_keys(index);
|
||||||
|
|
||||||
|
// Step 5: Replay protection and authentication
|
||||||
|
// TODO: replay protection
|
||||||
|
self.authenticate(packet)?;
|
||||||
|
|
||||||
|
// Step 6: Decryption
|
||||||
|
let result = self.decrypt(packet)?;
|
||||||
|
|
||||||
|
// Step 7: Update ROC, highest sequence number and replay protection
|
||||||
|
// TODO: replay protection
|
||||||
|
// https://tools.ietf.org/html/rfc3711#section-3.3.1
|
||||||
|
if rollover_counter == self.rollover_counter {
|
||||||
|
if seq_num > self.highest_recv_seq_num {
|
||||||
|
self.highest_recv_seq_num = seq_num;
|
||||||
|
}
|
||||||
|
} else if rollover_counter > self.rollover_counter {
|
||||||
|
self.highest_recv_seq_num = seq_num;
|
||||||
|
self.rollover_counter = rollover_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -161,6 +212,9 @@ pub struct SrtcpContext {
|
||||||
// TODO: support other fields
|
// TODO: support other fields
|
||||||
pub master_key: Vec<u8>,
|
pub master_key: Vec<u8>,
|
||||||
pub master_salt: Vec<u8>,
|
pub master_salt: Vec<u8>,
|
||||||
|
// Since actual kdr is a power of two, this only stores the power (+1).
|
||||||
|
// i.e. actual kdr is 2^(key_derivation_rate-1) (or 0 in case of 0)
|
||||||
|
pub key_derivation_rate: u8,
|
||||||
pub highest_recv_index: u32, // NOTE: 31-bits
|
pub highest_recv_index: u32, // NOTE: 31-bits
|
||||||
pub encryption: EncryptionAlgorithm,
|
pub encryption: EncryptionAlgorithm,
|
||||||
pub authentication: AuthenticationAlgorithm,
|
pub authentication: AuthenticationAlgorithm,
|
||||||
|
@ -176,6 +230,7 @@ impl SrtcpContext {
|
||||||
SrtcpContext {
|
SrtcpContext {
|
||||||
master_key: Vec::from(master_key),
|
master_key: Vec::from(master_key),
|
||||||
master_salt: Vec::from(master_salt),
|
master_salt: Vec::from(master_salt),
|
||||||
|
key_derivation_rate: 0,
|
||||||
highest_recv_index: 0,
|
highest_recv_index: 0,
|
||||||
encryption: EncryptionAlgorithm::default(),
|
encryption: EncryptionAlgorithm::default(),
|
||||||
authentication: AuthenticationAlgorithm::default(),
|
authentication: AuthenticationAlgorithm::default(),
|
||||||
|
@ -186,9 +241,18 @@ impl SrtcpContext {
|
||||||
auth_tag_len: 80 / 8,
|
auth_tag_len: 80 / 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn update_session_keys(&mut self) {
|
pub fn update_session_keys(&mut self, index: u32) {
|
||||||
|
let index = if self.key_derivation_rate == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
index >> (self.key_derivation_rate - 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: only recalculate if index changed, probably also cache surrounding indices
|
||||||
|
// but make sure the initial updates happens
|
||||||
|
|
||||||
// See: https://tools.ietf.org/html/rfc3711#section-4.3.2
|
// See: https://tools.ietf.org/html/rfc3711#section-4.3.2
|
||||||
let index = BigUint::from(self.highest_recv_index);
|
let index = BigUint::from(index);
|
||||||
|
|
||||||
let enc_key_id = BigUint::from_bytes_be(&[3, 0, 0, 0, 0, 0, 0]) + index.clone();
|
let enc_key_id = BigUint::from_bytes_be(&[3, 0, 0, 0, 0, 0, 0]) + index.clone();
|
||||||
let auth_key_id = BigUint::from_bytes_be(&[4, 0, 0, 0, 0, 0, 0]) + index.clone();
|
let auth_key_id = BigUint::from_bytes_be(&[4, 0, 0, 0, 0, 0, 0]) + index.clone();
|
||||||
|
@ -251,6 +315,35 @@ impl SrtcpContext {
|
||||||
|
|
||||||
Ok(decrypted)
|
Ok(decrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://tools.ietf.org/html/rfc3711#section-3.3
|
||||||
|
// https://tools.ietf.org/html/rfc3711#section-3.4
|
||||||
|
pub fn process_incoming(&mut self, packet: &[u8]) -> Result<Vec<u8>> {
|
||||||
|
// Step 1: determining the correct context (has already happened at this point)
|
||||||
|
|
||||||
|
// Step 2: Determine index of the SRTCP packet
|
||||||
|
let index = track_try!((&mut &packet[packet.len() - self.auth_tag_len - 4..]).read_u32be());
|
||||||
|
let index = index & 0x7FFF_FFFF; // remove uppermost bit which isn't part of the index
|
||||||
|
|
||||||
|
// Step 3: Determine master key and salt
|
||||||
|
// TODO: support re-keying
|
||||||
|
// TODO: support MKI
|
||||||
|
|
||||||
|
// Step 4: Determine session keys and salt
|
||||||
|
self.update_session_keys(index);
|
||||||
|
|
||||||
|
// Step 5: Replay protection and authentication
|
||||||
|
// TODO: replay protection
|
||||||
|
track_try!(self.authenticate(packet));
|
||||||
|
|
||||||
|
// Step 6: Decryption
|
||||||
|
let result = track_try!(self.decrypt(packet));
|
||||||
|
|
||||||
|
// Step 7: Update replay protection
|
||||||
|
// TODO: replay protection
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -264,7 +357,6 @@ where
|
||||||
T::Packet: RtpPacket,
|
T::Packet: RtpPacket,
|
||||||
{
|
{
|
||||||
pub fn new(mut context: SrtpContext, inner: T) -> Self {
|
pub fn new(mut context: SrtpContext, inner: T) -> Self {
|
||||||
context.update_session_keys();
|
|
||||||
SrtpPacketReader {
|
SrtpPacketReader {
|
||||||
context: context,
|
context: context,
|
||||||
inner: inner,
|
inner: inner,
|
||||||
|
@ -279,8 +371,7 @@ where
|
||||||
type Packet = T::Packet;
|
type Packet = T::Packet;
|
||||||
fn read_packet<R: Read>(&mut self, reader: &mut R) -> Result<Self::Packet> {
|
fn read_packet<R: Read>(&mut self, reader: &mut R) -> Result<Self::Packet> {
|
||||||
let packet_bytes = track_try!(reader.read_all_bytes());
|
let packet_bytes = track_try!(reader.read_all_bytes());
|
||||||
track_try!(self.context.authenticate(&packet_bytes));
|
let decrypted_packet_bytes = track_try!(self.context.process_incoming(&packet_bytes));
|
||||||
let decrypted_packet_bytes = track_try!(self.context.decrypt(&packet_bytes));
|
|
||||||
track_err!(self.inner.read_packet(&mut &decrypted_packet_bytes[..]))
|
track_err!(self.inner.read_packet(&mut &decrypted_packet_bytes[..]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +391,6 @@ where
|
||||||
T::Packet: RtcpPacket,
|
T::Packet: RtcpPacket,
|
||||||
{
|
{
|
||||||
pub fn new(mut context: SrtcpContext, inner: T) -> Self {
|
pub fn new(mut context: SrtcpContext, inner: T) -> Self {
|
||||||
context.update_session_keys();
|
|
||||||
SrtcpPacketReader {
|
SrtcpPacketReader {
|
||||||
context: context,
|
context: context,
|
||||||
inner: inner,
|
inner: inner,
|
||||||
|
@ -315,8 +405,7 @@ where
|
||||||
type Packet = T::Packet;
|
type Packet = T::Packet;
|
||||||
fn read_packet<R: Read>(&mut self, reader: &mut R) -> Result<Self::Packet> {
|
fn read_packet<R: Read>(&mut self, reader: &mut R) -> Result<Self::Packet> {
|
||||||
let packet_bytes = track_try!(reader.read_all_bytes());
|
let packet_bytes = track_try!(reader.read_all_bytes());
|
||||||
track_try!(self.context.authenticate(&packet_bytes));
|
let decrypted_packet_bytes = track_try!(self.context.process_incoming(&packet_bytes));
|
||||||
let decrypted_packet_bytes = track_try!(self.context.decrypt(&packet_bytes));
|
|
||||||
track_err!(self.inner.read_packet(&mut &decrypted_packet_bytes[..]))
|
track_err!(self.inner.read_packet(&mut &decrypted_packet_bytes[..]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue