style and text. Might need some hint for the next step when/how unhash output is used

This commit is contained in:
iceman1001 2024-10-01 10:15:44 +02:00
commit e162cc3953
3 changed files with 86 additions and 52 deletions

View file

@ -4156,13 +4156,14 @@ static int CmdHFiClassUnhash(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass unhash",
"Reverses the hash0 function used generate iclass diversified keys after DES encryption, returning the DES crypted CSN.",
"hf iclass unhash --divkey B4F12AADC5301A2D"
"Reverses the hash0 function used generate iclass diversified keys after DES encryption,\n"
"Function returns the DES crypted CSN. Next step bruteforcing.",
"hf iclass unhash -k B4F12AADC5301A2D"
);
void *argtable[] = {
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
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -4174,14 +4175,16 @@ static int CmdHFiClassUnhash(const char *Cmd) {
CLIParserFree(ctx);
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;
}
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);
// iceman: add hint for next step?
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}

View file

@ -424,12 +424,16 @@ void invert_hash0(uint8_t k[8]) {
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]
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);
p |= ((k[i] & 0x01) << i);
}
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
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);
if (remainder < 0) {
p = ~p;
@ -450,19 +454,26 @@ void invert_hash0(uint8_t k[8]) {
uint8_t pre_image_base[8] = {0};
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
for (int img = 0; img < x_count; img++) { // for each potential value of x calculate a pre-image
zTil_img[img] = zTilde;
pre_image_base[0] = x_array[img];
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
pc = ~p;
}
// calculate zTilde for the x preimage
for (int i = 0; i < 8; i++) {
uint8_t p_i = (pc >> i) & 0x1; // this is correct!
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 (p_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~
PrintAndLogEx(INFO, " p or ~p : %02x", pc); // value of p (at some point in the original hash0)
}
// reverse permute
BitstreamIn_t p_in = { &pc, 8, 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
// 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
int heads_count = 1; // Track number of forks
// Iterate 4 times as per the original loop
for (int n = 0; n < 8; n++) {
uint8_t hydra_head = getSixBitByte(c, n);
if (hydra_head <= (n % 4) || hydra_head >= 63 - (n % 4)) {
// Create new forks by duplicating existing uint64_t values
int new_head = heads_count * 2;
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
for (int i = 0; i < heads_count; i++) {
// Duplicate current value
hydra_heads[heads_count + i] = hydra_heads[i];
uint8_t small_hydra_head = 0;
uint8_t big_hydra_head = 0;
uint8_t hydra_lil_spawns[4] = {0x00, 0x01, 0x02, 0x03};
uint8_t hydra_big_spawns[4] = {0x3f, 0x3e, 0x3d, 0x3c};
if (hydra_head <= n % 4) { // check if is in the lower range
// replace with big spawn in one hydra and keep small in another
small_hydra_head = hydra_head;
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];
}
}
} else if (hydra_head >= 63 - (n % 4)) { // or the higher range
// replace with small in one hydra and keep big in another
big_hydra_head = hydra_head;
for (int fh = 0; fh < 4; fh++) {
@ -579,7 +600,8 @@ void invert_hash0(uint8_t k[8]) {
}
// Update the count of total values
heads_count = new_head;
} else { //no hydra head spawns
} else {
// no hydra head spawns
for (int i = 0; i < heads_count; i++) {
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++) {
// restore the two most significant bytes (x and y)
hydra_heads[i] |= ((uint64_t)x_array[img] << 56);
hydra_heads[i] |= ((uint64_t)y << 48);
if (g_debugMode > 0) {
PrintAndLogEx(DEBUG, " | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
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
bool image_match = true;
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;
}
}
uint8_t des_pre_image[8] = {0};
x_num_to_bytes(original_z, sizeof(original_z), des_pre_image);
if (image_match) {
PrintAndLogEx(INFO, _GREEN_("Valid pre-image: ")_YELLOW_("%s"), sprint_hex(des_pre_image, sizeof(des_pre_image)));
} else if (!image_match && g_debugMode > 0) {
PrintAndLogEx(INFO, _RED_("Invalid pre-image: %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 (g_debugMode > 0) {
PrintAndLogEx(INFO, "Pre-image......... " _YELLOW_("%s") " ( "_RED_("invalid") " )", sprint_hex_inrow(des_pre_image, sizeof(des_pre_image)));
}
}
}
// Free allocated memory

View file

@ -3656,16 +3656,16 @@
},
"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": [
"hf iclass unhash --divkey B4F12AADC5301A2D"
"hf iclass unhash -k B4F12AADC5301A2D"
],
"offline": true,
"options": [
"-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": {
"command": "hf iclass view",
@ -12956,6 +12956,6 @@
"metadata": {
"commands_extracted": 747,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2024-10-01T07:52:00"
"extracted_on": "2024-10-01T08:14:57"
}
}