Skip to content

Commit e4317ff

Browse files
committed
Add code to crack a PRIOS key from a bunch of frames.
1 parent 26dba11 commit e4317ff

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

Diff for: PC/Makefile

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
all: cracker
2+
3+
cracker: prios_key_cracker.c ../ST-STEVAL-FKI868V1/Src/PRIOS.c
4+
gcc -c -Wall -Werror -std=c99 -pedantic prios_key_cracker.c -I ../ST-STEVAL-FKI868V1/Inc
5+
gcc -c -Wall -Werror -std=c99 -pedantic ../ST-STEVAL-FKI868V1/Src/PRIOS.c -I ../ST-STEVAL-FKI868V1/Inc
6+
gcc -o prios_key_cracker prios_key_cracker.o PRIOS.o

Diff for: PC/config.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#define TEST_YEAR 20
2+
#define TEST_MONTH 4
3+
#define TEST_DAY 1
4+
#define CONSUMPTION_RANGE_MIN 1
5+
#define CONSUMPTION_RANGE_MAX 1000000
6+
7+
uint8_t frames[32][28] = {
8+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x03, 0x12, 0x00, 0x13, 0xB7, 0x88, 0x9D, 0x6B, 0xEC, 0x89, 0xE2, 0xE1, 0x3B, 0x4C, 0xA5},
9+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x03, 0x12, 0x00, 0x13, 0xB7, 0x89, 0x9D, 0x6B, 0xEC, 0x89, 0xE2, 0xE1, 0x3B, 0x4C, 0xA5},
10+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x03, 0x12, 0x00, 0x13, 0xB7, 0x8E, 0x9D, 0x6B, 0xEC, 0x89, 0xE2, 0xE1, 0x3B, 0x4C, 0xA5},
11+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x03, 0x12, 0x00, 0x13, 0xB7, 0x8F, 0x9D, 0x6B, 0xEC, 0x89, 0xE2, 0xE1, 0x3B, 0x4C, 0xA5},
12+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x13, 0x12, 0x00, 0x13, 0xB7, 0x98, 0xB2, 0x22, 0x47, 0xA8, 0x31, 0x38, 0xE0, 0x55, 0xA7},
13+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x13, 0x12, 0x00, 0x13, 0xB7, 0x99, 0xB2, 0x22, 0x47, 0xA8, 0x31, 0x38, 0xE0, 0x55, 0xA7},
14+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x13, 0x12, 0x00, 0x13, 0xB7, 0x9E, 0xB2, 0x22, 0x47, 0xA8, 0x31, 0x38, 0xE0, 0x55, 0xA7},
15+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x13, 0x12, 0x00, 0x13, 0xB7, 0x9F, 0xB2, 0x22, 0x47, 0xA8, 0x31, 0x38, 0xE0, 0x55, 0xA7},
16+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x23, 0x12, 0x00, 0x13, 0xB7, 0xA0, 0xC3, 0xF8, 0xBA, 0xCA, 0x45, 0x52, 0x8D, 0x7E, 0xA0},
17+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x23, 0x12, 0x00, 0x13, 0xB7, 0xA1, 0xC3, 0xF8, 0xBA, 0xCA, 0x45, 0x52, 0x8D, 0x7E, 0xA0},
18+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x23, 0x12, 0x00, 0x13, 0xB7, 0xA6, 0xC3, 0xF8, 0xBA, 0xCA, 0x45, 0x52, 0x8D, 0x7E, 0xA0},
19+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x23, 0x12, 0x00, 0x13, 0xB7, 0xA7, 0xC3, 0xF8, 0xBA, 0xCA, 0x45, 0x52, 0x8D, 0x7E, 0xA0},
20+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x33, 0x12, 0x00, 0x13, 0xB7, 0xB0, 0xEC, 0xB1, 0x11, 0xEB, 0x96, 0x8B, 0x56, 0x67, 0xA2},
21+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x33, 0x12, 0x00, 0x13, 0xB7, 0xB1, 0xEC, 0xB1, 0x11, 0xEB, 0x96, 0x8B, 0x56, 0x67, 0xA2},
22+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x33, 0x12, 0x00, 0x13, 0xB7, 0xB6, 0xEC, 0xB1, 0x11, 0xEB, 0x96, 0x8B, 0x56, 0x67, 0xA2},
23+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x33, 0x12, 0x00, 0x13, 0xB7, 0xB7, 0xEC, 0xB1, 0x11, 0xEB, 0x96, 0x8B, 0x56, 0x67, 0xA2},
24+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x43, 0x12, 0x00, 0x13, 0xB7, 0xD2, 0x20, 0x4D, 0x40, 0x0E, 0xAD, 0x86, 0x57, 0x28, 0xAF},
25+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x43, 0x12, 0x00, 0x13, 0xB7, 0xD3, 0x20, 0x4D, 0x40, 0x0E, 0xAD, 0x86, 0x57, 0x28, 0xAF},
26+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x43, 0x12, 0x00, 0x13, 0xB7, 0xD4, 0x20, 0x4D, 0x40, 0x0E, 0xAD, 0x86, 0x57, 0x28, 0xAF},
27+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x43, 0x12, 0x00, 0x13, 0xB7, 0xD5, 0x20, 0x4D, 0x40, 0x0E, 0xAD, 0x86, 0x57, 0x28, 0xAF},
28+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x53, 0x12, 0x00, 0x13, 0xB7, 0xC2, 0x0F, 0x04, 0xEB, 0x2F, 0x7E, 0x5F, 0x8C, 0x31, 0xAD},
29+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x53, 0x12, 0x00, 0x13, 0xB7, 0xC3, 0x0F, 0x04, 0xEB, 0x2F, 0x7E, 0x5F, 0x8C, 0x31, 0xAD},
30+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x53, 0x12, 0x00, 0x13, 0xB7, 0xC4, 0x0F, 0x04, 0xEB, 0x2F, 0x7E, 0x5F, 0x8C, 0x31, 0xAD},
31+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x53, 0x12, 0x00, 0x13, 0xB7, 0xC5, 0x0F, 0x04, 0xEB, 0x2F, 0x7E, 0x5F, 0x8C, 0x31, 0xAD},
32+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x63, 0x12, 0x00, 0x13, 0xB7, 0xFA, 0x7E, 0xDE, 0x16, 0x4D, 0x0A, 0x35, 0xE1, 0x1A, 0xAA},
33+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x63, 0x12, 0x00, 0x13, 0xB7, 0xFB, 0x7E, 0xDE, 0x16, 0x4D, 0x0A, 0x35, 0xE1, 0x1A, 0xAA},
34+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x63, 0x12, 0x00, 0x13, 0xB7, 0xFC, 0x7E, 0xDE, 0x16, 0x4D, 0x0A, 0x35, 0xE1, 0x1A, 0xAA},
35+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x63, 0x12, 0x00, 0x13, 0xB7, 0xFD, 0x7E, 0xDE, 0x16, 0x4D, 0x0A, 0x35, 0xE1, 0x1A, 0xAA},
36+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x73, 0x12, 0x00, 0x13, 0xB7, 0xEA, 0x51, 0x97, 0xBD, 0x6C, 0xD9, 0xEC, 0x3A, 0x03, 0xA8},
37+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x73, 0x12, 0x00, 0x13, 0xB7, 0xEB, 0x51, 0x97, 0xBD, 0x6C, 0xD9, 0xEC, 0x3A, 0x03, 0xA8},
38+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x73, 0x12, 0x00, 0x13, 0xB7, 0xEC, 0x51, 0x97, 0xBD, 0x6C, 0xD9, 0xEC, 0x3A, 0x03, 0xA8},
39+
{0x19, 0x44, 0x30, 0x4C, 0x15, 0x8C, 0xD7, 0x20, 0xD4, 0x01, 0x00, 0x00, 0xA2, 0x73, 0x12, 0x00, 0x13, 0xB7, 0xED, 0x51, 0x97, 0xBD, 0x6C, 0xD9, 0xEC, 0x3A, 0x03, 0xA8}
40+
};

Diff for: PC/prios_key_cracker.c

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//
2+
// Take a bunch of PRIOS WMBus frames, and find a decryption key that allows decoding all of them.
3+
// Unpolished code: do not use in production.
4+
//
5+
6+
#include <stdio.h>
7+
#include <stdint.h>
8+
#include <time.h>
9+
10+
// Use the PRIOS functions from the ST code.
11+
#include <PRIOS.h>
12+
#include "config.h"
13+
14+
// Declare those since they're not exported by the ST code.
15+
uint32_t read_uint32_le(uint8_t *data, int offset);
16+
uint32_t read_uint32_be(uint8_t *data, int offset);
17+
uint32_t preparePRIOSKey(uint8_t *bytes);
18+
19+
// Try to decode a payload with a key:
20+
uint8_t try_key(uint8_t *key_bytes, uint8_t *frame, uint8_t *out) {
21+
uint32_t prepared_key = preparePRIOSKey(key_bytes);
22+
return decodePRIOSPayload(frame, 11, prepared_key, out);
23+
}
24+
25+
// Check that a decoded payload is coherent with the data we expect:
26+
uint8_t check_decoded_payload(uint8_t *decoded_frame, uint32_t *total_consumption, uint32_t *last_month_total_consumption, uint8_t *year, uint8_t *month, uint8_t *day) {
27+
// Check that the consumptions look correct:
28+
*total_consumption = read_uint32_le(decoded_frame, 1);
29+
*last_month_total_consumption = read_uint32_le(decoded_frame, 5);
30+
if (*last_month_total_consumption > *total_consumption) {
31+
return 0;
32+
}
33+
#ifdef CONSUMPTION_RANGE_MIN
34+
if (*total_consumption < CONSUMPTION_RANGE_MIN) {
35+
return 0;
36+
}
37+
if (*last_month_total_consumption < CONSUMPTION_RANGE_MIN) {
38+
return 0;
39+
}
40+
#endif
41+
#ifdef CONSUMPTION_RANGE_MAX
42+
if (*total_consumption > CONSUMPTION_RANGE_MAX) {
43+
return 0;
44+
}
45+
if (*last_month_total_consumption > CONSUMPTION_RANGE_MAX) {
46+
return 0;
47+
}
48+
#endif
49+
50+
// Check that the date is correct:
51+
*year = ((decoded_frame[10] & 0xF0) >> 1) + ((decoded_frame[9] & 0xE0) >> 5);
52+
*month = decoded_frame[10] & 0xF;
53+
*day = decoded_frame[9] & 0x1F;
54+
if (*year > 99 || *month > 12 || *day > 31) {
55+
return 0;
56+
}
57+
#ifdef TEST_YEAR
58+
if (*year != TEST_YEAR) {
59+
return 0;
60+
}
61+
#endif
62+
#ifdef TEST_MONTH
63+
if (*month != TEST_MONTH) {
64+
return 0;
65+
}
66+
#endif
67+
#ifdef TEST_DAY
68+
if (*day != TEST_DAY) {
69+
return 0;
70+
}
71+
#endif
72+
73+
return 1;
74+
}
75+
76+
int main(void) {
77+
uint32_t total_consumption; uint32_t last_month_total_consumption; uint8_t year; uint8_t month; uint8_t day;
78+
uint8_t found_keys = 0;
79+
uint8_t decoded_frame[11];
80+
time_t prevtime = 0;
81+
82+
// Loop over all the possible keys:
83+
for (uint64_t i=0; i<0xffffffffffffffff; i++) {
84+
time_t curtime = time(NULL);
85+
if (curtime > prevtime + 1) {
86+
printf("%.16llx keys tried\n", i);
87+
prevtime = curtime;
88+
}
89+
90+
// Test all frames in sequence until one fails:
91+
uint8_t success = 1;
92+
for (uint8_t j=0, count=sizeof(frames) / sizeof(frames[0]); j<count; j++) {
93+
// Check if the payload can be decoded:
94+
if (!try_key((uint8_t *) &i, frames[j], decoded_frame)) {
95+
success = 0;
96+
break;
97+
}
98+
99+
// Check the decoded payload for consistency:
100+
if (!check_decoded_payload(decoded_frame, &total_consumption, &last_month_total_consumption, &year, &month, &day)) {
101+
success = 0;
102+
break;
103+
}
104+
}
105+
106+
if (success) {
107+
printf(
108+
"Candidate key: {0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x}: First frame: current: %d, H0: %d H0 date: %.2d-%.2d-%.2d\n",
109+
(uint8_t)(i & 0xFF), (uint8_t)((i >> 8) & 0xFF), (uint8_t)((i >> 16) & 0xFF), (uint8_t)((i >> 24) & 0xFF), (uint8_t)((i >> 32) & 0xFF), (uint8_t)((i >> 40) & 0xFF), (uint8_t)((i >> 48) & 0xFF), (uint8_t)((i >> 56) & 0xFF),
110+
total_consumption, last_month_total_consumption, year, month, day
111+
);
112+
found_keys++;
113+
}
114+
}
115+
116+
return found_keys > 0;
117+
}

0 commit comments

Comments
 (0)