From b01f4e5c2ec741223f0830ac6233c21a8a188812 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 7 Mar 2023 21:53:11 +0100 Subject: [PATCH 1/9] corrected ASCII plaintext check from >=20 to >=0x20 --- OpenCL/m25400-pure.cl | 4 ++-- OpenCL/m26610-pure.cl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenCL/m25400-pure.cl b/OpenCL/m25400-pure.cl index 5063d09f1..145196636 100644 --- a/OpenCL/m25400-pure.cl +++ b/OpenCL/m25400-pure.cl @@ -364,7 +364,7 @@ KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) // we don't use the user-password in the attack now (as we don't need it), // however we could use it in the comparison of the decrypted o-value, // yet it may make this attack a bit more fragile, as now we just check for ASCII - if ((u8OutBufPtr[i] >= 20 && u8OutBufPtr[i] <= 0x7e) || + if ((u8OutBufPtr[i] >= 0x20 && u8OutBufPtr[i] <= 0x7e) || (u8OutBufPtr[i] == u8OutPadPtr[i_padding])) { if (u8OutBufPtr[i] == u8OutPadPtr[i_padding]) @@ -374,7 +374,7 @@ KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) } else { - if (u8OutBufPtr[i] >= 20 && u8OutBufPtr[i] <= 0x7e) + if (u8OutBufPtr[i] >= 0x20 && u8OutBufPtr[i] <= 0x7e) { //printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); } diff --git a/OpenCL/m26610-pure.cl b/OpenCL/m26610-pure.cl index 1b3827ba7..ea0cac6e3 100644 --- a/OpenCL/m26610-pure.cl +++ b/OpenCL/m26610-pure.cl @@ -376,7 +376,7 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh for(int i=0;i<16;i++) { - if(u8OutBufPtr[i] >=20 && u8OutBufPtr[i] <= 0x7e) { + if(u8OutBufPtr[i] >=0x20 && u8OutBufPtr[i] <= 0x7e) { //if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); } else { From 45b803988cb2f5f987c6be3c4fc5b85b40dffecc Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 7 Mar 2023 23:38:09 +0100 Subject: [PATCH 2/9] 25400 working with 32 bytes plaintext check --- OpenCL/m25400-pure.cl | 81 ++++++++++++++++++++++++-------------- src/modules/module_25400.c | 20 +++++++--- 2 files changed, 66 insertions(+), 35 deletions(-) diff --git a/OpenCL/m25400-pure.cl b/OpenCL/m25400-pure.cl index 145196636..ed5f3d259 100644 --- a/OpenCL/m25400-pure.cl +++ b/OpenCL/m25400-pure.cl @@ -3,7 +3,7 @@ * License.....: MIT */ -// https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf +// https://web.archive.org/web/20220306152229/https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf #ifdef KERNEL_STATIC #include M2S(INCLUDE_PATH/inc_vendor.h) @@ -43,7 +43,7 @@ typedef struct pdf typedef struct pdf14_tmp { u32 digest[4]; - u32 out[4]; + u32 out[8]; } pdf14_tmp_t; @@ -183,6 +183,10 @@ KERNEL_FQ void m25400_init (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) tmps[gid].out[1] = rc4data[1]; tmps[gid].out[2] = 0; tmps[gid].out[3] = 0; + tmps[gid].out[4] = 0; // we only need the size of out for the plaintext check + tmps[gid].out[5] = 0; // we only need the size of out for the plaintext check + tmps[gid].out[6] = 0; // we only need the size of out for the plaintext check + tmps[gid].out[7] = 0; // we only need the size of out for the plaintext check } KERNEL_FQ void m25400_loop (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) @@ -212,12 +216,6 @@ KERNEL_FQ void m25400_loop (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) digest[2] = tmps[gid].digest[2]; digest[3] = tmps[gid].digest[3]; - u32 out[4]; - out[0] = tmps[gid].out[0]; - out[1] = tmps[gid].out[1]; - out[2] = tmps[gid].out[2]; - out[3] = tmps[gid].out[3]; - for (u32 i = 0, j = LOOP_POS; i < LOOP_CNT; i++, j++) { if (j < 50) @@ -255,10 +253,19 @@ KERNEL_FQ void m25400_loop (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) } } + + u32 out[4]; out[0] = esalt_bufs[DIGESTS_OFFSET_HOST].o_buf[0]; // store original o-value in out (scratchpad) out[1] = esalt_bufs[DIGESTS_OFFSET_HOST].o_buf[1]; out[2] = esalt_bufs[DIGESTS_OFFSET_HOST].o_buf[2]; out[3] = esalt_bufs[DIGESTS_OFFSET_HOST].o_buf[3]; + + u32 out2[4]; + out2[0] = esalt_bufs[DIGESTS_OFFSET_HOST].o_buf[4]; // store original o-value in out (scratchpad) + out2[1] = esalt_bufs[DIGESTS_OFFSET_HOST].o_buf[5]; + out2[2] = esalt_bufs[DIGESTS_OFFSET_HOST].o_buf[6]; + out2[3] = esalt_bufs[DIGESTS_OFFSET_HOST].o_buf[7]; + u32 o_rc4_decryption_key[4]; o_rc4_decryption_key[0] = digest[0]; // store the owner-key o_rc4_decryption_key[1] = digest[1]; @@ -268,6 +275,7 @@ KERNEL_FQ void m25400_loop (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) // we decrypt the o-value to obtain either the owner-password (or user-password if no owner-password is set) // see: "Algorithm 3.3 Computing the encryption dictionary’s O (owner password) value": "If there is no owner password, use the user password instead". u32 tmp[4]; + u8 j; for (u32 i = 19; i>0; i--) { // xor the iterator into the rc4 key @@ -282,11 +290,12 @@ KERNEL_FQ void m25400_loop (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) tmp[3] = o_rc4_decryption_key[3] ^ xv; rc4_init_128 (S, tmp, lid); - rc4_next_16 (S, 0, 0, out, out, lid); + j = rc4_next_16 (S, 0, 0, out, out, lid); + rc4_next_16 (S, 16, j, out2, out2, lid); } rc4_init_128 (S, o_rc4_decryption_key, lid); - rc4_next_16 (S, 0, 0, out, out, lid); // output of the rc4 decrypt of the o-value should be the padded user-password + j = rc4_next_16 (S, 0, 0, out, out, lid); // output of the rc4 decrypt of the o-value should be the padded user-password tmps[gid].digest[0] = digest[0]; tmps[gid].digest[1] = digest[1]; @@ -297,6 +306,15 @@ KERNEL_FQ void m25400_loop (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) tmps[gid].out[1] = out[1]; tmps[gid].out[2] = out[2]; tmps[gid].out[3] = out[3]; + if ((gid == 0) && (lid == 0)) printf ("out[3]=%08x\n", out[3]); + + rc4_next_16 (S, 16, j, out2, out2, lid); // decrypt a second block of rc4 to improve plaintext check and limit false positives + if ((gid == 0) && (lid == 0)) printf ("out2[0]=%08x\n", out2[0]); + tmps[gid].out[4] = out2[0]; + if ((gid == 0) && (lid == 0)) printf ("tmps[gid].out[4]=%08x\n", tmps[gid].out[4]); + tmps[gid].out[5] = out2[1]; + tmps[gid].out[6] = out2[2]; + tmps[gid].out[7] = out2[3]; } KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) @@ -334,12 +352,16 @@ KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) #define il_pos 0 - const u32 out[4] = + const u32 out[8] = { tmps[gid].out[0], tmps[gid].out[1], tmps[gid].out[2], - tmps[gid].out[3] + tmps[gid].out[3], + tmps[gid].out[4], + tmps[gid].out[5], + tmps[gid].out[6], + tmps[gid].out[7] }; @@ -351,7 +373,7 @@ KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) int i_padding=0; - for (int i = 0; i < 16; i++) + for (int i = 0; i < 32; i++) // check all 32 bytes of the decrypted o-value, this including the padding. { // cast out buffer to byte such that we can do a byte per byte comparison PRIVATE_AS const u32 *u32OutBufPtr = (PRIVATE_AS u32 *) out; @@ -363,39 +385,40 @@ KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) // we don't use the user-password in the attack now (as we don't need it), // however we could use it in the comparison of the decrypted o-value, - // yet it may make this attack a bit more fragile, as now we just check for ASCII + // yet it may make this attack a bit more fragile, as now we just check for padding and ASCII if ((u8OutBufPtr[i] >= 0x20 && u8OutBufPtr[i] <= 0x7e) || (u8OutBufPtr[i] == u8OutPadPtr[i_padding])) { if (u8OutBufPtr[i] == u8OutPadPtr[i_padding]) { - //printf("correct padding byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); + if ((gid == 0) && (lid == 0)) printf("correct padding byte[%d]=0x%02x==0x%02x\n", i, u8OutBufPtr[i], u8OutPadPtr[i_padding]); i_padding = i_padding + 1; } else { if (u8OutBufPtr[i] >= 0x20 && u8OutBufPtr[i] <= 0x7e) { - //printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); + if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); } } } else { - //printf("wrong byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); - // - //printf("u8OutBufPtr=0x"); - //for(int j=0;j<16;j++) { - // printf("%02x", u8OutBufPtr[j]); - //} - //printf("\n"); - // - //printf("u8OutPadPtr=0x"); - //for(int j=0;j<16;j++) { - // printf("%02x", u8OutPadPtr[j]); - //} - //printf("\n"); + if ((gid == 0) && (lid == 0)) { + printf("wrong byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); + printf("u8OutBufPtr=0x"); + for(int j=0;j<32;j++) { + printf("%02x", u8OutBufPtr[j]); + } + printf("\n"); + + printf("u8OutPadPtr=0x"); + for(int j=0;j<32;j++) { + printf("%02x", u8OutPadPtr[j]); + } + printf("\n"); + } correct = false; break; } diff --git a/src/modules/module_25400.c b/src/modules/module_25400.c index c38c91de9..baad6e6fd 100644 --- a/src/modules/module_25400.c +++ b/src/modules/module_25400.c @@ -74,7 +74,7 @@ typedef struct pdf typedef struct pdf14_tmp { u32 digest[4]; - u32 out[4]; + u32 out[8]; } pdf14_tmp_t; @@ -501,7 +501,11 @@ int module_build_plain_postprocess (MAYBE_UNUSED const hashconfig_t *hashconfig, if (pdf_tmp->out[0] == padding[0] && pdf_tmp->out[1] == padding[1] && pdf_tmp->out[2] == padding[2] && - pdf_tmp->out[3] == padding[3]) + pdf_tmp->out[3] == padding[3] && + pdf_tmp->out[4] == padding[4] && + pdf_tmp->out[5] == padding[5] && + pdf_tmp->out[6] == padding[6] && + pdf_tmp->out[7] == padding[7]) { return snprintf ((char *) dst_buf, dst_sz, "%s (user password not set)", (char *) src_buf); } @@ -534,10 +538,14 @@ int module_build_plain_postprocess (MAYBE_UNUSED const hashconfig_t *hashconfig, // however, we'd need to include a lot of code/complexity here to do so (or call into 10500 kernel). // this seems relevant: run_kernel (hashcat_ctx, device_param, KERN_RUN_3, 0, 1, false, 0) - if (pdf_tmp->out[0] == src_buf[0] && - pdf_tmp->out[1] == src_buf[1] && - pdf_tmp->out[2] == src_buf[2] && - pdf_tmp->out[3] == src_buf[3]) + if (pdf_tmp->out[0] == padding[0] && + pdf_tmp->out[1] == padding[1] && + pdf_tmp->out[2] == padding[2] && + pdf_tmp->out[3] == padding[3] && + pdf_tmp->out[4] == padding[4] && + pdf_tmp->out[5] == padding[5] && + pdf_tmp->out[6] == padding[6] && + pdf_tmp->out[7] == padding[7]) { if (pdf->u_pass_len == 0) { From 6bc86d06b100074c4f2a3bc41ded5c677369defe Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 7 Mar 2023 23:50:49 +0100 Subject: [PATCH 3/9] remove debug printfs, added changes.txt --- OpenCL/m25400-pure.cl | 58 ++++++++++++++++++++----------------------- docs/changes.txt | 1 + 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/OpenCL/m25400-pure.cl b/OpenCL/m25400-pure.cl index ed5f3d259..a027577d3 100644 --- a/OpenCL/m25400-pure.cl +++ b/OpenCL/m25400-pure.cl @@ -296,25 +296,21 @@ KERNEL_FQ void m25400_loop (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) rc4_init_128 (S, o_rc4_decryption_key, lid); j = rc4_next_16 (S, 0, 0, out, out, lid); // output of the rc4 decrypt of the o-value should be the padded user-password + tmps[gid].out[0] = out[0]; + tmps[gid].out[1] = out[1]; + tmps[gid].out[2] = out[2]; + tmps[gid].out[3] = out[3]; + + rc4_next_16 (S, 16, j, out2, out2, lid); // decrypt a second block of rc4 to improve plaintext check and limit false positives + tmps[gid].out[4] = out2[0]; + tmps[gid].out[5] = out2[1]; + tmps[gid].out[6] = out2[2]; + tmps[gid].out[7] = out2[3]; tmps[gid].digest[0] = digest[0]; tmps[gid].digest[1] = digest[1]; tmps[gid].digest[2] = digest[2]; tmps[gid].digest[3] = digest[3]; - - tmps[gid].out[0] = out[0]; - tmps[gid].out[1] = out[1]; - tmps[gid].out[2] = out[2]; - tmps[gid].out[3] = out[3]; - if ((gid == 0) && (lid == 0)) printf ("out[3]=%08x\n", out[3]); - - rc4_next_16 (S, 16, j, out2, out2, lid); // decrypt a second block of rc4 to improve plaintext check and limit false positives - if ((gid == 0) && (lid == 0)) printf ("out2[0]=%08x\n", out2[0]); - tmps[gid].out[4] = out2[0]; - if ((gid == 0) && (lid == 0)) printf ("tmps[gid].out[4]=%08x\n", tmps[gid].out[4]); - tmps[gid].out[5] = out2[1]; - tmps[gid].out[6] = out2[2]; - tmps[gid].out[7] = out2[3]; } KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) @@ -391,34 +387,34 @@ KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) { if (u8OutBufPtr[i] == u8OutPadPtr[i_padding]) { - if ((gid == 0) && (lid == 0)) printf("correct padding byte[%d]=0x%02x==0x%02x\n", i, u8OutBufPtr[i], u8OutPadPtr[i_padding]); + //if ((gid == 0) && (lid == 0)) printf("correct padding byte[%d]=0x%02x==0x%02x\n", i, u8OutBufPtr[i], u8OutPadPtr[i_padding]); i_padding = i_padding + 1; } else { if (u8OutBufPtr[i] >= 0x20 && u8OutBufPtr[i] <= 0x7e) { - if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); + //if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); } } } else { - if ((gid == 0) && (lid == 0)) { - printf("wrong byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); - - printf("u8OutBufPtr=0x"); - for(int j=0;j<32;j++) { - printf("%02x", u8OutBufPtr[j]); - } - printf("\n"); - - printf("u8OutPadPtr=0x"); - for(int j=0;j<32;j++) { - printf("%02x", u8OutPadPtr[j]); - } - printf("\n"); - } + //if ((gid == 0) && (lid == 0)) { + // printf("wrong byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); + // + // printf("u8OutBufPtr=0x"); + // for(int j=0;j<32;j++) { + // printf("%02x", u8OutBufPtr[j]); + // } + // printf("\n"); + // + // printf("u8OutPadPtr=0x"); + // for(int j=0;j<32;j++) { + // printf("%02x", u8OutPadPtr[j]); + // } + // printf("\n"); + //} correct = false; break; } diff --git a/docs/changes.txt b/docs/changes.txt index 83f5b75eb..cdb126c09 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -40,6 +40,7 @@ - Prevent Hashcat from hanging by checking during startup that the output file is a named pipe - Fixed debug mode 5 by adding the missing colon between original-word and finding-rule - Skip generated rule that was the result of chaining rule operation and caused this generated rule to exceed the maximum number of function calls +- Fixed incorrect plaintext check for 25400 and 26610. Increased plaintext check to 32 bytes for 25400 to prevent false positives. ## ## Technical From b035c6e408691f37d690c5fd7ba4caa0ec83dadc Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 8 Mar 2023 00:15:51 +0100 Subject: [PATCH 4/9] m26610 second block of AES-GCM also decrypting --- OpenCL/m26610-pure.cl | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/OpenCL/m26610-pure.cl b/OpenCL/m26610-pure.cl index ea0cac6e3..997a6ac1f 100644 --- a/OpenCL/m26610-pure.cl +++ b/OpenCL/m26610-pure.cl @@ -348,22 +348,37 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh AES_GCM_Prepare_J0 (iv, iv_len, subKey, J0); - //ct + //first block of ciphertext u32 ct[4] = { esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0], esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1], esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3] + esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3] }; + + // second block of ciphertext + u32 ct2[4] = { + esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4], + esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[5], + esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[6], + esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[7] + }; + //if ((gid == 0) && (lid == 0)) printf("esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]=0x%08x\n", esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]); + //if ((gid == 0) && (lid == 0)) printf("esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4]=0x%08x\n", esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4]); u32 pt[4] = { 0 }; + u32 pt2[4] = { 0 }; // we try to decrypt the ciphertext // TODO this can be moved to a separate decryption function in inc_cipher_aes-gcm.cl AES_GCM_inc32(J0); // the first ctr is used to compute the tag, only the second is used for decryption: https://en.wikipedia.org/wiki/Galois/Counter_Mode#/media/File:GCM-Galois_Counter_Mode_with_IV.svg - AES_GCM_GCTR (key, J0, ct, 16, pt, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the ciphertext + AES_GCM_GCTR (key, J0, ct, 16, pt, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the first block of ciphertext - // if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x\n", pt[0]); // should be 5b7b2274 or [{"type" + AES_GCM_inc32(J0); + AES_GCM_GCTR (key, J0, ct2, 16, pt2, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the second block of ciphertext + + //if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x\n", pt[0]); // should be 5b7b2274 or [{"type" + if ((gid == 0) && (lid == 0)) printf ("pt2[0]=%08x%08x\n", pt2[0], pt2[1]); // should be 2054726565222c22 or Tree"," // cast plaintext buffer to byte such that we can do a byte per byte comparison PRIVATE_AS const u32 *u32OutBufPtr = (PRIVATE_AS u32 *) pt; From 70885319f37e51cc89887b9d57ec6bc41706c347 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 8 Mar 2023 00:50:40 +0100 Subject: [PATCH 5/9] m26610 now also checking second block of plaintext, moved AES_GCM_decrypt to seperate function --- OpenCL/inc_cipher_aes-gcm.cl | 6 ++++++ OpenCL/inc_cipher_aes-gcm.h | 1 + OpenCL/m26610-pure.cl | 31 ++++++++++++------------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/OpenCL/inc_cipher_aes-gcm.cl b/OpenCL/inc_cipher_aes-gcm.cl index 388356a48..b882095c8 100644 --- a/OpenCL/inc_cipher_aes-gcm.cl +++ b/OpenCL/inc_cipher_aes-gcm.cl @@ -303,3 +303,9 @@ DECLSPEC void AES_GCM_GHASH_GLOBAL (PRIVATE_AS const u32 *subkey, PRIVATE_AS con AES_GCM_ghash (subkey, len_buf, 16, out); } + +void AES_GCM_decrypt (PRIVATE_AS u32 *key, PRIVATE_AS u32 *J0, PRIVATE_AS const u32 *in, int in_len, PRIVATE_AS u32 *out, SHM_TYPE u32 *s_te0, SHM_TYPE u32 *s_te1, SHM_TYPE u32 *s_te2, SHM_TYPE u32 *s_te3, SHM_TYPE u32 *s_te4) +{ + AES_GCM_inc32(J0); // the first ctr is used to compute the tag, only the second is used for decryption: https://en.wikipedia.org/wiki/Galois/Counter_Mode#/media/File:GCM-Galois_Counter_Mode_with_IV.svg + AES_GCM_GCTR (key, J0, in, in_len, out, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the first block of ciphertext +} \ No newline at end of file diff --git a/OpenCL/inc_cipher_aes-gcm.h b/OpenCL/inc_cipher_aes-gcm.h index 3c40c20b9..1b5e52d9f 100644 --- a/OpenCL/inc_cipher_aes-gcm.h +++ b/OpenCL/inc_cipher_aes-gcm.h @@ -17,5 +17,6 @@ DECLSPEC void AES_GCM_gctr (PRIVATE_AS const u32 *key, PRIVATE_AS const u32 *iv, DECLSPEC void AES_GCM_GCTR (PRIVATE_AS u32 *key, PRIVATE_AS u32 *J0, PRIVATE_AS const u32 *in, int in_len, PRIVATE_AS u32 *out, SHM_TYPE u32 *s_te0, SHM_TYPE u32 *s_te1, SHM_TYPE u32 *s_te2, SHM_TYPE u32 *s_te3, SHM_TYPE u32 *s_te4); DECLSPEC void AES_GCM_GHASH (PRIVATE_AS const u32 *subkey, PRIVATE_AS const u32 *aad_buf, int aad_len, PRIVATE_AS const u32 *enc_buf, int enc_len, PRIVATE_AS u32 *out); DECLSPEC void AES_GCM_GHASH_GLOBAL (PRIVATE_AS const u32 *subkey, PRIVATE_AS const u32 *aad_buf, int aad_len, GLOBAL_AS const u32 *enc_buf, int enc_len, PRIVATE_AS u32 *out); +DECLSPEC void AES_GCM_decrypt (PRIVATE_AS u32 *key, PRIVATE_AS u32 *J0, PRIVATE_AS const u32 *in, int in_len, PRIVATE_AS u32 *out, SHM_TYPE u32 *s_te0, SHM_TYPE u32 *s_te1, SHM_TYPE u32 *s_te2, SHM_TYPE u32 *s_te3, SHM_TYPE u32 *s_te4); #endif // INC_CIPHER_AES_GCM_H diff --git a/OpenCL/m26610-pure.cl b/OpenCL/m26610-pure.cl index 997a6ac1f..1431665d0 100644 --- a/OpenCL/m26610-pure.cl +++ b/OpenCL/m26610-pure.cl @@ -348,17 +348,12 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh AES_GCM_Prepare_J0 (iv, iv_len, subKey, J0); - //first block of ciphertext - u32 ct[4] = { - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0], + u32 ct[8] = { + esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0], //first block of ciphertext esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1], esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3] - }; - - // second block of ciphertext - u32 ct2[4] = { - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4], + esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3], + esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4], // second block of ciphertext esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[5], esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[6], esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[7] @@ -366,19 +361,17 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh //if ((gid == 0) && (lid == 0)) printf("esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]=0x%08x\n", esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]); //if ((gid == 0) && (lid == 0)) printf("esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4]=0x%08x\n", esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4]); - u32 pt[4] = { 0 }; - u32 pt2[4] = { 0 }; + u32 pt[8] = { 0 }; + AES_GCM_decrypt (key, J0, ct, 32, pt, s_te0, s_te1, s_te2, s_te3, s_te4); - // we try to decrypt the ciphertext - // TODO this can be moved to a separate decryption function in inc_cipher_aes-gcm.cl - AES_GCM_inc32(J0); // the first ctr is used to compute the tag, only the second is used for decryption: https://en.wikipedia.org/wiki/Galois/Counter_Mode#/media/File:GCM-Galois_Counter_Mode_with_IV.svg - AES_GCM_GCTR (key, J0, ct, 16, pt, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the first block of ciphertext - AES_GCM_inc32(J0); - AES_GCM_GCTR (key, J0, ct2, 16, pt2, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the second block of ciphertext + // TODO check entropy, but not sure what MAX_ENTROPY should be.. + //const float entropy = hc_get_entropy (pt, 8); + //printf("entropy=%f\n", entropy); + //if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x\n", pt[0]); // should be 5b7b2274 or [{"type" - if ((gid == 0) && (lid == 0)) printf ("pt2[0]=%08x%08x\n", pt2[0], pt2[1]); // should be 2054726565222c22 or Tree"," + //if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x%08x\n", pt[4], pt[5]); // should be 2054726565222c22 or Tree"," // cast plaintext buffer to byte such that we can do a byte per byte comparison PRIVATE_AS const u32 *u32OutBufPtr = (PRIVATE_AS u32 *) pt; @@ -389,7 +382,7 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh // if not, decryption was not successful bool correct = true; - for(int i=0;i<16;i++) + for(int i=0;i<32;i++) { if(u8OutBufPtr[i] >=0x20 && u8OutBufPtr[i] <= 0x7e) { //if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); From 6c653fa89d102da52b5e5475d0c81d024025168e Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 8 Mar 2023 00:53:25 +0100 Subject: [PATCH 6/9] m26610 also in changes --- docs/changes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changes.txt b/docs/changes.txt index cdb126c09..93909e8db 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -40,7 +40,7 @@ - Prevent Hashcat from hanging by checking during startup that the output file is a named pipe - Fixed debug mode 5 by adding the missing colon between original-word and finding-rule - Skip generated rule that was the result of chaining rule operation and caused this generated rule to exceed the maximum number of function calls -- Fixed incorrect plaintext check for 25400 and 26610. Increased plaintext check to 32 bytes for 25400 to prevent false positives. +- Fixed incorrect plaintext check for 25400 and 26610. Increased plaintext check to 32 bytes to prevent false positives. ## ## Technical From db9debdd1910fd29f9634db6bf4cf67840dad996 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 8 Mar 2023 21:06:11 +0100 Subject: [PATCH 7/9] resolve merge conflicts with master --- OpenCL/m26610-pure.cl | 85 ++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 54 deletions(-) diff --git a/OpenCL/m26610-pure.cl b/OpenCL/m26610-pure.cl index 1431665d0..4bc6bfbf3 100644 --- a/OpenCL/m26610-pure.cl +++ b/OpenCL/m26610-pure.cl @@ -335,12 +335,13 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh AES_GCM_Init (ukey, key_len, key, subKey, s_te0, s_te1, s_te2, s_te3, s_te4); // iv - const u32 iv[4] = { - esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[0], - esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[1], - esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[2], - esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[3] - }; + + u32 iv[4]; + + iv[0] = esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[0]; + iv[1] = esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[1]; + iv[2] = esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[2]; + iv[3] = esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[3]; const u32 iv_len = esalt_bufs[DIGESTS_OFFSET_HOST].iv_len; @@ -348,66 +349,42 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh AES_GCM_Prepare_J0 (iv, iv_len, subKey, J0); - u32 ct[8] = { - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0], //first block of ciphertext - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4], // second block of ciphertext - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[5], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[6], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[7] - }; - //if ((gid == 0) && (lid == 0)) printf("esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]=0x%08x\n", esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]); - //if ((gid == 0) && (lid == 0)) printf("esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4]=0x%08x\n", esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4]); - - u32 pt[8] = { 0 }; - AES_GCM_decrypt (key, J0, ct, 32, pt, s_te0, s_te1, s_te2, s_te3, s_te4); + //ct + u32 ct[4]; - // TODO check entropy, but not sure what MAX_ENTROPY should be.. - //const float entropy = hc_get_entropy (pt, 8); - //printf("entropy=%f\n", entropy); + ct[0] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0]; + ct[1] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1]; + ct[2] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2]; + ct[3] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]; + u32 pt[4] = { 0 }; - //if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x\n", pt[0]); // should be 5b7b2274 or [{"type" - //if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x%08x\n", pt[4], pt[5]); // should be 2054726565222c22 or Tree"," + // we try to decrypt the ciphertext + // TODO this can be moved to a separate decryption function in inc_cipher_aes-gcm.cl + AES_GCM_inc32(J0); // the first ctr is used to compute the tag, only the second is used for decryption: https://en.wikipedia.org/wiki/Galois/Counter_Mode#/media/File:GCM-Galois_Counter_Mode_with_IV.svg + AES_GCM_GCTR (key, J0, ct, 16, pt, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the ciphertext - // cast plaintext buffer to byte such that we can do a byte per byte comparison - PRIVATE_AS const u32 *u32OutBufPtr = (PRIVATE_AS u32 *) pt; - PRIVATE_AS const u8 *u8OutBufPtr = (PRIVATE_AS u8 *) u32OutBufPtr; + // if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x\n", pt[0]); // should be 5b7b2274 or [{"type" - // the best comparison I can think of is checking each byte - // whether it's ASCII, if so we're good, - // if not, decryption was not successful - bool correct = true; - - for(int i=0;i<32;i++) - { - if(u8OutBufPtr[i] >=0x20 && u8OutBufPtr[i] <= 0x7e) { - //if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); - } - else { - //if ((gid == 0) && (lid == 0)) printf("NOT correct! byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); - correct = false; - break; - } - } + u32 digest[4]; + + digest[0] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0]; + digest[1] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1]; + digest[2] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2]; + digest[3] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]; - const u32 digest[4] = - { - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2], - esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3], - }; - //if ((gid == 0) && (lid == 0)) printf ("ct[0]=%08x\n", ct[0]); //if ((gid == 0) && (lid == 0)) printf ("ct[1]=%08x\n", ct[1]); //if ((gid == 0) && (lid == 0)) printf ("ct[2]=%08x\n", ct[2]); //if ((gid == 0) && (lid == 0)) printf ("ct[3]=%08x\n", ct[3]); - if (correct) + const int correct = is_valid_printable_32 (pt[0]) + + is_valid_printable_32 (pt[1]) + + is_valid_printable_32 (pt[2]) + + is_valid_printable_32 (pt[3]); + + if (correct == 4) { int digest_pos = find_hash (digest, DIGESTS_CNT, &digests_buf[DIGESTS_OFFSET_HOST]); From c68602aa104e1b476670470ecc4795f6f70ebb1c Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 8 Mar 2023 21:29:13 +0100 Subject: [PATCH 8/9] m26610 add check for second block of plaintext --- OpenCL/m26610-pure.cl | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/OpenCL/m26610-pure.cl b/OpenCL/m26610-pure.cl index 4bc6bfbf3..e625af1c3 100644 --- a/OpenCL/m26610-pure.cl +++ b/OpenCL/m26610-pure.cl @@ -349,23 +349,23 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh AES_GCM_Prepare_J0 (iv, iv_len, subKey, J0); - //ct - - u32 ct[4]; - - ct[0] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0]; + u32 ct[8]; + ct[0] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0]; // first block of ciphertext ct[1] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1]; ct[2] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2]; ct[3] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]; + ct[4] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4]; // second block of ciphertext + ct[5] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[5]; + ct[6] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[6]; + ct[7] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[7]; - u32 pt[4] = { 0 }; + u32 pt[8] = { 0 }; - // we try to decrypt the ciphertext - // TODO this can be moved to a separate decryption function in inc_cipher_aes-gcm.cl - AES_GCM_inc32(J0); // the first ctr is used to compute the tag, only the second is used for decryption: https://en.wikipedia.org/wiki/Galois/Counter_Mode#/media/File:GCM-Galois_Counter_Mode_with_IV.svg - AES_GCM_GCTR (key, J0, ct, 16, pt, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the ciphertext + + AES_GCM_decrypt (key, J0, ct, 32, pt, s_te0, s_te1, s_te2, s_te3, s_te4); // if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x\n", pt[0]); // should be 5b7b2274 or [{"type" + // if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x%08x\n", pt[4], pt[5]); // should be 2054726565222c22 or Tree"," u32 digest[4]; @@ -382,9 +382,15 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh const int correct = is_valid_printable_32 (pt[0]) + is_valid_printable_32 (pt[1]) + is_valid_printable_32 (pt[2]) - + is_valid_printable_32 (pt[3]); + + is_valid_printable_32 (pt[3]) + + is_valid_printable_32 (pt[4]) + + is_valid_printable_32 (pt[5]) + + is_valid_printable_32 (pt[6]) + + is_valid_printable_32 (pt[7]); - if (correct == 4) + // if ((gid == 0) && (lid == 0)) printf("correct=%d\n", correct); + + if (correct == 8) { int digest_pos = find_hash (digest, DIGESTS_CNT, &digests_buf[DIGESTS_OFFSET_HOST]); From 4dc96cd76559144fcdbba93558c7026f79c5204a Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 8 Mar 2023 21:29:37 +0100 Subject: [PATCH 9/9] m25400 make use of new is_valid_printable --- OpenCL/m25400-pure.cl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenCL/m25400-pure.cl b/OpenCL/m25400-pure.cl index a027577d3..8ab75831c 100644 --- a/OpenCL/m25400-pure.cl +++ b/OpenCL/m25400-pure.cl @@ -382,7 +382,7 @@ KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) // we don't use the user-password in the attack now (as we don't need it), // however we could use it in the comparison of the decrypted o-value, // yet it may make this attack a bit more fragile, as now we just check for padding and ASCII - if ((u8OutBufPtr[i] >= 0x20 && u8OutBufPtr[i] <= 0x7e) || + if (is_valid_printable_8(u8OutBufPtr[i]) || (u8OutBufPtr[i] == u8OutPadPtr[i_padding])) { if (u8OutBufPtr[i] == u8OutPadPtr[i_padding]) @@ -392,7 +392,7 @@ KERNEL_FQ void m25400_comp (KERN_ATTR_TMPS_ESALT (pdf14_tmp_t, pdf_t)) } else { - if (u8OutBufPtr[i] >= 0x20 && u8OutBufPtr[i] <= 0x7e) + if (is_valid_printable_8(u8OutBufPtr[i])) { //if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]); }