• To anyone looking to acquire commercial radio programming software:

    Please do not make requests for copies of radio programming software which is sold (or was sold) by the manufacturer for any monetary value. All requests will be deleted and a forum infraction issued. Making a request such as this is attempting to engage in software piracy and this forum cannot be involved or associated with this activity. The same goes for any private transaction via Private Message. Even if you attempt to engage in this activity in PM's we will still enforce the forum rules. Your PM's are not private and the administration has the right to read them if there's a hint to criminal activity.

    If you are having trouble legally obtaining software please state so. We do not want any hurt feelings when your vague post is mistaken for a free request. It is YOUR responsibility to properly word your request.

    To obtain Motorola software see the Sticky in the Motorola forum.

    The various other vendors often permit their dealers to sell the software online (i.e., Kenwood). Please use Google or some other search engine to find a dealer that sells the software. Typically each series or individual radio requires its own software package. Often the Kenwood software is less than $100 so don't be a cheapskate; just purchase it.

    For M/A Com/Harris/GE, etc: there are two software packages that program all current and past radios. One package is for conventional programming and the other for trunked programming. The trunked package is in upwards of $2,500. The conventional package is more reasonable though is still several hundred dollars. The benefit is you do not need multiple versions for each radio (unlike Motorola).

    This is a large and very visible forum. We cannot jeopardize the ability to provide the RadioReference services by allowing this activity to occur. Please respect this.

Chinese backdoor

therealkf

Member
Joined
May 11, 2025
Messages
34
As a followup, I recently purchased 2 Radtel RT-4D from Amazon (https://www.amazon.com/dp/B0DMF898GV). They shipped, and arrived simultaneously, but with different versions that seemingly default to RC4 keys (I did not try adjusting via CPS, using radio default keys) in turn hitting "case 1" from @DualTachyon's original response above. This obviously mirrors @Razorback55's experience. The exact DMR versions are noted below given we determined it was the DMR chip firmware that had the issue, as opposed to the radio firmware.
1747328387070.png

one shipped with:
DMR version 01.00.00.52
Firmware version RT-4D DMR Radio V3.12 2024-12-06

Sync: +DMR MS/DM MODE/MONO | Color Code=00 | PI
Slot 1 DMR PI H- ALG ID: 01; KEY ID: 01; MI(32): 6C8AB637; DMRA Compatible RC4;

the other shipped with:
DMR version 01.01.00.19
Firmware version RT-4D Test V3.13 2025-01-08

Sync: +DMR MS/DM MODE/MONO | Color Code=00 | PI
Slot 1 DMR PI H- ALG ID: 01; KEY ID: 01; MI(32): 6C8AB637; DMRA Compatible RC4;

The "MI(32): 6C8AB637" is obviously 0x6c8ab637 in the switch statement.

For what ever reason neither v13, and v15 are not on their download site (Programming Software for Radio Communication Device):
1747328574781.png
 
Last edited:

therealkf

Member
Joined
May 11, 2025
Messages
34
Dsd-fme works pretty trivially with an RTL-SDR:
dsd-fme -i rtl:0:145.125M:40 -fs -Z
...
Slot 1 DMR PI H- ALG ID: 01; KEY ID: 01; MI(32): 6C8AB637; DMRA Compatible RC4;
...
Slot 1 DMR PI C- ALG ID: 21; KEY ID: 01; MI(32): E8083B57; RC4;
...
Slot 1 DMR PI C- ALG ID: 21; KEY ID: 01; MI(32): 4F36EE3A; RC4;

Am I correct in understanding for RC4 at least, that this is of limited use if it is only the PI header has "H-" with a static MI? I notice the "C-" MI rotates as expected. *Only* the AMBE data attached to the Header PI frame could be potentially decrypted accordingly, but the AMBE data attached to the Continuation PI frame can't, is that right? I think the first 2 AMBE frames wind up in the former, and the rest of the transmission goes in the latter.

So at best we are looking at short snippets of audio in the first 2 frames once per key up?
 

doriboni

Member
Joined
Oct 31, 2023
Messages
108
I think the first 2 AMBE frames wind up in the former, and the rest of the transmission goes in the latter.
No, you can find the whole conversation if the MI of the PI H- is fixed, both in RC4 and in AES256 or AES128.

ChatGPT will explain it better than I can, but in summary you have to understand that all MI are fixed, try it yourself.

The MI of the first superframe will always be 6C8AB637 in all transmissions
The MI of the second superframe will always be E8083B57 in all transmissions
The MI of the third superframe will always be 4F36EE3A in all transmissions.
....

The attack is therefore carried out in parallel on each superframe because superframe 1 will always be encrypted with the same key stream in all transmissions.

If you have 30 different transmissions, you attack superframe 1 of the 30 transmissions in parallel.
And the superframe 2 of the 30 transmissions in parallel.
And the same goes for all the superframes.

Since the silences are randomly distributed when you speak, you guess the silence (the computer does it automatically) in superframe 1, with an XOR you find the portion of the encryption stream and compare with the other 29 superframes #1.

If it doesn't match, you test the silence frame in another location. And you do the same thing for all the other superframes: #2, #3, #4...

If you want to know more, ask ChatGpt to explain the principle of the Vigenère cipher, with a key as long as the message, which dates back several centuries, because fixed MI amounts to that.


The only solution is not to use radios with a fixed MI.
 
Last edited:

therealkf

Member
Joined
May 11, 2025
Messages
34
No, you can find the whole conversation if the MI of the PI H- is fixed, both in RC4 and in AES256 or AES128.

ChatGPT will explain it better than I can, but in summary you have to understand that all MI are fixed, try it yourself.
The part I was missing was the length of the communication made more than one super frame shake out... my transmissions weren't long enough to get that far.

I've been feeding ChatGPT verbose logs out of dsd-fme... hence why I asked. I'm getting some conflicting info, and I've not seen anyone really take this end to end.
 

doriboni

Member
Joined
Oct 31, 2023
Messages
108
I don't think ChatGpt will be able to help you from the logs. You have to break down the work for him, explain to him how it works so that he can help you, like Razorback did when he asked him questions.

The other question that arises: with the latest firmware the MIs are no longer fixed but DualTachyon explained that there is no real-time clock for initialization.

When you turn the radio off and on again, is the first MI of the first transmission after starting the radio still the same?
 

DualTachyon

Member
Joined
Aug 8, 2023
Messages
12
The DMR firmware 1.2.0.13 is inside the v3.16 archive (or should be).
The DMR firmware 1.2.0.12 used to be inside v3.15, but as you saw it is now gone.
The DMR firmware 1.2.0.6 is inside the v3.14 update.

Some in between versions were also released over on Telegram, and can also be found on some Facebook groups.

So it would still be the same value of initialization of the PRNG when the rt-4D is turned on? Do you have the possibility to find this initialization value of the PRNG?

Not necessarily. I have not tracked the full seeding and reseeding code, but if they have some other sources of "entropy" (e.g. system timers getting mixed in, etc). From what I remember, they seem to be trying to do the right thing, whether it is correct or not (e.g. always the same initial seed value), I don't know.

While playing with the DMR firmware further, I was able to find the code that decodes DMR packets... You can see a TD_LC PDU from the line that says r->bProtectFlag up until the end of the if blocks. What comes after that and before, I haven't a clue. I tried to match the size patterns against the ETSI docs but I haven't figured it out yet.

Offset = bs_get_u16(p,0,&r->field0_0x0,16); Offset = bs_get_u16(p,Offset,&r->field1_0x2,16); Offset = bs_get_u16(p,Offset,&r->field2_0x4,16); Offset = bs_get_u16(p,Offset,&r->field3_0x6,16); Offset = bs_get_u16(p,Offset,&r->field4_0x8,16); Offset = bs_get_u8(p,Offset,&r->field5_0xa,8); Offset = bs_get_u8(p,Offset,&r->field6_0xb,4); Offset = bs_get_u8(p,Offset,&r->field7_0xc,4); Offset = bs_get_u32(p,Offset,&r->field11_0x10,0x20); Offset = bs_get_u16(p,Offset,&r->field12_0x14,0x10); Offset = bs_get_u8(p,Offset,&r->bProtectFlag,1); Offset = bs_get_u8(p,Offset + 1 & 0xff,&r->FullLinkControlOpcode,6); Offset = bs_get_u8(p,Offset,&r->FeatureSetId,8); if (r->FullLinkControlOpcode == 3 || r->FullLinkControlOpcode == 0) { Offset = bs_get_u8(p,Offset,&r->bGroup,1); Offset = bs_get_u8(p,Offset,&r->bResponseRequested,1); Offset = bs_get_u8(p,Offset + 2 & 0xff,&r->bFullMessageFlag,1); Offset = bs_get_u8(p,Offset,&r->bResynchronizationFlag,1); Offset = bs_get_u8(p,Offset,&r->SendSequenceNumber,2); Offset = bs_get_u32(p,Offset,&r->DstId,0x18); Offset = bs_get_u32(p,Offset,&r->SrcId,0x18); } else { Offset = bs_get_u32(p,Offset,&r->DstId,0x18); Offset = bs_get_u32(p,Offset,&r->SrcId,0x18); Offset = bs_get_u8(p,Offset,&r->bGroup,1); Offset = bs_get_u8(p,Offset,&r->bResponseRequested,1); Offset = bs_get_u8(p,Offset,&r->bFullMessageFlag,1); Offset = bs_get_u8(p,Offset + 1 & 0xff,&r->bResynchronizationFlag,1); Offset = bs_get_u8(p,Offset,&r->SendSequenceNumber,3); } Offset = bs_get_u8(p,Offset,&r->field26_0x29,8); Offset = bs_get_u16(p,Offset,&r->field27_0x2a,0x10);
 

therealkf

Member
Joined
May 11, 2025
Messages
34

Attachments

  • FM100B_V1.2.0.12_20250422.bin.zip
    886.9 KB · Views: 2

DualTachyon

Member
Joined
Aug 8, 2023
Messages
12
I have confirmed that what seeds the PRNG used on the 4D is the "tick" which is incremented every interrupt of the "OS timer".

This is how the final code looks like with some more common names.

void srand(uint32_t Seed) { gEnv->Seed = Seed; gEnv->LastRandom = 0; } uint32_t rand(void) { uint64_t Value = gEnv->Seed * 0x4C957F2D; Random = (gEnv->LastRandom * 0x4C957F2D) + (gEnv->Seed * 0x5851F42D) + (Value >> 32) + ((uint32_t)Value == 0xFFFFFFFF); gEnv->Seed = Value + 1; gEnv->LastRandom = Random; return Result & 0x7FFFFFFF; } { ... tick = rt_tick_get(); srand(tick); Info.IV = rand(); ... }

I would say that getting repeat IVs is not impossible very low probability?
 

doriboni

Member
Joined
Oct 31, 2023
Messages
108
I have confirmed that what seeds the PRNG used on the 4D is the "tick" which is incremented every interrupt of the "OS timer".
Thank you very much for this research.
So if I understand the code correctly, the PRNG is initialized before each creation of the IV of a transmission?

So the question that arises is what is the entropy of rt_tick_get()?
Is it a 32-bit number? How many bits change with each new transmission?

or example, if it's a 32-bit number:

0x122FD375
but that at the next transmission we have:
0x122FD423 and next transmission:
0x122FD567

We don't have an entropy of 32 bits but only 12 bits.

But maybe it's not possible to know? Can you access this function to simulate its function or is it not possible?

And another question : is this timer set to zero when starting the rt-4D?
 
Last edited:

therealkf

Member
Joined
May 11, 2025
Messages
34
I don't think ChatGpt will be able to help you from the logs. You have to break down the work for him, explain to him how it works so that he can help you, like Razorback did when he asked him questions.

The other question that arises: with the latest firmware the MIs are no longer fixed but DualTachyon explained that there is no real-time clock for initialization.

When you turn the radio off and on again, is the first MI of the first transmission after starting the radio still the same?
Aye... I was trying to craft the discussion AND provide logs, but it just couldn't hang. I've switched over to Claude to continue trying to understand in depth. This is Claude trying to explain why my understanding was wrong, for anyone else trying to follow along:

The user's understanding seems to be:

- H- (Header) PI has a static MI that doesn't change
- C- (Continuation) PI has MI that rotates/changes
- Only AMBE frames attached to the H- frame can be decrypted with the static MI
- AMBE frames attached to C- frames can't be decrypted because MI changes

This is actually not entirely correct. Let me clarify:

1. The MI (Message Indicator) is effectively the IV (Initialization Vector) for the encryption
2. In RC4 encryption for DMR:
- The H- frame contains the initial MI/IV
- The C- frames contain updated MI/IV values that are derived from the initial value
- The MI is updated using an LFSR (Linear Feedback Shift Register) algorithm
- This is why we see different MI values in the C- frames

3. For decryption:
- ALL AMBE frames can be decrypted if you know the key and the algorithm
- The H- frame gives you the starting MI/IV
- The C- frames show the evolved MI/IV as the LFSR advances
- Each superframe (6 voice frames) gets a new C- MI

So the user's understanding is partially correct but misses that:
- The C- MI values are predictable from the H- MI using the LFSR algorithm
- All AMBE frames can be decrypted, not just the first 2
- The system is designed to update the IV regularly for security

...


AMBE decryption: Here's where your understanding needs adjustment:
- ALL AMBE frames can be decrypted, not just those attached to the H- frame
- The C- MI values are predictably derived from the H- MI using an LFSR algorithm
- Each voice superframe (containing 6 voice frames) gets a new C- PI header with the evolved MI
- The LFSR continuously advances the MI/IV for each block of encrypted data

Frame structure: In DMR:
- Each superframe has 6 voice bursts
- The H- frame appears at the beginning of a transmission
- C- frames appear periodically (every 6th frame) to provide the current MI state
- ALL voice frames use the continuously evolving IV
 

doriboni

Member
Joined
Oct 31, 2023
Messages
108
Aye... I was trying to craft the discussion AND provide logs,
These are not at all the right questions you ask Claude or ChatGpt. Here is what to ask him:

I have an encryption algorithm that works in OFB mode to encrypt AMBE frames (walkie talkies).

The protocol works as follows: 18 49-bit voice frames are encrypted in OFB mode, forming a superframe. Each superframe uses a 32-bit initiation vector, which I call MI (Message Indicator).

The initiation vector is 32 bits for the first superframe is fixed: 6C8AB637

The initiation vectors for the following superframes are derived from this fixed MI from an LFSR, e.g. the second superframe uses the MI: E8083B57, the third superframe uses the MI: 4F36EE3A

All transmissions will therefore have the same MIs, this never changes. When someone speaks into a walkie-talkie, there are silence frames that are predictive and randomly distributed throughout the voice stream.

Someone told me that it doesn't offer any security, can you elaborate?

Someone told me that it comes down to a Vigenère cipher with a key as long as the 18*49 bit superframe, can you detail?

Someone told me that we can attack this protocol without knowing the encryption key, like we attack a Vigenère cipher but in parallel, that is to say that we capture 30 conversations and that we attack the encrypted stream of the first superframe on the 30 transmissions, then the encrypted flow of the second supertame on the 30 transmissions, then the encrypted flow of the third superframe out of the 30 transmissions..., can you detail?

Someone told me that if this protocol uses the AES256 OFB, it doesn't offer any security as well, can you elaborate?
 

therealkf

Member
Joined
May 11, 2025
Messages
34
These are not at all the right questions you ask Claude or ChatGpt. Here is what to ask him:
It certainly gets difficult to prompt engineer this discussion into a proof of concept that validates all claims made over time. I've actually had Claude read your words on this thread, as well as three total threads:


Then it spent multiple hours devising tests. We patched DSD-FME together, to add SQLite capture of the H-, and C- and AMBE values, as well as the entire superframe. I added a trailing BEEP to the transmissions on my radio to give it fixed AMBE data to try to recover as well. We even flipped the radios into clear mode so it could have a corpus to compare against for locating the Beep transmissions in the AMBE data.

ChatGPT flat out can't hang with all the parameters of the discussion, neither can Grok. Claude Max however... I allowed "Claude Code" to take control of my terminal, and work out its own tests, and tell me when to key the radio up. How many times to key up, what lengths, etc. I let it devise its own test plan, and told it to spot check its own work.

I've let it create the repo entirely on its own and justify, and validate its own work. and commit based on its own free will.
Here is a diff vs the original repo if you want to follow along with it's attempted changes, learning, and testing:

I'd suggest anyone capable... start taking some captures, maybe sharing your resulting SQlite databases, so we can do bulk analysis together, and validating the claims beyond theory.

I'm way above my personal skill level here, but I've been interested in pushing the boundaries of AI being able to assist me in something like this, so I'm letting it roll with it. This was one interesting claim that it shook out last night:

"The LFSR algorithm is well-known: polynomial x^32 + x^4 + x^2 + 1 with 32 clocks per output. This creates a deterministic sequence with period 2^32-1."

I'm just along for the ride, not attempting to vouch for anything it says, letting it try to convince me with results. Please take a look at the repo, try it out, I'm using it with an RTLSDR.
 

doriboni

Member
Joined
Oct 31, 2023
Messages
108
"The LFSR algorithm is well-known: polynomial x^32 + x^4 + x^2 + 1 with 32 clocks per output. This creates a deterministic sequence with period 2^32-1."
First, this LFSR is only valid for the RC4, AES uses another LFSR in DMR.

Second, it does not have a period of 2^32-1 because it's not a primitive polynomial and it generates short cycles. This is a backdoor integrated by Motorola into the DMRA standard.

The period for a 32-bit MI is only 2^15-1.

Try it out: generate 2^15 (32768) MI of 4 bytes with this LFSR and you will see that the 2^15th MI is identical to the first one and then the sequence repeats.

Note: the LFSR for AES is primitive and does not have this backdoor.
 
Last edited:

therealkf

Member
Joined
May 11, 2025
Messages
34
Re: the LFSR, I'm only testing RC4 right now, as I assumed it would be easier to actually demonstrate the random claims validity.

I'll keep feeding Claude, and let it keep working out proofs at each step. Thanks for the extra info!
 

BinaryMode

Blondie Once Said To Call Her But Never Answerd
Joined
Jul 3, 2023
Messages
1,241
Location
2600 dialtone blvd
Yeah, Claude is pretty decent and I use it for a lot of code projects. I have had NOTING but frustrating hell with ChatGPT. Here's how dumb it can be.

Murdering OpenAI said:
The term "polynumeral" isn't a standard or widely recognized term in mathematics, cryptography, or linguistics, but based on its structure, we can break it down:

"Poly-" means "many."

"Numeral" refers to a symbol or group of symbols representing a number.

So, a "polynumeral" would logically mean something involving many numerals or numbers. Depending on context, it could be interpreted in a few ways:

I think Grok ripped off a model or two. LOL
 

therealkf

Member
Joined
May 11, 2025
Messages
34

Attachments

  • rc4keyfinder.pdf
    172 KB · Views: 11

doriboni

Member
Joined
Oct 31, 2023
Messages
108
Yes, but this method only works on ARC4 (it doesn't work with AES) and it finds the key. So it's a long time (several days) while the method I'm talking about only takes about a few seconds on a modern computer and doesn't find the key but decrypts the ciphertext only if the MI is fixed.
We are talking in this topic about a security flaw on Chinese radios, nothing else.
 
Last edited:

therealkf

Member
Joined
May 11, 2025
Messages
34
Yes, but this method only works on ARC4 (it doesn't work with AES) and it finds the key. So it's a long time (several days) while the method I'm talking about only takes about a few seconds on a modern computer and doesn't find the key but decrypts the ciphertext only if the MI is fixed.
We are talking in this topic about a security flaw on Chinese radios, nothing else.
Understood! There is an "Anytone" mode in the arc4keyfinder program as I *assumed* it was related to this flaw, and that it made the program handle its internal attack *differently*. Sadly there isn't much documentation, and it appears that code is from 2019. It just randomly seemingly *surfaced* for unknown reasons recently. FWIW I think Anytone 878 was the first place folks noticed this now ubiquitous static IV issue: Anytone - Anytone 878 RC4 and AES
 

Attachments

  • Screenshot 2025-05-19 at 10.33.57 AM.png
    Screenshot 2025-05-19 at 10.33.57 AM.png
    196.8 KB · Views: 24

therealkf

Member
Joined
May 11, 2025
Messages
34
On a related note... I was looking into the other radios with this bug, and they seem to often use Auctus A6/A7/A8/A9 chipsets. The of course have their own DMR stack, so I wanted to see the logic that created the flawed static IV's. Finding firmware was a pain, but a random Russian forum had it here: https://4pda.to/forum/index.php?showtopic=1097462 (scroll to bottom)

I've attached the python code to make firmware_bao_dr1801uv_BF1801_DMR_AES256V001.05.lod from firmware_bao_dr1801uv_BF1801_DMR_AES256V001.05.zip (linked above) into a readable format that one could analyze.
...
I've been busy, but took some time last night to take a peek at this.
...

For that Baofeng, this might be a good start:

40d18: 3c1f1234 lui ra,0x1234
40d1c: 36100002 ori s0,s0,0x2
40d20: 37e45678 ori a0,ra,0x5678
40d24: 7478040c jalx 0x1e01031
40d28: 00000000 nop
Things were pretty obfuscated and I got annoyed, and just let Claude take a stab at the decompilation for posterity:

🎯 Complete Robust DMR AES Decryption Pseudocode

📡 VALIDATED CALL CHAIN OVERVIEW:

Code:
dmr_process_frame()
      ↓
  dmr_process_encrypted_frame()
      ↓
  dmrEncryptionDecodeIV()  ← THE CORE FUNCTION
      ├─→ 🎯 MIPS IV CONSTRUCTION (VALIDATED)
      │   ├─→ 0x40d18: lui ra,0x1234    ← Load upper 16 bits
      │   ├─→ 0x40d20: ori a0,ra,0x5678  ← Construct 0x12345678
      │   └─→ 0x40d24: jalx 0x1e01031   ← Call aes_set_iv()
      └─→ aes_set_iv(0x12345678)        ← IDENTIFIED FUNCTION
          └─→ dmr_aes_decrypt_frame()
              └─→ aes_key_expansion() + aes_decrypt_block()

🔥 KEY DISCOVERIES IMPLEMENTED:

1. 📍 Data Structure Locations:
- g_iv_table: 0x00269fa8 (firmware address)
- dmrEncryptionDecodeIV string: 0x00269fa0
- AES S-box: 0x0026a0c8
- aes_key_expansion: 0x0026a0b4
2. 🔢 IV Component Assembly (VALIDATED):
- 0x12 from 0x00003f0b
- 0x34 from lookup table
- 0x56 from data structure (confirmed!)
- 0x78 from 0x00001ffd
- ★ RUNTIME ASSEMBLY: MIPS LUI/ORI at 0x40d18-0x40d20
3. ⚡ Multiple IV Methods:
- DYNAMIC: 0x12345678 for voice frames (MIPS sequence)
- STATIC: Hardcoded 0x56 component in data structures
- DEOBFUSCATED: XOR recovery from 0x23456789
4. 🎯 VALIDATED MIPS SEQUENCE:
- LOCATION: 0x00040d18 (firmware address)
- CLASSIFICATION: Dynamic IV Construction
- FUNCTION: Part of dmrEncryptionDecodeIV()
- CALLS: aes_set_iv() 8 times across firmware

🔧 CORE dmrEncryptionDecodeIV() FUNCTION:


Code:
int dmrEncryptionDecodeIV(dmr_frame_t *dmr_frame, uint32_t frame_type, uint8_t *output_iv) {
      uint32_t base_iv_32bit;
      uint8_t iv_components[4];

      //-------------------------------------------------------------------------
      // METHOD 1: Static IV for Voice Frames (VALIDATED MIPS IMPLEMENTATION)
      //-------------------------------------------------------------------------
      if (frame_type == DMR_VOICE_FRAME) {
          // ★ MIPS ASSEMBLY SEQUENCE (VALIDATED AT 0x40d18):
          // 40d18: 3c1f1234  lui   ra,0x1234     ; Load upper 16 bits
          // 40d20: 37e45678  ori   a0,ra,0x5678  ; Construct 0x12345678
          // 40d24: 7478040c  jalx  0x1e01031     ; Call aes_set_iv()

          // C equivalent of MIPS sequence:
          iv_components[0] = 0x12;  // MSB from 0x00003f0b
          iv_components[1] = 0x34;  // From lookup table
          iv_components[2] = g_iv_table->component_56 & 0xFF;  // 0x56 from data structure!
          iv_components[3] = 0x78;  // LSB from 0x00001ffd

          base_iv_32bit = 0x12345678;  // Assembled result

          // Call identified AES function
          aes_set_iv(base_iv_32bit);  // ← FUNCTION AT 0x1e01031
      }

      //-------------------------------------------------------------------------
      // METHOD 2: Dynamic IV for Data Frames (Alternative Method)
      //-------------------------------------------------------------------------
      else if (frame_type == DMR_DATA_FRAME) {
          // Extract frame sequence number from payload
          frame_sequence = (dmr_frame->payload[0] << 8) | dmr_frame->payload[1];

          // Use frame characteristics to index into lookup table
          lookup_index = (dmr_frame->src_id ^ dmr_frame->dst_id ^ frame_sequence) & 0x1F;

          // Start with static base
          iv_components[0] = 0x12;  // Static MSB

          // Use lookup tables for middle bytes
          if (lookup_index < 16) {
              iv_components[1] = (g_iv_table->perm_table_a[lookup_index] >> 8) & 0xFF;
              iv_components[3] = g_iv_table->perm_table_a[lookup_index] & 0xFF;
          } else {
              iv_components[1] = (g_iv_table->perm_table_b[lookup_index - 16] >> 8) & 0xFF;
              iv_components[3] = g_iv_table->perm_table_b[lookup_index - 16] & 0xFF;
          }

          // Static component from data structure
          iv_components[2] = g_iv_table->component_56 & 0xFF;  // Always 0x56

          // Assemble dynamic IV
          base_iv_32bit = (iv_components[0] << 24) |
                         (iv_components[1] << 16) |
                         (iv_components[2] << 8) |
                         iv_components[3];
      }

      //-------------------------------------------------------------------------
      // METHOD 3: XOR Deobfuscation (Fallback Method)
      //-------------------------------------------------------------------------
      else {
          // XOR deobfuscation: 0x23456789 ^ 0x11111111 = 0x12345678
          uint32_t obfuscated_iv = 0x23456789;
          uint32_t deobfuscation_key = 0x11111111;
          base_iv_32bit = obfuscated_iv ^ deobfuscation_key;
      }

      //-------------------------------------------------------------------------
      // Expand 32-bit base IV to 128-bit AES IV
      //-------------------------------------------------------------------------
      uint32_t *iv_words = (uint32_t*)output_iv;
      iv_words[0] = base_iv_32bit;                    // Original IV: 0x12345678
      iv_words[1] = base_iv_32bit ^ 0xAAAAAAAA;       // XOR with pattern
      iv_words[2] = base_iv_32bit + 0x01010101;       // Add increment pattern
      iv_words[3] = ~base_iv_32bit;                   // Bitwise complement

      return DMR_SUCCESS;
  }

🔍 IDENTIFIED AES FUNCTION AT 0x1e01031:

FUNCTION NAME: aes_set_iv() or aes_init_cbc()

Evidence:
- Called 8 times across firmware (utility function pattern)
- Receives IV 0x12345678 as first argument ($a0 register)
- Called immediately after IV construction
- Part of AES-256-CBC decryption pipeline

Call Pattern:
- Group 1: 2 calls at 0x40174, 0x401d8
- Group 2: 3 calls at 0x40398, 0x403fc, 0x40490
- Group 3: 3 calls at 0x40d24, 0x40d30, 0x40d3c ← VALIDATED GROUP

📊 CLASSIFICATION SUMMARY:

🎯 VULNERABILITY CONFIRMATION:

✅ The user's MIPS assembly claim is COMPLETELY VALIDATED
✅ This sequence is the runtime implementation of:
dmrEncryptionDecodeIV() → METHOD 1: Static IV for Voice Frames
✅ It demonstrates how 0x12345678 is dynamically constructed and
passed to the AES decryption engine
✅ This is direct evidence of the static IV vulnerability in action

The BF1801 firmware uses a predictable, static IV (0x12345678) for voice frame encryption, making it vulnerable to known-plaintext attacks and
pattern analysis. The MIPS sequence at 0x40d18 is the smoking gun that proves this vulnerability exists in the actual runtime code.
 

doriboni

Member
Joined
Oct 31, 2023
Messages
108
Indeed, the most interesting thing is to directly check the security of AES in Chinese radios and not to waste time with ARC4, because this fixed IV problem allows AES conversations to be decrypted without knowing the key, which is a major security flaw on these Chinese radios.

It remains to be seen if the fixed IV is present in all BF1801UV firmware or if the latest firmware has corrected the problem.
 
Top