diff --git a/OpenCL/m26500-pure.cl b/OpenCL/m26500-pure.cl new file mode 100644 index 000000000..1efa12821 --- /dev/null +++ b/OpenCL/m26500-pure.cl @@ -0,0 +1,457 @@ +/** + * 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 + +#define COMPARE_S "inc_comp_single.cl" +#define COMPARE_M "inc_comp_multi.cl" + +typedef struct iphone_passcode_tmp +{ + u32 key0[4]; // original key from pbkdf2 + u32 key1[4]; // original key from pbkdf2 + + u32 iterated_key0[4]; // updated key from pbkdf2 with iterations + u32 iterated_key1[4]; // updated key from pbkdf2 with iterations + + u32 iv[4]; // current iv + +} iphone_passcode_tmp_t; + +typedef struct iphone_passcode +{ + u32 uidkey[4]; + u32 classkey1[10]; + +} iphone_passcode_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); +} + +KERNEL_FQ void m26500_init (KERN_ATTR_TMPS_ESALT (iphone_passcode_tmp_t, iphone_passcode_t)) +{ + /** + * base + */ + + const u64 gid = get_global_id (0); + + if (gid >= gid_max) return; + + sha1_hmac_ctx_t sha1_hmac_ctx0; + + sha1_hmac_init_global_swap (&sha1_hmac_ctx0, pws[gid].i, pws[gid].pw_len); + + sha1_hmac_update_global (&sha1_hmac_ctx0, salt_bufs[SALT_POS].salt_buf, salt_bufs[SALT_POS].salt_len); + + // we can reuse context intermediate buffer values for pbkdf2 + + sha1_hmac_ctx_t sha1_hmac_ctx1 = sha1_hmac_ctx0; + sha1_hmac_ctx_t sha1_hmac_ctx2 = sha1_hmac_ctx0; + + u32 w0[4]; + u32 w1[4]; + u32 w2[4]; + u32 w3[4]; + + w0[0] = 1; + 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_ctx1, w0, w1, w2, w3, 4); + + sha1_hmac_final (&sha1_hmac_ctx1); + + w0[0] = 2; + 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); + + // save + + tmps[gid].key0[0] = hc_swap32_S (sha1_hmac_ctx1.opad.h[0]); + tmps[gid].key0[1] = hc_swap32_S (sha1_hmac_ctx1.opad.h[1]); + tmps[gid].key0[2] = hc_swap32_S (sha1_hmac_ctx1.opad.h[2]); + tmps[gid].key0[3] = hc_swap32_S (sha1_hmac_ctx1.opad.h[3]); + tmps[gid].key1[0] = hc_swap32_S (sha1_hmac_ctx1.opad.h[4]); + tmps[gid].key1[1] = hc_swap32_S (sha1_hmac_ctx2.opad.h[0]); + tmps[gid].key1[2] = hc_swap32_S (sha1_hmac_ctx2.opad.h[1]); + tmps[gid].key1[3] = hc_swap32_S (sha1_hmac_ctx2.opad.h[2]); + + tmps[gid].iterated_key0[0] = tmps[gid].key0[0]; + tmps[gid].iterated_key0[1] = tmps[gid].key0[1]; + tmps[gid].iterated_key0[2] = tmps[gid].key0[2]; + tmps[gid].iterated_key0[3] = tmps[gid].key0[3]; + tmps[gid].iterated_key1[0] = tmps[gid].key1[0]; + tmps[gid].iterated_key1[1] = tmps[gid].key1[1]; + tmps[gid].iterated_key1[2] = tmps[gid].key1[2]; + tmps[gid].iterated_key1[3] = tmps[gid].key1[3]; + + tmps[gid].iv[0] = 0; + tmps[gid].iv[1] = 0; + tmps[gid].iv[2] = 0; + tmps[gid].iv[3] = 0; +} + +KERNEL_FQ void m26500_loop (KERN_ATTR_TMPS_ESALT (iphone_passcode_tmp_t, iphone_passcode_t)) +{ + 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_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_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_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; + + // load stuff + + u32 key0[4]; + u32 key1[4]; + + key0[0] = tmps[gid].key0[0]; + key0[1] = tmps[gid].key0[1]; + key0[2] = tmps[gid].key0[2]; + key0[3] = tmps[gid].key0[3]; + key1[0] = tmps[gid].key1[0]; + key1[1] = tmps[gid].key1[1]; + key1[2] = tmps[gid].key1[2]; + key1[3] = tmps[gid].key1[3]; + + u32 iterated_key0[4]; + u32 iterated_key1[4]; + + iterated_key0[0] = tmps[gid].iterated_key0[0]; + iterated_key0[1] = tmps[gid].iterated_key0[1]; + iterated_key0[2] = tmps[gid].iterated_key0[2]; + iterated_key0[3] = tmps[gid].iterated_key0[3]; + iterated_key1[0] = tmps[gid].iterated_key1[0]; + iterated_key1[1] = tmps[gid].iterated_key1[1]; + iterated_key1[2] = tmps[gid].iterated_key1[2]; + iterated_key1[3] = tmps[gid].iterated_key1[3]; + + u32 iv[4]; + + iv[0] = tmps[gid].iv[0]; + iv[1] = tmps[gid].iv[1]; + iv[2] = tmps[gid].iv[2]; + iv[3] = tmps[gid].iv[3]; + + u32 ukey[4]; + + ukey[0] = esalt_bufs[DIGESTS_OFFSET].uidkey[0]; + ukey[1] = esalt_bufs[DIGESTS_OFFSET].uidkey[1]; + ukey[2] = esalt_bufs[DIGESTS_OFFSET].uidkey[2]; + ukey[3] = esalt_bufs[DIGESTS_OFFSET].uidkey[3]; + + u32 ks[44]; + + AES128_set_encrypt_key (ks, ukey, s_te0, s_te1, s_te2, s_te3); + + // here's what counts + + for (u32 i = 0, xorkey = loop_pos + 1; i < loop_cnt; i++, xorkey++) + { + u32 in[4]; + + in[0] = key0[0] ^ iv[0] ^ xorkey; + in[1] = key0[1] ^ iv[1] ^ xorkey; + in[2] = key0[2] ^ iv[2] ^ xorkey; + in[3] = key0[3] ^ iv[3] ^ xorkey; + + aes128_encrypt (ks, in, iv, s_te0, s_te1, s_te2, s_te3, s_te4); + + iterated_key0[0] ^= iv[0]; + iterated_key0[1] ^= iv[1]; + iterated_key0[2] ^= iv[2]; + iterated_key0[3] ^= iv[3]; + + in[0] = key1[0] ^ iv[0] ^ xorkey; + in[1] = key1[1] ^ iv[1] ^ xorkey; + in[2] = key1[2] ^ iv[2] ^ xorkey; + in[3] = key1[3] ^ iv[3] ^ xorkey; + + aes128_encrypt (ks, in, iv, s_te0, s_te1, s_te2, s_te3, s_te4); + + iterated_key1[0] ^= iv[0]; + iterated_key1[1] ^= iv[1]; + iterated_key1[2] ^= iv[2]; + iterated_key1[3] ^= iv[3]; + } + + tmps[gid].iterated_key0[0] = iterated_key0[0]; + tmps[gid].iterated_key0[1] = iterated_key0[1]; + tmps[gid].iterated_key0[2] = iterated_key0[2]; + tmps[gid].iterated_key0[3] = iterated_key0[3]; + tmps[gid].iterated_key1[0] = iterated_key1[0]; + tmps[gid].iterated_key1[1] = iterated_key1[1]; + tmps[gid].iterated_key1[2] = iterated_key1[2]; + tmps[gid].iterated_key1[3] = iterated_key1[3]; + + tmps[gid].iv[0] = iv[0]; + tmps[gid].iv[1] = iv[1]; + tmps[gid].iv[2] = iv[2]; + tmps[gid].iv[3] = iv[3]; +} + +KERNEL_FQ void m26500_comp (KERN_ATTR_TMPS_ESALT (iphone_passcode_tmp_t, iphone_passcode_t)) +{ + 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; + + /** + * aes + */ + + u32 ukey[8]; + + ukey[0] = tmps[gid].iterated_key0[0]; + ukey[1] = tmps[gid].iterated_key0[1]; + ukey[2] = tmps[gid].iterated_key0[2]; + ukey[3] = tmps[gid].iterated_key0[3]; + ukey[4] = tmps[gid].iterated_key1[0]; + ukey[5] = tmps[gid].iterated_key1[1]; + ukey[6] = tmps[gid].iterated_key1[2]; + ukey[7] = tmps[gid].iterated_key1[3]; + + u32 ks[60]; + + aes256_set_decrypt_key (ks, ukey, s_te0, s_te1, s_te2, s_te3, s_td0, s_td1, s_td2, s_td3); + + u32 cipher[4]; + + cipher[0] = esalt_bufs[DIGESTS_OFFSET].classkey1[0]; + cipher[1] = esalt_bufs[DIGESTS_OFFSET].classkey1[1]; + cipher[2] = 0; + cipher[3] = 0; + + u32 lsb[8]; + + lsb[0] = esalt_bufs[DIGESTS_OFFSET].classkey1[8]; + lsb[1] = esalt_bufs[DIGESTS_OFFSET].classkey1[9]; + lsb[2] = esalt_bufs[DIGESTS_OFFSET].classkey1[6]; + lsb[3] = esalt_bufs[DIGESTS_OFFSET].classkey1[7]; + lsb[4] = esalt_bufs[DIGESTS_OFFSET].classkey1[4]; + lsb[5] = esalt_bufs[DIGESTS_OFFSET].classkey1[5]; + lsb[6] = esalt_bufs[DIGESTS_OFFSET].classkey1[2]; + lsb[7] = esalt_bufs[DIGESTS_OFFSET].classkey1[3]; + + for (int j = 5; j >= 0; j--) + { + // 1st + + cipher[1] ^= (4 * j + 4); + + cipher[2] = lsb[0]; + cipher[3] = lsb[1]; + + AES256_decrypt (ks, cipher, cipher, s_td0, s_td1, s_td2, s_td3, s_td4); + + lsb[0] = cipher[2]; + lsb[1] = cipher[3]; + + // 2nd + + cipher[1] ^= (4 * j + 3); + + cipher[2] = lsb[2]; + cipher[3] = lsb[3]; + + AES256_decrypt (ks, cipher, cipher, s_td0, s_td1, s_td2, s_td3, s_td4); + + lsb[2] = cipher[2]; + lsb[3] = cipher[3]; + + // 3rd + + cipher[1] ^= (4 * j + 2); + + cipher[2] = lsb[4]; + cipher[3] = lsb[5]; + + AES256_decrypt (ks, cipher, cipher, s_td0, s_td1, s_td2, s_td3, s_td4); + + lsb[4] = cipher[2]; + lsb[5] = cipher[3]; + + // 4th + + cipher[1] ^= (4 * j + 1); + + cipher[2] = lsb[6]; + cipher[3] = lsb[7]; + + AES256_decrypt (ks, cipher, cipher, s_td0, s_td1, s_td2, s_td3, s_td4); + + lsb[6] = cipher[2]; + lsb[7] = cipher[3]; + } + + if ((cipher[0] == 0xa6a6a6a6) && (cipher[1] == 0xa6a6a6a6)) + { + if (hc_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); + } + + return; + } +} diff --git a/docs/changes.txt b/docs/changes.txt index bbaa736b5..e120ec9dc 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -10,6 +10,7 @@ - Added hash-mode: AES-128-ECB NOKDF (PT = $salt, key = $pass) - Added hash-mode: AES-192-ECB NOKDF (PT = $salt, key = $pass) - Added hash-mode: AES-256-ECB NOKDF (PT = $salt, key = $pass) +- Added hash-mode: iPhone passcode (UID key + System Keybag) ## ## Bugs diff --git a/docs/readme.txt b/docs/readme.txt index 8b618a8c1..1125cda5c 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -207,6 +207,7 @@ NVIDIA GPUs require "NVIDIA Driver" (440.64 or later) and "CUDA Toolkit" (9.0 or - Juniper IVE - Juniper NetScreen/SSG (ScreenOS) - Juniper/NetBSD sha1crypt +- iPhone passcode (UID key + System Keybag) - macOS v10.4, macOS v10.5, MacOS v10.6 - macOS v10.7 - macOS v10.8+ (PBKDF2-SHA512) diff --git a/src/modules/module_26500.c b/src/modules/module_26500.c new file mode 100644 index 000000000..b473bd0fb --- /dev/null +++ b/src/modules/module_26500.c @@ -0,0 +1,315 @@ +/** + * 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_OS; +static const char *HASH_NAME = "iPhone passcode (UID key + System Keybag)"; +static const u64 KERN_TYPE = 26500; +static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE; +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 = "$uido$77889b1bca161ce876d976a102c7bf82$3090545724551425617156367874312887832777$50000$2d4c86b71c0c04129a47c6468e2437d1fecd88e232a7b15112d5364682dc391dbbbb921cf6e02664"; + +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 iphone_passcode_tmp +{ + u32 key0[4]; // original key from pbkdf2 + u32 key1[4]; // original key from pbkdf2 + + u32 iterated_key0[4]; // updated key from pbkdf2 with iterations + u32 iterated_key1[4]; // updated key from pbkdf2 with iterations + + u32 iv[4]; // current iv + +} iphone_passcode_tmp_t; + +typedef struct iphone_passcode +{ + u32 uidkey[4]; + u32 classkey1[10]; + +} iphone_passcode_t; + +static const char *SIGNATURE_IPHONE_PASSCODE = "$uido$"; + +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 (iphone_passcode_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 (iphone_passcode_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; + + iphone_passcode_t *iphone_passcode = (iphone_passcode_t *) esalt_buf; + + token_t token; + + token.token_cnt = 5; + + token.signatures_cnt = 1; + token.signatures_buf[0] = SIGNATURE_IPHONE_PASSCODE; + + token.len[0] = 6; + token.attr[0] = TOKEN_ATTR_FIXED_LENGTH + | TOKEN_ATTR_VERIFY_SIGNATURE; + + token.sep[1] = '$'; + token.len_min[1] = 32; + token.len_max[1] = 32; + token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH + | TOKEN_ATTR_VERIFY_HEX; + + token.sep[2] = '$'; + token.len_min[2] = 40; + token.len_max[2] = 40; + token.attr[2] = TOKEN_ATTR_VERIFY_LENGTH + | TOKEN_ATTR_VERIFY_HEX; + + token.sep[3] = '$'; + token.len_min[3] = 1; + token.len_max[3] = 7; + token.attr[3] = TOKEN_ATTR_VERIFY_LENGTH + | TOKEN_ATTR_VERIFY_DIGIT; + + token.sep[4] = '$'; + token.len_min[4] = 80; + token.len_max[4] = 80; + 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); + + // uidkey + + const u8 *uidkey_pos = token.buf[1]; + + iphone_passcode->uidkey[0] = hex_to_u32 (uidkey_pos + 0); + iphone_passcode->uidkey[1] = hex_to_u32 (uidkey_pos + 8); + iphone_passcode->uidkey[2] = hex_to_u32 (uidkey_pos + 16); + iphone_passcode->uidkey[3] = hex_to_u32 (uidkey_pos + 24); + + iphone_passcode->uidkey[0] = byte_swap_32 (iphone_passcode->uidkey[0]); + iphone_passcode->uidkey[1] = byte_swap_32 (iphone_passcode->uidkey[1]); + iphone_passcode->uidkey[2] = byte_swap_32 (iphone_passcode->uidkey[2]); + iphone_passcode->uidkey[3] = byte_swap_32 (iphone_passcode->uidkey[3]); + + // salt + + const u8 *salt_pos = token.buf[2]; + + 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[0] = byte_swap_32 (salt->salt_buf[0]); + salt->salt_buf[1] = byte_swap_32 (salt->salt_buf[1]); + salt->salt_buf[2] = byte_swap_32 (salt->salt_buf[2]); + salt->salt_buf[3] = byte_swap_32 (salt->salt_buf[3]); + salt->salt_buf[4] = byte_swap_32 (salt->salt_buf[4]); + + salt->salt_len = 20; + + // iter + + const u8 *iter_pos = token.buf[3]; + + int iter = hc_strtoul ((const char *) iter_pos, NULL, 10); + + salt->salt_iter = iter; + + // classkey1 + + const u8 *classkey1_pos = token.buf[4]; + + iphone_passcode->classkey1[0] = hex_to_u32 (classkey1_pos + 0); + iphone_passcode->classkey1[1] = hex_to_u32 (classkey1_pos + 8); + iphone_passcode->classkey1[2] = hex_to_u32 (classkey1_pos + 16); + iphone_passcode->classkey1[3] = hex_to_u32 (classkey1_pos + 24); + iphone_passcode->classkey1[4] = hex_to_u32 (classkey1_pos + 32); + iphone_passcode->classkey1[5] = hex_to_u32 (classkey1_pos + 40); + iphone_passcode->classkey1[6] = hex_to_u32 (classkey1_pos + 48); + iphone_passcode->classkey1[7] = hex_to_u32 (classkey1_pos + 56); + iphone_passcode->classkey1[8] = hex_to_u32 (classkey1_pos + 64); + iphone_passcode->classkey1[9] = hex_to_u32 (classkey1_pos + 72); + + iphone_passcode->classkey1[0] = byte_swap_32 (iphone_passcode->classkey1[0]); + iphone_passcode->classkey1[1] = byte_swap_32 (iphone_passcode->classkey1[1]); + iphone_passcode->classkey1[2] = byte_swap_32 (iphone_passcode->classkey1[2]); + iphone_passcode->classkey1[3] = byte_swap_32 (iphone_passcode->classkey1[3]); + iphone_passcode->classkey1[4] = byte_swap_32 (iphone_passcode->classkey1[4]); + iphone_passcode->classkey1[5] = byte_swap_32 (iphone_passcode->classkey1[5]); + iphone_passcode->classkey1[6] = byte_swap_32 (iphone_passcode->classkey1[6]); + iphone_passcode->classkey1[7] = byte_swap_32 (iphone_passcode->classkey1[7]); + iphone_passcode->classkey1[8] = byte_swap_32 (iphone_passcode->classkey1[8]); + iphone_passcode->classkey1[9] = byte_swap_32 (iphone_passcode->classkey1[9]); + + // hash + + digest[0] = iphone_passcode->classkey1[0]; + digest[1] = iphone_passcode->classkey1[1]; + digest[2] = iphone_passcode->classkey1[2]; + digest[3] = iphone_passcode->classkey1[3]; + + 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 iphone_passcode_t *iphone_passcode = (const iphone_passcode_t *) esalt_buf; + + u8 *out_buf = (u8 *) line_buf; + + const int out_len = snprintf ((char *) out_buf, line_size, "%s%08x%08x%08x%08x$%08x%08x%08x%08x%08x$%d$%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", + SIGNATURE_IPHONE_PASSCODE, + iphone_passcode->uidkey[0], + iphone_passcode->uidkey[1], + iphone_passcode->uidkey[2], + iphone_passcode->uidkey[3], + salt->salt_buf[0], + salt->salt_buf[1], + salt->salt_buf[2], + salt->salt_buf[3], + salt->salt_buf[4], + salt->salt_iter, + iphone_passcode->classkey1[0], + iphone_passcode->classkey1[1], + iphone_passcode->classkey1[2], + iphone_passcode->classkey1[3], + iphone_passcode->classkey1[4], + iphone_passcode->classkey1[5], + iphone_passcode->classkey1[6], + iphone_passcode->classkey1[7], + iphone_passcode->classkey1[8], + iphone_passcode->classkey1[9]); + + return out_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_hook_extra_param_size = MODULE_DEFAULT; + module_ctx->module_hook_extra_param_init = MODULE_DEFAULT; + module_ctx->module_hook_extra_param_term = 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/m26500.pm b/tools/test_modules/m26500.pm new file mode 100644 index 000000000..f09f23bd9 --- /dev/null +++ b/tools/test_modules/m26500.pm @@ -0,0 +1,235 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Crypt::PBKDF2; +use Crypt::Mode::ECB; + +sub module_constraints { [[0, 256], [40, 40], [-1, -1], [-1, -1], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + my $iterations = shift // 50000; + my $uidkey = shift // random_hex_string (32); + my @classkeys = @_; + + my $pbkdf2 = Crypt::PBKDF2->new + ( + hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1'), + iterations => 1, + output_len => 32 + ); + + my $salt_bin = pack ("H*", $salt); + + my $data = $pbkdf2->PBKDF2 ($salt_bin, $word); + + my $uidkey_bin = pack ("H*", $uidkey); + + my $m = Crypt::Mode::ECB->new ('AES', 0); + + my $data0 = substr ($data, 0, 16); + my $data1 = substr ($data, 16, 16); + + my $iterated_key0 = $data0; + my $iterated_key1 = $data1; + + my $iv = "\x00" x 16; + + for (my $i = 0, my $xorkey = 1; $i < $iterations; $i++, $xorkey++) + { + my $xorkey_bin = pack ("LLLL", $xorkey, $xorkey, $xorkey, $xorkey); + + my $in0 = $data0 ^ $iv ^ $xorkey_bin; + + $iv = $m->encrypt ($in0, $uidkey_bin); + + $iterated_key0 ^= $iv; + + my $in1 = $data1 ^ $iv ^ $xorkey_bin; + + $iv = $m->encrypt ($in1, $uidkey_bin); + + $iterated_key1 ^= $iv; + } + + my $iterated_key = $iterated_key0 . $iterated_key1; + + my $UIDO_BACKUP_KEY = 12008468691120727718; # 0xa6a6a6a6a6a6a6a6 + + if (scalar @classkeys) + { + my $classkey1_bin = pack ("H*", $classkeys[0]); + + my ($A, $R) = uido_aes_unwrap ($iterated_key, $classkey1_bin); + + if ($A != $UIDO_BACKUP_KEY) + { + $classkeys[0] = "0" x 80; + } + } + else + { + my $max_number = 18446744073709551615; # 0xffffffffffffffff + + my @R; + + for (my $i = 0; $i < 4; $i++) + { + $R[$i] = random_number (0, $max_number); + } + + my $classkey1_bin = uido_aes_wrap ($iterated_key, $UIDO_BACKUP_KEY, \@R); + + push (@classkeys, unpack ("H*", $classkey1_bin)); + } + + my $hash = sprintf ("\$uido\$%s\$%s\$%u\$%s", unpack ("H*", $uidkey_bin), unpack ("H*", $salt_bin), $iterations, join ("\$", @classkeys)); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split (':', $line); + + return unless defined $hash; + return unless defined $word; + + my @data = split ('\$', $hash); + + shift @data; + + my $signature = shift @data; + my $uidkey = shift @data; + my $salt = shift @data; + my $iterations = shift @data; + + return unless ($signature eq 'uido'); + + return unless defined $uidkey; + return unless length ($uidkey) == 32; + return unless defined $salt; + return unless defined $iterations; + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt, $iterations, $uidkey, @data); + + return ($new_hash, $word); +} + +sub uido_aes_wrap +{ + my $key = shift; + my $A = shift; + my $R_l = shift; + + my $k = scalar (@$R_l); + my $n = $k + 1; + + my @R; + + for (my $i = 0; $i < $n; $i++) + { + $R[$i] = @$R_l[$i]; + } + + # AES mode ECB + + my $m = Crypt::Mode::ECB->new ('AES', 0); + + # main wrap loop + + my ($i, $j, $a); + + for ($j = 0; $j <= 5; $j++) + { + for ($i = 1, $a = 0; $i <= $k; $i++, $a++) + { + my $input; + + $input = pack ("Q>", $A); + $input .= pack ("Q>", $R[$a]); + + my $t = $m->encrypt ($input, $key); + + $A = unpack ("Q>", substr ($t, 0, 8)); + $A ^= $k * $j + $i; + + $R[$a] = unpack ("Q>", substr ($t, 8, 8)); + } + } + + my $WPKY = pack ("Q>", $A); + + for (my $i = 0; $i < $k; $i++) + { + $WPKY .= pack ("Q>", $R[$i]); + } + + return $WPKY; +} + +sub uido_aes_unwrap +{ + my $key = shift; + my $WPKY = shift; + + my @B; + + for (my $i = 0; $i < length ($WPKY) / 8; $i++) + { + $B[$i] = unpack ("Q>", substr ($WPKY, $i * 8, 8)); + } + + my $n = scalar (@B); + my $k = $n - 1; + + my @R; + + for (my $i = 0; $i < $k; $i++) + { + $R[$i] = $B[$i + 1]; + } + + # AES mode ECB + + my $m = Crypt::Mode::ECB->new ('AES', 0); + + # main unwrap loop + + my $A = $B[0]; + + my ($i, $j, $a); + + for ($j = 5; $j >= 0; $j--) + { + for ($i = $k, $a = $k - 1; $i > 0; $i--, $a--) + { + my $input; + + $input = pack ("Q>", $A ^ ($k * $j + $i)); + $input .= pack ("Q>", $R[$a]); + + my $t = $m->decrypt ($input, $key); + + $A = unpack ("Q>", substr ($t, 0, 8)); + $R[$a] = unpack ("Q>", substr ($t, 8, 8)); + } + } + + return ($A, \@R); +} + +1;