Expand description
Partial implementation of security for 802.4.15 frames.
For specifications of the procedures and structures, see section 7.4 of the 802.15.4-2011 standard.
Example on how to use frames with security
Note that the example below is very insecure, and should not be used in any production setting
use ieee802154::mac::{
frame::security::{
KeyDescriptorLookup,
DeviceDescriptorLookup,
DeviceDescriptor,
SecurityContext,
AddressingMode,
U16,
KeyIdentifier,
SecurityControl,
AuxiliarySecurityHeader,
SecurityLevel,
KeySource,
},
Address,
ExtendedAddress,
PanId,
Header,
Frame,
FrameVersion,
FrameContent,
FrameType,
FrameSerDesContext,
FooterMode,
};
use ccm::aead::generic_array::GenericArray;
use aes::Aes128;
use byte::TryWrite;
/// Static key descriptor lookup struct that always returns
/// the same key, given that the input address is
/// an extended address
struct StaticKeyLookup;
impl KeyDescriptorLookup<U16> for StaticKeyLookup {
fn lookup_key_descriptor(
&self,
_address_mode: AddressingMode,
_key_identifier: Option<KeyIdentifier>,
device_address: Option<Address>,
) -> Option<(u64, GenericArray<u8, U16>)> {
let key = GenericArray::default();
if let Some(Address::Extended(pan_id, ExtendedAddress(u64_id))) = device_address {
Some((u64_id, key))
} else {
None
}
}
}
/// A device descriptor lookup that always returns the same
/// device descriptor
struct BasicDevDescriptorLookup<'a> {
descriptor: &'a mut DeviceDescriptor,
}
impl<'a> BasicDevDescriptorLookup<'a> {
pub fn new(descriptor: &'a mut DeviceDescriptor) -> Self {
Self { descriptor }
}
}
impl<'a> DeviceDescriptorLookup for BasicDevDescriptorLookup<'a> {
fn lookup_device(
&mut self,
_addressing_mode: AddressingMode,
_address: Address,
) -> Option<&mut DeviceDescriptor> {
Some(self.descriptor)
}
}
const STATIC_KEY_LOOKUP: StaticKeyLookup = StaticKeyLookup {};
const FRAME_CTR: u32 = 0x00000000;
/// Get a new security context that uses the Aes128 block cipher for CCM operations,
/// and the static key lookup for determining the key to use
fn aes_sec_ctx<'a>(source_euid: u64, frame_counter: u32) -> SecurityContext<Aes128, StaticKeyLookup> {
SecurityContext::new(source_euid, frame_counter, STATIC_KEY_LOOKUP)
}
fn main() {
let source_euid = 0x01;
let source = Some(Address::Extended(PanId(0x111), ExtendedAddress(source_euid)));
let destination = Some(Address::Extended(PanId(0x111), ExtendedAddress(0x02)));
let device_desc = &mut DeviceDescriptor {
frame_counter: FRAME_CTR,
exempt: false,
};
let mut sec_ctx = aes_sec_ctx(source_euid, FRAME_CTR);
let auxiliary_security_header = Some(AuxiliarySecurityHeader::new(
SecurityControl::new(SecurityLevel::ENCMIC128),
Some(KeyIdentifier {
key_source: Some(KeySource::Long(0xAA)),
key_index: 48,
}),
));
let payload = &[0u8, 1u8, 2u8, 3u8, 4u8];
let frame_to_secure = Frame {
header: Header {
ie_present: false,
seq_no_suppress: false,
frame_type: FrameType::Data,
frame_pending: false,
ack_request: false,
pan_id_compress: false,
version: FrameVersion::Ieee802154,
seq: 127,
destination,
source,
auxiliary_security_header,
},
content: FrameContent::Data,
payload,
footer: [0x00, 0x00],
};
let mut buffer = [0u8; 128];
// Write/"send" a MAC frame. Security is applied if an auxiliary security header
// is present (which it is, in this case)
// Note that this does _not_ change the contents of the frame, the secured data
// is only written to the buffer
let len = match frame_to_secure.try_write(
&mut buffer,
&mut FrameSerDesContext::new(FooterMode::None, Some(&mut sec_ctx)),
) {
Ok(size) => size,
Err(e) => 0,
};
// Verify that encryption succeeded and tag was appended correctly
assert_eq!(&buffer[..len], &[
0x9, 0xec, 0x7f, 0x11, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x1, 0x1, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x0, 0x0, 0x0, 0x0, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x30, 0xf8, 0x58, 0x90, 0xd2, 0x7f, 0x46, 0xcf, 0x1a, 0x73, 0xd3, 0xad, 0x65, 0xda, 0x6c, 0xd1,
0x4b, 0x73, 0xef, 0xbe, 0x79, 0x31,
]);
// Read/"receive" a MAC frame. Unsecuring it is attempted if the header
// has security enabled
let unsecured_frame = match Frame::try_read_and_unsecure(
&mut buffer[..len],
&mut FrameSerDesContext::new(FooterMode::None, Some(&mut sec_ctx)),
&mut BasicDevDescriptorLookup::new(device_desc),
) {
Ok((frame, _)) => frame,
Err(e) => panic!("Could not unsecure frame! {:?}", e),
};
assert_eq!(unsecured_frame.payload, &[0u8, 1u8, 2u8, 3u8, 4u8])
}
Modules
Provides a default AEAD, key descriptor lookup, and device descriptor lookups to satisfy the type requirements for (de-)serializing frames without providing any security
Structs
A struct describing the Auxiliary Security Header
A partial device descriptor
A key identifier
A context that used to keep track of cryptographic properties that are necessary for securing/unsecuring frames
The Security Control header
Enums
The addressing mode to use during descriptor lookups
The key identifier mode
A key source
Errors that can occur while performing security operations on frames
The level of security applied to the payload
Traits
Trait which marks a type as being a block cipher.
Encrypt-only functionality for block ciphers.
Perform a lookup of a device descriptor based on the provided address
Used to create a KeyDescriptor from a KeyIdentifier and device address
Instantiate a BlockCipher
algorithm.