added Radmin3

pull/3295/head
piwvvo 2 years ago
parent 7284f17f7d
commit b0ceb41e4a

File diff suppressed because it is too large Load Diff

@ -0,0 +1,22 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#ifndef _INC_BIGNUM_OPERATIONS_H
#define _INC_BIGNUM_OPERATIONS_H
DECLSPEC void mod_4096 (PRIVATE_AS u32 *n, PRIVATE_AS const u32 *m);
DECLSPEC void mul (PRIVATE_AS u32 *r, PRIVATE_AS const u32 *x, PRIVATE_AS const u32 *y);
DECLSPEC void mul_masked (PRIVATE_AS u32 *r, PRIVATE_AS const u32 *x, PRIVATE_AS const u32 *y);
DECLSPEC void mul_mod (PRIVATE_AS u32 *x, PRIVATE_AS const u32 *y, PRIVATE_AS const u32 *m, PRIVATE_AS const u32 *fact);
DECLSPEC void pow_mod_precomp_g (PRIVATE_AS u32 *r, PRIVATE_AS const u32 *b_pre, PRIVATE_AS const u32 *y, PRIVATE_AS const u32 *m, PRIVATE_AS const u32 *fact);
DECLSPEC void pow_mod (PRIVATE_AS u32 *r, PRIVATE_AS u32 *x, PRIVATE_AS const u32 *y, PRIVATE_AS const u32 *m, PRIVATE_AS const u32 *fact);
DECLSPEC void simple_euclidean_gcd (PRIVATE_AS u32 *u, PRIVATE_AS u32 *v, PRIVATE_AS const u32 *m);
DECLSPEC void to_montgomery (PRIVATE_AS u32 *r, PRIVATE_AS const u32 *a, PRIVATE_AS const u32 *m);
DECLSPEC void from_montgomery (PRIVATE_AS u32 *r, PRIVATE_AS const u32* a, PRIVATE_AS const u32 *m, PRIVATE_AS const u32 *rinv);
#endif // _INC_BIGNUM_OPERATIONS_H

@ -0,0 +1,73 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#ifndef _INC_RADMIN3_CONSTANTS_H
#define _INC_RADMIN3_CONSTANTS_H
#define PRECOMP_BITS 10
#define PRECOMP_VECLEN 160 // SHA1 hash (in bits, 20 bytes)
#define PRECOMP_SLOTS (PRECOMP_VECLEN / PRECOMP_BITS)
#define PRECOMP_ENTRIES (1 << PRECOMP_BITS) // 2 ^ PRECOMP_BITS
#define PRECOMP_ENTRYLEN 256 / 4 // data len in u32 (therefore divided by 4 bytes)
#define PRECOMP_DATALEN (PRECOMP_ENTRIES - 1) * PRECOMP_SLOTS * PRECOMP_ENTRYLEN
#define PRECOMP_MASK 0xffffffff >> (32 - PRECOMP_BITS)
CONSTANT_VK u32 RADMIN3_M[128] =
{
0x740a682f, 0x7b379fd7, 0x4af5b8d3, 0xd70b2bca, 0xd7f51544, 0xe5a4ccf5,
0x24c9e5a2, 0x30ebc4fd, 0x40a71f19, 0xfaa0c43b, 0x2bfe7dba, 0xac9278b9,
0x97245bd2, 0x9c4d18f6, 0x89dfd06c, 0x6091acea, 0x8ba2332d, 0x2cfb3b52,
0x5350dec7, 0x34fd0fd4, 0x125db8ad, 0x149167ea, 0x01f560dd, 0x0fdbaf46,
0x6b0c6bdb, 0xc5473fdb, 0x36fc4f80, 0xb8f90dea, 0x48598f2c, 0x590387f5,
0xe63ec4b3, 0x021c881a, 0xa0d18a79, 0xbdd952f7, 0xe99e6127, 0xedbba5ea,
0x102fc6ce, 0xf8bdd56a, 0x66261cd3, 0xdb701022, 0x0db4db96, 0x2d7cdf81,
0x2cbdd4ac, 0xca9f0806, 0x5503342e, 0x81a32da9, 0xfd0f9e29, 0xffd8df96,
0x4dd09947, 0xef2fcd2a, 0x0dfe4178, 0x86b0dbe6, 0x92cf3357, 0x8e0c3bff,
0x53e36fb6, 0xcafca04a, 0x3e2cec58, 0x13b406f2, 0xd4304b01, 0xaec0b980,
0x587d8f77, 0x5d02f19d, 0x0f891dfd, 0x9847fc7e, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000,
};
CONSTANT_VK u32 RADMIN3_R[64] =
{
0x8bf597d1, 0x84c86028, 0xb50a472c, 0x28f4d435, 0x280aeabb, 0x1a5b330a,
0xdb361a5d, 0xcf143b02, 0xbf58e0e6, 0x055f3bc4, 0xd4018245, 0x536d8746,
0x68dba42d, 0x63b2e709, 0x76202f93, 0x9f6e5315, 0x745dccd2, 0xd304c4ad,
0xacaf2138, 0xcb02f02b, 0xeda24752, 0xeb6e9815, 0xfe0a9f22, 0xf02450b9,
0x94f39424, 0x3ab8c024, 0xc903b07f, 0x4706f215, 0xb7a670d3, 0xa6fc780a,
0x19c13b4c, 0xfde377e5, 0x5f2e7586, 0x4226ad08, 0x16619ed8, 0x12445a15,
0xefd03931, 0x07422a95, 0x99d9e32c, 0x248fefdd, 0xf24b2469, 0xd283207e,
0xd3422b53, 0x3560f7f9, 0xaafccbd1, 0x7e5cd256, 0x02f061d6, 0x00272069,
0xb22f66b8, 0x10d032d5, 0xf201be87, 0x794f2419, 0x6d30cca8, 0x71f3c400,
0xac1c9049, 0x35035fb5, 0xc1d313a7, 0xec4bf90d, 0x2bcfb4fe, 0x513f467f,
0xa7827088, 0xa2fd0e62, 0xf076e202, 0x67b80381,
};
CONSTANT_VK u32 RADMIN3_FACT[64] =
{
0xfdac2131, 0x56654c77, 0x3e4a8d19, 0x5a1a861c, 0x7906adbd, 0x89d806d0,
0x26a253a8, 0xcb8c8be2, 0xb62eb887, 0xa2364fb0, 0xbff19140, 0x79aa7301,
0x78ee9576, 0x554ba4e6, 0xa4f3efd8, 0x7637a767, 0xb413facb, 0xf333933b,
0xb50a03bc, 0xf100305f, 0x0e3d5ca2, 0x57c949a8, 0x4e73b61d, 0xced3203c,
0x578439b1, 0x37ed2593, 0x8fb7c6d4, 0x7cb1f2ab, 0xc035c148, 0xd9defd19,
0x04bf254a, 0xcb970a46, 0xf2a7960c, 0x69a651f6, 0x6adc8010, 0x9e05042d,
0x4e56ef9d, 0x595b31c9, 0x3f455d15, 0xf703c3e3, 0x3f164848, 0xe4bd5f3a,
0x62101b16, 0x01138387, 0xf346380e, 0x2358d5cd, 0xc839e279, 0xa31123b1,
0x45f240ea, 0xe39f2352, 0x91e590cb, 0x6d11e378, 0x04e89126, 0x904b2390,
0xa11b556d, 0xb6d7dcfb, 0x6e826c53, 0x1392b6e4, 0xa76eefe9, 0x6c770e4d,
0x0312ac4d, 0x73aa4ff4, 0x39ad3b1f, 0xfad6fce6,
};
#endif // _INC_RADMIN3_CONSTANTS_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,470 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
* This algorithm for password-storage for the Radmin 3 software was analyzed and made public by synacktiv:
* https://www.synacktiv.com/publications/cracking-radmin-server-3-passwords.html
*/
//#define NEW_SIMD_CODE
#ifdef KERNEL_STATIC
#include M2S(INCLUDE_PATH/inc_vendor.h)
#include M2S(INCLUDE_PATH/inc_types.h)
#include M2S(INCLUDE_PATH/inc_platform.cl)
#include M2S(INCLUDE_PATH/inc_common.cl)
#include M2S(INCLUDE_PATH/inc_rp.h)
#include M2S(INCLUDE_PATH/inc_rp.cl)
#include M2S(INCLUDE_PATH/inc_scalar.cl)
#include M2S(INCLUDE_PATH/inc_hash_sha1.cl)
#include M2S(INCLUDE_PATH/inc_bignum_operations.cl)
#include M2S(INCLUDE_PATH/inc_radmin3_constants.h)
#endif
typedef struct radmin3
{
u32 user[64];
u32 user_len;
u32 pre[PRECOMP_DATALEN]; // 38400 for PRECOMP_BITS = 4
} radmin3_t;
KERNEL_FQ void m29200_mxx (KERN_ATTR_RULES_ESALT (radmin3_t))
{
/**
* modifier
*/
const u64 lid = get_local_id (0);
const u64 gid = get_global_id (0);
const u64 lsz = get_local_size (0);
/**
* cache constant values to shared memory
*/
LOCAL_VK u32 m[64];
LOCAL_VK u32 r[64];
LOCAL_VK u32 fact[64];
for (u32 i = lid; i < 64; i += lsz)
{
m[i] = RADMIN3_M[i];
r[i] = RADMIN3_R[i];
fact[i] = RADMIN3_FACT[i];
}
SYNC_THREADS ();
if (gid >= GID_CNT) return;
/**
* base
*/
// ctx0 with user
sha1_ctx_t ctx0;
sha1_init (&ctx0);
sha1_update_global (&ctx0, esalt_bufs[DIGESTS_OFFSET_HOST].user, esalt_bufs[DIGESTS_OFFSET_HOST].user_len);
// ctx1 with main salt
sha1_ctx_t ctx1;
sha1_init (&ctx1);
sha1_update_global (&ctx1, salt_bufs[SALT_POS_HOST].salt_buf, salt_bufs[SALT_POS_HOST].salt_len);
COPY_PW (pws[gid]);
/**
* loop
*/
for (u32 il_pos = 0; il_pos < IL_CNT; il_pos++)
{
pw_t tmp = PASTE_PW;
tmp.pw_len = apply_rules (rules_buf[il_pos].cmds, tmp.i, tmp.pw_len);
// add password to the user name (and colon, included):
sha1_ctx_t c0 = ctx0;
sha1_update_utf16le_swap (&c0, tmp.i, tmp.pw_len);
sha1_final (&c0);
// add first SHA1 result to main salt:
sha1_ctx_t c1 = ctx1;
u32 w0[4] = { 0 };
u32 w1[4] = { 0 };
u32 w2[4] = { 0 };
u32 w3[4] = { 0 };
w0[0] = c0.h[0];
w0[1] = c0.h[1];
w0[2] = c0.h[2];
w0[3] = c0.h[3];
w1[0] = c0.h[4];
sha1_update_64 (&c1, w0, w1, w2, w3, 20);
sha1_final (&c1);
const u32 e[5] = { c1.h[4], c1.h[3], c1.h[2], c1.h[1], c1.h[0] };
// u32 r_t[64]; for (u32 i = 0; i < 64; i++) r_t[i] = r[i];
u32 r_t[64] =
{
r[ 0], r[ 1], r[ 2], r[ 3], r[ 4], r[ 5], r[ 6], r[ 7],
r[ 8], r[ 9], r[10], r[11], r[12], r[13], r[14], r[15],
r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23],
r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31],
r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39],
r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47],
r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55],
r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63],
};
// main loop over the SHA1 result/vector e[]:
for (u32 i = 0, j = 0; i < PRECOMP_SLOTS; i += 1, j += PRECOMP_ENTRIES - 1)
{
const u32 div = (PRECOMP_BITS * i) / 32; // for 4 bits: (i / 8)
const u32 shift = (PRECOMP_BITS * i) % 32; // for 4 bits: (i % 8) * 4
// const
u32 cur_sel = (e[div] >> shift) & PRECOMP_MASK; // 0x0f == 0b1111 (4 bits)
// working with non-divisible u32 (see PRECOMP_BITS):
if (32 - shift < PRECOMP_BITS)
{
cur_sel |= (e[div + 1] << (32 - shift)) & PRECOMP_MASK;
}
if (cur_sel == 0) continue;
const u32 pre_idx = (j + cur_sel - 1) * PRECOMP_ENTRYLEN; // x * 64 is same as x << 6
// u32 pre[64]; for (u32 i = 0; i < 64; i++) pre[i] = esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + i];
const u32 pre[64] =
{
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 0],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 1],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 2],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 3],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 4],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 5],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 6],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 7],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 8],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 9],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 10],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 11],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 12],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 13],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 14],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 15],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 16],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 17],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 18],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 19],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 20],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 21],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 22],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 23],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 24],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 25],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 26],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 27],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 28],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 29],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 30],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 31],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 32],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 33],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 34],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 35],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 36],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 37],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 38],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 39],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 40],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 41],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 42],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 43],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 44],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 45],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 46],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 47],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 48],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 49],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 50],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 51],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 52],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 53],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 54],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 55],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 56],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 57],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 58],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 59],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 60],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 61],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 62],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 63],
};
mul_mod (r_t, pre, m, fact); // r_t = (r_t * RADMIN3_PRE[n]) % m
}
const u32 r0 = r_t[0];
const u32 r1 = r_t[1];
const u32 r2 = r_t[2];
const u32 r3 = r_t[3];
COMPARE_M_SCALAR (r0, r1, r2, r3);
}
}
KERNEL_FQ void m29200_sxx (KERN_ATTR_RULES_ESALT (radmin3_t))
{
/**
* modifier
*/
const u64 lid = get_local_id (0);
const u64 gid = get_global_id (0);
const u64 lsz = get_local_size (0);
/**
* cache constant values to shared memory
*/
LOCAL_VK u32 m[64];
LOCAL_VK u32 r[64];
LOCAL_VK u32 fact[64];
for (u32 i = lid; i < 64; i += lsz)
{
m[i] = RADMIN3_M[i];
r[i] = RADMIN3_R[i];
fact[i] = RADMIN3_FACT[i];
}
SYNC_THREADS ();
if (gid >= GID_CNT) return;
/**
* digest
*/
const u32 search[4] =
{
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R0],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R1],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R2],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R3]
};
/**
* base
*/
// ctx0 with user
sha1_ctx_t ctx0;
sha1_init (&ctx0);
sha1_update_global (&ctx0, esalt_bufs[DIGESTS_OFFSET_HOST].user, esalt_bufs[DIGESTS_OFFSET_HOST].user_len);
// ctx1 with main salt
sha1_ctx_t ctx1;
sha1_init (&ctx1);
sha1_update_global (&ctx1, salt_bufs[SALT_POS_HOST].salt_buf, salt_bufs[SALT_POS_HOST].salt_len);
COPY_PW (pws[gid]);
/**
* loop
*/
for (u32 il_pos = 0; il_pos < IL_CNT; il_pos++)
{
pw_t tmp = PASTE_PW;
tmp.pw_len = apply_rules (rules_buf[il_pos].cmds, tmp.i, tmp.pw_len);
// add password to the user name (and colon, included):
sha1_ctx_t c0 = ctx0;
sha1_update_utf16le_swap (&c0, tmp.i, tmp.pw_len);
sha1_final (&c0);
// add first SHA1 result to main salt:
sha1_ctx_t c1 = ctx1;
u32 w0[4] = { 0 };
u32 w1[4] = { 0 };
u32 w2[4] = { 0 };
u32 w3[4] = { 0 };
w0[0] = c0.h[0];
w0[1] = c0.h[1];
w0[2] = c0.h[2];
w0[3] = c0.h[3];
w1[0] = c0.h[4];
sha1_update_64 (&c1, w0, w1, w2, w3, 20);
sha1_final (&c1);
const u32 e[5] = { c1.h[4], c1.h[3], c1.h[2], c1.h[1], c1.h[0] };
// u32 r_t[64]; for (u32 i = 0; i < 64; i++) r_t[i] = r[i];
u32 r_t[64] =
{
r[ 0], r[ 1], r[ 2], r[ 3], r[ 4], r[ 5], r[ 6], r[ 7],
r[ 8], r[ 9], r[10], r[11], r[12], r[13], r[14], r[15],
r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23],
r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31],
r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39],
r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47],
r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55],
r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63],
};
// main loop over the SHA1 result/vector e[]:
for (u32 i = 0, j = 0; i < PRECOMP_SLOTS; i += 1, j += PRECOMP_ENTRIES - 1)
{
const u32 div = (PRECOMP_BITS * i) / 32; // for 4 bits: (i / 8)
const u32 shift = (PRECOMP_BITS * i) % 32; // for 4 bits: (i % 8) * 4
// const
u32 cur_sel = (e[div] >> shift) & PRECOMP_MASK; // 0x0f == 0b1111 (4 bits)
// working with non-divisible u32 (see PRECOMP_BITS):
if (32 - shift < PRECOMP_BITS)
{
cur_sel |= (e[div + 1] << (32 - shift)) & PRECOMP_MASK;
}
if (cur_sel == 0) continue;
const u32 pre_idx = (j + cur_sel - 1) * PRECOMP_ENTRYLEN; // x * 64 is same as x << 6
// u32 pre[64]; for (u32 i = 0; i < 64; i++) pre[i] = esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + i];
const u32 pre[64] =
{
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 0],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 1],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 2],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 3],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 4],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 5],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 6],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 7],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 8],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 9],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 10],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 11],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 12],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 13],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 14],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 15],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 16],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 17],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 18],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 19],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 20],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 21],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 22],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 23],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 24],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 25],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 26],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 27],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 28],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 29],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 30],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 31],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 32],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 33],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 34],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 35],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 36],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 37],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 38],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 39],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 40],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 41],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 42],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 43],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 44],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 45],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 46],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 47],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 48],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 49],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 50],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 51],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 52],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 53],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 54],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 55],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 56],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 57],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 58],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 59],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 60],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 61],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 62],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 63],
};
mul_mod (r_t, pre, m, fact); // r_t = (r_t * RADMIN3_PRE[n]) % m
}
const u32 r0 = r_t[0];
const u32 r1 = r_t[1];
const u32 r2 = r_t[2];
const u32 r3 = r_t[3];
COMPARE_S_SCALAR (r0, r1, r2, r3);
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,479 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
* This algorithm for password-storage for the Radmin 3 software was analyzed and made public by synacktiv:
* https://www.synacktiv.com/publications/cracking-radmin-server-3-passwords.html
*/
//#define NEW_SIMD_CODE
#ifdef KERNEL_STATIC
#include M2S(INCLUDE_PATH/inc_vendor.h)
#include M2S(INCLUDE_PATH/inc_types.h)
#include M2S(INCLUDE_PATH/inc_platform.cl)
#include M2S(INCLUDE_PATH/inc_common.cl)
#include M2S(INCLUDE_PATH/inc_scalar.cl)
#include M2S(INCLUDE_PATH/inc_hash_sha1.cl)
#include M2S(INCLUDE_PATH/inc_bignum_operations.cl)
#include M2S(INCLUDE_PATH/inc_radmin3_constants.h)
#endif
typedef struct radmin3
{
u32 user[64];
u32 user_len;
u32 pre[PRECOMP_DATALEN]; // 38400 for PRECOMP_BITS = 4
} radmin3_t;
KERNEL_FQ void m29200_mxx (KERN_ATTR_ESALT (radmin3_t))
{
/**
* modifier
*/
const u64 lid = get_local_id (0);
const u64 gid = get_global_id (0);
const u64 lsz = get_local_size (0);
/**
* cache constant values to shared memory
*/
LOCAL_VK u32 m[64];
LOCAL_VK u32 r[64];
LOCAL_VK u32 fact[64];
for (u32 i = lid; i < 64; i += lsz)
{
m[i] = RADMIN3_M[i];
r[i] = RADMIN3_R[i];
fact[i] = RADMIN3_FACT[i];
}
SYNC_THREADS ();
if (gid >= GID_CNT) return;
/**
* base
*/
const u32 pw_len = pws[gid].pw_len;
u32x w[64] = { 0 };
for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
{
w[idx] = pws[gid].i[idx];
}
// ctx0 with user
sha1_ctx_t ctx0;
sha1_init (&ctx0);
sha1_update_global (&ctx0, esalt_bufs[DIGESTS_OFFSET_HOST].user, esalt_bufs[DIGESTS_OFFSET_HOST].user_len);
sha1_update_utf16le_swap (&ctx0, w, pw_len);
// ctx1 with main salt
sha1_ctx_t ctx1;
sha1_init (&ctx1);
sha1_update_global (&ctx1, salt_bufs[SALT_POS_HOST].salt_buf, salt_bufs[SALT_POS_HOST].salt_len);
/**
* loop
*/
for (u32 il_pos = 0; il_pos < IL_CNT; il_pos++)
{
// add password to the user name (and colon and first part of the password, included):
sha1_ctx_t c0 = ctx0;
sha1_update_global_utf16le_swap (&c0, combs_buf[il_pos].i, combs_buf[il_pos].pw_len);
sha1_final (&c0);
// add first SHA1 result to main salt:
sha1_ctx_t c1 = ctx1;
u32 w0_t[4] = { 0 };
u32 w1_t[4] = { 0 };
u32 w2_t[4] = { 0 };
u32 w3_t[4] = { 0 };
w0_t[0] = c0.h[0];
w0_t[1] = c0.h[1];
w0_t[2] = c0.h[2];
w0_t[3] = c0.h[3];
w1_t[0] = c0.h[4];
sha1_update_64 (&c1, w0_t, w1_t, w2_t, w3_t, 20);
sha1_final (&c1);
const u32 e[5] = { c1.h[4], c1.h[3], c1.h[2], c1.h[1], c1.h[0] };
// u32 r_t[64]; for (u32 i = 0; i < 64; i++) r_t[i] = r[i];
u32 r_t[64] =
{
r[ 0], r[ 1], r[ 2], r[ 3], r[ 4], r[ 5], r[ 6], r[ 7],
r[ 8], r[ 9], r[10], r[11], r[12], r[13], r[14], r[15],
r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23],
r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31],
r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39],
r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47],
r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55],
r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63],
};
// main loop over the SHA1 result/vector e[]:
for (u32 i = 0, j = 0; i < PRECOMP_SLOTS; i += 1, j += PRECOMP_ENTRIES - 1)
{
const u32 div = (PRECOMP_BITS * i) / 32; // for 4 bits: (i / 8)
const u32 shift = (PRECOMP_BITS * i) % 32; // for 4 bits: (i % 8) * 4
// const
u32 cur_sel = (e[div] >> shift) & PRECOMP_MASK; // 0x0f == 0b1111 (4 bits)
// working with non-divisible u32 (see PRECOMP_BITS):
if (32 - shift < PRECOMP_BITS)
{
cur_sel |= (e[div + 1] << (32 - shift)) & PRECOMP_MASK;
}
if (cur_sel == 0) continue;
const u32 pre_idx = (j + cur_sel - 1) * PRECOMP_ENTRYLEN; // x * 64 is same as x << 6
// u32 pre[64]; for (u32 i = 0; i < 64; i++) pre[i] = esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + i];
const u32 pre[64] =
{
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 0],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 1],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 2],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 3],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 4],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 5],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 6],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 7],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 8],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 9],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 10],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 11],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 12],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 13],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 14],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 15],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 16],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 17],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 18],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 19],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 20],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 21],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 22],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 23],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 24],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 25],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 26],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 27],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 28],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 29],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 30],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 31],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 32],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 33],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 34],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 35],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 36],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 37],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 38],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 39],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 40],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 41],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 42],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 43],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 44],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 45],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 46],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 47],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 48],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 49],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 50],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 51],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 52],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 53],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 54],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 55],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 56],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 57],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 58],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 59],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 60],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 61],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 62],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 63],
};
mul_mod (r_t, pre, m, fact); // r_t = (r_t * RADMIN3_PRE[n]) % m
}
const u32 r0 = r_t[0];
const u32 r1 = r_t[1];
const u32 r2 = r_t[2];
const u32 r3 = r_t[3];
COMPARE_M_SCALAR (r0, r1, r2, r3);
}
}
KERNEL_FQ void m29200_sxx (KERN_ATTR_ESALT (radmin3_t))
{
/**
* modifier
*/
const u64 lid = get_local_id (0);
const u64 gid = get_global_id (0);
const u64 lsz = get_local_size (0);
/**
* cache constant values to shared memory
*/
LOCAL_VK u32 m[64];
LOCAL_VK u32 r[64];
LOCAL_VK u32 fact[64];
for (u32 i = lid; i < 64; i += lsz)
{
m[i] = RADMIN3_M[i];
r[i] = RADMIN3_R[i];
fact[i] = RADMIN3_FACT[i];
}
SYNC_THREADS ();
if (gid >= GID_CNT) return;
/**
* digest
*/
const u32 search[4] =
{
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R0],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R1],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R2],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R3]
};
/**
* base
*/
const u32 pw_len = pws[gid].pw_len;
u32x w[64] = { 0 };
for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
{
w[idx] = pws[gid].i[idx];
}
// ctx0 with user
sha1_ctx_t ctx0;
sha1_init (&ctx0);
sha1_update_global (&ctx0, esalt_bufs[DIGESTS_OFFSET_HOST].user, esalt_bufs[DIGESTS_OFFSET_HOST].user_len);
sha1_update_utf16le_swap (&ctx0, w, pw_len);
// ctx1 with main salt
sha1_ctx_t ctx1;
sha1_init (&ctx1);
sha1_update_global (&ctx1, salt_bufs[SALT_POS_HOST].salt_buf, salt_bufs[SALT_POS_HOST].salt_len);
/**
* loop
*/
for (u32 il_pos = 0; il_pos < IL_CNT; il_pos++)
{
// add password to the user name (and colon and first part of the password, included):
sha1_ctx_t c0 = ctx0;
sha1_update_global_utf16le_swap (&c0, combs_buf[il_pos].i, combs_buf[il_pos].pw_len);
sha1_final (&c0);
// add first SHA1 result to main salt:
sha1_ctx_t c1 = ctx1;
u32 w0_t[4] = { 0 };
u32 w1_t[4] = { 0 };
u32 w2_t[4] = { 0 };
u32 w3_t[4] = { 0 };
w0_t[0] = c0.h[0];
w0_t[1] = c0.h[1];
w0_t[2] = c0.h[2];
w0_t[3] = c0.h[3];
w1_t[0] = c0.h[4];
sha1_update_64 (&c1, w0_t, w1_t, w2_t, w3_t, 20);
sha1_final (&c1);
const u32 e[5] = { c1.h[4], c1.h[3], c1.h[2], c1.h[1], c1.h[0] };
// u32 r_t[64]; for (u32 i = 0; i < 64; i++) r_t[i] = r[i];
u32 r_t[64] =
{
r[ 0], r[ 1], r[ 2], r[ 3], r[ 4], r[ 5], r[ 6], r[ 7],
r[ 8], r[ 9], r[10], r[11], r[12], r[13], r[14], r[15],
r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23],
r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31],
r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39],
r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47],
r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55],
r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63],
};
// main loop over the SHA1 result/vector e[]:
for (u32 i = 0, j = 0; i < PRECOMP_SLOTS; i += 1, j += PRECOMP_ENTRIES - 1)
{
const u32 div = (PRECOMP_BITS * i) / 32; // for 4 bits: (i / 8)
const u32 shift = (PRECOMP_BITS * i) % 32; // for 4 bits: (i % 8) * 4
// const
u32 cur_sel = (e[div] >> shift) & PRECOMP_MASK; // 0x0f == 0b1111 (4 bits)
// working with non-divisible u32 (see PRECOMP_BITS):
if (32 - shift < PRECOMP_BITS)
{
cur_sel |= (e[div + 1] << (32 - shift)) & PRECOMP_MASK;
}
if (cur_sel == 0) continue;
const u32 pre_idx = (j + cur_sel - 1) * PRECOMP_ENTRYLEN; // x * 64 is same as x << 6
// u32 pre[64]; for (u32 i = 0; i < 64; i++) pre[i] = esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + i];
const u32 pre[64] =
{
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 0],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 1],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 2],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 3],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 4],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 5],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 6],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 7],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 8],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 9],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 10],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 11],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 12],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 13],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 14],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 15],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 16],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 17],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 18],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 19],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 20],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 21],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 22],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 23],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 24],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 25],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 26],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 27],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 28],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 29],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 30],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 31],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 32],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 33],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 34],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 35],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 36],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 37],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 38],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 39],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 40],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 41],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 42],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 43],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 44],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 45],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 46],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 47],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 48],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 49],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 50],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 51],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 52],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 53],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 54],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 55],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 56],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 57],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 58],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 59],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 60],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 61],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 62],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 63],
};
mul_mod (r_t, pre, m, fact); // r_t = (r_t * RADMIN3_PRE[n]) % m
}
const u32 r0 = r_t[0];
const u32 r1 = r_t[1];
const u32 r2 = r_t[2];
const u32 r3 = r_t[3];
COMPARE_S_SCALAR (r0, r1, r2, r3);
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,493 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
* This algorithm for password-storage for the Radmin 3 software was analyzed and made public by synacktiv:
* https://www.synacktiv.com/publications/cracking-radmin-server-3-passwords.html
*/
//#define NEW_SIMD_CODE
#ifdef KERNEL_STATIC
#include M2S(INCLUDE_PATH/inc_vendor.h)
#include M2S(INCLUDE_PATH/inc_types.h)
#include M2S(INCLUDE_PATH/inc_platform.cl)
#include M2S(INCLUDE_PATH/inc_common.cl)
#include M2S(INCLUDE_PATH/inc_scalar.cl)
#include M2S(INCLUDE_PATH/inc_hash_sha1.cl)
#include M2S(INCLUDE_PATH/inc_bignum_operations.cl)
#include M2S(INCLUDE_PATH/inc_radmin3_constants.h)
#endif
typedef struct radmin3
{
u32 user[64];
u32 user_len;
u32 pre[PRECOMP_DATALEN]; // 38400 for PRECOMP_BITS = 4
} radmin3_t;
KERNEL_FQ void m29200_mxx (KERN_ATTR_VECTOR_ESALT (radmin3_t))
{
/**
* modifier
*/
const u64 lid = get_local_id (0);
const u64 gid = get_global_id (0);
const u64 lsz = get_local_size (0);
/**
* cache constant values to shared memory
*/
LOCAL_VK u32 m[64];
LOCAL_VK u32 r[64];
LOCAL_VK u32 fact[64];
for (u32 i = lid; i < 64; i += lsz)
{
m[i] = RADMIN3_M[i];
r[i] = RADMIN3_R[i];
fact[i] = RADMIN3_FACT[i];
}
SYNC_THREADS ();
if (gid >= GID_CNT) return;
/**
* base
*/
const u32 pw_len = pws[gid].pw_len;
u32x w[64] = { 0 };
for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
{
w[idx] = pws[gid].i[idx];
}
// ctx0 with user
sha1_ctx_t ctx0;
sha1_init (&ctx0);
sha1_update_global (&ctx0, esalt_bufs[DIGESTS_OFFSET_HOST].user, esalt_bufs[DIGESTS_OFFSET_HOST].user_len);
// ctx1 with main salt
sha1_ctx_t ctx1;
sha1_init (&ctx1);
sha1_update_global (&ctx1, salt_bufs[SALT_POS_HOST].salt_buf, salt_bufs[SALT_POS_HOST].salt_len);
/**
* loop
*/
u32x w0l = w[0];
for (u32 il_pos = 0; il_pos < IL_CNT; il_pos += VECT_SIZE)
{
const u32x w0r = words_buf_r[il_pos / VECT_SIZE];
const u32x w0 = w0l | w0r;
w[0] = w0;
// add password to the user name (and colon, included):
sha1_ctx_t c0 = ctx0;
sha1_update_utf16le_swap (&c0, w, pw_len);
sha1_final (&c0);
// add first SHA1 result to main salt:
sha1_ctx_t c1 = ctx1;
u32 w0_t[4] = { 0 };
u32 w1_t[4] = { 0 };
u32 w2_t[4] = { 0 };
u32 w3_t[4] = { 0 };
w0_t[0] = c0.h[0];
w0_t[1] = c0.h[1];
w0_t[2] = c0.h[2];
w0_t[3] = c0.h[3];
w1_t[0] = c0.h[4];
sha1_update_64 (&c1, w0_t, w1_t, w2_t, w3_t, 20);
sha1_final (&c1);
const u32 e[5] = { c1.h[4], c1.h[3], c1.h[2], c1.h[1], c1.h[0] };
// u32 r_t[64]; for (u32 i = 0; i < 64; i++) r_t[i] = r[i];
u32 r_t[64] =
{
r[ 0], r[ 1], r[ 2], r[ 3], r[ 4], r[ 5], r[ 6], r[ 7],
r[ 8], r[ 9], r[10], r[11], r[12], r[13], r[14], r[15],
r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23],
r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31],
r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39],
r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47],
r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55],
r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63],
};
// main loop over the SHA1 result/vector e[]:
for (u32 i = 0, j = 0; i < PRECOMP_SLOTS; i += 1, j += PRECOMP_ENTRIES - 1)
{
const u32 div = (PRECOMP_BITS * i) / 32; // for 4 bits: (i / 8)
const u32 shift = (PRECOMP_BITS * i) % 32; // for 4 bits: (i % 8) * 4
// const
u32 cur_sel = (e[div] >> shift) & PRECOMP_MASK; // 0x0f == 0b1111 (4 bits)
// working with non-divisible u32 (see PRECOMP_BITS):
if (32 - shift < PRECOMP_BITS)
{
cur_sel |= (e[div + 1] << (32 - shift)) & PRECOMP_MASK;
}
if (cur_sel == 0) continue;
const u32 pre_idx = (j + cur_sel - 1) * PRECOMP_ENTRYLEN; // x * 64 is same as x << 6
// u32 pre[64]; for (u32 i = 0; i < 64; i++) pre[i] = esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + i];
const u32 pre[64] =
{
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 0],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 1],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 2],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 3],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 4],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 5],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 6],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 7],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 8],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 9],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 10],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 11],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 12],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 13],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 14],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 15],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 16],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 17],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 18],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 19],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 20],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 21],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 22],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 23],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 24],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 25],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 26],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 27],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 28],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 29],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 30],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 31],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 32],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 33],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 34],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 35],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 36],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 37],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 38],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 39],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 40],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 41],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 42],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 43],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 44],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 45],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 46],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 47],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 48],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 49],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 50],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 51],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 52],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 53],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 54],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 55],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 56],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 57],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 58],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 59],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 60],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 61],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 62],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 63],
};
mul_mod (r_t, pre, m, fact); // r_t = (r_t * RADMIN3_PRE[n]) % m
}
const u32 r0 = r_t[0];
const u32 r1 = r_t[1];
const u32 r2 = r_t[2];
const u32 r3 = r_t[3];
COMPARE_M_SCALAR (r0, r1, r2, r3);
}
}
KERNEL_FQ void m29200_sxx (KERN_ATTR_VECTOR_ESALT (radmin3_t))
{
/**
* modifier
*/
const u64 lid = get_local_id (0);
const u64 gid = get_global_id (0);
const u64 lsz = get_local_size (0);
/**
* cache constant values to shared memory
*/
LOCAL_VK u32 m[64];
LOCAL_VK u32 r[64];
LOCAL_VK u32 fact[64];
for (u32 i = lid; i < 64; i += lsz)
{
m[i] = RADMIN3_M[i];
r[i] = RADMIN3_R[i];
fact[i] = RADMIN3_FACT[i];
}
SYNC_THREADS ();
if (gid >= GID_CNT) return;
/**
* digest
*/
const u32 search[4] =
{
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R0],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R1],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R2],
digests_buf[DIGESTS_OFFSET_HOST].digest_buf[DGST_R3]
};
/**
* base
*/
// ctx0 with user
sha1_ctx_t ctx0;
sha1_init (&ctx0);
sha1_update_global (&ctx0, esalt_bufs[DIGESTS_OFFSET_HOST].user, esalt_bufs[DIGESTS_OFFSET_HOST].user_len);
// ctx1 with main salt
sha1_ctx_t ctx1;
sha1_init (&ctx1);
sha1_update_global (&ctx1, salt_bufs[SALT_POS_HOST].salt_buf, salt_bufs[SALT_POS_HOST].salt_len);
const u32 pw_len = pws[gid].pw_len;
u32x w[64] = { 0 };
for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
{
w[idx] = pws[gid].i[idx];
}
/**
* loop
*/
u32x w0l = w[0];
for (u32 il_pos = 0; il_pos < IL_CNT; il_pos += VECT_SIZE)
{
const u32x w0r = words_buf_r[il_pos / VECT_SIZE];
const u32x w0 = w0l | w0r;
w[0] = w0;
// add password to the user name (and colon, included):
sha1_ctx_t c0 = ctx0;
sha1_update_utf16le_swap (&c0, w, pw_len);
sha1_final (&c0);
// add first SHA1 result to main salt:
sha1_ctx_t c1 = ctx1;
u32 w0_t[4] = { 0 };
u32 w1_t[4] = { 0 };
u32 w2_t[4] = { 0 };
u32 w3_t[4] = { 0 };
w0_t[0] = c0.h[0];
w0_t[1] = c0.h[1];
w0_t[2] = c0.h[2];
w0_t[3] = c0.h[3];
w1_t[0] = c0.h[4];
sha1_update_64 (&c1, w0_t, w1_t, w2_t, w3_t, 20);
sha1_final (&c1);
const u32 e[5] = { c1.h[4], c1.h[3], c1.h[2], c1.h[1], c1.h[0] };
// u32 r_t[64]; for (u32 i = 0; i < 64; i++) r_t[i] = r[i];
u32 r_t[64] =
{
r[ 0], r[ 1], r[ 2], r[ 3], r[ 4], r[ 5], r[ 6], r[ 7],
r[ 8], r[ 9], r[10], r[11], r[12], r[13], r[14], r[15],
r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23],
r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31],
r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39],
r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47],
r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55],
r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63],
};
// main loop over the SHA1 result/vector e[]:
for (u32 i = 0, j = 0; i < PRECOMP_SLOTS; i += 1, j += PRECOMP_ENTRIES - 1)
{
const u32 div = (PRECOMP_BITS * i) / 32; // for 4 bits: (i / 8)
const u32 shift = (PRECOMP_BITS * i) % 32; // for 4 bits: (i % 8) * 4
// const
u32 cur_sel = (e[div] >> shift) & PRECOMP_MASK; // 0x0f == 0b1111 (4 bits)
// working with non-divisible u32 (see PRECOMP_BITS):
if (32 - shift < PRECOMP_BITS)
{
cur_sel |= (e[div + 1] << (32 - shift)) & PRECOMP_MASK;
}
if (cur_sel == 0) continue;
const u32 pre_idx = (j + cur_sel - 1) * PRECOMP_ENTRYLEN; // x * 64 is same as x << 6
// u32 pre[64]; for (u32 i = 0; i < 64; i++) pre[i] = esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + i];
const u32 pre[64] =
{
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 0],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 1],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 2],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 3],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 4],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 5],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 6],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 7],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 8],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 9],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 10],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 11],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 12],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 13],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 14],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 15],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 16],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 17],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 18],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 19],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 20],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 21],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 22],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 23],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 24],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 25],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 26],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 27],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 28],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 29],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 30],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 31],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 32],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 33],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 34],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 35],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 36],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 37],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 38],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 39],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 40],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 41],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 42],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 43],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 44],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 45],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 46],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 47],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 48],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 49],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 50],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 51],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 52],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 53],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 54],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 55],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 56],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 57],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 58],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 59],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 60],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 61],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 62],
esalt_bufs[DIGESTS_OFFSET_HOST].pre[pre_idx + 63],
};
mul_mod (r_t, pre, m, fact); // r_t = (r_t * RADMIN3_PRE[n]) % m
}
const u32 r0 = r_t[0];
const u32 r1 = r_t[1];
const u32 r2 = r_t[2];
const u32 r3 = r_t[3];
COMPARE_S_SCALAR (r0, r1, r2, r3);
}
}

@ -14,6 +14,7 @@
- Added hash-mode: Kerberos 5, etype 17, DB
- Added hash-mode: Kerberos 5, etype 18, DB
- Added hash-mode: PostgreSQL SCRAM-SHA-256
- Added hash-mode: Radmin3
- Added hash-mode: Teamspeak 3 (channel hash)
- Added hash-mode: bcrypt(sha512($pass)) / bcryptsha512
- Added hash-mode: sha1($salt.sha1(utf16le($username).':'.utf16le($pass)))

@ -207,6 +207,7 @@ NVIDIA GPUs require "NVIDIA Driver" (440.64 or later) and "CUDA Toolkit" (9.0 or
- BSDi Crypt, Extended DES
- NTLM
- Radmin2
- Radmin3
- Samsung Android Password/PIN
- Windows Hello PIN/Password
- Windows Phone 8+ PIN/password

@ -0,0 +1,14 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#ifndef _EMU_INC_BIGNUM_OPERATIONS_H
#define _EMU_INC_BIGNUM_OPERATIONS_H
#include "emu_general.h"
#include "inc_vendor.h"
#include "inc_bignum_operations.h"
#endif // _EMU_INC_BIGNUM_OPERATIONS_H

@ -0,0 +1,14 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#ifndef _EMU_INC_RADMIN3_CONSTANTS_H
#define _EMU_INC_RADMIN3_CONSTANTS_H
#include "emu_general.h"
#include "inc_vendor.h"
#include "inc_radmin3_constants.h"
#endif // _EMU_INC_RADMIN3_CONSTANTS_H

@ -394,7 +394,7 @@ CXXFLAGS :=
EMU_OBJS_ALL := emu_general emu_inc_common emu_inc_platform emu_inc_scalar emu_inc_simd
EMU_OBJS_ALL += emu_inc_rp emu_inc_rp_optimized
EMU_OBJS_ALL += emu_inc_hash_md4 emu_inc_hash_md5 emu_inc_hash_ripemd160 emu_inc_hash_sha1 emu_inc_hash_sha256 emu_inc_hash_sha384 emu_inc_hash_sha512 emu_inc_hash_streebog256 emu_inc_hash_streebog512 emu_inc_ecc_secp256k1
EMU_OBJS_ALL += emu_inc_hash_md4 emu_inc_hash_md5 emu_inc_hash_ripemd160 emu_inc_hash_sha1 emu_inc_hash_sha256 emu_inc_hash_sha384 emu_inc_hash_sha512 emu_inc_hash_streebog256 emu_inc_hash_streebog512 emu_inc_ecc_secp256k1 emu_inc_bignum_operations
EMU_OBJS_ALL += emu_inc_cipher_aes emu_inc_cipher_camellia emu_inc_cipher_des emu_inc_cipher_kuznyechik emu_inc_cipher_serpent emu_inc_cipher_twofish
OBJS_ALL := affinity autotune backend benchmark bitmap bitops combinator common convert cpt cpu_crc32 debugfile dictstat dispatch dynloader event ext_ADL ext_cuda ext_hip ext_nvapi ext_nvml ext_nvrtc ext_hiprtc ext_OpenCL ext_sysfs_amdgpu ext_sysfs_cpu ext_iokit ext_lzma filehandling folder hashcat hashes hlfmt hwmon induct interface keyboard_layout locking logfile loopback memory monitor mpsp outfile_check outfile pidfile potfile restore rp rp_cpu selftest slow_candidates shared status stdout straight terminal thread timer tuningdb usage user_options wordlist $(EMU_OBJS_ALL)

@ -0,0 +1,12 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#include "types.h"
#include "common.h"
#include "emu_general.h"
#include "inc_vendor.h"
#include "inc_platform.h"
#include "inc_bignum_operations.cl"

@ -0,0 +1,349 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
* This algorithm for password-storage for the Radmin 3 software was analyzed and made public by synacktiv:
* https://www.synacktiv.com/publications/cracking-radmin-server-3-passwords.html
*/
#include "common.h"
#include "types.h"
#include "modules.h"
#include "bitops.h"
#include "convert.h"
#include "shared.h"
#include "emu_inc_bignum_operations.h"
#include "emu_inc_radmin3_constants.h"
static const u32 ATTACK_EXEC = ATTACK_EXEC_INSIDE_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 = "Radmin3";
static const u64 KERN_TYPE = 29200;
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
| OPTI_TYPE_NOT_ITERATED;
static const u64 OPTS_TYPE = OPTS_TYPE_STOCK_MODULE
| OPTS_TYPE_PT_GENERATE_BE
| OPTS_TYPE_PT_ADD80
| OPTS_TYPE_PT_ADDBITS15
| OPTS_TYPE_PT_UTF16LE
| OPTS_TYPE_ST_HEX;
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
static const char *ST_PASS = "hashcat";
static const char *ST_HASH = "$radmin3$75007300650072006e0061006d006500*c63bf695069d564844c4849e7df6d41f1fbc5f3a7d8fe27c5f20545a238398fa*0062fb848c21d606baa0a91d7177daceb69ad2f6d090c2f1b3a654cfb417be66f739ae952f5c7c5170743459daf854a22684787b24f8725337b3c3bd1e0f2a6285768ceccca77f26c579d42a66372df7782b2eefccb028a0efb51a4257dd0804d05e0a83f611f2a0f10ffe920568cc7af1ec426f450ec99ade1f2a4905fd319f8c190c2db0b0e24627d635bc2b4a2c4c9ae956b1e02784c9ce958eb9883c60ba8ea2731dd0e515f492c44f39324e4027587c1330f14216e17f212eaec949273797ae74497782ee8b6f640dd2d124c59db8c37724c8a5a63bad005f8e491b459ff1b92f861ab6d99a2548cb8902b0840c7f20a108ede6bf9a60093053781216fe";
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; }
static const char *SIGNATURE_RADMIN3 = "$radmin3$";
typedef struct radmin3
{
u32 user[64];
u32 user_len;
u32 pre[PRECOMP_DATALEN]; // 38400 for PRECOMP_BITS = 4
} radmin3_t;
// trick to include binary data file in assembly:
// credits go to http://elm-chan.org/junk/32bit/binclude.html#inc_c
#define INCLUDE_BIN(name, file) asm \
( \
".section .rodata \n" \
".balign 4 \n" \
".global " name " \n" \
name ": \n" \
".incbin \"" file "\" \n" \
".section .text \n" \
)
INCLUDE_BIN ("RADMIN3_PRE", "include/inc_radmin3_constants_pre.data");
#undef INCLUDE_BIN
extern const u32 RADMIN3_PRE[PRECOMP_DATALEN];
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 (radmin3_t);
return esalt_size;
}
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;
radmin3_t *esalt = (radmin3_t *) esalt_buf;
hc_token_t token;
token.token_cnt = 4;
token.signatures_cnt = 1;
token.signatures_buf[0] = SIGNATURE_RADMIN3;
token.len[0] = 9;
token.attr[0] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_SIGNATURE;
// user name
token.sep[1] = '*';
token.len_min[1] = (SALT_MIN * 2);
token.len_max[1] = (SALT_MAX * 2) - 1; // we store the colon (:) in esalt->user[]
token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH;
// SHA1 salt
token.sep[2] = '*';
token.len_min[2] = 64;
token.len_max[2] = 64;
token.attr[2] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_HEX;
// verifier
token.len[3] = 512;
token.attr[3] = TOKEN_ATTR_FIXED_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);
// user name:
if ((token.len[1] % 2) != 0) return (PARSER_SALT_LENGTH);
u8 *u = (u8 *) esalt->user;
hex_decode (token.buf[1], token.len[1], u);
esalt->user_len = token.len[1] / 2;
u[esalt->user_len] = ':';
esalt->user_len++;
// call byte_swap () to avoid it in the kernel:
for (u32 i = 0; i < 64; i++)
{
esalt->user[i] = byte_swap_32 (esalt->user[i]);
}
// salt (for salted SHA1):
if ((token.len[2] % 2) != 0) return (PARSER_SALT_LENGTH);
u8 *s = (u8 *) salt->salt_buf;
hex_decode (token.buf[2], token.len[2], s);
salt->salt_len = token.len[2] / 2;
// call byte_swap () to avoid it in the kernel:
for (u32 i = 0; i < 64; i++)
{
salt->salt_buf[i] = byte_swap_32 (salt->salt_buf[i]);
}
// verifier:
if ((token.len[3] % 2) != 0) return (PARSER_SALT_LENGTH);
u8 *v = (u8 *) salt->salt_buf_pc;
hex_decode (token.buf[3], token.len[3], v);
// change the order (byte_swap () and v[63] <-> v[0], v[62] <-> u[1] etc):
for (u32 i = 0, j = 63; i < 32; i++, j--)
{
u32 t1 = salt->salt_buf_pc[i];
u32 t2 = salt->salt_buf_pc[j];
salt->salt_buf_pc[j] = byte_swap_32 (t1);
salt->salt_buf_pc[i] = byte_swap_32 (t2);
}
// digest
// convert our verifier to Montgomery form (s.t. we avoid converting it back on GPU):
u32 dgst[64] = { 0 };
to_montgomery (dgst, salt->salt_buf_pc, RADMIN3_M);
digest[0] = dgst[0];
digest[1] = dgst[1];
digest[2] = dgst[2];
digest[3] = dgst[3];
/*
* pre-computed values for BigNum exponentiation:
*/
memcpy (esalt->pre, RADMIN3_PRE, sizeof (RADMIN3_PRE));
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)
{
radmin3_t *esalt = (radmin3_t *) esalt_buf;
u8 *out_buf = (u8 *) line_buf;
// signature
int out_len = snprintf (line_buf, line_size, "%s", SIGNATURE_RADMIN3);
// user
u32 u[64];
for (u32 i = 0; i < 64; i++)
{
u[i] = byte_swap_32 (esalt->user[i]);
}
out_len += generic_salt_encode (hashconfig, (const u8 *) u, (const int) esalt->user_len - 1, out_buf + out_len); // -1 because of the ':' optimization
out_buf[out_len] = '*';
out_len++;
// salt
u32 s[64];
for (u32 i = 0; i < 64; i++)
{
s[i] = byte_swap_32 (salt->salt_buf[i]);
}
out_len += generic_salt_encode (hashconfig, (const u8 *) s, (const int) salt->salt_len, out_buf + out_len);
out_buf[out_len] = '*';
out_len++;
// verifier
u32 verifier[64];
for (u32 i = 0, j = 63; i < 32; i++, j--) // fix the order
{
u32 t1 = salt->salt_buf_pc[i];
u32 t2 = salt->salt_buf_pc[j];
verifier[j] = byte_swap_32 (t1);
verifier[i] = byte_swap_32 (t2);
}
out_len += generic_salt_encode (hashconfig, (const u8 *) verifier, 256, out_buf + out_len);
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_deprecated_notice = 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_extra_tuningdb_block = 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_postprocess = 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_DEFAULT;
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_DEFAULT;
module_ctx->module_unstable_warning = MODULE_DEFAULT;
module_ctx->module_warmup_disable = MODULE_DEFAULT;
}

@ -0,0 +1,289 @@
#!/usr/bin/env perl
##
## Author......: See docs/credits.txt
## License.....: MIT
##
# for this hashcat extraction tool the input should be a export/dump of the registry key
# [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Radmin\v3.0\Server\Parameters\Radmin Security\1]
#
# "reg export" cmd command can be used for this:
# reg export "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Radmin\v3.0\Server\Parameters\Radmin Security\1" radmin3_export.reg
#
# Note: this tool is intentionally not designed to do an automatic registry key read
# but this could be done easily also in software/perl:
# use Win32::TieRegistry (Delimiter => '/');
# my $reg_key = $Registry->{'HKEY_LOCAL_MACHINE/SOFTWARE/WOW6432Node/Radmin/v3.0/Server/Parameters/Radmin Security'};
# my $file_content = $reg_key->{'/1'};
#
# An example input file (first command line parameter):
#
# [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Radmin\v3.0\Server\Parameters\Radmin Security\1]
# "1"=hex:10,00,00,0a,72,00,6f,00,67,00,65,00,72,00,30,00,01,00,98,47,fc,7e,0f,\
# 89,1d,fd,5d,02,f1,9d,58,7d,8f,77,ae,c0,b9,80,d4,30,4b,01,13,b4,06,f2,3e,2c,\
# ec,58,ca,fc,a0,4a,53,e3,6f,b6,8e,0c,3b,ff,92,cf,33,57,86,b0,db,e6,0d,fe,41,\
# 78,ef,2f,cd,2a,4d,d0,99,47,ff,d8,df,96,fd,0f,9e,29,81,a3,2d,a9,55,03,34,2e,\
# ca,9f,08,06,2c,bd,d4,ac,2d,7c,df,81,0d,b4,db,96,db,70,10,22,66,26,1c,d3,f8,\
# bd,d5,6a,10,2f,c6,ce,ed,bb,a5,ea,e9,9e,61,27,bd,d9,52,f7,a0,d1,8a,79,02,1c,\
# 88,1a,e6,3e,c4,b3,59,03,87,f5,48,59,8f,2c,b8,f9,0d,ea,36,fc,4f,80,c5,47,3f,\
# db,6b,0c,6b,db,0f,db,af,46,01,f5,60,dd,14,91,67,ea,12,5d,b8,ad,34,fd,0f,d4,\
# 53,50,de,c7,2c,fb,3b,52,8b,a2,33,2d,60,91,ac,ea,89,df,d0,6c,9c,4d,18,f6,97,\
# 24,5b,d2,ac,92,78,b9,2b,fe,7d,ba,fa,a0,c4,3b,40,a7,1f,19,30,eb,c4,fd,24,c9,\
# e5,a2,e5,a4,cc,f5,d7,f5,15,44,d7,0b,2b,ca,4a,f5,b8,d3,7b,37,9f,d7,74,0a,68,\
# 2f,40,00,00,01,05,50,00,00,20,f9,89,48,2b,a8,3b,63,45,fd,1d,d7,e2,13,13,dc,\
# d5,55,22,ba,57,15,b5,79,ea,b8,74,d7,64,33,92,8d,72,60,00,01,00,01,2a,1b,fd,\
# 53,4a,88,d9,19,40,70,e6,1e,76,07,fd,69,90,94,ea,b6,3b,53,b2,76,6b,0c,f3,5e,\
# 73,fb,cc,21,41,ae,d3,28,1f,64,ca,62,0b,27,95,1c,f5,e2,c2,78,60,37,54,27,5f,\
# c1,63,51,ee,f0,8f,bb,e3,0c,f5,d9,27,be,c5,61,e5,ea,98,a6,df,a1,ee,e9,00,4b,\
# 00,83,4f,d9,ca,d5,ae,59,1e,ef,4f,c8,8b,f9,73,75,04,d2,9e,c5,93,34,6c,cd,1d,\
# 76,18,82,37,73,8e,0b,6e,8a,f8,47,ef,4a,74,a9,a4,d9,df,04,8d,5d,6b,f2,19,c7,\
# ab,f5,40,72,00,c3,5d,3c,dc,d5,e7,e2,c6,51,fe,0d,77,bc,60,41,e1,51,96,46,f5,\
# 8b,1c,cc,a2,11,1a,37,25,86,6b,be,2b,60,4f,9d,17,2f,28,53,9a,97,5d,1d,0f,99,\
# 7e,4c,d2,8c,49,7f,ad,62,a7,90,e7,35,2f,19,40,1e,fb,7d,7f,b6,ba,cb,85,e0,67,\
# 4e,ab,03,1d,78,2f,a0,e7,3d,8e,b4,b4,0a,c6,ee,cc,a8,d9,87,fd,b9,0c,c1,01,54,\
# a5,39,6a,26,7c,69,cb,47,68,c3,a6,43,59,12,bb,b6,0d,68,91,d2,1b,de,bc,da,0f,\
# 0a,b5,20,00,00,04,ff,01,00,00
use strict;
use warnings;
use utf8;
#
# Constants:
#
my $REGISTRY_PREFIX = "=hex:";
my $ENTRY_KEY_USER = 16;
my $ENTRY_KEY_MODULUS = 48;
my $ENTRY_KEY_GENERATOR = 64;
my $ENTRY_KEY_SALT = 80;
my $ENTRY_KEY_VERIFIER = 96;
my $HARD_CODED_GENERATOR = "05";
my $HARD_CODED_MODULUS = "9847fc7e0f891dfd5d02f19d587d8f77aec0b980d4304b0113b406f23e2cec58cafca04a53e36fb68e0c3bff92cf335786b0dbe60dfe4178ef2fcd2a4dd09947ffd8df96fd0f9e2981a32da95503342eca9f08062cbdd4ac2d7cdf810db4db96db70102266261cd3f8bdd56a102fc6ceedbba5eae99e6127bdd952f7a0d18a79021c881ae63ec4b3590387f548598f2cb8f90dea36fc4f80c5473fdb6b0c6bdb0fdbaf4601f560dd149167ea125db8ad34fd0fd45350dec72cfb3b528ba2332d6091acea89dfd06c9c4d18f697245bd2ac9278b92bfe7dbafaa0c43b40a71f1930ebc4fd24c9e5a2e5a4ccf5d7f51544d70b2bca4af5b8d37b379fd7740a682f";
#
# Start:
#
if (scalar (@ARGV) < 1)
{
print STDERR "Usage:\n" . $0 . " <radmin3.reg>\n\n";
print STDERR "Please specify the Radmin 3 registry export file as command line parameter\n\n";
print STDERR "The registry key is something like:\n";
print STDERR "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Radmin\\v3.0\\Server\\Parameters\\Radmin Security\\1\n";
exit (1);
}
my $file_name = $ARGV[0];
my $fh;
if (! open ($fh, "<", $file_name))
{
print STDERR "ERROR: Could not open the registry dump file '$file_name'\n";
exit (1);
}
binmode ($fh);
my $file_content = "";
{
local $/ = undef;
$file_content = <$fh>;
}
close ($fh);
if (length ($file_content) < 5 + 0) # replace 0 with minimum expected length
{
print STDERR "ERROR: File size of file '$file_name' is invalid\n";
exit (1);
}
$file_content =~ s/[\x00]//g; # this could be true if UTF16 + BOM are being used
my $prefix_idx = index ($file_content, $REGISTRY_PREFIX);
if ($prefix_idx < 0)
{
print STDERR "ERROR: Could not find the key '=hex:' within the file content\n";
exit (1);
}
$file_content = substr ($file_content, $prefix_idx + length ($REGISTRY_PREFIX));
# $file_content =~ s/[ \r\n,\\]//g;
# we could also remove every character that is not an hexadecimal symbol:
$file_content =~ s/[^0-9a-fA-F]//g;
$file_content = pack ("H*", $file_content);
# final length check (needed ?):
my $file_content_len = length ($file_content);
if ($file_content_len < 2 + 1 + 2 + 1 + 2 + 32 + 2 + 256 + 2 + 256) # replace with min length
{
print STDERR "ERROR: File content of file '$file_name' is too short\n";
exit (1);
}
# loop over the data:
my $user = "";
my $salt = "";
my $verifier = "";
my $found_user = 0;
my $found_modulus = 0;
my $found_generator = 0;
my $found_salt = 0;
my $found_verifier = 0;
for (my $i = 0; $i < $file_content_len; $i += 4)
{
if ($i + 4 > $file_content_len)
{
print STDERR "ERROR: Unexpected EOF (end of file) in file '$file_name'\n";
exit (1);
}
my $type = ord (substr ($file_content, $i + 1, 1)) * 256 +
ord (substr ($file_content, $i + 0, 1));
my $len = ord (substr ($file_content, $i + 2, 1)) * 256 +
ord (substr ($file_content, $i + 3, 1));
my $pos = $i + 4;
$i += $len;
# we are not interested in other values than what we need:
if (($type != $ENTRY_KEY_USER) &&
($type != $ENTRY_KEY_MODULUS) &&
($type != $ENTRY_KEY_GENERATOR) &&
($type != $ENTRY_KEY_SALT) &&
($type != $ENTRY_KEY_VERIFIER))
{
next;
}
if ($i > $file_content_len)
{
print STDERR "ERROR: Unexpected EOF (end of file) in file '$file_name'\n";
exit (1);
}
#
# get the data, finally:
#
my $value = substr ($file_content, $pos, $len);
$value = unpack ("H*", $value);
if ($type == $ENTRY_KEY_USER)
{
$user = $value;
$found_user = 1;
}
elsif ($type == $ENTRY_KEY_MODULUS)
{
if ($value ne $HARD_CODED_MODULUS)
{
print STDERR "ERROR: Non-default modulus found in file '$file_name'\n";
exit (1);
}
$found_modulus = 1;
}
elsif ($type == $ENTRY_KEY_GENERATOR)
{
if ($value ne $HARD_CODED_GENERATOR)
{
print STDERR "ERROR: Non-default generator found in file '$file_name'\n";
exit (1);
}
$found_generator = 1;
}
elsif ($type == $ENTRY_KEY_SALT)
{
$salt = $value;
$found_salt = 1;
}
elsif ($type == $ENTRY_KEY_VERIFIER)
{
$verifier = $value;
$found_verifier = 1;
}
}
if ($found_user == 0)
{
print STDERR "ERROR: No user name found in file '$file_name'\n";
exit (1);
}
if ($found_modulus == 0)
{
print STDERR "ERROR: No modulus found in file '$file_name'\n";
exit (1);
}
if ($found_generator == 0)
{
print STDERR "ERROR: No generator found in file '$file_name'\n";
exit (1);
}
if ($found_salt == 0)
{
print STDERR "ERROR: No salt found in file '$file_name'\n";
exit (1);
}
if ($found_verifier == 0)
{
print STDERR "ERROR: No verifier found in file '$file_name'\n";
exit (1);
}
#
# Output:
#
print sprintf ("\$radmin3\$%s*%s*%s\n",
$user,
$salt,
$verifier);

@ -0,0 +1,92 @@
#!/usr/bin/env perl
##
## Author......: See docs/credits.txt
## License.....: MIT
##
use strict;
use warnings;
use Digest::SHA qw (sha1 sha1_hex);
use Crypt::OpenSSL::Bignum::CTX;
use Encode;
sub module_constraints { [[0, 256], [32, 32], [-1, -1], [-1, -1], [-1, -1]] }
my $GENERATOR = "05";
my $MODULUS = "9847fc7e0f891dfd5d02f19d587d8f77aec0b980d4304b0113b406f23e2cec58cafca04a53e36fb68e0c3bff92cf335786b0dbe60dfe4178ef2fcd2a4dd09947ffd8df96fd0f9e2981a32da95503342eca9f08062cbdd4ac2d7cdf810db4db96db70102266261cd3f8bdd56a102fc6ceedbba5eae99e6127bdd952f7a0d18a79021c881ae63ec4b3590387f548598f2cb8f90dea36fc4f80c5473fdb6b0c6bdb0fdbaf4601f560dd149167ea125db8ad34fd0fd45350dec72cfb3b528ba2332d6091acea89dfd06c9c4d18f697245bd2ac9278b92bfe7dbafaa0c43b40a71f1930ebc4fd24c9e5a2e5a4ccf5d7f51544d70b2bca4af5b8d37b379fd7740a682f";
sub module_generate_hash
{
my $word = shift;
my $salt = shift;
my $user = shift;
if (! defined ($user))
{
$user = random_mixedcase_string (int (rand (128)));
$user = encode ('UTF16-LE', $user);
}
my $word_utf16 = encode ("UTF-16LE", $word);
my $exponent = sha1_hex ($salt . sha1 ($user . ":" . $word_utf16));
my $g = Crypt::OpenSSL::Bignum->new_from_hex ($GENERATOR);
my $m = Crypt::OpenSSL::Bignum->new_from_hex ($MODULUS);
my $e = Crypt::OpenSSL::Bignum->new_from_hex ($exponent);
my $ctx = Crypt::OpenSSL::Bignum::CTX->new ();
my $pow = $g->mod_exp ($e, $m, $ctx);
my $res = $pow->to_bin ();
# IMPORTANT step:
$res = "\x00" x (256 - length ($res)) . $res; # pad it to exactly 256 bytes
my $hash = sprintf ("\$radmin3\$%s*%s*%s", unpack ("H*", $user), unpack ("H*", $salt), unpack ("H*", $res));
return $hash;
}
sub module_verify_hash
{
my $line = shift;
my $idx = index ($line, ':');
return unless $idx >= 0;
my $hash = substr ($line, 0, $idx);
my $word = substr ($line, $idx + 1);
return unless substr ($hash, 0, 9) eq '$radmin3$';
my ($user, $salt, $verifier) = split ('\*', substr ($hash, 9));
return unless defined $user;
return unless defined $salt;
return unless defined $verifier;
return unless length ($salt) == 64;
return unless $user =~ m/^[0-9a-fA-F]*$/;
return unless $salt =~ m/^[0-9a-fA-F]*$/;
return unless $verifier =~ m/^[0-9a-fA-F]*$/;
$salt = pack ("H*", $salt);
$user = pack ("H*", $user);
my $word_packed = pack_if_HEX_notation ($word);
my $new_hash = module_generate_hash ($word_packed, $salt, $user);
return ($new_hash, $word);
}
1;
Loading…
Cancel
Save