mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
style and text. Might need some hint for the next step when/how unhash output is used
This commit is contained in:
parent
f4d2d2e5db
commit
e162cc3953
3 changed files with 86 additions and 52 deletions
|
@ -4156,13 +4156,14 @@ static int CmdHFiClassUnhash(const char *Cmd) {
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf iclass unhash",
|
CLIParserInit(&ctx, "hf iclass unhash",
|
||||||
"Reverses the hash0 function used generate iclass diversified keys after DES encryption, returning the DES crypted CSN.",
|
"Reverses the hash0 function used generate iclass diversified keys after DES encryption,\n"
|
||||||
"hf iclass unhash --divkey B4F12AADC5301A2D"
|
"Function returns the DES crypted CSN. Next step bruteforcing.",
|
||||||
|
"hf iclass unhash -k B4F12AADC5301A2D"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1(NULL, "divkey", "<hex>", "The card's Diversified Key value"),
|
arg_str1("k", "divkey", "<hex>", "Card diversified key"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
@ -4174,14 +4175,16 @@ static int CmdHFiClassUnhash(const char *Cmd) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (dk_len && dk_len != PICOPASS_BLOCK_SIZE) {
|
if (dk_len && dk_len != PICOPASS_BLOCK_SIZE) {
|
||||||
PrintAndLogEx(ERR, "Diversified Key is incorrect length");
|
PrintAndLogEx(ERR, "Diversified key is incorrect length");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, _YELLOW_("Div Key: ")"%s", sprint_hex(div_key, sizeof(div_key)));
|
PrintAndLogEx(INFO, "Diversified key... %s", sprint_hex_inrow(div_key, sizeof(div_key)));
|
||||||
|
|
||||||
invert_hash0(div_key);
|
invert_hash0(div_key);
|
||||||
|
|
||||||
|
// iceman: add hint for next step?
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,12 +424,16 @@ void invert_hash0(uint8_t k[8]) {
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
y |= ((k[i] & 0x80) >> (7 - i)); // Recover the bit of y from the leftmost bit of k[i]
|
y |= ((k[i] & 0x80) >> (7 - i)); // Recover the bit of y from the leftmost bit of k[i]
|
||||||
pushbackSixBitByte(&zTilde, (k[i] & 0x7E) >> 1, i); // Recover the six bits of zTilde from the middle of k[i]
|
pushbackSixBitByte(&zTilde, (k[i] & 0x7E) >> 1, i); // Recover the six bits of zTilde from the middle of k[i]
|
||||||
|
|
||||||
if (g_debugMode > 0) printState("z~", zTilde);
|
if (g_debugMode > 0) printState("z~", zTilde);
|
||||||
|
|
||||||
p |= ((k[i] & 0x01) << i);
|
p |= ((k[i] & 0x01) << i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_debugMode > 0) PrintAndLogEx(INFO, " y : %02x", y); // value of y (recovered 1 byte of the pre-image)
|
if (g_debugMode > 0) PrintAndLogEx(INFO, " y : %02x", y); // value of y (recovered 1 byte of the pre-image)
|
||||||
// check if p is part of the array pi, if not invert it
|
// check if p is part of the array pi, if not invert it
|
||||||
if (g_debugMode > 0) PrintAndLogEx(INFO, " p : %02x", p); // value of p (at some point in the original hash0)
|
if (g_debugMode > 0) PrintAndLogEx(INFO, " p : %02x", p); // value of p (at some point in the original hash0)
|
||||||
|
|
||||||
int remainder = find_p_in_pi(p);
|
int remainder = find_p_in_pi(p);
|
||||||
if (remainder < 0) {
|
if (remainder < 0) {
|
||||||
p = ~p;
|
p = ~p;
|
||||||
|
@ -450,19 +454,26 @@ void invert_hash0(uint8_t k[8]) {
|
||||||
|
|
||||||
uint8_t pre_image_base[8] = {0};
|
uint8_t pre_image_base[8] = {0};
|
||||||
pre_image_base[1] = y;
|
pre_image_base[1] = y;
|
||||||
//calculate pre-images based on the potential values of x (should we use pre-flip p and post flip p just in case?)
|
|
||||||
|
// calculate pre-images based on the potential values of x. Sshould we use pre-flip p and post flip p just in case?
|
||||||
uint64_t zTil_img[8] = {0}; // 8 is the max size it'll have as per max number of X pre-images
|
uint64_t zTil_img[8] = {0}; // 8 is the max size it'll have as per max number of X pre-images
|
||||||
|
|
||||||
for (int img = 0; img < x_count; img++) { // for each potential value of x calculate a pre-image
|
for (int img = 0; img < x_count; img++) { // for each potential value of x calculate a pre-image
|
||||||
|
|
||||||
zTil_img[img] = zTilde;
|
zTil_img[img] = zTilde;
|
||||||
pre_image_base[0] = x_array[img];
|
pre_image_base[0] = x_array[img];
|
||||||
|
|
||||||
uint8_t pc = p; // redefine and reassociate it here or it'll keep changing through the loops
|
uint8_t pc = p; // redefine and reassociate it here or it'll keep changing through the loops
|
||||||
if (x_array[img] & 1) { // Check if potential x7 is 1, if it is then invert p
|
if (x_array[img] & 1) { // Check if potential x7 is 1, if it is then invert p
|
||||||
pc = ~p;
|
pc = ~p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate zTilde for the x preimage
|
// calculate zTilde for the x preimage
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
|
|
||||||
uint8_t p_i = (pc >> i) & 0x1; // this is correct!
|
uint8_t p_i = (pc >> i) & 0x1; // this is correct!
|
||||||
uint8_t zTilde_i = getSixBitByte(zTilde, i) << 1;
|
uint8_t zTilde_i = getSixBitByte(zTilde, i) << 1;
|
||||||
|
|
||||||
if (k[i] & 0x80) { // this checks the value of the first bit of the byte (value of y_i)
|
if (k[i] & 0x80) { // this checks the value of the first bit of the byte (value of y_i)
|
||||||
if (p_i) {
|
if (p_i) {
|
||||||
zTilde_i--;
|
zTilde_i--;
|
||||||
|
@ -481,6 +492,7 @@ void invert_hash0(uint8_t k[8]) {
|
||||||
printState("0|0|z~", zTil_img[img]); // we retrieve the values of z~
|
printState("0|0|z~", zTil_img[img]); // we retrieve the values of z~
|
||||||
PrintAndLogEx(INFO, " p or ~p : %02x", pc); // value of p (at some point in the original hash0)
|
PrintAndLogEx(INFO, " p or ~p : %02x", pc); // value of p (at some point in the original hash0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reverse permute
|
// reverse permute
|
||||||
BitstreamIn_t p_in = { &pc, 8, 0 };
|
BitstreamIn_t p_in = { &pc, 8, 0 };
|
||||||
uint8_t outbuffer_1[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
uint8_t outbuffer_1[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
@ -537,26 +549,33 @@ void invert_hash0(uint8_t k[8]) {
|
||||||
// When these values are present we need to generate additional pre-images if they have the same modulo as other values
|
// When these values are present we need to generate additional pre-images if they have the same modulo as other values
|
||||||
|
|
||||||
// Initialize an array of pointers to uint64_t (start with one value, initialized to 0)
|
// Initialize an array of pointers to uint64_t (start with one value, initialized to 0)
|
||||||
uint64_t *hydra_heads = (uint64_t *)malloc(sizeof(uint64_t)); // Start with one uint64_t
|
uint64_t *hydra_heads = (uint64_t *)calloc(sizeof(uint64_t), 1); // Start with one uint64_t
|
||||||
hydra_heads[0] = 0; // Initialize first value to 0
|
hydra_heads[0] = 0; // Initialize first value to 0
|
||||||
int heads_count = 1; // Track number of forks
|
int heads_count = 1; // Track number of forks
|
||||||
|
|
||||||
// Iterate 4 times as per the original loop
|
// Iterate 4 times as per the original loop
|
||||||
for (int n = 0; n < 8; n++) {
|
for (int n = 0; n < 8; n++) {
|
||||||
|
|
||||||
uint8_t hydra_head = getSixBitByte(c, n);
|
uint8_t hydra_head = getSixBitByte(c, n);
|
||||||
|
|
||||||
if (hydra_head <= (n % 4) || hydra_head >= 63 - (n % 4)) {
|
if (hydra_head <= (n % 4) || hydra_head >= 63 - (n % 4)) {
|
||||||
|
|
||||||
// Create new forks by duplicating existing uint64_t values
|
// Create new forks by duplicating existing uint64_t values
|
||||||
int new_head = heads_count * 2;
|
int new_head = heads_count * 2;
|
||||||
hydra_heads = (uint64_t *)realloc(hydra_heads, new_head * sizeof(uint64_t));
|
hydra_heads = (uint64_t *)realloc(hydra_heads, new_head * sizeof(uint64_t));
|
||||||
|
|
||||||
// Duplicate all current values and add the value to both original and new ones
|
// Duplicate all current values and add the value to both original and new ones
|
||||||
for (int i = 0; i < heads_count; i++) {
|
for (int i = 0; i < heads_count; i++) {
|
||||||
|
|
||||||
// Duplicate current value
|
// Duplicate current value
|
||||||
hydra_heads[heads_count + i] = hydra_heads[i];
|
hydra_heads[heads_count + i] = hydra_heads[i];
|
||||||
uint8_t small_hydra_head = 0;
|
uint8_t small_hydra_head = 0;
|
||||||
uint8_t big_hydra_head = 0;
|
uint8_t big_hydra_head = 0;
|
||||||
uint8_t hydra_lil_spawns[4] = {0x00, 0x01, 0x02, 0x03};
|
uint8_t hydra_lil_spawns[4] = {0x00, 0x01, 0x02, 0x03};
|
||||||
uint8_t hydra_big_spawns[4] = {0x3f, 0x3e, 0x3d, 0x3c};
|
uint8_t hydra_big_spawns[4] = {0x3f, 0x3e, 0x3d, 0x3c};
|
||||||
|
|
||||||
if (hydra_head <= n % 4) { // check if is in the lower range
|
if (hydra_head <= n % 4) { // check if is in the lower range
|
||||||
|
|
||||||
// replace with big spawn in one hydra and keep small in another
|
// replace with big spawn in one hydra and keep small in another
|
||||||
small_hydra_head = hydra_head;
|
small_hydra_head = hydra_head;
|
||||||
for (int fh = 0; fh < 4; fh++) {
|
for (int fh = 0; fh < 4; fh++) {
|
||||||
|
@ -564,7 +583,9 @@ void invert_hash0(uint8_t k[8]) {
|
||||||
big_hydra_head = hydra_big_spawns[fh];
|
big_hydra_head = hydra_big_spawns[fh];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (hydra_head >= 63 - (n % 4)) { // or the higher range
|
} else if (hydra_head >= 63 - (n % 4)) { // or the higher range
|
||||||
|
|
||||||
// replace with small in one hydra and keep big in another
|
// replace with small in one hydra and keep big in another
|
||||||
big_hydra_head = hydra_head;
|
big_hydra_head = hydra_head;
|
||||||
for (int fh = 0; fh < 4; fh++) {
|
for (int fh = 0; fh < 4; fh++) {
|
||||||
|
@ -579,7 +600,8 @@ void invert_hash0(uint8_t k[8]) {
|
||||||
}
|
}
|
||||||
// Update the count of total values
|
// Update the count of total values
|
||||||
heads_count = new_head;
|
heads_count = new_head;
|
||||||
} else { //no hydra head spawns
|
} else {
|
||||||
|
// no hydra head spawns
|
||||||
for (int i = 0; i < heads_count; i++) {
|
for (int i = 0; i < heads_count; i++) {
|
||||||
pushbackSixBitByte(&hydra_heads[i], hydra_head, n);;
|
pushbackSixBitByte(&hydra_heads[i], hydra_head, n);;
|
||||||
}
|
}
|
||||||
|
@ -587,9 +609,11 @@ void invert_hash0(uint8_t k[8]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < heads_count; i++) {
|
for (int i = 0; i < heads_count; i++) {
|
||||||
|
|
||||||
// restore the two most significant bytes (x and y)
|
// restore the two most significant bytes (x and y)
|
||||||
hydra_heads[i] |= ((uint64_t)x_array[img] << 56);
|
hydra_heads[i] |= ((uint64_t)x_array[img] << 56);
|
||||||
hydra_heads[i] |= ((uint64_t)y << 48);
|
hydra_heads[i] |= ((uint64_t)y << 48);
|
||||||
|
|
||||||
if (g_debugMode > 0) {
|
if (g_debugMode > 0) {
|
||||||
PrintAndLogEx(DEBUG, " | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
|
PrintAndLogEx(DEBUG, " | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
|
||||||
printState("origin_r1", hydra_heads[i]);
|
printState("origin_r1", hydra_heads[i]);
|
||||||
|
@ -609,17 +633,24 @@ void invert_hash0(uint8_t k[8]) {
|
||||||
// verify result, if it matches add it to the list as a valid pre-image
|
// verify result, if it matches add it to the list as a valid pre-image
|
||||||
bool image_match = true;
|
bool image_match = true;
|
||||||
for (int v = 0; v < 8; v++) {
|
for (int v = 0; v < 8; v++) {
|
||||||
if (img_div_key[v] != k[v]) { //compare against input key k
|
|
||||||
|
// compare against input key k
|
||||||
|
if (img_div_key[v] != k[v]) {
|
||||||
image_match = false;
|
image_match = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t des_pre_image[8] = {0};
|
uint8_t des_pre_image[8] = {0};
|
||||||
x_num_to_bytes(original_z, sizeof(original_z), des_pre_image);
|
x_num_to_bytes(original_z, sizeof(original_z), des_pre_image);
|
||||||
|
|
||||||
if (image_match) {
|
if (image_match) {
|
||||||
PrintAndLogEx(INFO, _GREEN_("Valid pre-image: ")_YELLOW_("%s"), sprint_hex(des_pre_image, sizeof(des_pre_image)));
|
PrintAndLogEx(INFO, "Pre-image......... " _YELLOW_("%s") " ( "_GREEN_("valid") " )", sprint_hex_inrow(des_pre_image, sizeof(des_pre_image)));
|
||||||
} else if (!image_match && g_debugMode > 0) {
|
} else {
|
||||||
PrintAndLogEx(INFO, _RED_("Invalid pre-image: %s"), sprint_hex(des_pre_image, sizeof(des_pre_image)));
|
|
||||||
|
if (g_debugMode > 0) {
|
||||||
|
PrintAndLogEx(INFO, "Pre-image......... " _YELLOW_("%s") " ( "_RED_("invalid") " )", sprint_hex_inrow(des_pre_image, sizeof(des_pre_image)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Free allocated memory
|
// Free allocated memory
|
||||||
|
|
|
@ -3656,16 +3656,16 @@
|
||||||
},
|
},
|
||||||
"hf iclass unhash": {
|
"hf iclass unhash": {
|
||||||
"command": "hf iclass unhash",
|
"command": "hf iclass unhash",
|
||||||
"description": "Reverses the hash0 function used generate iclass diversified keys after DES encryption, returning the DES crypted CSN.",
|
"description": "Reverses the hash0 function used generate iclass diversified keys after DES encryption, Function returns the DES crypted CSN. Next step bruteforcing.",
|
||||||
"notes": [
|
"notes": [
|
||||||
"hf iclass unhash --divkey B4F12AADC5301A2D"
|
"hf iclass unhash -k B4F12AADC5301A2D"
|
||||||
],
|
],
|
||||||
"offline": true,
|
"offline": true,
|
||||||
"options": [
|
"options": [
|
||||||
"-h, --help This help",
|
"-h, --help This help",
|
||||||
"--divkey <hex> The card's Diversified Key value"
|
"-k, --divkey <hex> Card diversified key"
|
||||||
],
|
],
|
||||||
"usage": "hf iclass unhash [-h] --divkey <hex>"
|
"usage": "hf iclass unhash [-h] -k <hex>"
|
||||||
},
|
},
|
||||||
"hf iclass view": {
|
"hf iclass view": {
|
||||||
"command": "hf iclass view",
|
"command": "hf iclass view",
|
||||||
|
@ -12956,6 +12956,6 @@
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"commands_extracted": 747,
|
"commands_extracted": 747,
|
||||||
"extracted_by": "PM3Help2JSON v1.00",
|
"extracted_by": "PM3Help2JSON v1.00",
|
||||||
"extracted_on": "2024-10-01T07:52:00"
|
"extracted_on": "2024-10-01T08:14:57"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue