diff --git a/OpenCL/m22600-pure.cl b/OpenCL/m22600-pure.cl new file mode 100644 index 000000000..46bedd975 --- /dev/null +++ b/OpenCL/m22600-pure.cl @@ -0,0 +1,529 @@ +/** + * Author......: See docs/credits.txt + * License.....: MIT + */ + +#define NEW_SIMD_CODE + +#ifdef KERNEL_STATIC +#include "inc_vendor.h" +#include "inc_types.h" +#include "inc_platform.cl" +#include "inc_common.cl" +#include "inc_simd.cl" +#include "inc_hash_sha1.cl" +#include "inc_cipher_aes.cl" +#endif + +typedef struct telegram_tmp +{ + u32 ipad[5]; + u32 opad[5]; + + u32 dgst[35]; + u32 out [35]; + +} telegram_tmp_t; + +typedef struct telegram +{ + u32 data[72]; + +} telegram_t; + +DECLSPEC void hmac_sha1_run_V (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad, u32x *digest) +{ + digest[0] = ipad[0]; + digest[1] = ipad[1]; + digest[2] = ipad[2]; + digest[3] = ipad[3]; + digest[4] = ipad[4]; + + sha1_transform_vector (w0, w1, w2, w3, digest); + + w0[0] = digest[0]; + w0[1] = digest[1]; + w0[2] = digest[2]; + w0[3] = digest[3]; + w1[0] = digest[4]; + w1[1] = 0x80000000; + w1[2] = 0; + w1[3] = 0; + w2[0] = 0; + w2[1] = 0; + w2[2] = 0; + w2[3] = 0; + w3[0] = 0; + w3[1] = 0; + w3[2] = 0; + w3[3] = (64 + 20) * 8; + + digest[0] = opad[0]; + digest[1] = opad[1]; + digest[2] = opad[2]; + digest[3] = opad[3]; + digest[4] = opad[4]; + + sha1_transform_vector (w0, w1, w2, w3, digest); +} + +DECLSPEC void sha1_run (u32 *w, u32 *res) +{ + u32 w0[4]; + u32 w1[4]; + u32 w2[4]; + u32 w3[4]; + + w0[0] = w[ 0]; + w0[1] = w[ 1]; + w0[2] = w[ 2]; + w0[3] = w[ 3]; + w1[0] = w[ 4]; + w1[1] = w[ 5]; + w1[2] = w[ 6]; + w1[3] = w[ 7]; + w2[0] = w[ 8]; + w2[1] = w[ 9]; + w2[2] = w[10]; + w2[3] = w[11]; + w3[0] = 0x80000000; + w3[1] = 0; + w3[2] = 0; + w3[3] = 48 * 8; + + u32 digest[5]; + + digest[0] = SHA1M_A; + digest[1] = SHA1M_B; + digest[2] = SHA1M_C; + digest[3] = SHA1M_D; + digest[4] = SHA1M_E; + + sha1_transform (w0, w1, w2, w3, digest); + + res[0] = digest[0]; + res[1] = digest[1]; + res[2] = digest[2]; + res[3] = digest[3]; + res[4] = digest[4]; +} + +KERNEL_FQ void m22600_init (KERN_ATTR_TMPS_ESALT (telegram_tmp_t, telegram_t)) +{ + /** + * base + */ + + const u64 gid = get_global_id (0); + + if (gid >= gid_max) return; + + sha1_hmac_ctx_t sha1_hmac_ctx; + + sha1_hmac_init_global_swap (&sha1_hmac_ctx, pws[gid].i, pws[gid].pw_len); + + tmps[gid].ipad[0] = sha1_hmac_ctx.ipad.h[0]; + tmps[gid].ipad[1] = sha1_hmac_ctx.ipad.h[1]; + tmps[gid].ipad[2] = sha1_hmac_ctx.ipad.h[2]; + tmps[gid].ipad[3] = sha1_hmac_ctx.ipad.h[3]; + tmps[gid].ipad[4] = sha1_hmac_ctx.ipad.h[4]; + + tmps[gid].opad[0] = sha1_hmac_ctx.opad.h[0]; + tmps[gid].opad[1] = sha1_hmac_ctx.opad.h[1]; + tmps[gid].opad[2] = sha1_hmac_ctx.opad.h[2]; + tmps[gid].opad[3] = sha1_hmac_ctx.opad.h[3]; + tmps[gid].opad[4] = sha1_hmac_ctx.opad.h[4]; + + // salt length is always 32 bytes: + + sha1_hmac_update_global_swap (&sha1_hmac_ctx, salt_bufs[salt_pos].salt_buf, salt_bufs[salt_pos].salt_len); + + for (u32 i = 0, j = 1; i < 34; i += 5, j += 1) + { + sha1_hmac_ctx_t sha1_hmac_ctx2 = sha1_hmac_ctx; + + u32 w0[4]; + u32 w1[4]; + u32 w2[4]; + u32 w3[4]; + + w0[0] = j; + w0[1] = 0; + w0[2] = 0; + w0[3] = 0; + w1[0] = 0; + w1[1] = 0; + w1[2] = 0; + w1[3] = 0; + w2[0] = 0; + w2[1] = 0; + w2[2] = 0; + w2[3] = 0; + w3[0] = 0; + w3[1] = 0; + w3[2] = 0; + w3[3] = 0; + + sha1_hmac_update_64 (&sha1_hmac_ctx2, w0, w1, w2, w3, 4); + + sha1_hmac_final (&sha1_hmac_ctx2); + + tmps[gid].dgst[i + 0] = sha1_hmac_ctx2.opad.h[0]; + tmps[gid].dgst[i + 1] = sha1_hmac_ctx2.opad.h[1]; + tmps[gid].dgst[i + 2] = sha1_hmac_ctx2.opad.h[2]; + tmps[gid].dgst[i + 3] = sha1_hmac_ctx2.opad.h[3]; + tmps[gid].dgst[i + 4] = sha1_hmac_ctx2.opad.h[4]; + + tmps[gid].out[i + 0] = tmps[gid].dgst[i + 0]; + tmps[gid].out[i + 1] = tmps[gid].dgst[i + 1]; + tmps[gid].out[i + 2] = tmps[gid].dgst[i + 2]; + tmps[gid].out[i + 3] = tmps[gid].dgst[i + 3]; + tmps[gid].out[i + 4] = tmps[gid].dgst[i + 4]; + } +} + +KERNEL_FQ void m22600_loop (KERN_ATTR_TMPS_ESALT (telegram_tmp_t, telegram_t)) +{ + const u64 gid = get_global_id (0); + + if ((gid * VECT_SIZE) >= gid_max) return; + + u32x ipad[5]; + u32x opad[5]; + + ipad[0] = packv (tmps, ipad, gid, 0); + ipad[1] = packv (tmps, ipad, gid, 1); + ipad[2] = packv (tmps, ipad, gid, 2); + ipad[3] = packv (tmps, ipad, gid, 3); + ipad[4] = packv (tmps, ipad, gid, 4); + + opad[0] = packv (tmps, opad, gid, 0); + opad[1] = packv (tmps, opad, gid, 1); + opad[2] = packv (tmps, opad, gid, 2); + opad[3] = packv (tmps, opad, gid, 3); + opad[4] = packv (tmps, opad, gid, 4); + + for (u32 i = 0; i < 34; i += 5) + { + u32x dgst[5]; + u32x out[5]; + + dgst[0] = packv (tmps, dgst, gid, i + 0); + dgst[1] = packv (tmps, dgst, gid, i + 1); + dgst[2] = packv (tmps, dgst, gid, i + 2); + dgst[3] = packv (tmps, dgst, gid, i + 3); + dgst[4] = packv (tmps, dgst, gid, i + 4); + + out[0] = packv (tmps, out, gid, i + 0); + out[1] = packv (tmps, out, gid, i + 1); + out[2] = packv (tmps, out, gid, i + 2); + out[3] = packv (tmps, out, gid, i + 3); + out[4] = packv (tmps, out, gid, i + 4); + + for (u32 j = 0; j < loop_cnt; j++) + { + u32x w0[4]; + u32x w1[4]; + u32x w2[4]; + u32x w3[4]; + + w0[0] = dgst[0]; + w0[1] = dgst[1]; + w0[2] = dgst[2]; + w0[3] = dgst[3]; + w1[0] = dgst[4]; + w1[1] = 0x80000000; + w1[2] = 0; + w1[3] = 0; + w2[0] = 0; + w2[1] = 0; + w2[2] = 0; + w2[3] = 0; + w3[0] = 0; + w3[1] = 0; + w3[2] = 0; + w3[3] = (64 + 20) * 8; + + hmac_sha1_run_V (w0, w1, w2, w3, ipad, opad, dgst); + + out[0] ^= dgst[0]; + out[1] ^= dgst[1]; + out[2] ^= dgst[2]; + out[3] ^= dgst[3]; + out[4] ^= dgst[4]; + } + + unpackv (tmps, dgst, gid, i + 0, dgst[0]); + unpackv (tmps, dgst, gid, i + 1, dgst[1]); + unpackv (tmps, dgst, gid, i + 2, dgst[2]); + unpackv (tmps, dgst, gid, i + 3, dgst[3]); + unpackv (tmps, dgst, gid, i + 4, dgst[4]); + + unpackv (tmps, out, gid, i + 0, out[0]); + unpackv (tmps, out, gid, i + 1, out[1]); + unpackv (tmps, out, gid, i + 2, out[2]); + unpackv (tmps, out, gid, i + 3, out[3]); + unpackv (tmps, out, gid, i + 4, out[4]); + } +} + +KERNEL_FQ void m22600_comp (KERN_ATTR_TMPS_ESALT (telegram_tmp_t, telegram_t)) +{ + /** + * base + */ + + const u64 gid = get_global_id (0); + const u64 lid = get_local_id (0); + const u64 lsz = get_local_size (0); + + /** + * aes shared + */ + + #ifdef REAL_SHM + + LOCAL_VK u32 s_td0[256]; + LOCAL_VK u32 s_td1[256]; + LOCAL_VK u32 s_td2[256]; + LOCAL_VK u32 s_td3[256]; + LOCAL_VK u32 s_td4[256]; + + LOCAL_VK u32 s_te0[256]; + LOCAL_VK u32 s_te1[256]; + LOCAL_VK u32 s_te2[256]; + LOCAL_VK u32 s_te3[256]; + LOCAL_VK u32 s_te4[256]; + + for (u32 i = lid; i < 256; i += lsz) + { + s_td0[i] = td0[i]; + s_td1[i] = td1[i]; + s_td2[i] = td2[i]; + s_td3[i] = td3[i]; + s_td4[i] = td4[i]; + + s_te0[i] = te0[i]; + s_te1[i] = te1[i]; + s_te2[i] = te2[i]; + s_te3[i] = te3[i]; + s_te4[i] = te4[i]; + } + + SYNC_THREADS (); + + #else + + CONSTANT_AS u32a *s_td0 = td0; + CONSTANT_AS u32a *s_td1 = td1; + CONSTANT_AS u32a *s_td2 = td2; + CONSTANT_AS u32a *s_td3 = td3; + CONSTANT_AS u32a *s_td4 = td4; + + CONSTANT_AS u32a *s_te0 = te0; + CONSTANT_AS u32a *s_te1 = te1; + CONSTANT_AS u32a *s_te2 = te2; + CONSTANT_AS u32a *s_te3 = te3; + CONSTANT_AS u32a *s_te4 = te4; + + #endif + + if (gid >= gid_max) return; + + u32 message_key[4]; + + message_key[0] = esalt_bufs[digests_offset].data[0]; + message_key[1] = esalt_bufs[digests_offset].data[1]; + message_key[2] = esalt_bufs[digests_offset].data[2]; + message_key[3] = esalt_bufs[digests_offset].data[3]; + + u32 data_a[12]; + u32 data_b[12]; + u32 data_c[12]; + u32 data_d[12]; + + data_a[ 0] = message_key[0]; + data_a[ 1] = message_key[1]; + data_a[ 2] = message_key[2]; + data_a[ 3] = message_key[3]; + + data_b[ 4] = message_key[0]; + data_b[ 5] = message_key[1]; + data_b[ 6] = message_key[2]; + data_b[ 7] = message_key[3]; + + data_c[ 8] = message_key[0]; + data_c[ 9] = message_key[1]; + data_c[10] = message_key[2]; + data_c[11] = message_key[3]; + + data_d[ 0] = message_key[0]; + data_d[ 1] = message_key[1]; + data_d[ 2] = message_key[2]; + data_d[ 3] = message_key[3]; + + data_a[ 4] = tmps[gid].out[ 2]; // not a bug: out[0], out[1] are ignored + data_a[ 5] = tmps[gid].out[ 3]; + data_a[ 6] = tmps[gid].out[ 4]; + data_a[ 7] = tmps[gid].out[ 5]; + data_a[ 8] = tmps[gid].out[ 6]; + data_a[ 9] = tmps[gid].out[ 7]; + data_a[10] = tmps[gid].out[ 8]; + data_a[11] = tmps[gid].out[ 9]; + + data_b[ 0] = tmps[gid].out[10]; + data_b[ 1] = tmps[gid].out[11]; + data_b[ 2] = tmps[gid].out[12]; + data_b[ 3] = tmps[gid].out[13]; + + data_b[ 8] = tmps[gid].out[14]; + data_b[ 9] = tmps[gid].out[15]; + data_b[10] = tmps[gid].out[16]; + data_b[11] = tmps[gid].out[17]; + + data_c[ 0] = tmps[gid].out[18]; + data_c[ 1] = tmps[gid].out[19]; + data_c[ 2] = tmps[gid].out[20]; + data_c[ 3] = tmps[gid].out[21]; + data_c[ 4] = tmps[gid].out[22]; + data_c[ 5] = tmps[gid].out[23]; + data_c[ 6] = tmps[gid].out[24]; + data_c[ 7] = tmps[gid].out[25]; + + data_d[ 4] = tmps[gid].out[26]; + data_d[ 5] = tmps[gid].out[27]; + data_d[ 6] = tmps[gid].out[28]; + data_d[ 7] = tmps[gid].out[29]; + data_d[ 8] = tmps[gid].out[30]; + data_d[ 9] = tmps[gid].out[31]; + data_d[10] = tmps[gid].out[32]; + data_d[11] = tmps[gid].out[33]; + + // hash (SHA1 ()) the data_*: + + u32 a[5]; + + sha1_run (data_a, a); + + u32 b[5]; + + sha1_run (data_b, b); + + u32 c[5]; + + sha1_run (data_c, c); + + u32 d[5]; + + sha1_run (data_d, d); + + // set up AES key and AES IV: + + u32 key[8]; + + key[0] = a[0]; + key[1] = a[1]; + key[2] = b[2]; + key[3] = b[3]; + key[4] = b[4]; + key[5] = c[1]; + key[6] = c[2]; + key[7] = c[3]; + + u32 iv[8]; + + iv[0] = a[2]; + iv[1] = a[3]; + iv[2] = a[4]; + iv[3] = b[0]; + iv[4] = b[1]; + iv[5] = c[4]; + iv[6] = d[0]; + iv[7] = d[1]; + + // decrypt with AES-IGE: + + #define KEYLEN 60 + + u32 ks[KEYLEN]; + + AES256_set_decrypt_key (ks, key, s_te0, s_te1, s_te2, s_te3, s_td0, s_td1, s_td2, s_td3); + + u32 x_prev[4]; + + x_prev[0] = iv[0]; + x_prev[1] = iv[1]; + x_prev[2] = iv[2]; + x_prev[3] = iv[3]; + + u32 y_prev[4]; + + y_prev[0] = iv[4]; + y_prev[1] = iv[5]; + y_prev[2] = iv[6]; + y_prev[3] = iv[7]; + + u32 out[80] = { 0 }; // 64-byte aligned for SHA1 + + for (int i = 0; i < 68; i += 4) + { + u32 x[4]; + + x[0] = esalt_bufs[digests_offset].data[4 + i]; + x[1] = esalt_bufs[digests_offset].data[5 + i]; + x[2] = esalt_bufs[digests_offset].data[6 + i]; + x[3] = esalt_bufs[digests_offset].data[7 + i]; + + u32 y[4]; + + y[0] = x[0] ^ y_prev[0]; + y[1] = x[1] ^ y_prev[1]; + y[2] = x[2] ^ y_prev[2]; + y[3] = x[3] ^ y_prev[3]; + + u32 dec[4]; + + AES256_decrypt (ks, y, dec, s_td0, s_td1, s_td2, s_td3, s_td4); + + y_prev[0] = dec[0] ^ x_prev[0]; + y_prev[1] = dec[1] ^ x_prev[1]; + y_prev[2] = dec[2] ^ x_prev[2]; + y_prev[3] = dec[3] ^ x_prev[3]; + + out[i + 0] = y_prev[0]; + out[i + 1] = y_prev[1]; + out[i + 2] = y_prev[2]; + out[i + 3] = y_prev[3]; + + x_prev[0] = x[0]; + x_prev[1] = x[1]; + x_prev[2] = x[2]; + x_prev[3] = x[3]; + } + + // final SHA1 checksum of the decrypted data (out): + + sha1_ctx_t ctx; + + sha1_init (&ctx); + sha1_update (&ctx, out, 272); + sha1_final (&ctx); + + const u32 r0 = ctx.h[0]; + const u32 r1 = ctx.h[1]; + const u32 r2 = ctx.h[2]; + const u32 r3 = ctx.h[3]; + + // verify: + + if (r0 == message_key[0] && + r1 == message_key[1] && + r2 == message_key[2] && + r3 == message_key[3]) + { + if (atomic_inc (&hashes_shown[digests_offset]) == 0) + { + mark_hash (plains_buf, d_return_buf, salt_pos, digests_cnt, 0, digests_offset + 0, gid, 0, 0, 0); + } + } +} diff --git a/docs/changes.txt b/docs/changes.txt index 74457c42f..864d1cc47 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -64,7 +64,8 @@ - Added hash-mode: sha256(sha256_bin($pass)) - Added hash-mode: sha256(sha256($pass).$salt) - Added hash-mode: SolarWinds Orion -- Added hash-mode: Telegram client app passcode (SHA256) +- Added hash-mode: Telegram Desktop App Passcode (PBKDF2-HMAC-SHA1) +- Added hash-mode: Telegram Mobile App Passcode (SHA256) - Added hash-mode: Web2py pbkdf2-sha512 - Added hash-mode: WPA-PBKDF2-PMKID+EAPOL - Added hash-mode: WPA-PMK-PMKID+EAPOL diff --git a/docs/hashcat-plugin-development-guide.md b/docs/hashcat-plugin-development-guide.md index b764145b6..0aa85db22 100644 --- a/docs/hashcat-plugin-development-guide.md +++ b/docs/hashcat-plugin-development-guide.md @@ -528,7 +528,7 @@ Additionally there is a couple of command line parameters that you want to use: * --potfile-disable: The moment when your implementation is almost complete and you start cracking the hash for the first time as expected it is very likely it will turn out some other things are not perfect. For instance, the encoding of the cracked hash. So you need to change some code and run hashcat again to verify this option will prevent hashcat from writing the cracked hash to the potfile. This will allow you to restart hashcat without the need to remove the potfile manually. * --self-test-disable: The self-test feature serves to test the kernel each time the user starts hashcat to ensure it works on the users hardware as expected. Hashcat does not know you are implementing a new kernel, so it will call the kernel you are implementing, too. This has two unwanted side-effects. First, it will print a self-test failure which is clear to us, but not to hashcat. Second and more relevant, if you use printf(), it is very likely to print values which you are not expecting. This is because you are expecting values based on the hash or password you gave on the command line, not the values produced by the self-test hash or self-test password. If you use the same hash and password, you may wonder why it is printed twice. -* -n 1 -u 1 -T 1: The combination of these three options with these exact values will disable the auto tune. This is hardcoded into hashcat. This is an undocumented feature. The auto tune will create the same problems as the self-test feature. +* -n 1 -u 1 -T 1: The combination of these three options with these exact values will disable the auto tune. This is hardcoded into hashcat. This is an undocumented feature. The auto tune will create the same problems as the self-test feature. You need to use --force to be able to use these manual tuning parameters. * --quiet: When you are expecting printf() results, try to limit the hashcat output to a minimum. The printf() itself is not affected by this option. * --backend-vector-width 1: Only required if you are developing the kernel by using a CPU as compute device. Printing elements from vector data types is possible (for instance `printf (a.s1);`), but we should avoid any influence. Some OpenCL runtimes even support printf() of a vector data type, which results in very weird outputs. * -d 1: In case you have multi compute devices in your system, limit it to a single compute device. This is to reduce startup and JiT compile time. diff --git a/docs/readme.txt b/docs/readme.txt index e550b3c81..baa1883c3 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -159,7 +159,8 @@ NVIDIA GPUs require "NVIDIA Driver" (440.64 or later) and "CUDA Toolkit" (9.0 or - NetNTLMv1 / NetNTLMv1+ESS - NetNTLMv2 - Skype -- Telegram client app passcode (SHA256) +- Telegram Desktop App Passcode (PBKDF2-HMAC-SHA1) +- Telegram Mobile App Passcode (SHA256) - PostgreSQL CRAM (MD5) - MySQL CRAM (SHA1) - RACF diff --git a/src/backend.c b/src/backend.c index 2843d6f71..8feaa2b4e 100644 --- a/src/backend.c +++ b/src/backend.c @@ -373,9 +373,9 @@ static bool opencl_test_instruction (hashcat_ctx_t *hashcat_ctx, cl_context cont OCL_PTR *ocl = (OCL_PTR *) backend_ctx->ocl; - const int fd_stderr = fileno (stderr); #ifndef DEBUG + const int fd_stderr = fileno (stderr); const int stderr_bak = dup (fd_stderr); #ifdef _WIN const int tmp = open ("NUL", O_WRONLY); diff --git a/src/modules/module_22301.c b/src/modules/module_22301.c index cda57a6e7..b0500f6f7 100644 --- a/src/modules/module_22301.c +++ b/src/modules/module_22301.c @@ -16,8 +16,8 @@ static const u32 DGST_POS1 = 7; static const u32 DGST_POS2 = 2; static const u32 DGST_POS3 = 6; static const u32 DGST_SIZE = DGST_SIZE_4_8; -static const u32 HASH_CATEGORY = HASH_CATEGORY_RAW_HASH_SALTED; -static const char *HASH_NAME = "Telegram client app passcode (SHA256)"; +static const u32 HASH_CATEGORY = HASH_CATEGORY_NETWORK_PROTOCOL; +static const char *HASH_NAME = "Telegram Mobile App Passcode (SHA256)"; static const u64 KERN_TYPE = 22300; static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE | OPTI_TYPE_PRECOMPUTE_INIT diff --git a/src/modules/module_22600.c b/src/modules/module_22600.c new file mode 100644 index 000000000..0780812fc --- /dev/null +++ b/src/modules/module_22600.c @@ -0,0 +1,296 @@ +/** + * Author......: See docs/credits.txt + * License.....: MIT + */ + +#include "common.h" +#include "types.h" +#include "modules.h" +#include "bitops.h" +#include "convert.h" +#include "shared.h" + +static const u32 ATTACK_EXEC = ATTACK_EXEC_OUTSIDE_KERNEL; +static const u32 DGST_POS0 = 0; +static const u32 DGST_POS1 = 1; +static const u32 DGST_POS2 = 2; +static const u32 DGST_POS3 = 3; +static const u32 DGST_SIZE = DGST_SIZE_4_4; +static const u32 HASH_CATEGORY = HASH_CATEGORY_NETWORK_PROTOCOL; +static const char *HASH_NAME = "Telegram Desktop App Passcode (PBKDF2-HMAC-SHA1)"; +static const u64 KERN_TYPE = 22600; +static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE + | OPTI_TYPE_SLOW_HASH_SIMD_LOOP; +static const u64 OPTS_TYPE = OPTS_TYPE_PT_GENERATE_LE; +static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED; +static const char *ST_PASS = "hashcat"; +static const char *ST_HASH = "$telegram$1*4000*913a7e42143b4eed0fb532dacfa04e3a0eae036ae66dd02de76323046c575531*cde5f7a3bda3812b4a3cd4df1269c6be18ca7536981522c251cab531c274776804634cdca5313dc8beb9895f903a40d874cd50dbb82e5e4d8f264820f3f2e2111a5831e1a2f16b1a75b2264c4b4485dfe0f789071130160af205f9f96aef378ee05602de2562f8c3b136a75ea01f54f4598af93f9e7f98eb66a5fd3dabaa864708fe0e84b59b77686974060f1533e3acc5367bc493915b5614603cf5601cfa0a6b8eae4c4bd24948176dd7ff470bc0863f35fdfce31a667c70e37743f662bc9c5ec86baff3ebb6bf7de96bcdfaca18baf9617a979424f792ef6e65e346ea2cbc1d53377f47c3fc681d7eda8169e6e20cd6a22dd94bf24933b8ffc4878216fa9edc7c72a073446a14b63e12b223f840217a7eac51b6afcc15bfa12afd3e85d3bd"; + +u32 module_attack_exec (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ATTACK_EXEC; } +u32 module_dgst_pos0 (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS0; } +u32 module_dgst_pos1 (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS1; } +u32 module_dgst_pos2 (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS2; } +u32 module_dgst_pos3 (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS3; } +u32 module_dgst_size (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_SIZE; } +u32 module_hash_category (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return HASH_CATEGORY; } +const char *module_hash_name (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return HASH_NAME; } +u64 module_kern_type (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return KERN_TYPE; } +u32 module_opti_type (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return OPTI_TYPE; } +u64 module_opts_type (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return OPTS_TYPE; } +u32 module_salt_type (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return SALT_TYPE; } +const char *module_st_hash (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_HASH; } +const char *module_st_pass (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_PASS; } + +typedef struct telegram_tmp +{ + u32 ipad[5]; + u32 opad[5]; + + u32 dgst[35]; + u32 out [35]; + +} telegram_tmp_t; + +typedef struct telegram +{ + u32 data[72]; + +} telegram_t; + +static const char *SIGNATURE_TELEGRAM = "$telegram$"; +static const int DATA_LEN_TELEGRAM = 288; +static const int SALT_LEN_TELEGRAM = 32; + +u64 module_esalt_size (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) +{ + const u64 esalt_size = (const u64) sizeof (telegram_t); + + return esalt_size; +} + +u64 module_tmp_size (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) +{ + const u64 tmp_size = (const u64) sizeof (telegram_tmp_t); + + return tmp_size; +} + +u32 module_pw_max (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) +{ + // this overrides the reductions of PW_MAX in case optimized kernel is selected + // IOW, even in optimized kernel mode it support length 256 + + const u32 pw_max = PW_MAX; + + return pw_max; +} + +int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED void *digest_buf, MAYBE_UNUSED salt_t *salt, MAYBE_UNUSED void *esalt_buf, MAYBE_UNUSED void *hook_salt_buf, MAYBE_UNUSED hashinfo_t *hash_info, const char *line_buf, MAYBE_UNUSED const int line_len) +{ + u32 *digest = (u32 *) digest_buf; + + telegram_t *telegram = (telegram_t *) esalt_buf; + + token_t token; + + token.token_cnt = 5; + + token.signatures_cnt = 1; + token.signatures_buf[0] = SIGNATURE_TELEGRAM; + + token.len[0] = 10; + token.attr[0] = TOKEN_ATTR_FIXED_LENGTH + | TOKEN_ATTR_VERIFY_SIGNATURE; + + token.sep[1] = '*'; + token.len_min[1] = 1; + token.len_max[1] = 1; + token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH + | TOKEN_ATTR_VERIFY_DIGIT; + + token.sep[2] = '*'; + token.len_min[2] = 1; + token.len_max[2] = 5; + token.attr[2] = TOKEN_ATTR_VERIFY_LENGTH + | TOKEN_ATTR_VERIFY_DIGIT; + + token.sep[3] = '*'; + token.len_min[3] = 64; + token.len_max[3] = 64; + token.attr[3] = TOKEN_ATTR_VERIFY_LENGTH + | TOKEN_ATTR_VERIFY_HEX; + + token.sep[4] = '*'; + token.len_min[4] = DATA_LEN_TELEGRAM * 2; + token.len_max[4] = DATA_LEN_TELEGRAM * 2; + token.attr[4] = TOKEN_ATTR_VERIFY_LENGTH + | TOKEN_ATTR_VERIFY_HEX; + + const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token); + + if (rc_tokenizer != PARSER_OK) return (rc_tokenizer); + + u8 version = token.buf[1][0]; + + if (version != '1') return (PARSER_SALT_VALUE); + + // iter + + const u8 *iter_pos = token.buf[2]; + + salt->salt_iter = hc_strtoul ((const char *) iter_pos, NULL, 10); + + if (salt->salt_iter < 2) return (PARSER_SALT_ITERATION); + + salt->salt_iter--; + + // salt + + const u8 *salt_pos = token.buf[3]; + + salt->salt_buf[0] = hex_to_u32 (salt_pos + 0); + salt->salt_buf[1] = hex_to_u32 (salt_pos + 8); + salt->salt_buf[2] = hex_to_u32 (salt_pos + 16); + salt->salt_buf[3] = hex_to_u32 (salt_pos + 24); + salt->salt_buf[4] = hex_to_u32 (salt_pos + 32); + salt->salt_buf[5] = hex_to_u32 (salt_pos + 40); + salt->salt_buf[6] = hex_to_u32 (salt_pos + 48); + salt->salt_buf[7] = hex_to_u32 (salt_pos + 56); + + salt->salt_len = SALT_LEN_TELEGRAM; + + // digest + + const u8 *message_pos = token.buf[4]; + + digest[0] = hex_to_u32 (message_pos + 0); + digest[1] = hex_to_u32 (message_pos + 8); + digest[2] = hex_to_u32 (message_pos + 16); + digest[3] = hex_to_u32 (message_pos + 24); + + // data + + for (int i = 0, j = 0; i < DATA_LEN_TELEGRAM / 4; i += 1, j += 8) + { + telegram->data[i] = hex_to_u32 (message_pos + j); + + telegram->data[i] = byte_swap_32 (telegram->data[i]); + } + + return (PARSER_OK); +} + +int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const void *digest_buf, MAYBE_UNUSED const salt_t *salt, MAYBE_UNUSED const void *esalt_buf, MAYBE_UNUSED const void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size) +{ + const telegram_t *telegram = (const telegram_t *) esalt_buf; + + // salt + + #define SALT_BUF_LEN (SALT_LEN_TELEGRAM * 2 + 1) + + char salt_buf[SALT_BUF_LEN]; + + memset (salt_buf, 0, SALT_BUF_LEN); + + for (int i = 0, j = 0; i < SALT_LEN_TELEGRAM / 4; i += 1, j += 8) + { + snprintf (salt_buf + j, SALT_BUF_LEN - j, "%08x", byte_swap_32 (salt->salt_buf[i])); + } + + // message + + #define DATA_BUF_LEN (DATA_LEN_TELEGRAM * 2 + 1) + + char message[DATA_BUF_LEN]; + + memset (message, 0, DATA_BUF_LEN); + + for (int i = 0, j = 0; i < DATA_LEN_TELEGRAM / 4; i += 1, j += 8) + { + snprintf (message + j, DATA_BUF_LEN - j, "%08x", telegram->data[i]); + } + + // output + + const int line_len = snprintf (line_buf, line_size, "%s%i*%i*%s*%s", + SIGNATURE_TELEGRAM, + 1, + salt->salt_iter + 1, + salt_buf, + message); + + return line_len; +} + +void module_init (module_ctx_t *module_ctx) +{ + module_ctx->module_context_size = MODULE_CONTEXT_SIZE_CURRENT; + module_ctx->module_interface_version = MODULE_INTERFACE_VERSION_CURRENT; + + module_ctx->module_attack_exec = module_attack_exec; + module_ctx->module_benchmark_esalt = MODULE_DEFAULT; + module_ctx->module_benchmark_hook_salt = MODULE_DEFAULT; + module_ctx->module_benchmark_mask = MODULE_DEFAULT; + module_ctx->module_benchmark_salt = MODULE_DEFAULT; + module_ctx->module_build_plain_postprocess = MODULE_DEFAULT; + module_ctx->module_deep_comp_kernel = MODULE_DEFAULT; + module_ctx->module_dgst_pos0 = module_dgst_pos0; + module_ctx->module_dgst_pos1 = module_dgst_pos1; + module_ctx->module_dgst_pos2 = module_dgst_pos2; + module_ctx->module_dgst_pos3 = module_dgst_pos3; + module_ctx->module_dgst_size = module_dgst_size; + module_ctx->module_dictstat_disable = MODULE_DEFAULT; + module_ctx->module_esalt_size = module_esalt_size; + module_ctx->module_extra_buffer_size = MODULE_DEFAULT; + module_ctx->module_extra_tmp_size = MODULE_DEFAULT; + module_ctx->module_forced_outfile_format = MODULE_DEFAULT; + module_ctx->module_hash_binary_count = MODULE_DEFAULT; + module_ctx->module_hash_binary_parse = MODULE_DEFAULT; + module_ctx->module_hash_binary_save = MODULE_DEFAULT; + module_ctx->module_hash_decode_potfile = MODULE_DEFAULT; + module_ctx->module_hash_decode_zero_hash = MODULE_DEFAULT; + module_ctx->module_hash_decode = module_hash_decode; + module_ctx->module_hash_encode_status = MODULE_DEFAULT; + module_ctx->module_hash_encode_potfile = MODULE_DEFAULT; + module_ctx->module_hash_encode = module_hash_encode; + module_ctx->module_hash_init_selftest = MODULE_DEFAULT; + module_ctx->module_hash_mode = MODULE_DEFAULT; + module_ctx->module_hash_category = module_hash_category; + module_ctx->module_hash_name = module_hash_name; + module_ctx->module_hashes_count_min = MODULE_DEFAULT; + module_ctx->module_hashes_count_max = MODULE_DEFAULT; + module_ctx->module_hlfmt_disable = MODULE_DEFAULT; + module_ctx->module_hook12 = MODULE_DEFAULT; + module_ctx->module_hook23 = MODULE_DEFAULT; + module_ctx->module_hook_salt_size = MODULE_DEFAULT; + module_ctx->module_hook_size = MODULE_DEFAULT; + module_ctx->module_jit_build_options = MODULE_DEFAULT; + module_ctx->module_jit_cache_disable = MODULE_DEFAULT; + module_ctx->module_kernel_accel_max = MODULE_DEFAULT; + module_ctx->module_kernel_accel_min = MODULE_DEFAULT; + module_ctx->module_kernel_loops_max = MODULE_DEFAULT; + module_ctx->module_kernel_loops_min = MODULE_DEFAULT; + module_ctx->module_kernel_threads_max = MODULE_DEFAULT; + module_ctx->module_kernel_threads_min = MODULE_DEFAULT; + module_ctx->module_kern_type = module_kern_type; + module_ctx->module_kern_type_dynamic = MODULE_DEFAULT; + module_ctx->module_opti_type = module_opti_type; + module_ctx->module_opts_type = module_opts_type; + module_ctx->module_outfile_check_disable = MODULE_DEFAULT; + module_ctx->module_outfile_check_nocomp = MODULE_DEFAULT; + module_ctx->module_potfile_custom_check = MODULE_DEFAULT; + module_ctx->module_potfile_disable = MODULE_DEFAULT; + module_ctx->module_potfile_keep_all_hashes = MODULE_DEFAULT; + module_ctx->module_pwdump_column = MODULE_DEFAULT; + module_ctx->module_pw_max = module_pw_max; + module_ctx->module_pw_min = MODULE_DEFAULT; + module_ctx->module_salt_max = MODULE_DEFAULT; + module_ctx->module_salt_min = MODULE_DEFAULT; + module_ctx->module_salt_type = module_salt_type; + module_ctx->module_separator = MODULE_DEFAULT; + module_ctx->module_st_hash = module_st_hash; + module_ctx->module_st_pass = module_st_pass; + module_ctx->module_tmp_size = module_tmp_size; + module_ctx->module_unstable_warning = MODULE_DEFAULT; + module_ctx->module_warmup_disable = MODULE_DEFAULT; +} diff --git a/tools/test_modules/m22600.pm b/tools/test_modules/m22600.pm new file mode 100644 index 000000000..d02056065 --- /dev/null +++ b/tools/test_modules/m22600.pm @@ -0,0 +1,245 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Crypt::PBKDF2; +use Digest::SHA1 qw (sha1); +use Crypt::Mode::ECB; + +sub module_constraints { [[0, 256], [32, 32], [-1, -1], [-1, -1], [-1, -1]] } + +my $AES256_IGE_BLOCK_SIZE = 16; + +# +# Helper functions: +# + +sub exclusive_or +{ + my $in1 = shift; + my $in2 = shift; + + # MIN () function (should always be 16 for us): + # my $len = (length ($in1) <= length ($in2)) ? length ($in2) : length ($in1); + + # padding if input not multiple of block size: + # $in1 .= "\x00" x ($AES256_IGE_BLOCK_SIZE - $len); + # $in2 .= "\x00" x ($AES256_IGE_BLOCK_SIZE - $len); + + my $out = ""; + + for (my $i = 0; $i < $AES256_IGE_BLOCK_SIZE; $i++) # $i < $len + { + $out .= chr (ord (substr ($in1, $i, 1)) ^ ord (substr ($in2, $i, 1))); + } + + return $out; +} + +sub aes256_encrypt_ige +{ + my $key = shift; + my $iv = shift; + my $in = shift; + + my $x_prev = substr ($iv, $AES256_IGE_BLOCK_SIZE, $AES256_IGE_BLOCK_SIZE); + my $y_prev = substr ($iv, 0, $AES256_IGE_BLOCK_SIZE); + + my $m = Crypt::Mode::ECB->new ('AES', 0); + + my $out = ""; + + for (my $i = 0; $i < length ($in); $i += $AES256_IGE_BLOCK_SIZE) + { + my $x = substr ($in, $i, $AES256_IGE_BLOCK_SIZE); + + my $y_xor = exclusive_or ($x, $y_prev); + + my $y_final = $m->encrypt ($y_xor, $key); + # $y_final .= "\x00" x ($AES256_IGE_BLOCK_SIZE - length ($y_final)); + + my $y = exclusive_or ($y_final, $x_prev); + + $x_prev = $x; + $y_prev = $y; + + $out .= $y; + } + + return $out; +} + +sub aes256_decrypt_ige +{ + my $key = shift; + my $iv = shift; + my $in = shift; + + my $x_prev = substr ($iv, 0, $AES256_IGE_BLOCK_SIZE); + my $y_prev = substr ($iv, $AES256_IGE_BLOCK_SIZE, $AES256_IGE_BLOCK_SIZE); + + my $m = Crypt::Mode::ECB->new ('AES', 0); + + my $out = ""; + + for (my $i = 0; $i < length ($in); $i += $AES256_IGE_BLOCK_SIZE) + { + my $x = substr ($in, $i, $AES256_IGE_BLOCK_SIZE); + + my $y_xor = exclusive_or ($x, $y_prev); + + my $y_final = $m->decrypt ($y_xor, $key); + # $y_final .= "\x00" x ($AES256_IGE_BLOCK_SIZE - length ($y_final)); + + my $y = exclusive_or ($y_final, $x_prev); + + $x_prev = $x; + $y_prev = $y; + + $out .= $y; + } + + return $out; +} + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + my $iter = shift // 4000; + my $data = shift; + + my $pbkdf = Crypt::PBKDF2->new + ( + hash_class => 'HMACSHA1', + iterations => $iter, + output_len => 136 + ); + + my $authkey = $pbkdf->PBKDF2 ($salt, $word); + + my $message = ""; + my $message_key = ""; + + if (defined ($data)) + { + $message = substr ($data, 16); + $message_key = substr ($data, 0, 16); + } + else + { + $message = random_bytes (272); + $message_key = substr (sha1 ($message), 0, 16); + } + + my $data_a = "\x00" x 48; + my $data_b = "\x00" x 48; + my $data_c = "\x00" x 48; + my $data_d = "\x00" x 48; + + substr ($data_a, 0, 16) = $message_key; # memcpy () + substr ($data_b, 16, 16) = $message_key; + substr ($data_c, 32, 16) = $message_key; + substr ($data_d, 0, 16) = $message_key; + + substr ($data_a, 16, 32) = substr ($authkey, 8, 32); + substr ($data_b, 0, 16) = substr ($authkey, 40, 16); + substr ($data_b, 32, 16) = substr ($authkey, 56, 16); + substr ($data_c, 0, 32) = substr ($authkey, 72, 32); + substr ($data_d, 16, 32) = substr ($authkey, 104, 32); + + my $sha1_a = sha1 ($data_a); + my $sha1_b = sha1 ($data_b); + my $sha1_c = sha1 ($data_c); + my $sha1_d = sha1 ($data_d); + + my $aes_key = substr ($sha1_a, 0, 8) . # 8 + + substr ($sha1_b, 8, 12) . # 12 + + substr ($sha1_c, 4, 12); # 12 = 32 + + my $aes_iv = substr ($sha1_a, 8, 12) . # 12 + + substr ($sha1_b, 0, 8) . # 8 + + substr ($sha1_c, 16, 4) . # 4 + + substr ($sha1_d, 0, 8); # 8 = 32 + + my $enc_data = ""; + + if (defined ($data)) + { + # AES256 IGE decrypt: + + my $dec_data = aes256_decrypt_ige ($aes_key, $aes_iv, $message); + + my $h = substr (sha1 ($dec_data), 0, 16); + + if ($h eq $message_key) + { + $enc_data = $data; + } + } + else + { + # AES256 IGE encrypt: + + my $enc_random_data = aes256_encrypt_ige ($aes_key, $aes_iv, $message); + + $enc_data = $message_key . $enc_random_data; + } + + my $hash = sprintf ("\$telegram\$1*%i*%s*%s", $iter, unpack ("H*", $salt), unpack ("H*", $enc_data)); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my $idx = index ($line, ':'); + + return if ($idx == -1); + + my $hash = substr ($line, 0, $idx); + my $word = substr ($line, $idx + 1); + + return unless defined $hash; + return unless defined $word; + + my $signature = substr ($hash, 0, 10); + + return unless ($signature eq "\$telegram\$"); + + my $version = substr ($hash, 10, 1); + + return unless ($version eq "1"); + + my @split = split ('\*', $hash); + + return unless scalar @split == 4; + + shift @split; + + my $iter = shift @split; + my $salt = shift @split; + my $data = shift @split; + + return unless length ($salt) == 64; + return unless length ($data) == 576; + + $salt = pack ("H*", $salt); + $data = pack ("H*", $data); + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt, $iter, $data); + + return ($new_hash, $word); +} + +1;