Add module and unit test for hash-mode 15000

pull/1887/head
jsteube 5 years ago
parent fc90bfc00c
commit c67287e754

@ -643,17 +643,6 @@ typedef struct keepass_tmp
} keepass_tmp_t;
typedef struct dpapimk_tmp_v2
{
u64 ipad64[8];
u64 opad64[8];
u64 dgst64[16];
u64 out64[16];
u32 userKey[8];
} dpapimk_tmp_v2_t;
typedef struct apple_secure_notes_tmp
{
u32 ipad[8];
@ -664,7 +653,6 @@ typedef struct apple_secure_notes_tmp
} apple_secure_notes_tmp_t;
typedef struct struct_psafe2_hdr
{
u32 random[2];
@ -927,7 +915,6 @@ typedef enum kern_type
KERN_TYPE_JKS_SHA1 = 15500,
KERN_TYPE_ETHEREUM_PBKDF2 = 15600,
KERN_TYPE_ETHEREUM_SCRYPT = 15700,
KERN_TYPE_DPAPIMK_V2 = 15900,
KERN_TYPE_TRIPCODE = 16000,
KERN_TYPE_TACACS_PLUS = 16100,
KERN_TYPE_APPLE_SECURE_NOTES = 16200,
@ -1010,7 +997,6 @@ typedef enum rounds_count
ROUNDS_ITUNES102_BACKUP = 10000,
ROUNDS_ATLASSIAN = 10000,
ROUNDS_NETBSD_SHA1CRYPT = 20000,
ROUNDS_DPAPIMK_V2 = 8000 - 1, // from 4000 to 24000 (possibly more)
ROUNDS_ETHEREUM_PBKDF2 = 262144 - 1,
ROUNDS_APPLE_SECURE_NOTES = 20000,
ROUNDS_ETHEREUM_PRESALE = 2000 - 1,

@ -105,7 +105,6 @@
" 11500 | CRC32 | Checksums",
" 1100 | Domain Cached Credentials (DCC), MS Cache | Operating Systems",
" 2100 | Domain Cached Credentials 2 (DCC2), MS Cache 2 | Operating Systems",
" 15900 | DPAPI masterkey file v2 | Operating Systems",
" 12800 | MS-AzureSync PBKDF2-HMAC-SHA256 | Operating Systems",
" 12400 | BSDi Crypt, Extended DES | Operating Systems",
" 7400 | sha256crypt $5$, SHA256 (Unix) | Operating Systems",
@ -448,7 +447,6 @@ static const char *ST_HASH_15400 = "$chacha20$*0400000000000003*35*0200000000000
static const char *ST_HASH_15500 = "$jksprivk$*338BD2FBEBA7B3EF198A4CBFC6E18AFF1E229367*5225850113575146134463704406336350011656*D5253EB151EB92DC73E542D8C0A4D7A848A5B0C0E370E625E6547D4E6F23416FC85A27BC295731B8021CDFBD003551C66C434FFBC87DACAD1FDF39022320034A2F86E779F2B1B3325428A666518FA89507AD63E15FD9C57B9E36EF5B642A2F448A9A3F09B79AD93D65F46B8692CD07539FD140146F8F219DC262971AF019E18EDC16C3C240569E1673F4D98BC818CCF28298D5A7BFF038A663DD10FE5E48643C3217C237D342164E2D41EF15075431FBD5B34800E5AE7EB80FAA5AE9982A55F35379AA7B31217E7F1C5F1964A15024A305AE4B3981FE1C80C163BC38ECA5581F11867E5C34C5D124D0367B3737E5E5BB14D2CAB26A698C8DAAB755C82BA6B823BCAECDD4A89C831651ACE5A6029FD0D3515C5D1D53AD8B9062CE8C445373862035CBBF60D490CA2E4975EE6E0358EC32E871FAB15347E3032E21F30F543BAAB01D779BA833CA0B8C7591B42C7C59A8FDD46D7DECEC0E91ADBF331177605E7830ABED62FAD7D5D806D8EFD01C38765940B7F97168FC72C39BF4C98F944FFC310CA8F4EB1D0F960F352CC5E2BB23A1EB221072A5471EDA2CE81C04595B8D37088CFB5C14F6A4A881AD12125DEFBB8154EB4C130AB7FD9933FD36DF1A6A26B51AB169866788678FCED988C8E017CA84354F487A5508210181AFB8B3AD0753E3E28BE674DFBD4E4FBDFD1E30D592F4EA3A77A2F0F5CF9A175DBC590EF5D42971A39918F12B92DCD8BFD56BE9A3459856B5587603C7B53062663A4C8894BBC9894FB1663BF30F32D907664328138B7A50EAC7F8E3183D74562A5C90FE1889AC4C5FE43EBEB8974563B6682F92591ECA4FA0DA72236C3851DA102DB6BA0CC07BFD32F7E962AB0EDCF4A8DEA6525174F5BB5C021E2A9A3F7F761E9CA90B6E27FB7E55CD91DA184FAC5E534E8AD25314C56CE5796506A0CA70881782F9C5147D87705065D68BD67D2B0344205BA6445D562273690004CA5A303274FB283A75F49BA968D7947943AA98F2AF9CB8253B425B86225E7395A331AC4CB1B1700C64D4F458D5D642C54148AE6DA41D9E26657D331B157D76042C2CF3057B83997C23D8BF68FB3C7337CAFB8B324AD0DF7A80B554B4D7F9AD6ED527E7932F1741A573C152A41610F6517E3F4A3BC6B66685871A7CE3795C559BD47CDB8E34CB2C1DFE980518D79E2078C258C54F312EB38609F640E7DC013E0F2A16A25BB5971882B4308D27930CA99FEC231AE927B62215A1B56098C362B7F20593953B29428681875070E84BF5B60BEA3948127151634123DA77C814AAD54CE10905763C8C19BC191C0C40458C809402E1957C4C05C4EAE27576B2D30593F7FDCC9A248DB5DB23CF2FA22A92C016090F611690BF0AB5B8B2866ED25F345EFE85DF3311C9E91C37CEE709CF16E7CB09D01BECD2961D094C02D42EC85BF47FAB1B67A13B9A1741C15F7156D57A71BFFABB03B71E69707913A5C136B3D69CE3F71ABFE376F0A21D723FFA2E60AC180689D3E8AF4348C9F555CD897387327FC8BA2B9C51A7298547E556A11A60441EF5331A1BFB847A3D23DD9F7C50E636A2C6309BC82E1A8852F5A8569B6D93*14*78D6A2424484CF5149932B7EA8BF*test";
static const char *ST_HASH_15600 = "$ethereum$p*1024*38353131353831333338313138363430*a8b4dfe92687dbc0afeb5dae7863f18964241e96b264f09959903c8c924583fc*0a9252861d1e235994ce33dbca91c98231764d8ecb4950015a8ae20d6415b986";
//static const char *ST_HASH_15700 = "$ethereum$s*262144*8*1*3134313837333434333838303231333633373433323633373534333136363537*73da7f80ec3bd4f2a128c3a815cfb4d576ecb1a9b47024c902e62ea926f7795b*910e0f8dc1f7ba41959e1089bb769f3e919109591913cc33ba03953d7a905efd";
static const char *ST_HASH_15900 = "$DPAPImk$2*1*S-15-21-439882973-489230393-482956683-1522*aes256*sha512*12900*79f7ca399f2626e21aad108c3922af7c*288*c47bc8a985ca6aa708b01c97b004bff20cc52379dc2635b4acf59ce17970a2cb47ace98c7e8de977f265243c5c03d0a97e4b954b494d9e38d9158d0c1e729d16a28ba69e2e7c6c3bc0e3afc9c9b6306b83372ccb35d89b98925728fd36315b8ee95b4d4eccdcb31564769f9a4b9ee10828184e16d4af336675d5e31d987dd87233d34fbbb98880c5e1f64cbb9b043ad8";
static const char *ST_HASH_16000 = "pfaRCwDe0U";
static const char *ST_HASH_16100 = "$tacacs-plus$0$5fde8e68$4e13e8fb33df$c006";
static const char *ST_HASH_16200 = "$ASN$*1*20000*80771171105233481004850004085037*d04b17af7f6b184346aad3efefe8bec0987ee73418291a41";
@ -610,7 +608,6 @@ static const char *HT_15400 = "ChaCha20";
static const char *HT_15500 = "JKS Java Key Store Private Keys (SHA1)";
static const char *HT_15600 = "Ethereum Wallet, PBKDF2-HMAC-SHA256";
static const char *HT_15700 = "Ethereum Wallet, SCRYPT";
static const char *HT_15900 = "DPAPI masterkey file v2";
static const char *HT_16000 = "Tripcode";
static const char *HT_16100 = "TACACS+";
static const char *HT_16200 = "Apple Secure Notes";
@ -15873,8 +15870,6 @@ void hashconfig_benchmark_defaults (hashcat_ctx_t *hashcat_ctx, salt_t *salt, vo
break;
case 15700: salt->salt_iter = 1;
break;
case 15900: salt->salt_iter = ROUNDS_DPAPIMK_V2;
break;
case 16200: salt->salt_iter = ROUNDS_APPLE_SECURE_NOTES - 1;
break;
case 16300: salt->salt_iter = ROUNDS_ETHEREUM_PRESALE;
@ -18346,91 +18341,6 @@ int ascii_digest (hashcat_ctx_t *hashcat_ctx, char *out_buf, const int out_size,
digest_buf[7]
);
}
else if (hash_mode == 15900)
{
dpapimk_t *dpapimks = (dpapimk_t *) esalts_buf;
dpapimk_t *dpapimk = &dpapimks[digest_cur];
u32 version = 2;
u32 context = dpapimk->context;
u32 rounds = salt.salt_iter + 1;
u32 contents_len = dpapimk->contents_len;
u32 SID_len = dpapimk->SID_len;
u32 iv_len = 32;
u8 cipher_algorithm[8] = { 0 };
u8 hash_algorithm[8] = { 0 };
u8 SID[512] = { 0 };
u8* SID_tmp;
u32 *ptr_SID = (u32 *) dpapimk->SID;
u32 *ptr_iv = (u32 *) dpapimk->iv;
u32 *ptr_contents = (u32 *) dpapimk->contents;
u32 u32_iv[4];
u8 iv[32 + 1];
// convert back SID
SID_tmp = (u8 *) hcmalloc ((SID_len + 1) * sizeof(u8));
for (u32 i = 0; i < (SID_len / 4) + 1; i++)
{
u8 hex[8] = { 0 };
u32_to_hex (byte_swap_32 (ptr_SID[i]), hex);
for (u32 j = 0, k = 0; j < 8; j += 2, k++)
{
SID_tmp[i * 4 + k] = hex_to_u8 (&hex[j]);
}
}
// overwrite trailing 0x80
SID_tmp[SID_len] = 0;
for (u32 i = 0, j = 0 ; j < SID_len ; i++, j += 2)
{
SID[i] = SID_tmp[j];
}
hcfree(SID_tmp);
for (u32 i = 0; i < iv_len / 8; i++)
{
u32_iv[i] = byte_swap_32 (ptr_iv[i]);
u32_to_hex (u32_iv[i], iv + i * 8);
}
iv[32] = 0;
u32 u32_contents[36];
u8 contents[288 + 1];
for (u32 i = 0; i < contents_len / 8; i++)
{
u32_contents[i] = byte_swap_32 (ptr_contents[i]);
u32_to_hex (u32_contents[i], contents + i * 8);
}
contents[288] = 0;
if (contents_len == 288)
{
memcpy(cipher_algorithm, "aes256", strlen("aes256"));
memcpy(hash_algorithm, "sha512", strlen("sha512"));
}
snprintf (out_buf, out_size, "%s%d*%d*%s*%s*%s*%d*%s*%d*%s",
SIGNATURE_DPAPIMK,
version,
context,
SID,
cipher_algorithm,
hash_algorithm,
rounds,
iv,
contents_len,
contents);
}
else if (hash_mode == 16000)
{
memset (tmp_buf, 0, sizeof (tmp_buf));
@ -23018,25 +22928,6 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx)
hashconfig->st_pass = ST_PASS_HASHCAT_PLAIN;
break;
case 15900: hashconfig->hash_type = HASH_TYPE_DPAPIMK;
hashconfig->salt_type = SALT_TYPE_EMBEDDED;
hashconfig->attack_exec = ATTACK_EXEC_OUTSIDE_KERNEL;
hashconfig->opts_type = OPTS_TYPE_PT_GENERATE_LE
| OPTS_TYPE_PREFERED_THREAD;
hashconfig->kern_type = KERN_TYPE_DPAPIMK_V2;
hashconfig->dgst_size = DGST_SIZE_4_4;
hashconfig->parse_func = dpapimk_parse_hash;
hashconfig->opti_type = OPTI_TYPE_ZERO_BYTE
| OPTI_TYPE_USES_BITS_64
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
hashconfig->dgst_pos0 = 0;
hashconfig->dgst_pos1 = 1;
hashconfig->dgst_pos2 = 2;
hashconfig->dgst_pos3 = 3;
hashconfig->st_hash = ST_HASH_15900;
hashconfig->st_pass = ST_PASS_HASHCAT_PLAIN;
break;
case 16000: hashconfig->hash_type = HASH_TYPE_DESCRYPT;
hashconfig->salt_type = SALT_TYPE_NONE;
hashconfig->attack_exec = ATTACK_EXEC_INSIDE_KERNEL;
@ -23419,7 +23310,6 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx)
case 15500: hashconfig->esalt_size = sizeof (jks_sha1_t); break;
case 15600: hashconfig->esalt_size = sizeof (ethereum_pbkdf2_t); break;
case 15700: hashconfig->esalt_size = sizeof (ethereum_scrypt_t); break;
case 15900: hashconfig->esalt_size = sizeof (dpapimk_t); break;
case 16100: hashconfig->esalt_size = sizeof (tacacs_plus_t); break;
case 16200: hashconfig->esalt_size = sizeof (apple_secure_notes_t); break;
case 16300: hashconfig->esalt_size = sizeof (ethereum_presale_t); break;
@ -23522,7 +23412,6 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx)
case 15100: hashconfig->tmp_size = sizeof (pbkdf1_sha1_tmp_t); break;
case 15200: hashconfig->tmp_size = sizeof (mywallet_tmp_t); break;
case 15600: hashconfig->tmp_size = sizeof (pbkdf2_sha256_tmp_t); break;
case 15900: hashconfig->tmp_size = sizeof (dpapimk_tmp_v2_t); break;
case 16200: hashconfig->tmp_size = sizeof (apple_secure_notes_tmp_t); break;
case 16300: hashconfig->tmp_size = sizeof (pbkdf2_sha256_tmp_t); break;
case 16700: hashconfig->tmp_size = sizeof (apple_secure_notes_tmp_t); break;
@ -23716,7 +23605,6 @@ u32 default_pw_max (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED co
case 15400: pw_max = 32; break; // Underlaying ChaCha20 fixed
case 15600: pw_max = PW_MAX; break;
case 15700: pw_max = PW_MAX; break;
case 15900: pw_max = PW_MAX; break;
case 16000: pw_max = 8; break; // Underlaying DES max
case 16900: pw_max = PW_MAX; break;
}

@ -22,9 +22,11 @@ static const char *HASH_NAME = "DPAPI masterkey file v1";
static const u32 HASH_TYPE = HASH_TYPE_GENERIC;
static const u64 KERN_TYPE = 15300;
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
| OPTI_TYPE_USES_BITS_64
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
static const u64 OPTS_TYPE = OPTS_TYPE_STATE_BUFFER_LE
| OPTS_TYPE_PT_GENERATE_LE;
| OPTS_TYPE_PT_GENERATE_LE
| OPTS_TYPE_PREFERED_THREAD;
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
static const char *ST_PASS = "hashcat";
static const char *ST_HASH = "$DPAPImk$1*1*S-15-21-466364039-425773974-453930460-1925*des3*sha1*24000*b038489dee5ad04e3e3cab4d957258b5*208*cb9b5b7d96a0d2a00305ca403d3fd9c47c561e35b4b2cf3aebfd1d3199a6481d56972be7ebd6c291b199e6f1c2ffaee91978706737e9b1209e6c7d3aa3d8c3c3e38ad1ccfa39400d62c2415961c17fd0bd6b0f7bbd49cc1de1a394e64b7237f56244238da8d37d78";
@ -294,13 +296,15 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
u8 cipher_algorithm[8] = { 0 };
u8 hash_algorithm[8] = { 0 };
u8 SID[512] = { 0 };
u8* SID_tmp;
u32 *ptr_SID = (u32 *) dpapimk->SID;
u32 *ptr_iv = (u32 *) dpapimk->iv;
u32 *ptr_contents = (u32 *) dpapimk->contents;
u32 *ptr_SID = (u32 *) dpapimk->SID;
u32 *ptr_iv = (u32 *) dpapimk->iv;
u32 *ptr_contents = (u32 *) dpapimk->contents;
u32 u32_iv[4];
u8 iv[32 + 1];
// convert back SID
@ -310,6 +314,7 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
for (u32 i = 0; i < (SID_len / 4) + 1; i++)
{
u8 hex[8] = { 0 };
u32_to_hex (byte_swap_32 (ptr_SID[i]), hex);
for (u32 j = 0, k = 0; j < 8; j += 2, k++)
@ -317,6 +322,7 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
SID_tmp[i * 4 + k] = hex_to_u8 (&hex[j]);
}
}
// overwrite trailing 0x80
SID_tmp[SID_len] = 0;
@ -330,17 +336,21 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
for (u32 i = 0; i < iv_len / 8; i++)
{
u32_iv[i] = byte_swap_32 (ptr_iv[i]);
u32_to_hex (u32_iv[i], iv + i * 8);
}
iv[32] = 0;
u32 u32_contents[36];
u8 contents[288 + 1];
u8 contents[288 + 1];
for (u32 i = 0; i < contents_len / 8; i++)
{
u32_contents[i] = byte_swap_32 (ptr_contents[i]);
u32_to_hex (u32_contents[i], contents + i * 8);
u32_to_hex (u32_contents[i], contents + i * 8);
}
contents[208] = 0;
@ -348,7 +358,8 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
if (contents_len == 208)
{
memcpy (cipher_algorithm, "des3", strlen("des3"));
memcpy (hash_algorithm, "sha1", strlen("sha1"));
memcpy (hash_algorithm, "sha1", strlen("sha1"));
}
const int line_len = snprintf (line_buf, line_size, "%s%u*%u*%s*%s*%s*%u*%s*%u*%s",

@ -0,0 +1,442 @@
/**
* 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"
#include "memory.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_OS;
static const char *HASH_NAME = "DPAPI masterkey file v2";
static const u32 HASH_TYPE = HASH_TYPE_GENERIC;
static const u64 KERN_TYPE = 15900;
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
static const u64 OPTS_TYPE = OPTS_TYPE_STATE_BUFFER_LE
| OPTS_TYPE_PT_GENERATE_LE;
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
static const char *ST_PASS = "hashcat";
static const char *ST_HASH = "$DPAPImk$2*1*S-15-21-439882973-489230393-482956683-1522*aes256*sha512*12900*79f7ca399f2626e21aad108c3922af7c*288*c47bc8a985ca6aa708b01c97b004bff20cc52379dc2635b4acf59ce17970a2cb47ace98c7e8de977f265243c5c03d0a97e4b954b494d9e38d9158d0c1e729d16a28ba69e2e7c6c3bc0e3afc9c9b6306b83372ccb35d89b98925728fd36315b8ee95b4d4eccdcb31564769f9a4b9ee10828184e16d4af336675d5e31d987dd87233d34fbbb98880c5e1f64cbb9b043ad8";
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; }
u32 module_hash_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 HASH_TYPE; }
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 dpapimk
{
u32 context;
u32 SID[32];
u32 SID_len;
u32 SID_offset;
/* here only for possible
forward compatibiliy
*/
// u8 cipher_algo[16];
// u8 hash_algo[16];
u32 iv[4];
u32 contents_len;
u32 contents[128];
} dpapimk_t;
typedef struct dpapimk_tmp_v2
{
u64 ipad64[8];
u64 opad64[8];
u64 dgst64[16];
u64 out64[16];
u32 userKey[8];
} dpapimk_tmp_v2_t;
static const char *SIGNATURE_DPAPIMK = "$DPAPImk$";
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 (dpapimk_tmp_v2_t);
return tmp_size;
}
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 (dpapimk_t);
return esalt_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)
{
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 hashinfo_t *hash_info, const char *line_buf, MAYBE_UNUSED const int line_len)
{
u32 *digest = (u32 *) digest_buf;
dpapimk_t *dpapimk = (dpapimk_t *) esalt_buf;
token_t token;
token.token_cnt = 10;
token.signatures_cnt = 1;
token.signatures_buf[0] = SIGNATURE_DPAPIMK;
// signature
token.len[0] = 9;
token.attr[0] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_SIGNATURE;
// version
token.len_min[1] = 1;
token.len_max[1] = 1;
token.sep[1] = '*';
token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_DIGIT;
// context
token.len_min[2] = 1;
token.len_max[2] = 1;
token.sep[2] = '*';
token.attr[2] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_DIGIT;
// sid
token.len_min[3] = 10;
token.len_max[3] = 60;
token.sep[3] = '*';
token.attr[3] = TOKEN_ATTR_VERIFY_LENGTH;
// cipher
token.len_min[4] = 4;
token.len_max[4] = 6;
token.sep[4] = '*';
token.attr[4] = TOKEN_ATTR_VERIFY_LENGTH;
// hash
token.len_min[5] = 4;
token.len_max[5] = 6;
token.sep[5] = '*';
token.attr[5] = TOKEN_ATTR_VERIFY_LENGTH;
// iterations
token.len_min[6] = 1;
token.len_max[6] = 6;
token.sep[6] = '*';
token.attr[6] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_DIGIT;
// iv
token.len_min[7] = 32;
token.len_max[7] = 32;
token.sep[7] = '*';
token.attr[7] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_HEX;
// content len
token.len_min[8] = 1;
token.len_max[8] = 6;
token.sep[8] = '*';
token.attr[8] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_DIGIT;
// content
token.len_min[9] = 0;
token.len_max[9] = 1024;
token.attr[9] = 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);
const u8 *version_pos = token.buf[1];
const u8 *context_pos = token.buf[2];
const u8 *SID_pos = token.buf[3];
const u8 *rounds_pos = token.buf[6];
const u8 *iv_pos = token.buf[7];
const u8 *contents_len_pos = token.buf[8];
const u8 *contents_pos = token.buf[9];
/**
* content verification
*/
const int version = hc_strtoul ((const char *) version_pos, NULL, 10);
const int contents_len = hc_strtoul ((const char *) contents_len_pos, NULL, 10);
if (version == 1)
{
if (contents_len != 208) return (PARSER_SALT_LENGTH);
}
else if (version == 2)
{
if (contents_len != 288) return (PARSER_SALT_LENGTH);
}
else
{
return (PARSER_SALT_VALUE);
}
if (contents_len != token.len[9]) return (PARSER_SALT_LENGTH);
dpapimk->contents_len = contents_len;
dpapimk->context = hc_strtoul ((const char *) context_pos, NULL, 10);
// division by 4 should be fine because contents_len is either 208 or 288
for (u32 i = 0; i < dpapimk->contents_len / 4; i++)
{
dpapimk->contents[i] = hex_to_u32 ((const u8 *) &contents_pos[i * 8]);
dpapimk->contents[i] = byte_swap_32 (dpapimk->contents[i]);
}
// SID
const int SID_len = token.len[3];
u8 SID_utf16le[128] = { 0 };
for (int i = 0; i < SID_len; i++)
{
SID_utf16le[i * 2] = SID_pos[i];
}
/* Specific to DPAPI: needs trailing '\0' while computing hash */
dpapimk->SID_len = (SID_len + 1) * 2;
SID_utf16le[dpapimk->SID_len] = 0x80;
memcpy ((u8 *) dpapimk->SID, SID_utf16le, sizeof (SID_utf16le));
for (u32 i = 0; i < 32; i++)
{
dpapimk->SID[i] = byte_swap_32 (dpapimk->SID[i]);
}
// iv
dpapimk->iv[0] = hex_to_u32 ((const u8 *) &iv_pos[ 0]);
dpapimk->iv[1] = hex_to_u32 ((const u8 *) &iv_pos[ 8]);
dpapimk->iv[2] = hex_to_u32 ((const u8 *) &iv_pos[16]);
dpapimk->iv[3] = hex_to_u32 ((const u8 *) &iv_pos[24]);
dpapimk->iv[0] = byte_swap_32 (dpapimk->iv[0]);
dpapimk->iv[1] = byte_swap_32 (dpapimk->iv[1]);
dpapimk->iv[2] = byte_swap_32 (dpapimk->iv[2]);
dpapimk->iv[3] = byte_swap_32 (dpapimk->iv[3]);
digest[0] = dpapimk->iv[0];
digest[1] = dpapimk->iv[1];
digest[2] = dpapimk->iv[2];
digest[3] = dpapimk->iv[3];
salt->salt_buf[0] = dpapimk->iv[0];
salt->salt_buf[1] = dpapimk->iv[1];
salt->salt_buf[2] = dpapimk->iv[2];
salt->salt_buf[3] = dpapimk->iv[3];
salt->salt_len = 16;
// iter
salt->salt_iter = hc_strtoul ((const char *) rounds_pos, NULL, 10) - 1;
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 hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
{
const u32 *digest = (const u32 *) digest_buf;
const dpapimk_t *dpapimk = (const dpapimk_t *) esalt_buf;
u32 version = 2;
u32 context = dpapimk->context;
u32 rounds = salt->salt_iter + 1;
u32 contents_len = dpapimk->contents_len;
u32 SID_len = dpapimk->SID_len;
u32 iv_len = 32;
u8 cipher_algorithm[8] = { 0 };
u8 hash_algorithm[8] = { 0 };
u8 SID[512] = { 0 };
u8* SID_tmp;
u32 *ptr_SID = (u32 *) dpapimk->SID;
u32 *ptr_iv = (u32 *) dpapimk->iv;
u32 *ptr_contents = (u32 *) dpapimk->contents;
u32 u32_iv[4];
u8 iv[32 + 1];
// convert back SID
SID_tmp = (u8 *) hcmalloc ((SID_len + 1) * sizeof(u8));
for (u32 i = 0; i < (SID_len / 4) + 1; i++)
{
u8 hex[8] = { 0 };
u32_to_hex (byte_swap_32 (ptr_SID[i]), hex);
for (u32 j = 0, k = 0; j < 8; j += 2, k++)
{
SID_tmp[i * 4 + k] = hex_to_u8 (&hex[j]);
}
}
// overwrite trailing 0x80
SID_tmp[SID_len] = 0;
for (u32 i = 0, j = 0 ; j < SID_len ; i++, j += 2)
{
SID[i] = SID_tmp[j];
}
hcfree (SID_tmp);
for (u32 i = 0; i < iv_len / 8; i++)
{
u32_iv[i] = byte_swap_32 (ptr_iv[i]);
u32_to_hex (u32_iv[i], iv + i * 8);
}
iv[32] = 0;
u32 u32_contents[36];
u8 contents[288 + 1];
for (u32 i = 0; i < contents_len / 8; i++)
{
u32_contents[i] = byte_swap_32 (ptr_contents[i]);
u32_to_hex (u32_contents[i], contents + i * 8);
}
contents[288] = 0;
if (contents_len == 288)
{
memcpy (cipher_algorithm, "aes256", strlen ("aes256"));
memcpy (hash_algorithm, "sha512", strlen ("sha512"));
}
const int line_len = snprintf (line_buf, line_size, "%s%d*%d*%s*%s*%s*%d*%s*%d*%s",
SIGNATURE_DPAPIMK,
version,
context,
SID,
cipher_algorithm,
hash_algorithm,
rounds,
iv,
contents_len,
contents);
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_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_binary_verify = MODULE_DEFAULT;
module_ctx->module_hash_decode_outfile = 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 = 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_hash_type = module_hash_type;
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_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_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_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;
}

@ -8,10 +8,10 @@
use strict;
use warnings;
use Encode;
use Crypt::ECB qw (encrypt);
use Digest::MD4 qw (md4);
use Digest::SHA qw (sha1 hmac_sha1);
use Crypt::ECB qw (encrypt);
use Encode;
sub module_constraints { [[0, 255], [-1, -1], [0, 27], [-1, -1], [-1, -1]] }

@ -0,0 +1,412 @@
#!/usr/bin/env perl
##
## Author......: See docs/credits.txt
## License.....: MIT
##
use strict;
use warnings;
use Crypt::CBC;
use Crypt::ECB qw (encrypt);
use Digest::MD4 qw (md4);
use Digest::SHA qw (sha1 hmac_sha1 hmac_sha512);
use Encode;
sub module_constraints { [[0, 255], [-1, -1], [0, 27], [-1, -1], [-1, -1]] }
sub get_random_dpapimk_salt
{
my $version = shift;
my $salt_buf = "";
my $context = random_number (1, 2);
my $cipher_algo = "";
my $hash_algo = "";
my $iterations;
my $SID = sprintf ('S-15-21-%d-%d-%d-%d',
random_number (400000000,490000000),
random_number (400000000,490000000),
random_number (400000000,490000000),
random_number (1000,1999));
my $cipher_len = 0;
if ($version == 1)
{
$iterations = random_number (4000, 24000);
$cipher_algo = "des3";
$hash_algo = "sha1";
$cipher_len = 208;
}
elsif ($version == 2)
{
$iterations = random_number (8000, 17000);
$cipher_algo = "aes256";
$hash_algo = "sha512";
$cipher_len = 288;
}
my $iv = random_bytes (16);
$iv = unpack ("H*", $iv);
$salt_buf = $version . '*' .
$context . '*' .
$SID . '*' .
$cipher_algo . '*' .
$hash_algo . '*' .
$iterations . '*' .
$iv . '*' .
$cipher_len . '*';
return $salt_buf;
}
#Thanks to Jochen Hoenicke <hoenicke@gmail.com>
# (one of the authors of Palm Keyring)
# for these next two subs.
sub dpapi_pbkdf2
{
my ($password, $salt, $iter, $keylen, $prf) = @_;
my ($k, $t, $u, $ui, $i);
$t = "";
for ($k = 1; length ($t) < $keylen; $k++)
{
$u = $ui = &$prf ($salt.pack ('N', $k), $password);
for ($i = 1; $i < $iter; $i++)
{
# modification to fit Microsoft
# weird pbkdf2 implementation...
$ui = &$prf ($u, $password);
$u ^= $ui;
}
$t .= $u;
}
return substr ($t, 0, $keylen);
}
sub module_generate_hash
{
my $word_buf = shift;
my $salt_buf = shift;
my $dpapimk_salt = shift // get_random_dpapimk_salt (2);
my $cipher = shift;
my @salt_arr = split ('\*', $dpapimk_salt);
my $version = $salt_arr[0];
my $context = $salt_arr[1];
my $SID = $salt_arr[2];
my $cipher_algorithm = $salt_arr[3];
my $hash_algorithm = $salt_arr[4];
my $iterations = $salt_arr[5];
my $salt = pack ("H*", $salt_arr[6]);
my $cipher_len = $salt_arr[7];
# intermediate values
my $user_hash;
my $user_derivationKey;
my $encKey;
my $expected_hmac;
my $cleartext;
if ($context == 1)
{
$user_hash = sha1 (encode ("UTF-16LE", $word_buf));
}
elsif ($context == 2)
{
$user_hash = md4 (encode ("UTF-16LE", $word_buf));
}
$user_derivationKey = hmac_sha1 (encode ("UTF-16LE", $SID . "\x00"), $user_hash);
my $hmacSalt = random_bytes (16);
my $last_key = random_bytes (64);
if ($version == 1)
{
$encKey = hmac_sha1 ($hmacSalt, $user_derivationKey);
$expected_hmac = hmac_sha1 ($last_key, $encKey);
# need padding because keyLen is 24 and hashLen 20
$expected_hmac = $expected_hmac . random_bytes (4);
}
elsif ($version == 2)
{
$encKey = hmac_sha512 ($hmacSalt, $user_derivationKey);
$expected_hmac = hmac_sha512 ($last_key, $encKey);
}
$cleartext = $hmacSalt . $expected_hmac . $last_key;
my $derived_key;
my $key;
my $iv;
my $pbkdf2;
if ($version == 1)
{
$derived_key = dpapi_pbkdf2 ($user_derivationKey, $salt, $iterations, 32, \&hmac_sha1);
}
elsif ($version == 2)
{
$derived_key = dpapi_pbkdf2 ($user_derivationKey, $salt, $iterations, 48, \&hmac_sha512);
}
if (defined $cipher)
{
$cipher = pack ("H*", $cipher);
my $computed_hmac = "";
if ($version == 1)
{
$key = substr ($derived_key, 0, 24);
$iv = substr ($derived_key, 24, 8);
my $p1 = Crypt::ECB->new ({
key => substr ($key, 0, 8),
cipher => "DES",
literal_key => 1,
header => "none",
keysize => 8,
padding => "null",
});
my $p2 = Crypt::ECB->new ({
key => substr ($key, 8, 8),
cipher => "DES",
literal_key => 1,
header => "none",
keysize => 8,
padding => "null",
});
my $p3 = Crypt::ECB->new ({
key => substr ($key, 16, 8),
cipher => "DES",
literal_key => 1,
header => "none",
keysize => 8,
padding => "null",
});
# let's compute a 3DES-EDE-CBC decryption
my $out1;
my $out2;
my $out3;
my $expected_cleartext = "";
# size of cipherlen is 104 bytes
for (my $k = 0; $k < 13; $k++)
{
$out1 = $p3->decrypt (substr ($cipher, $k * 8, 8));
$out2 = $p2->encrypt ($out1);
$out3 = $p1->decrypt ($out2);
$expected_cleartext .= substr ($out3, 0, 8) ^ $iv;
$iv = substr ($cipher, $k * 8, 8);
}
$last_key = substr ($expected_cleartext, length ($expected_cleartext) - 64, 64);
$hmacSalt = substr ($expected_cleartext, 0, 16);
$expected_hmac = substr ($expected_cleartext, 16, 20);
$encKey = hmac_sha1 ($hmacSalt, $user_derivationKey);
$computed_hmac = hmac_sha1 ($last_key, $encKey);
$cleartext = $expected_cleartext;
if (unpack ("H*", $expected_hmac) ne unpack ("H*", $computed_hmac))
{
$cleartext = "0" x 104;
}
}
elsif ($version == 2)
{
$key = substr ($derived_key, 0, 32);
$iv = substr ($derived_key, 32, 16);
my $aes = Crypt::CBC->new ({
key => $key,
cipher => "Crypt::Rijndael",
iv => $iv,
literal_key => 1,
header => "none",
keysize => 32,
padding => "null",
});
my $expected_cleartext = $aes->decrypt ($cipher);
$last_key = substr ($expected_cleartext, length ($expected_cleartext) - 64, 64);
$hmacSalt = substr ($expected_cleartext, 0, 16);
$expected_hmac = substr ($expected_cleartext, 16, 64);
$encKey = hmac_sha512 ($hmacSalt, $user_derivationKey);
$computed_hmac = hmac_sha512 ($last_key, $encKey);
$cleartext = $expected_cleartext;
if (unpack ("H*", $expected_hmac) ne unpack ("H*", $computed_hmac))
{
$cleartext = "0" x 144;
}
}
}
if ($version == 1)
{
$key = substr ($derived_key, 0, 24);
$iv = substr ($derived_key, 24, 8);
my $p1 = Crypt::ECB->new ({
key => substr ($key, 0, 8),
cipher => "DES",
literal_key => 1,
header => "none",
keysize => 8,
padding => "null",
});
my $p2 = Crypt::ECB->new ({
key => substr ($key, 8, 8),
cipher => "DES",
literal_key => 1,
header => "none",
keysize => 8,
padding => "null",
});
my $p3 = Crypt::ECB->new ({
key => substr ($key, 16, 8),
cipher => "DES",
literal_key => 1,
header => "none",
keysize => 8,
padding => "null",
});
# let's compute a 3DES-EDE-CBC encryption
# compute first block
my $out1 = $p1->encrypt (substr ($cleartext, 0, 8) ^ $iv);
my $out2 = $p2->decrypt ($out1);
my $out3 = $p3->encrypt ($out2);
$cipher = substr ($out3, 0, 8);
# size of cipherlen is 104 bytes
for (my $k = 1; $k < 13; $k++)
{
$iv = $out3;
$out1 = $p1->encrypt (substr ($cleartext, $k * 8, 8) ^ $iv);
$out2 = $p2->decrypt ($out1);
$out3 = $p3->encrypt ($out2);
$cipher .= substr ($out3, 0, 8);
}
}
else
{
$key = substr ($derived_key, 0, 32);
$iv = substr ($derived_key, 32, 16);
my $aes = Crypt::CBC->new ({
key => $key,
cipher => "Crypt::Rijndael",
iv => $iv,
literal_key => 1,
header => "none",
keysize => 32,
padding => "null",
});
$cipher = $aes->encrypt ($cleartext);
}
my $tmp_hash = sprintf ('$DPAPImk$%d*%d*%s*%s*%s*%d*%s*%d*%s',
$version,
$context,
$SID,
$cipher_algorithm,
$hash_algorithm,
$iterations,
unpack ("H*", $salt),
$cipher_len,
unpack ("H*", $cipher));
return $tmp_hash;
}
sub module_verify_hash
{
my $line = shift;
my ($hash, $word) = split (':', $line);
return unless defined $hash;
return unless defined $word;
my @tmp_data = split ('\$', $hash);
my $signature = $tmp_data[1];
next unless ($signature eq 'DPAPImk');
my @data = split ('\*', $tmp_data[2]);
next unless (scalar @data == 9);
my $version = shift @data;
next unless ($version == 1 || $version == 2);
my $context = shift @data;
my $SID = shift @data;
my $cipher_algorithm = shift @data;
my $hash_algorithm = shift @data;
my $iteration = shift @data;
my $iv = shift @data;
my $cipher_len = shift @data;
my $cipher = shift @data;
next unless (length ($cipher) == $cipher_len);
if ($version == 1)
{
next unless ($cipher_len == 208);
}
elsif ($version == 2)
{
next unless ($cipher_len == 288);
}
my $dpapimk_salt = substr ($hash, length ('$DPAPImk$'));
my $word_packed = pack_if_HEX_notation ($word);
my $new_hash = module_generate_hash ($word_packed, undef, $dpapimk_salt, $cipher);
return ($new_hash, $word);
}
1;
Loading…
Cancel
Save