From 99b1fd2fe2ce53ed64e6bf32279d60032ff31cdb Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Thu, 18 Sep 2025 12:13:54 -0400 Subject: [PATCH] DMR: Tweaks to PDU Decryption; Allow Manually Loaded Key Value AES on DMR PDU; Add support for CCR AES-ECB PDU Decryption; --- src/dmr_block.c | 66 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/src/dmr_block.c b/src/dmr_block.c index c54abb6..d3b38cd 100644 --- a/src/dmr_block.c +++ b/src/dmr_block.c @@ -335,7 +335,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t //The SAP found here is the actual SAP of the message (like a P25 ndary SAP, and can chain together according to ETSI) fprintf (stderr, " - SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string); - //p_sap 1 on mfid 10 (moto) has been observed as the first block of LRRP data (unique fixed format?) + //p_sap 1 on mfid 10 MNIS Header if (p_mfid == 0x10 && p_sap == 1) { //add the header to the first 10 bytes of the storage (sans this header's CRC) @@ -1007,6 +1007,21 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte if (memcmp(kaes, empt, sizeof(kaes)) != 0) akl = 1; } + //if still not akl, see if there is anything manually loaded into K1, K2, K3, K4 instead + if (akl == 0) + { + for (i = 0; i < 8; i++) + { + kaes[i+0] = (state->K1) >> (56-(i*8)) & 0xFF; + kaes[i+8] = (state->K2) >> (56-(i*8)) & 0xFF; + kaes[i+16] = (state->K3) >> (56-(i*8)) & 0xFF; + kaes[i+24] = (state->K4) >> (56-(i*8)) & 0xFF; + } + + //if kaes is loaded with a key, then flag on the key loaded variable + if (memcmp(kaes, empt, sizeof(kaes)) != 0) akl = 1; + } + if (R == 0 && state->R != 0) R = state->R; //easier to manually load up rather than make a loop (RC4) @@ -1033,8 +1048,13 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte //generate 128-bit IV from 32-bit MI //expand 32-bit MI to 128-bit IV for AES mode data decryption //we only want to do this at the moment of keystream generation - if (alg == 5) + if (alg == 4 || alg == 5) { + //for the LFSR128d function to show the correct alg + if (state->currentslot == 0) + state->payload_algid += 0x20; + else state->payload_algidR += 0x20; + fprintf (stderr, "\n"); LFSR128d(state); if (state->currentslot == 0) @@ -1049,30 +1069,54 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte decrypted_pdu = 1; } - if (alg == 5 && akl == 1) //AES-256 + else if (alg == 5 && akl == 1 && mi != 0) //AES-256 OFB { int nblocks = (state->data_byte_ctr[slot] / 16) + 1; aes_ofb_keystream_output (maes, kaes, ob, 2, nblocks); decrypted_pdu = 1; } + else if (alg == 5 && akl == 1 && mi == 0) //AES-256 ECB (CCR without an IV) + { + //void aes_ecb_bytewise_payload_crypt (uint8_t * input, uint8_t * key, uint8_t * output, int type, int de) + int nblocks = (state->data_byte_ctr[slot] / 16) + 0; //was +1 + for (i = 0; i < nblocks; i++) + { + aes_ecb_bytewise_payload_crypt(state->dmr_pdu_sf[slot]+start, kaes, state->dmr_pdu_sf[slot]+start, 2, 0); + start += 16; + } + decrypted_pdu = 1; + } + //other algs available, not sure if others will be used in any DMRA offerings - if (alg == 2 && R != 0) //Tait DES + else if (alg == 2 && R != 0) //Tait DES { int nblocks = (state->data_byte_ctr[slot] / 8) + 1; des_multi_keystream_output (mi, R, ob, 1, nblocks); decrypted_pdu = 1; } - if (alg == 4 && akl == 1) //AES-128 + else if (alg == 4 && akl == 1 && mi != 0) //AES-128 OFB { int nblocks = (state->data_byte_ctr[slot] / 16) + 1; aes_ofb_keystream_output (maes, kaes, ob, 0, nblocks); decrypted_pdu = 1; } + else if (alg == 4 && akl == 1 && mi == 0) //AES-128 ECB (CCR without an IV) + { + //void aes_ecb_bytewise_payload_crypt (uint8_t * input, uint8_t * key, uint8_t * output, int type, int de) + int nblocks = (state->data_byte_ctr[slot] / 16) + 0; //was +1 + for (i = 0; i < nblocks; i++) + { + aes_ecb_bytewise_payload_crypt(state->dmr_pdu_sf[slot]+start, kaes, state->dmr_pdu_sf[slot]+start, 0, 0); + start += 16; + } + decrypted_pdu = 1; + } + //NOTE: Observed that keystream should not be applied to pad bytes or CRC - //apply keystream here, only if alg is 1 or 4 AND key is available! + //apply keystream here, only if key is available and keystream created, not ECB. if (alg == 1 && R != 0) { for (i = 0; i < end; i++) @@ -1084,15 +1128,17 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte for (i = 0; i < end; i++) state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096]; } - else if (alg == 4 && akl != 0) + + else if (alg == 4 && akl != 0 && mi != 0) { for (i = 0; i < end; i++) - state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096]; + state->dmr_pdu_sf[slot][i+start] ^= ob[(i+16)%3096]; } - else if (alg == 5 && akl != 0) + + else if (alg == 5 && akl != 0 && mi != 0) { for (i = 0; i < end; i++) - state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096]; + state->dmr_pdu_sf[slot][i+start] ^= ob[(i+16)%3096]; } //BP key application