use lora_packet::{
AppEui, AppKey, AppNonce, AppSKey, DevAddr, DevEui, DevNonce, Direction, DlSettings, FCtrl, FNwkSIntKey, JoinAccept,
JoinEui, LoraPacket, MType, NetId, NwkKey, NwkSEncKey, NwkSKey, Payload, SNwkSIntKey, V1_0MicKeys,
};
fn hex_to_vec(s: &str) -> Vec<u8> {
hex::decode(s).expect("valid hex string")
}
fn key_from_hex(s: &str) -> [u8; 16] {
let v = hex_to_vec(s);
let mut arr = [0u8; 16];
arr.copy_from_slice(&v);
arr
}
#[test]
fn should_create_packet_with_minimal_input() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(0)
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("40d4c3b2a10000000174657374")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
assert_eq!(packet.mhdr.as_byte(), 0x40);
assert_eq!(packet.mic, [0, 0, 0, 0]);
let d = packet.as_data().unwrap();
assert!(d.f_opts.is_empty());
assert_eq!(d.f_ctrl.as_byte(), 0x00);
assert_eq!(d.dev_addr.as_bytes(), &[0xa1, 0xb2, 0xc3, 0xd4]);
assert_eq!(d.f_cnt, [0x00, 0x00]);
assert_eq!(d.f_port, Some(0x01));
assert_eq!(d.frm_payload.as_deref(), Some(b"test".as_slice()));
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_omit_fport_if_no_payload_or_port() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(1)
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("40d4c3b2a1000100")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
assert_eq!(packet.mhdr.as_byte(), 0x40);
assert_eq!(packet.mic, [0, 0, 0, 0]);
let d = packet.as_data().unwrap();
assert!(d.f_opts.is_empty());
assert_eq!(d.f_ctrl.as_byte(), 0x00);
assert_eq!(d.dev_addr.as_bytes(), &[0xa1, 0xb2, 0xc3, 0xd4]);
assert_eq!(d.f_cnt, [0x01, 0x00]);
assert_eq!(d.f_port, None);
assert!(d.frm_payload.is_none());
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_create_packet_with_mtype_as_integer_5() {
let packet = LoraPacket::builder()
.data(Direction::Downlink, true) .dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(1)
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("A0d4c3b2a10001000174657374")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
assert_eq!(packet.mhdr.as_byte(), 0xA0);
let d = packet.as_data().unwrap();
assert_eq!(d.dev_addr.as_bytes(), &[0xa1, 0xb2, 0xc3, 0xd4]);
assert_eq!(d.f_cnt, [0x01, 0x00]);
assert_eq!(d.f_port, Some(0x01));
assert_eq!(d.frm_payload.as_deref(), Some(b"test".as_slice()));
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_create_packet_with_mtype_as_string_confirmed_data_up() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, true)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(1)
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("80d4c3b2a10001000174657374")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
assert_eq!(packet.mhdr.as_byte(), 0x80);
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_verify_mtype_confirmed() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, true)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(1)
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
assert!(packet.is_confirmed());
}
#[test]
fn should_verify_mtype_unconfirmed() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(1)
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
assert!(!packet.is_confirmed());
}
#[test]
fn should_create_packet_with_fcnt_as_buffer() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(0x1234)
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("40d4c3b2a10034120174657374")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
let d = packet.as_data().unwrap();
assert_eq!(d.f_cnt, [0x34, 0x12]);
assert_eq!(d.f_cnt(), 0x1234);
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_create_packet_with_fcnt_as_number() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(4660)
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("40d4c3b2a10034120174657374")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
let d = packet.as_data().unwrap();
assert_eq!(d.f_cnt, [0x34, 0x12]);
assert_eq!(d.f_cnt(), 4660);
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_create_packet_with_fopts() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_opts(&[0xF0, 0xF1, 0xF2, 0xF3])
.f_cnt(1)
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("40d4c3b2a1040100F0F1F2F30174657374")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
let d = packet.as_data().unwrap();
assert_eq!(d.f_opts, vec![0xF0, 0xF1, 0xF2, 0xF3]);
assert_eq!(d.f_ctrl.as_byte(), 0x04);
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_create_packet_with_correct_fctrl_ack() {
let packet_ack_true = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_ctrl(FCtrl(0x20))
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let d = packet_ack_true.as_data().unwrap();
assert_eq!(d.f_ctrl.as_byte(), 0x20);
assert!(d.f_ctrl.ack());
let packet_ack_false = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_ctrl(FCtrl(0x00))
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let d = packet_ack_false.as_data().unwrap();
assert_eq!(d.f_ctrl.as_byte(), 0x00);
assert!(!d.f_ctrl.ack());
}
#[test]
fn should_create_packet_with_correct_fctrl_adr() {
let packet_adr_true = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_ctrl(FCtrl(0x80))
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let d = packet_adr_true.as_data().unwrap();
assert_eq!(d.f_ctrl.as_byte(), 0x80);
assert!(d.f_ctrl.adr());
let packet_adr_false = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_ctrl(FCtrl(0x00))
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let d = packet_adr_false.as_data().unwrap();
assert_eq!(d.f_ctrl.as_byte(), 0x00);
assert!(!d.f_ctrl.adr());
}
#[test]
fn should_create_packet_with_correct_fctrl_all_flags() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_ctrl(FCtrl(0xF0))
.f_port(1)
.payload(b"test")
.build_unsigned()
.unwrap();
let d = packet.as_data().unwrap();
assert_eq!(d.f_ctrl.as_byte(), 0xF0);
assert!(d.f_ctrl.adr());
assert!(d.f_ctrl.adr_ack_req());
assert!(d.f_ctrl.ack());
assert!(d.f_ctrl.class_b());
}
#[test]
fn should_create_join_request_packet() {
let packet = LoraPacket::builder()
.join_request()
.join_eui(AppEui::new([0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD]))
.dev_eui(DevEui::new([0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD]))
.dev_nonce(DevNonce::new([0xAA, 0xBB]))
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("00DDCCBBAADDCCBBAADDCCBBAADDCCBBAABBAA")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
assert_eq!(packet.mhdr.as_byte(), 0x00);
let jr = packet.as_join_request().unwrap();
assert_eq!(
jr.join_eui.as_bytes(),
&[0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD]
);
assert_eq!(jr.dev_eui.as_bytes(), &[0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD]);
assert_eq!(jr.dev_nonce.as_bytes(), &[0xAA, 0xBB]);
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_create_join_accept_packet_with_minimal_input() {
let packet = LoraPacket::builder()
.join_accept()
.join_nonce(AppNonce::new([0xAA, 0xBB, 0xCC]))
.net_id(NetId::new([0xAA, 0xBB, 0xCC]))
.dev_addr(DevAddr::new([0xAA, 0xBB, 0xCC, 0xDD]))
.dl_settings(DlSettings(0x00))
.rx_delay(0x00)
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("20CCBBAACCBBAADDCCBBAA0000")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
let ja = packet.as_join_accept().unwrap();
assert_eq!(ja.join_nonce.as_bytes(), &[0xAA, 0xBB, 0xCC]);
assert_eq!(ja.net_id.as_bytes(), &[0xAA, 0xBB, 0xCC]);
assert_eq!(ja.dev_addr.as_bytes(), &[0xAA, 0xBB, 0xCC, 0xDD]);
assert_eq!(ja.dl_settings.as_byte(), 0x00);
assert_eq!(ja.rx_delay, 0x00);
assert!(ja.cf_list.is_none());
}
#[test]
fn should_create_join_accept_packet() {
let packet = LoraPacket::builder()
.join_accept()
.join_nonce(AppNonce::new([0xAA, 0xBB, 0xCC]))
.net_id(NetId::new([0xAA, 0xBB, 0xCC]))
.dev_addr(DevAddr::new([0xAA, 0xBB, 0xCC, 0xDD]))
.dl_settings(DlSettings(0x12))
.rx_delay(0x0F)
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("20CCBBAACCBBAADDCCBBAA120F")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
let ja = packet.as_join_accept().unwrap();
assert_eq!(ja.dl_settings.as_byte(), 0x12);
assert_eq!(ja.rx_delay, 0x0F);
assert!(ja.cf_list.is_none());
}
#[test]
fn should_create_join_accept_packet_with_cflist() {
let cf_list_bytes = hex_to_vec("11223311223311223311223311223300");
let mut cf_list = [0u8; 16];
cf_list.copy_from_slice(&cf_list_bytes);
let packet = LoraPacket::builder()
.join_accept()
.join_nonce(AppNonce::new([0xAA, 0xBB, 0xCC]))
.net_id(NetId::new([0xAA, 0xBB, 0xCC]))
.dev_addr(DevAddr::new([0xAA, 0xBB, 0xCC, 0xDD]))
.dl_settings(DlSettings(0x12))
.rx_delay(0x0F)
.cf_list(cf_list)
.build_unsigned()
.unwrap();
let expected_phy_payload = hex_to_vec("20CCBBAACCBBAADDCCBBAA120F11223311223311223311223311223300")
.into_iter()
.chain([0, 0, 0, 0])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_phy_payload);
let ja = packet.as_join_accept().unwrap();
assert_eq!(ja.cf_list.unwrap(), cf_list);
}
#[test]
fn should_create_packet_with_correct_fport() {
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_port(42)
.payload(b"test")
.build_unsigned()
.unwrap();
assert_eq!(packet.as_data().unwrap().f_port, Some(42));
}
#[test]
fn should_calculate_mic_if_keys_provided() {
let app_s_key = AppSKey::new(key_from_hex("ec925802ae430ca77fd3dd73cb2cc588"));
let nwk_s_key = NwkSKey::new(key_from_hex("44024241ed4ce9a68c6a8bc055233fd3"));
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0x49, 0xbe, 0x7d, 0xf1]))
.f_cnt(2)
.f_port(1)
.payload(b"test")
.sign_and_encrypt(&app_s_key, &nwk_s_key)
.unwrap();
let expected_phy_payload = hex_to_vec("40f17dbe4900020001954378762b11ff0d");
assert_eq!(packet.phy_payload, expected_phy_payload);
assert_eq!(packet.mhdr.as_byte(), 0x40);
assert_eq!(packet.mic, [0x2b, 0x11, 0xff, 0x0d]);
let d = packet.as_data().unwrap();
assert_eq!(d.dev_addr.as_bytes(), &[0x49, 0xbe, 0x7d, 0xf1]);
assert_eq!(d.f_cnt, [0x02, 0x00]);
assert_eq!(d.f_port, Some(0x01));
assert_eq!(d.frm_payload.as_deref(), Some(&[0x95, 0x43, 0x78, 0x76][..]));
let parsed = LoraPacket::from_wire(&packet.phy_payload).unwrap();
assert_eq!(parsed, packet);
}
#[test]
fn should_encrypt_if_keys_provided() {
let app_s_key = AppSKey::new(key_from_hex("ec925802ae430ca77fd3dd73cb2cc588"));
let nwk_s_key = NwkSKey::new(key_from_hex("44024241ed4ce9a68c6a8bc055233fd3"));
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0x49, 0xbe, 0x7d, 0xf1]))
.f_cnt(2)
.f_port(1)
.payload(b"test")
.sign_and_encrypt(&app_s_key, &nwk_s_key)
.unwrap();
let expected_phy_payload = hex_to_vec("40f17dbe4900020001954378762b11ff0d");
assert_eq!(packet.phy_payload, expected_phy_payload);
}
#[test]
fn should_parse_packet_1() {
let bytes = hex_to_vec("4084412505A3010009110308B33750F504D4B86A");
let parsed = LoraPacket::from_wire(&bytes).unwrap();
let d = parsed.as_data().unwrap();
assert_eq!(d.f_opts, hex_to_vec("091103"));
}
#[test]
fn should_create_packet_with_port_0() {
let nwk_s_key = NwkSKey::new(key_from_hex("a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"));
let app_s_key = AppSKey::new([0u8; 16]);
let packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0xa1, 0xb2, 0xc3, 0xd4]))
.f_cnt(16)
.f_port(0)
.payload(&[0x02])
.sign_and_encrypt(&app_s_key, &nwk_s_key)
.unwrap();
let expected_phy_payload = hex_to_vec("40D4C3B2A1001000002712A3F9C9");
assert_eq!(packet.phy_payload, expected_phy_payload);
assert_eq!(packet.mhdr.as_byte(), 0x40);
assert_eq!(packet.mic, [0x12, 0xA3, 0xF9, 0xC9]);
let d = packet.as_data().unwrap();
assert_eq!(d.dev_addr.as_bytes(), &[0xa1, 0xb2, 0xc3, 0xd4]);
assert_eq!(d.f_cnt, [0x10, 0x00]);
assert_eq!(d.f_port, Some(0x00));
assert_eq!(d.frm_payload.as_deref(), Some(&[0x27][..]));
assert_eq!(d.f_ctrl.as_byte(), 0x00);
assert!(d.f_opts.is_empty());
}
#[test]
fn should_create_packet_with_opt_neg() {
let nwk_key = NwkKey::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let join_eui = AppEui::new([8, 7, 6, 5, 4, 3, 2, 1]);
let dev_nonce = DevNonce::new([1, 2]);
let mut packet = LoraPacket::builder()
.join_accept()
.join_nonce(AppNonce::new([0x01, 0x01, 0x01]))
.net_id(NetId::new([0x02, 0x02, 0x02]))
.dev_addr(DevAddr::new([0x01, 0x02, 0x03, 0x04]))
.dl_settings(DlSettings(0b1000_0000)) .rx_delay(0x00)
.build_unsigned()
.unwrap();
let js_int_key = lora_packet::JSIntKey::new(*nwk_key.as_bytes());
let mic_keys = lora_packet::V1_1MicKeys {
js_int_key: Some(&js_int_key),
join_eui: Some(join_eui),
dev_nonce: Some(dev_nonce),
join_req_type: Some(0xFF),
..Default::default()
};
packet.recalculate_mic_v1_1(&mic_keys).unwrap();
assert_eq!(packet.mic, [0x93, 0xff, 0x9a, 0x3a]);
let expected_plaintext = hex_to_vec("20010101020202040302018000")
.into_iter()
.chain([0x93, 0xff, 0x9a, 0x3a])
.collect::<Vec<_>>();
assert_eq!(packet.phy_payload, expected_plaintext);
let app_key = AppKey::new(*nwk_key.as_bytes());
let encrypted = JoinAccept::encrypt_for_wire(&packet.phy_payload, &app_key).unwrap();
let expected_encrypted = hex_to_vec("207abeea06b02920f11c02d0348fcf1815");
assert_eq!(encrypted, expected_encrypted);
}
#[test]
fn should_encode_packet_with_lorawan_1_0() {
let nwk_s_key = NwkSKey::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let app_s_key = AppSKey::new([16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
let packet = LoraPacket::builder()
.data(Direction::Uplink, true) .dev_addr(DevAddr::new([0x01, 0x02, 0x03, 0x04]))
.f_ctrl(FCtrl(0x03)) .f_port(10)
.f_opts(&[0x06, 0x73, 0x07])
.payload(&hex_to_vec("01020304"))
.sign_and_encrypt(&app_s_key, &nwk_s_key)
.unwrap();
assert_eq!(
hex::encode(&packet.phy_payload),
"80040302010300000673070ae264d4f7e117d2c0"
);
}
#[test]
fn should_encode_packet_with_lorawan_1_1_frm_payload() {
let s_nwk_s_int_key = SNwkSIntKey::new([2; 16]);
let f_nwk_s_int_key = FNwkSIntKey::new({
let mut k = [2u8; 16];
k[15] = 3;
k
});
let app_s_key = AppSKey::new([1; 16]);
let tx_dr = 0x02u8;
let tx_ch = 0x03u8;
let mut packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0x01, 0x02, 0x03, 0x04]))
.f_ctrl(FCtrl(0x80)) .f_cnt(1)
.f_port(1)
.payload(b"hello")
.build_unsigned()
.unwrap();
let nwk_s_key_unused = NwkSKey::new([0u8; 16]);
let encrypted = packet
.as_data()
.unwrap()
.encrypt_payload(b"hello", &app_s_key, &nwk_s_key_unused, 0)
.unwrap();
packet.as_data_mut().unwrap().frm_payload = Some(encrypted);
packet.phy_payload = packet.to_wire();
let mic_keys = lora_packet::V1_1MicKeys {
f_nwk_s_int_key: Some(&f_nwk_s_int_key),
s_nwk_s_int_key: Some(&s_nwk_s_int_key),
conf_fcnt_down_tx_dr_tx_ch: Some([0x00, 0x00, tx_dr, tx_ch]),
..Default::default()
};
packet.recalculate_mic_v1_1(&mic_keys).unwrap();
let expected = [64, 4, 3, 2, 1, 128, 1, 0, 1, 166, 148, 100, 38, 21, 118, 18, 54, 106];
assert_eq!(packet.phy_payload, expected);
}
#[test]
fn should_encode_packet_with_lorawan_1_1_frm_payload_with_ack() {
let s_nwk_s_int_key = SNwkSIntKey::new([2; 16]);
let f_nwk_s_int_key = FNwkSIntKey::new({
let mut k = [2u8; 16];
k[15] = 3;
k
});
let app_s_key = AppSKey::new([1; 16]);
let tx_dr = 0x02u8;
let tx_ch = 0x03u8;
let mut packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0x01, 0x02, 0x03, 0x04]))
.f_ctrl(FCtrl(0xA0)) .f_cnt(1)
.f_port(1)
.payload(b"hello")
.build_unsigned()
.unwrap();
let nwk_s_key_unused = NwkSKey::new([0u8; 16]);
let encrypted = packet
.as_data()
.unwrap()
.encrypt_payload(b"hello", &app_s_key, &nwk_s_key_unused, 0)
.unwrap();
packet.as_data_mut().unwrap().frm_payload = Some(encrypted);
packet.phy_payload = packet.to_wire();
let mic_keys = lora_packet::V1_1MicKeys {
f_nwk_s_int_key: Some(&f_nwk_s_int_key),
s_nwk_s_int_key: Some(&s_nwk_s_int_key),
conf_fcnt_down_tx_dr_tx_ch: Some([0x01, 0x00, tx_dr, tx_ch]),
..Default::default()
};
packet.recalculate_mic_v1_1(&mic_keys).unwrap();
let expected = [64, 4, 3, 2, 1, 160, 1, 0, 1, 166, 148, 100, 38, 21, 248, 66, 196, 185];
assert_eq!(packet.phy_payload, expected);
}
#[test]
fn should_encode_packet_with_lorawan_1_1_fopts_nfcntdown() {
let s_nwk_s_int_key = SNwkSIntKey::new([2; 16]);
let f_nwk_s_int_key = FNwkSIntKey::new({
let mut k = [2u8; 16];
k[15] = 3;
k
});
let nwk_s_enc_key = NwkSEncKey::new({
let mut k = [2u8; 16];
k[15] = 4;
k
});
let mut packet = LoraPacket::builder()
.data(Direction::Downlink, false) .dev_addr(DevAddr::new([0x01, 0x02, 0x03, 0x04]))
.f_cnt(0)
.f_opts(&[0x02, 0x07, 0x01])
.payload(b"")
.build_unsigned()
.unwrap();
let enc_fopts = packet.as_data().unwrap().encrypt_fopts(&nwk_s_enc_key, 0).unwrap();
packet.as_data_mut().unwrap().f_opts = enc_fopts;
packet.as_data_mut().unwrap().f_port = None;
packet.as_data_mut().unwrap().frm_payload = None;
packet.phy_payload = packet.to_wire();
let mic_keys = lora_packet::V1_1MicKeys {
s_nwk_s_int_key: Some(&s_nwk_s_int_key),
f_nwk_s_int_key: Some(&f_nwk_s_int_key),
..Default::default()
};
packet.recalculate_mic_v1_1(&mic_keys).unwrap();
let expected = [96, 4, 3, 2, 1, 3, 0, 0, 223, 180, 241, 226, 79, 31, 159];
assert_eq!(packet.phy_payload, expected);
}
#[test]
fn should_encode_packet_with_lorawan_1_1_fopts_afcntdown() {
let s_nwk_s_int_key = SNwkSIntKey::new([2; 16]);
let f_nwk_s_int_key = FNwkSIntKey::new({
let mut k = [2u8; 16];
k[15] = 3;
k
});
let mut packet = LoraPacket::builder()
.data(Direction::Downlink, false) .dev_addr(DevAddr::new([0x01, 0x02, 0x03, 0x04]))
.f_cnt(0)
.f_port(1)
.f_opts(&[0x02, 0x07, 0x01])
.payload(b"")
.build_unsigned()
.unwrap();
let mic_keys = lora_packet::V1_1MicKeys {
f_nwk_s_int_key: Some(&f_nwk_s_int_key),
s_nwk_s_int_key: Some(&s_nwk_s_int_key),
conf_fcnt_down_tx_dr_tx_ch: Some([0x00, 0x00, 0, 0]),
..Default::default()
};
packet.recalculate_mic_v1_1(&mic_keys).unwrap();
let expected = [96, 4, 3, 2, 1, 3, 0, 0, 2, 7, 1, 1, 119, 112, 30, 163];
assert_eq!(packet.phy_payload, expected);
}
#[test]
fn should_encode_packet_with_lorawan_1_1_fopts_in_frm_payload() {
let s_nwk_s_int_key = SNwkSIntKey::new([2; 16]);
let f_nwk_s_int_key = FNwkSIntKey::new({
let mut k = [2u8; 16];
k[15] = 3;
k
});
let nwk_s_enc_key = NwkSEncKey::new({
let mut k = [2u8; 16];
k[15] = 4;
k
});
let conf_fcnt = [0x00, 0x00];
let tx_dr = 0x02u8;
let tx_ch = 0x03u8;
let mac_commands = [0x02u8, 0x03, 0x05];
let mut packet = LoraPacket::builder()
.data(Direction::Uplink, false)
.dev_addr(DevAddr::new([0x01, 0x02, 0x03, 0x04]))
.f_cnt(0)
.f_port(0)
.payload(&mac_commands)
.build_unsigned()
.unwrap();
let nwk_s_as_enc = NwkSKey::new(*nwk_s_enc_key.as_bytes());
let app_unused = AppSKey::new([0u8; 16]);
let encrypted = packet
.as_data()
.unwrap()
.encrypt_payload(&mac_commands, &app_unused, &nwk_s_as_enc, 0)
.unwrap();
packet.as_data_mut().unwrap().frm_payload = Some(encrypted);
packet.phy_payload = packet.to_wire();
let mic_keys = lora_packet::V1_1MicKeys {
f_nwk_s_int_key: Some(&f_nwk_s_int_key),
s_nwk_s_int_key: Some(&s_nwk_s_int_key),
conf_fcnt_down_tx_dr_tx_ch: Some([conf_fcnt[0], conf_fcnt[1], tx_dr, tx_ch]),
..Default::default()
};
packet.recalculate_mic_v1_1(&mic_keys).unwrap();
let expected = hex_to_vec("400403020100000000f7ded3cc995ea7");
assert_eq!(packet.phy_payload, expected);
let decrypted = packet
.as_data()
.unwrap()
.decrypt_payload(&app_unused, &nwk_s_as_enc, 0)
.unwrap();
assert_eq!(decrypted, mac_commands);
}
#[allow(dead_code)]
fn _silence_unused_imports() {
let _ = JoinEui::new([0; 8]);
let _ = MType::JoinRequest;
let _ = Payload::Proprietary(Vec::new());
let _ = V1_0MicKeys::default();
}