mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-09-20 07:16:14 +08:00
mfd_multi_brute, a new tool that targets all crypto modes and six different LCG
This commit is contained in:
parent
623169fe02
commit
e17b0e43fb
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added new tool `mfd_multi_brute` - MIFARE DESfire / UL-C key recovery (@iceman1001)
|
||||
- Fixed `hf emrtd info` segfault on some platforms (@doegox)
|
||||
- Fixed `hf emrtd info` when offline (@doegox)
|
||||
- Fixed `commands.json` generation (@doegox)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
MYSRCPATHS = ../../common ../../common/mbedtls
|
||||
MYSRCS = util_posix.c
|
||||
MYSRCS = util_posix.c randoms.c
|
||||
MYINCLUDES = -I../../include -I../../common -I../../common/mbedtls
|
||||
MYCFLAGS = -march=native -Ofast
|
||||
MYDEFS =
|
||||
|
@ -9,7 +9,7 @@ ifneq ($(SKIPPTHREAD),1)
|
|||
MYLDLIBS += -lpthread
|
||||
endif
|
||||
|
||||
BINS = brute_key mfd_aes_brute
|
||||
BINS = brute_key mfd_aes_brute mfd_multi_brute
|
||||
INSTALLTOOLS = $(BINS)
|
||||
|
||||
include ../../Makefile.host
|
||||
|
@ -33,3 +33,5 @@ endif
|
|||
brute_key : $(OBJDIR)/brute_key.o $(MYOBJS)
|
||||
|
||||
mfd_aes_brute : $(OBJDIR)/mfd_aes_brute.o $(MYOBJS)
|
||||
|
||||
mfd_multi_brute : $(OBJDIR)/mfd_multi_brute.o $(MYOBJS)
|
||||
|
|
157
tools/mfd_aes_brute/aes-ni.h
Normal file
157
tools/mfd_aes_brute/aes-ni.h
Normal file
|
@ -0,0 +1,157 @@
|
|||
#ifndef __AES_NI_H__
|
||||
#define __AES_NI_H__
|
||||
|
||||
#include "aes-ni.h"
|
||||
#include <stdint.h> //for int8_t
|
||||
#include <string.h> //for memcmp
|
||||
#include <wmmintrin.h> //for intrinsics for AES-NI
|
||||
//compile using gcc and following arguments: -g;-O0;-Wall;-msse2;-msse;-march=native;-maes
|
||||
|
||||
/*
|
||||
static void AES_CBC_decrypt(const uint8_t *in, uint8_t *out, uint8_t iv[], uint8_t len, uint8_t *key) {
|
||||
|
||||
__m128i data, last_in;
|
||||
__m128i feedback = _mm_loadu_si128 ((__m128i*)iv);
|
||||
|
||||
uint j;
|
||||
for (uint8_t i = 0; i < len; i++){
|
||||
last_in =_mm_loadu_si128 (&((__m128i*)in)[i]);
|
||||
data = _mm_xor_si128 (last_in, ((__m128i*)key)[0]);
|
||||
|
||||
for (j = 1; j < 10; j++){
|
||||
data = _mm_aesdec_si128 (data, ((__m128i*)key)[j]);
|
||||
}
|
||||
data = _mm_aesdeclast_si128 (data,((__m128i*)key)[j]);
|
||||
data = _mm_xor_si128 (data, feedback);
|
||||
_mm_storeu_si128 (&((__m128i*)out)[i], data);
|
||||
feedback = last_in;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
INLINE static __m128i AES_128_ASSIST (__m128i temp1, __m128i temp2) {
|
||||
__m128i temp3;
|
||||
temp2 = _mm_shuffle_epi32 (temp2 ,0xff);
|
||||
temp3 = _mm_slli_si128 (temp1, 0x4);
|
||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
||||
temp3 = _mm_slli_si128 (temp3, 0x4);
|
||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
||||
temp3 = _mm_slli_si128 (temp3, 0x4);
|
||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
||||
temp1 = _mm_xor_si128 (temp1, temp2);
|
||||
return temp1;
|
||||
}
|
||||
|
||||
static void AES_128_Key_Expansion (uint8_t *userkey, __m128i *key) {
|
||||
__m128i temp1, temp2;
|
||||
temp1 = _mm_loadu_si128((__m128i*)userkey);
|
||||
key[0] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1 ,0x1);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[1] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x2);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[2] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x4);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[3] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x8);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[4] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x10);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[5] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x20);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[6] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x40);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[7] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x80);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[8] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x1b);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[9] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x36);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
key[10] = temp1;
|
||||
}
|
||||
|
||||
static void aes_inv_key_10(AESContext * ctx) {
|
||||
|
||||
__m128i* keysched = (__m128i*)ctx->keysched;
|
||||
__m128i* invkeysched = (__m128i*)ctx->invkeysched;
|
||||
|
||||
*(invkeysched + 10) = *(keysched + 0);
|
||||
*(invkeysched + 9) = _mm_aesimc_si128(*(keysched + 1));
|
||||
*(invkeysched + 8) = _mm_aesimc_si128(*(keysched + 2));
|
||||
*(invkeysched + 7) = _mm_aesimc_si128(*(keysched + 3));
|
||||
*(invkeysched + 6) = _mm_aesimc_si128(*(keysched + 4));
|
||||
*(invkeysched + 5) = _mm_aesimc_si128(*(keysched + 5));
|
||||
*(invkeysched + 4) = _mm_aesimc_si128(*(keysched + 6));
|
||||
*(invkeysched + 3) = _mm_aesimc_si128(*(keysched + 7));
|
||||
*(invkeysched + 2) = _mm_aesimc_si128(*(keysched + 8));
|
||||
*(invkeysched + 1) = _mm_aesimc_si128(*(keysched + 9));
|
||||
*(invkeysched + 0) = *(keysched + 10);
|
||||
}
|
||||
|
||||
static void aes_decrypt_cbc_ni(const uint8_t *in, uint8_t *out, uint8_t iv[], uint8_t len, uint8_t *key) {
|
||||
|
||||
__m128i dec = _mm_setzero_si128();
|
||||
__m128i* block = (__m128i*)in;
|
||||
const __m128i* finish = (__m128i*)(in + len);
|
||||
|
||||
// Load IV
|
||||
__m128i iv = _mm_loadu_si128((__m128i*)iv);
|
||||
|
||||
while (block < finish) {
|
||||
|
||||
// Key schedule ptr
|
||||
__m128i* keysched = (__m128i*)ctx->invkeysched;
|
||||
__m128i last = _mm_loadu_si128(block);
|
||||
|
||||
dec = _mm_xor_si128(last, *keysched);
|
||||
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdec_si128(dec, *(++keysched));
|
||||
dec = _mm_aesdeclast_si128(dec, *(++keysched));
|
||||
|
||||
/// Xor data with IV
|
||||
dec = _mm_xor_si128(iv, dec);
|
||||
|
||||
// Store data
|
||||
_mm_storeu_si128(block, dec);
|
||||
iv = last;
|
||||
|
||||
// Go to next block
|
||||
++block;
|
||||
}
|
||||
|
||||
// Update IV
|
||||
_mm_storeu_si128((__m128i*)iv, dec);
|
||||
}
|
||||
|
||||
static void aes_setup_ni(AESContext * ctx, uint8_t *key) {
|
||||
|
||||
__m128i *keysched = (__m128i*)ctx->keysched;
|
||||
|
||||
ctx->decrypt_cbc = aes_decrypt_cbc_ni;
|
||||
|
||||
// Now do the key setup itself.
|
||||
AES_128_Key_Expansion (key, keysched);
|
||||
|
||||
// Now prepare the modified keys for the inverse cipher.
|
||||
aes_inv_key_10(ctx);
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
493
tools/mfd_aes_brute/mfd_multi_brute.c
Normal file
493
tools/mfd_aes_brute/mfd_multi_brute.c
Normal file
|
@ -0,0 +1,493 @@
|
|||
// MIFARE bruteforce tool
|
||||
// It's Multi threaded and supports all DES/2TDEA/3TDEA/AES crypto authentication modes.
|
||||
// also supports six different LCG random generators.
|
||||
// as a consequece this tools also work on MIFARE Ultralight-C challenges
|
||||
//
|
||||
//
|
||||
// Based upon the bruteforcer from X41 D-Sec Gmbh
|
||||
//
|
||||
// Copyright Iceman 2022
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
//#include <mbedtls/aes.h>
|
||||
#include "util_posix.h"
|
||||
#include "aes-ni.h"
|
||||
#include "detectaes.h"
|
||||
#include "randoms.h"
|
||||
|
||||
#define AEND "\x1b[0m"
|
||||
#define _RED_(s) "\x1b[31m" s AEND
|
||||
#define _GREEN_(s) "\x1b[32m" s AEND
|
||||
#define _YELLOW_(s) "\x1b[33m" s AEND
|
||||
#define _CYAN_(s) "\x1b[36m" s AEND
|
||||
|
||||
|
||||
static generator_t generators[] = {
|
||||
{"Borland", make_key_borland_n},
|
||||
{"Recipies", make_key_recipies_n},
|
||||
{"GlibC", make_key_glibc_n},
|
||||
{"AnsiC", make_key_ansic_n},
|
||||
{"Turbo Pascal", make_key_turbopascal_n},
|
||||
{"posix rand_r", make_key_posix_rand_r_n},
|
||||
{"MS Visual/Quick C/C++", make_key_ms_rand_r_n},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
#define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
// a global mutex to prevent interlaced printing from different threads
|
||||
pthread_mutex_t print_lock;
|
||||
|
||||
static int global_found = 0;
|
||||
static int thread_count = 2;
|
||||
|
||||
typedef struct thread_args {
|
||||
int thread;
|
||||
int idx;
|
||||
uint8_t generator_idx;
|
||||
uint8_t algo;
|
||||
uint64_t starttime;
|
||||
uint64_t stoptime;
|
||||
uint8_t tag[16];
|
||||
uint8_t rdr[32];
|
||||
} targs;
|
||||
|
||||
|
||||
// source https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption#Decrypting_the_Message
|
||||
static void decrypt_aes(uint8_t ciphertext[], int ciphertext_len, uint8_t key[], uint8_t iv[], uint8_t plaintext[]) {
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
|
||||
// EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
int len = 0;
|
||||
EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
|
||||
EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static void decrypt_3kdes(uint8_t ciphertext[], int ciphertext_len, uint8_t key[], uint8_t iv[], uint8_t plaintext[]) {
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
|
||||
EVP_DecryptInit_ex(ctx, EVP_des_ede3_cbc(), NULL, key, iv);
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
int len = 0;
|
||||
EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
|
||||
EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static void decrypt_2kdes(uint8_t ciphertext[], int ciphertext_len, uint8_t key[], uint8_t iv[], uint8_t plaintext[]) {
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_DecryptInit_ex(ctx, EVP_des_ede_cbc(), NULL, key, iv);
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
int len = 0;
|
||||
EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
|
||||
EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static void decrypt_des(uint8_t ciphertext[], int ciphertext_len, uint8_t key[], uint8_t iv[], uint8_t plaintext[]) {
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_DecryptInit_ex(ctx, EVP_des_cbc(), NULL, key, iv);
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
int len = 0;
|
||||
EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
|
||||
EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static int hexstr_to_byte_array(char hexstr[], uint8_t bytes[], size_t byte_len) {
|
||||
size_t hexstr_len = strlen(hexstr);
|
||||
if (hexstr_len % 16) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (byte_len < (hexstr_len / 2)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
char *pos = &hexstr[0];
|
||||
for (size_t count = 0; *pos != 0; count++) {
|
||||
sscanf(pos, "%2hhx", &bytes[count]);
|
||||
pos += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_hex(const uint8_t *data, const size_t len) {
|
||||
if (data == NULL || len == 0) return;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
printf("%02X", data[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_time(uint64_t at) {
|
||||
|
||||
time_t t = at;
|
||||
struct tm lt;
|
||||
|
||||
#if defined(_WIN32)
|
||||
(void)localtime_s(<, &t);
|
||||
#else
|
||||
(void)localtime_r(&t, <);
|
||||
#endif
|
||||
|
||||
char res[32];
|
||||
strftime(res, sizeof(res), "%Y-%m-%d %H:%M:%S", <);
|
||||
|
||||
printf("%u ( '%s' )\n", (unsigned)t, res);
|
||||
}
|
||||
|
||||
static void *brute_thread(void *arguments) {
|
||||
|
||||
//const bool support_aesni = platform_aes_hw_available();
|
||||
|
||||
struct thread_args *args = (struct thread_args *) arguments;
|
||||
|
||||
uint64_t starttime = args->starttime;
|
||||
uint64_t stoptime = args->stoptime;
|
||||
uint8_t local_algo = args->algo;
|
||||
uint8_t gidx = args->generator_idx;
|
||||
uint8_t local_tag[16];
|
||||
uint8_t local_rdr[32];
|
||||
uint8_t keylen = 16;
|
||||
|
||||
if (local_algo == 0) {
|
||||
memcpy(local_tag, args->tag, 8);
|
||||
memcpy(local_rdr, args->rdr, 16);
|
||||
keylen = 8;
|
||||
} else if (local_algo == 1) {
|
||||
memcpy(local_tag, args->tag, 8);
|
||||
memcpy(local_rdr, args->rdr, 16);
|
||||
keylen = 16;
|
||||
} else if (local_algo == 2) {
|
||||
memcpy(local_tag, args->tag, 16);
|
||||
memcpy(local_rdr, args->rdr, 32);
|
||||
keylen = 24;
|
||||
} else if (local_algo == 3) {
|
||||
memcpy(local_tag, args->tag, 16);
|
||||
memcpy(local_rdr, args->rdr, 32);
|
||||
keylen = 16;
|
||||
}
|
||||
|
||||
for (uint64_t i = starttime + args->idx; i < stoptime; i += thread_count) {
|
||||
|
||||
if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t key[keylen];
|
||||
generators[gidx].Parse(i, key, keylen);
|
||||
//make_key_borland_n(i, key, keylen);
|
||||
|
||||
uint8_t iv[keylen << 1];
|
||||
uint8_t dec_tag[16] = {0x00};
|
||||
uint8_t dec_rdr[32] = {0x00};
|
||||
|
||||
if (local_algo == 0) {
|
||||
decrypt_des(local_tag, 8, key, iv, dec_tag);
|
||||
decrypt_des(local_rdr, 16, key, local_tag, dec_rdr);
|
||||
|
||||
// check rol byte first
|
||||
if (dec_tag[0] != dec_rdr[15]) continue;
|
||||
|
||||
// compare rest
|
||||
if (dec_tag[1] != dec_rdr[8]) continue;
|
||||
if (dec_tag[2] != dec_rdr[9]) continue;
|
||||
if (dec_tag[3] != dec_rdr[10]) continue;
|
||||
if (dec_tag[4] != dec_rdr[11]) continue;
|
||||
if (dec_tag[5] != dec_rdr[12]) continue;
|
||||
if (dec_tag[6] != dec_rdr[13]) continue;
|
||||
if (dec_tag[7] != dec_rdr[14]) continue;
|
||||
|
||||
} else if (local_algo == 1) {
|
||||
decrypt_2kdes(local_tag, 8, key, iv, dec_tag);
|
||||
decrypt_2kdes(local_rdr, 16, key, local_tag, dec_rdr);
|
||||
|
||||
// check rol byte first
|
||||
if (dec_tag[0] != dec_rdr[15]) continue;
|
||||
|
||||
// compare rest
|
||||
if (dec_tag[1] != dec_rdr[8]) continue;
|
||||
if (dec_tag[2] != dec_rdr[9]) continue;
|
||||
if (dec_tag[3] != dec_rdr[10]) continue;
|
||||
if (dec_tag[4] != dec_rdr[11]) continue;
|
||||
if (dec_tag[5] != dec_rdr[12]) continue;
|
||||
if (dec_tag[6] != dec_rdr[13]) continue;
|
||||
if (dec_tag[7] != dec_rdr[14]) continue;
|
||||
|
||||
} else if (local_algo == 2) {
|
||||
decrypt_3kdes(local_tag, 16, key, iv, dec_tag);
|
||||
decrypt_3kdes(local_rdr, 32, key, local_tag, dec_rdr);
|
||||
|
||||
// check rol byte first
|
||||
if (dec_tag[0] != dec_rdr[31]) continue;
|
||||
|
||||
// compare rest
|
||||
if (dec_tag[1] != dec_rdr[16]) continue;
|
||||
if (dec_tag[2] != dec_rdr[17]) continue;
|
||||
if (dec_tag[3] != dec_rdr[18]) continue;
|
||||
if (dec_tag[4] != dec_rdr[19]) continue;
|
||||
if (dec_tag[5] != dec_rdr[20]) continue;
|
||||
if (dec_tag[6] != dec_rdr[21]) continue;
|
||||
if (dec_tag[7] != dec_rdr[22]) continue;
|
||||
if (dec_tag[8] != dec_rdr[23]) continue;
|
||||
if (dec_tag[9] != dec_rdr[24]) continue;
|
||||
if (dec_tag[10] != dec_rdr[25]) continue;
|
||||
if (dec_tag[11] != dec_rdr[26]) continue;
|
||||
if (dec_tag[12] != dec_rdr[27]) continue;
|
||||
if (dec_tag[13] != dec_rdr[28]) continue;
|
||||
if (dec_tag[14] != dec_rdr[29]) continue;
|
||||
if (dec_tag[15] != dec_rdr[30]) continue;
|
||||
|
||||
} else if (local_algo == 3) {
|
||||
decrypt_aes(local_tag, 16, key, iv, dec_tag);
|
||||
decrypt_aes(local_rdr, 32, key, local_tag, dec_rdr);
|
||||
|
||||
// check rol byte first
|
||||
if (dec_tag[0] != dec_rdr[31]) continue;
|
||||
|
||||
// compare rest
|
||||
if (dec_tag[1] != dec_rdr[16]) continue;
|
||||
if (dec_tag[2] != dec_rdr[17]) continue;
|
||||
if (dec_tag[3] != dec_rdr[18]) continue;
|
||||
if (dec_tag[4] != dec_rdr[19]) continue;
|
||||
if (dec_tag[5] != dec_rdr[20]) continue;
|
||||
if (dec_tag[6] != dec_rdr[21]) continue;
|
||||
if (dec_tag[7] != dec_rdr[22]) continue;
|
||||
if (dec_tag[8] != dec_rdr[23]) continue;
|
||||
if (dec_tag[9] != dec_rdr[24]) continue;
|
||||
if (dec_tag[10] != dec_rdr[25]) continue;
|
||||
if (dec_tag[11] != dec_rdr[26]) continue;
|
||||
if (dec_tag[12] != dec_rdr[27]) continue;
|
||||
if (dec_tag[13] != dec_rdr[28]) continue;
|
||||
if (dec_tag[14] != dec_rdr[29]) continue;
|
||||
if (dec_tag[15] != dec_rdr[30]) continue;
|
||||
}
|
||||
|
||||
__sync_fetch_and_add(&global_found, 1);
|
||||
|
||||
// lock this section to avoid interlacing prints from different threats
|
||||
pthread_mutex_lock(&print_lock);
|
||||
printf("Found timestamp........ ");
|
||||
print_time(i);
|
||||
|
||||
printf("Key.................... \x1b[32m");
|
||||
print_hex(key, keylen);
|
||||
printf(AEND);
|
||||
|
||||
pthread_mutex_unlock(&print_lock);
|
||||
break;
|
||||
}
|
||||
free(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int usage(const char *s) {
|
||||
|
||||
printf("\n");
|
||||
printf(_CYAN_("Multi Brute tool\n"));
|
||||
printf("Works on authentication challenges from MIFARE DESfire, MIFARE UL-C.\n");
|
||||
printf("If the key was generated by taking the Unixstamp as seed to a LCG random generator this software might find it.\n");
|
||||
printf("This version is multi-threaded, multi-crypto support and multi LCG generator support.\n");
|
||||
printf("\n");
|
||||
printf(_CYAN_("syntax") "\n");
|
||||
printf(" %s <crypto algo> <generator> <unix timestamp> <16 byte tag challenge> <32 byte reader response challenge>\n\n", s);
|
||||
printf(" crypt algo - <DES|2KDES|3KDES|AES>\n");
|
||||
printf(" generator - <0-5>\n");
|
||||
printf("\n");
|
||||
printf(_CYAN_("samples") "\n");
|
||||
printf(" %s DES 0 1599999999 118565f6e5e6c839 d570fd1578079e6b22aaa187b99f0a2a\n", s);
|
||||
printf(" %s 2TDEA 0 1599999999 02bdc73fd33cc07d 0e2281d59686bda6a6c5ad218dbfaa8c\n", s);
|
||||
printf(" %s 3TDEA 0 1599999999 1fe1f0330e9da5407cd2bc9294e56a7e 920037b5e02872b2fd9a070eade2b172ddc0fe6b10e5e55dd32cebdcc94747b4 \n", s);
|
||||
printf(" %s AES 0 1599999999 bb6aea729414a5b1eff7b16328ce37fd 82f5f498dbc29f7570102397a2e5ef2b6dc14a864f665b3c54d11765af81e95c\n", s);
|
||||
printf("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc != 6) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
char *algostr = argv[1];
|
||||
if (strlen(algostr) > 5 || strlen(algostr) < 3) {
|
||||
printf("No valid crypto algo\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int8_t algo = -1;
|
||||
if (strcasecmp(algostr, "des") == 0) {
|
||||
algo = 0;
|
||||
} else if (strcasecmp(algostr, "2tdea") == 0) {
|
||||
algo = 1;
|
||||
} else if (strcasecmp(algostr, "3tdea") == 0) {
|
||||
algo = 2;
|
||||
} else if (strcasecmp(algostr, "aes") == 0) {
|
||||
algo = 3;
|
||||
}
|
||||
|
||||
if (algo == -1) {
|
||||
printf("No valid crypto algo\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t g_idx = atoi(argv[2]);
|
||||
uint64_t start_time = atoi(argv[3]);
|
||||
|
||||
const bool support_aesni = platform_aes_hw_available();
|
||||
|
||||
printf("Crypto algo............ " _GREEN_("%s") "\n", algostr);
|
||||
printf("LCR Random generator... " _GREEN_("%s") "\n", generators[g_idx].Name);
|
||||
printf("AES-NI detected........ " _GREEN_("%s") "\n", (support_aesni) ? "yes" : "no");
|
||||
printf("Starting timestamp..... ");
|
||||
print_time(start_time);
|
||||
|
||||
uint8_t tag_challenge[16] = {0x00};
|
||||
uint8_t rdr_resp_challenge[32] = {0x00};
|
||||
|
||||
if (algo == 0) {
|
||||
if (hexstr_to_byte_array(argv[4], tag_challenge, 8))
|
||||
return 2;
|
||||
if (hexstr_to_byte_array(argv[5], rdr_resp_challenge, 16))
|
||||
return 3;
|
||||
|
||||
printf("Tag Challenge.......... ");
|
||||
print_hex(tag_challenge, 8);
|
||||
|
||||
printf("Rdr Resp & Challenge... ");
|
||||
print_hex(rdr_resp_challenge, 16);
|
||||
|
||||
} else if (algo == 1) {
|
||||
if (hexstr_to_byte_array(argv[4], tag_challenge, 8))
|
||||
return 2;
|
||||
if (hexstr_to_byte_array(argv[5], rdr_resp_challenge, 16))
|
||||
return 3;
|
||||
|
||||
printf("Tag Challenge.......... ");
|
||||
print_hex(tag_challenge, 8);
|
||||
|
||||
printf("Rdr Resp & Challenge... ");
|
||||
print_hex(rdr_resp_challenge, 16);
|
||||
|
||||
} else if (algo == 2) {
|
||||
if (hexstr_to_byte_array(argv[4], tag_challenge, 16))
|
||||
return 2;
|
||||
if (hexstr_to_byte_array(argv[5], rdr_resp_challenge, 32))
|
||||
return 3;
|
||||
|
||||
printf("Tag Challenge.......... ");
|
||||
print_hex(tag_challenge, 16);
|
||||
|
||||
printf("Rdr Resp & Challenge... ");
|
||||
print_hex(rdr_resp_challenge, 32);
|
||||
|
||||
} else if (algo == 3) {
|
||||
if (hexstr_to_byte_array(argv[4], tag_challenge, 16))
|
||||
return 2;
|
||||
if (hexstr_to_byte_array(argv[5], rdr_resp_challenge, 32))
|
||||
return 3;
|
||||
|
||||
printf("Tag Challenge.......... ");
|
||||
print_hex(tag_challenge, 16);
|
||||
|
||||
printf("Rdr Resp & Challenge... ");
|
||||
print_hex(rdr_resp_challenge, 32);
|
||||
}
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
#if !defined(_WIN32) || !defined(__WIN32__)
|
||||
thread_count = sysconf(_SC_NPROCESSORS_CONF);
|
||||
if (thread_count < 2)
|
||||
thread_count = 2;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
printf("\nBruteforce using " _YELLOW_("%d") " threads\n", thread_count);
|
||||
|
||||
pthread_t threads[thread_count];
|
||||
void *res;
|
||||
|
||||
// create a mutex to avoid interlacing print commands from our different threads
|
||||
pthread_mutex_init(&print_lock, NULL);
|
||||
|
||||
// threads
|
||||
uint64_t stop_time = time(NULL);
|
||||
for (int i = 0; i < thread_count; ++i) {
|
||||
struct thread_args *a = calloc(1, sizeof(struct thread_args));
|
||||
a->thread = i;
|
||||
a->idx = i;
|
||||
a->generator_idx = g_idx;
|
||||
a->algo = (uint8_t)algo;
|
||||
a->starttime = start_time;
|
||||
a->stoptime = stop_time;
|
||||
|
||||
if (algo == 0) {
|
||||
memcpy(a->tag, tag_challenge, 8);
|
||||
memcpy(a->rdr, rdr_resp_challenge, 16);
|
||||
} else if (algo == 1) {
|
||||
memcpy(a->tag, tag_challenge, 8);
|
||||
memcpy(a->rdr, rdr_resp_challenge, 16);
|
||||
} else if (algo == 2) {
|
||||
memcpy(a->tag, tag_challenge, 16);
|
||||
memcpy(a->rdr, rdr_resp_challenge, 32);
|
||||
} else if (algo == 3) {
|
||||
memcpy(a->tag, tag_challenge, 16);
|
||||
memcpy(a->rdr, rdr_resp_challenge, 32);
|
||||
}
|
||||
|
||||
pthread_create(&threads[i], NULL, brute_thread, (void *)a);
|
||||
}
|
||||
|
||||
// wait for threads to terminate:
|
||||
for (int i = 0; i < thread_count; ++i) {
|
||||
pthread_join(threads[i], &res);
|
||||
free(res);
|
||||
}
|
||||
|
||||
if (global_found == false) {
|
||||
printf("\n" _RED_("!!!") " failed to find a key\n\n");
|
||||
}
|
||||
|
||||
t1 = msclock() - t1;
|
||||
if (t1 > 0) {
|
||||
printf("Execution time " _YELLOW_("%.2f") " sec\n", (float)t1 / 1000.0);
|
||||
}
|
||||
|
||||
// clean up mutex
|
||||
pthread_mutex_destroy(&print_lock);
|
||||
|
||||
return 0;
|
||||
}
|
102
tools/mfd_aes_brute/randoms.c
Normal file
102
tools/mfd_aes_brute/randoms.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include "randoms.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
// linear congruential generator (LCG)
|
||||
//
|
||||
// ref
|
||||
// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
|
||||
|
||||
void make_key_borland_n(uint32_t seed, uint8_t key[], const size_t keylen) {
|
||||
|
||||
uint32_t lseed = ((seed * 22695477U) + 1) % UINT_MAX;
|
||||
|
||||
for (int i = 0; i < keylen; i++) {
|
||||
lseed = ((lseed * 22695477U) + 1) % UINT_MAX;
|
||||
key[i] = ((lseed >> 16) & 0x7fff) % 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
void make_key_recipies_n(uint32_t seed, uint8_t key[], const size_t keylen) {
|
||||
|
||||
//uint32_t lseed = ((seed * 1664525) + 1013904223) % UINT_MAX;
|
||||
uint32_t lseed = seed;
|
||||
|
||||
for (int i = 0; i < keylen; i++) {
|
||||
lseed = ((lseed * 1664525U) + 1013904223U) % UINT_MAX;
|
||||
key[i] = (lseed % 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void make_key_glibc_n(uint32_t seed, uint8_t key[], const size_t keylen) {
|
||||
|
||||
//uint32_t lseed = ((seed * 1103515245) + 12345) % 0x7fffffff;
|
||||
uint32_t lseed = seed;
|
||||
|
||||
|
||||
for (int i = 0; i < keylen; i++) {
|
||||
lseed = ((lseed * 1103515245U) + 12345U) & 0x7fffffff;
|
||||
key[i] = (lseed & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void make_key_ansic_n(uint32_t seed, uint8_t key[], const size_t keylen) {
|
||||
|
||||
//uint32_t lseed = ((seed * 1103515245) + 12345) % 0x7fffffff;
|
||||
uint32_t lseed = seed;
|
||||
|
||||
for (int i = 0; i < keylen; i++) {
|
||||
lseed = ((lseed * 1103515245U) + 12345U) & 0x7fffffff;
|
||||
key[i] = ((lseed >> 16) & 0x7fff) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
void make_key_turbopascal_n(uint32_t seed, uint8_t key[], const size_t keylen) {
|
||||
|
||||
//uint32_t lseed = ((seed * 134775813 ) + 1 ) % UINT_MAX;
|
||||
uint32_t lseed = seed;
|
||||
|
||||
for (int i = 0; i < keylen; i++) {
|
||||
lseed = ((lseed * 134775813) + 1) % UINT_MAX;
|
||||
key[i] = (lseed % 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* This algorithm is mentioned in the ISO C standard, here extended
|
||||
for 32 bits. */
|
||||
void make_key_posix_rand_r_n(uint32_t seed, uint8_t key[], const size_t keylen) {
|
||||
|
||||
uint32_t lseed = seed;
|
||||
int result;
|
||||
|
||||
for (int i = 0; i < keylen; i++) {
|
||||
|
||||
lseed *= 1103515245;
|
||||
lseed += 12345;
|
||||
result = (uint16_t)(lseed / 0x10000) % 2048;
|
||||
|
||||
lseed *= 1103515245;
|
||||
lseed += 12345;
|
||||
result <<= 10;
|
||||
result ^= (uint16_t)(lseed / 0x10000) % 1024;
|
||||
|
||||
lseed *= 1103515245;
|
||||
lseed += 12345;
|
||||
result <<= 10;
|
||||
result ^= (uint16_t)(lseed / 0x10000) % 1024;
|
||||
|
||||
key[i] = (result % 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
// Microsoft C runtime lib rand
|
||||
void make_key_ms_rand_r_n(uint32_t seed, uint8_t key[], const size_t keylen) {
|
||||
|
||||
uint32_t lseed = seed;
|
||||
|
||||
for (int i = 0; i < keylen; i++) {
|
||||
lseed = ((lseed * 214013L) + 2531011L);
|
||||
key[i] = ((lseed >> 16) & 0x7FFF);
|
||||
}
|
||||
}
|
42
tools/mfd_aes_brute/randoms.h
Normal file
42
tools/mfd_aes_brute/randoms.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright Iceman 2022
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// linear congruential generator (LCG)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef RANDOMS_H__
|
||||
#define RANDOMS_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct generator_s {
|
||||
const char *Name;
|
||||
void (*Parse)(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
} generator_t;
|
||||
// generator_t array are expected to be NULL terminated
|
||||
|
||||
void make_key_rand_n(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
void make_key_borland_n(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
void make_key_recipies_n(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
void make_key_glibc_n(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
void make_key_ansic_n(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
void make_key_turbopascal_n(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
void make_key_posix_rand_r_n(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
void make_key_ms_rand_r_n(uint32_t seed, uint8_t key[], const size_t keylen);
|
||||
#endif
|
||||
|
Loading…
Reference in a new issue