1
mirror of https://github.com/hashcat/hashcat synced 2024-12-27 05:13:45 +01:00

Added rounds_count_length() function to detect optional rounds=

substring in *crypt hashes
The following parser functions have been rewritten to make use of
input_tokenizer():
phpass_parse_hash()
md5crypt_parse_hash()
md5apr1_parse_hash()
episerver_parse_hash()
This commit is contained in:
jsteube 2018-06-27 11:12:35 +02:00
parent f574cbc88a
commit 9196f1ba55
5 changed files with 219 additions and 133 deletions

View File

@ -14,12 +14,14 @@ size_t exec_unhexify (const u8 *in_buf, const size_t in_len, u8 *out_buf, const
bool need_hexify (const u8 *buf, const size_t len, const char separator, bool always_ascii);
void exec_hexify (const u8 *buf, const size_t len, u8 *out);
bool is_valid_base64_string (const u8 *s, const size_t len);
bool is_valid_base64_char (const u8 c);
bool is_valid_hex_string (const u8 *s, const size_t len);
bool is_valid_hex_char (const u8 c);
bool is_valid_digit_string (const u8 *s, const size_t len);
bool is_valid_digit_char (const u8 c);
bool is_valid_base64a_string (const u8 *s, const size_t len);
bool is_valid_base64a_char (const u8 c);
bool is_valid_base64b_string (const u8 *s, const size_t len);
bool is_valid_base64b_char (const u8 c);
bool is_valid_hex_string (const u8 *s, const size_t len);
bool is_valid_hex_char (const u8 c);
bool is_valid_digit_string (const u8 *s, const size_t len);
bool is_valid_digit_char (const u8 c);
u8 hex_convert (const u8 c);

View File

@ -1046,11 +1046,7 @@ typedef enum display_len
DISPLAY_LEN_MAX_200 = 16,
DISPLAY_LEN_MIN_300 = 40,
DISPLAY_LEN_MAX_300 = 40,
DISPLAY_LEN_MIN_400 = 34,
DISPLAY_LEN_MAX_400 = 34,
DISPLAY_LEN_MIN_500 = 3 + 1 + 0 + 22,
DISPLAY_LEN_MIN_501 = 104,
DISPLAY_LEN_MAX_500 = 3 + 1 + 8 + 22,
DISPLAY_LEN_MAX_501 = 104,
DISPLAY_LEN_MIN_600 = 8 + 128,
DISPLAY_LEN_MAX_600 = 8 + 128,
@ -1078,8 +1074,6 @@ typedef enum display_len
DISPLAY_LEN_MAX_1450H = 64 + 1 + (SALT_MAX * 2),
DISPLAY_LEN_MIN_1500 = 13,
DISPLAY_LEN_MAX_1500 = 13,
DISPLAY_LEN_MIN_1600 = 29 + 0,
DISPLAY_LEN_MAX_1600 = 29 + 8,
DISPLAY_LEN_MIN_1700 = 128,
DISPLAY_LEN_MAX_1700 = 128,
DISPLAY_LEN_MIN_1710 = 128 + 1 + 0,
@ -1361,8 +1355,6 @@ typedef enum display_len
DISPLAY_LEN_MAX_132 = 6 + 8 + 40,
DISPLAY_LEN_MIN_133 = 28,
DISPLAY_LEN_MAX_133 = 28,
DISPLAY_LEN_MIN_141 = 14 + 0 + 1 + 28,
DISPLAY_LEN_MAX_141 = 14 + 44 + 1 + 28,
DISPLAY_LEN_MIN_1411 = 9 + 44 + 0,
DISPLAY_LEN_MAX_1411 = 9 + 44 + 68,
DISPLAY_LEN_MIN_1441 = 14 + 0 + 1 + 43,

View File

@ -686,11 +686,13 @@ typedef enum user_options_map
typedef enum token_attr
{
TOKEN_ATTR_FIXED_LENGTH = 1 << 0,
TOKEN_ATTR_VERIFY_SIGNATURE = 1 << 1,
TOKEN_ATTR_VERIFY_LENGTH = 1 << 2,
TOKEN_ATTR_VERIFY_DIGIT = 1 << 3,
TOKEN_ATTR_VERIFY_HEX = 1 << 4,
TOKEN_ATTR_VERIFY_BASE64 = 1 << 5,
TOKEN_ATTR_OPTIONAL_ROUNDS = 1 << 1,
TOKEN_ATTR_VERIFY_SIGNATURE = 1 << 2,
TOKEN_ATTR_VERIFY_LENGTH = 1 << 3,
TOKEN_ATTR_VERIFY_DIGIT = 1 << 4,
TOKEN_ATTR_VERIFY_HEX = 1 << 5,
TOKEN_ATTR_VERIFY_BASE64A = 1 << 6,
TOKEN_ATTR_VERIFY_BASE64B = 1 << 7,
} token_attr_t;
@ -2102,6 +2104,9 @@ typedef struct token
int attr[MAX_TOKENS];
u8 *opt_buf;
int opt_len;
} token_t;
#endif // _TYPES_H

View File

@ -215,19 +215,44 @@ void exec_hexify (const u8 *buf, const size_t len, u8 *out)
out[max_len * 2] = 0;
}
bool is_valid_base64_string (const u8 *s, const size_t len)
bool is_valid_base64a_string (const u8 *s, const size_t len)
{
for (size_t i = 0; i < len; i++)
{
const u8 c = s[i];
if (is_valid_base64_char (c) == false) return false;
if (is_valid_base64a_char (c) == false) return false;
}
return true;
}
bool is_valid_base64_char (const u8 c)
bool is_valid_base64a_char (const u8 c)
{
if ((c >= '0') && (c <= '9')) return true;
if ((c >= 'A') && (c <= 'Z')) return true;
if ((c >= 'a') && (c <= 'z')) return true;
if (c == '+') return true;
if (c == '/') return true;
if (c == '=') return true;
return false;
}
bool is_valid_base64b_string (const u8 *s, const size_t len)
{
for (size_t i = 0; i < len; i++)
{
const u8 c = s[i];
if (is_valid_base64b_char (c) == false) return false;
}
return true;
}
bool is_valid_base64b_char (const u8 c)
{
if ((c >= '0') && (c <= '9')) return true;
if ((c >= 'A') && (c <= 'Z')) return true;
@ -235,6 +260,7 @@ bool is_valid_base64_char (const u8 c)
if (c == '.') return true;
if (c == '/') return true;
if (c == '=') return true;
return false;
}

View File

@ -603,7 +603,8 @@ static const char *SIGNATURE_DPAPIMK = "$DPAPImk$";
static const char *SIGNATURE_DRUPAL7 = "$S$";
static const char *SIGNATURE_ECRYPTFS = "$ecryptfs$";
static const char *SIGNATURE_EPISERVER4 = "$episerver$*1*";
static const char *SIGNATURE_EPISERVER = "$episerver$*0*";
static const char *SIGNATURE_EPISERVER0 = "$episerver$*0*";
static const char *SIGNATURE_EPISERVER = "$episerver$";
static const char *SIGNATURE_KEEPASS = "$keepass$";
static const char *SIGNATURE_KRB5PA = "$krb5pa$23";
static const char *SIGNATURE_KRB5TGS = "$krb5tgs$23";
@ -630,8 +631,6 @@ static const char *SIGNATURE_PBKDF2_SHA1 = "sha1:";
static const char *SIGNATURE_PBKDF2_SHA256 = "sha256:";
static const char *SIGNATURE_PBKDF2_SHA512 = "sha512:";
static const char *SIGNATURE_PDF = "$pdf$";
static const char *SIGNATURE_PHPASS1 = "$P$";
static const char *SIGNATURE_PHPASS2 = "$H$";
static const char *SIGNATURE_PHPS = "$PHPS$";
static const char *SIGNATURE_POSTGRESQL_AUTH = "$postgres$";
static const char *SIGNATURE_PSAFE3 = "PWS3";
@ -2452,6 +2451,27 @@ static void drupal7_encode (const u8 digest[64], u8 buf[43])
* parser
*/
static int rounds_count_length (const char *input_buf, const int input_len)
{
if (input_len >= 9) // 9 is minimum because of "rounds=X$"
{
static const char *rounds = "rounds=";
if (memcmp (input_buf, rounds, 7) == 0)
{
char *next_pos = strchr (input_buf + 8, '$');
if (next_pos == NULL) return -1;
const int rounds_len = next_pos - input_buf;
return rounds_len;
}
}
return -1;
}
static int input_tokenizer (u8 *input_buf, int input_len, token_t *token)
{
int len_left = input_len;
@ -2474,6 +2494,22 @@ static int input_tokenizer (u8 *input_buf, int input_len, token_t *token)
}
else
{
if (token->attr[token_idx] & TOKEN_ATTR_OPTIONAL_ROUNDS)
{
const int len = rounds_count_length (token->buf[token_idx], len_left);
token->opt_buf = token->buf[token_idx];
token->opt_len = len; // we want an eventual -1 in here, it's used later for verification
if (len > 0)
{
token->buf[token_idx] += len + 1; // +1 = separator
len_left -= len + 1; // +1 = separator
}
}
u8 *next_pos = (u8 *) strchr ((const char *) token->buf[token_idx], token->sep[token_idx]);
if (next_pos == NULL) return (PARSER_SEPARATOR_UNMATCHED);
@ -2510,9 +2546,14 @@ static int input_tokenizer (u8 *input_buf, int input_len, token_t *token)
if (is_valid_hex_string (token->buf[token_idx], token->len[token_idx]) == false) return (PARSER_TOKEN_ENCODING);
}
if (token->attr[token_idx] & TOKEN_ATTR_VERIFY_BASE64)
if (token->attr[token_idx] & TOKEN_ATTR_VERIFY_BASE64A)
{
if (is_valid_base64_string (token->buf[token_idx], token->len[token_idx]) == false) return (PARSER_TOKEN_ENCODING);
if (is_valid_base64a_string (token->buf[token_idx], token->len[token_idx]) == false) return (PARSER_TOKEN_ENCODING);
}
if (token->attr[token_idx] & TOKEN_ATTR_VERIFY_BASE64B)
{
if (is_valid_base64b_string (token->buf[token_idx], token->len[token_idx]) == false) return (PARSER_TOKEN_ENCODING);
}
}
@ -2803,11 +2844,11 @@ int bcrypt_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UNU
token.len[2] = 22;
token.attr[2] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_BASE64;
| TOKEN_ATTR_VERIFY_BASE64B;
token.len[3] = 31;
token.attr[3] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_BASE64;
| TOKEN_ATTR_VERIFY_BASE64B;
const int rc_tokenizer = input_tokenizer (input_buf, input_len, &token);
@ -2867,7 +2908,7 @@ int cisco4_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UNU
token.len_min[0] = 43;
token.len_max[0] = 43;
token.attr[0] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_BASE64;
| TOKEN_ATTR_VERIFY_BASE64B;
const int rc_tokenizer = input_tokenizer (input_buf, input_len, &token);
@ -3176,7 +3217,7 @@ int netscreen_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_
token.len_min[0] = 30;
token.len_max[0] = 30;
token.attr[0] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_BASE64;
| TOKEN_ATTR_VERIFY_BASE64B;
token.len_min[1] = 1;
token.len_max[1] = SALT_MAX;
@ -3933,33 +3974,49 @@ int psafe3_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UNU
int phpass_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UNUSED hashconfig_t *hashconfig)
{
if ((input_len < DISPLAY_LEN_MIN_400) || (input_len > DISPLAY_LEN_MAX_400)) return (PARSER_GLOBAL_LENGTH);
if ((memcmp (SIGNATURE_PHPASS1, input_buf, 3) != 0) && (memcmp (SIGNATURE_PHPASS2, input_buf, 3) != 0)) return (PARSER_SIGNATURE_UNMATCHED);
u32 *digest = (u32 *) hash_buf->digest;
salt_t *salt = hash_buf->salt;
u8 *iter_pos = input_buf + 3;
token_t token;
token.token_cnt = 4;
token.len[0] = 3;
token.attr[0] = TOKEN_ATTR_FIXED_LENGTH;
token.len[1] = 1;
token.attr[1] = TOKEN_ATTR_FIXED_LENGTH;
token.len[2] = 8;
token.attr[2] = TOKEN_ATTR_FIXED_LENGTH;
token.len[3] = 22;
token.attr[3] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_BASE64B;
const int rc_tokenizer = input_tokenizer (input_buf, input_len, &token);
if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
memcpy ((u8 *) salt->salt_sign, input_buf, 4);
u8 *iter_pos = token.buf[1];
u32 salt_iter = 1u << itoa64_to_int (iter_pos[0]);
if (salt_iter > 0x80000000) return (PARSER_SALT_ITERATION);
memcpy ((u8 *) salt->salt_sign, input_buf, 4);
salt->salt_iter = salt_iter;
u8 *salt_pos = iter_pos + 1;
u32 salt_len = 8;
u8 *salt_pos = token.buf[2];
int salt_len = token.len[2];
memcpy ((u8 *) salt->salt_buf, salt_pos, salt_len);
salt->salt_len = salt_len;
u8 *hash_pos = salt_pos + salt_len;
u8 *hash_pos = token.buf[3];
phpass_decode ((u8 *) digest, hash_pos);
@ -3968,59 +4025,48 @@ int phpass_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UNU
int md5crypt_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UNUSED hashconfig_t *hashconfig)
{
if (input_len < DISPLAY_LEN_MIN_500) return (PARSER_GLOBAL_LENGTH);
if (memcmp (SIGNATURE_MD5CRYPT, input_buf, 3) != 0) return (PARSER_SIGNATURE_UNMATCHED);
u32 *digest = (u32 *) hash_buf->digest;
salt_t *salt = hash_buf->salt;
u8 *salt_pos = input_buf + 3;
token_t token;
u32 iterations_len = 0;
token.token_cnt = 3;
token.signature = SIGNATURE_MD5CRYPT;
if (memcmp (salt_pos, "rounds=", 7) == 0)
token.len[0] = 3;
token.attr[0] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_SIGNATURE;
token.len_min[1] = 0;
token.len_max[1] = 8;
token.sep[1] = '$';
token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_OPTIONAL_ROUNDS;
token.len[2] = 22;
token.attr[2] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_BASE64B;
const int rc_tokenizer = input_tokenizer (input_buf, input_len, &token);
if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
salt->salt_iter = ROUNDS_MD5CRYPT;
if (token.opt_len != -1)
{
salt_pos += 7;
for (iterations_len = 0; salt_pos[0] >= '0' && salt_pos[0] <= '9' && iterations_len < 7; iterations_len++, salt_pos += 1) continue;
if (iterations_len == 0 ) return (PARSER_SALT_ITERATION);
if (salt_pos[0] != '$') return (PARSER_SIGNATURE_UNMATCHED);
salt_pos[0] = 0x0;
salt->salt_iter = hc_strtoul ((const char *) (salt_pos - iterations_len), NULL, 10);
salt_pos += 1;
iterations_len += 8;
}
else
{
salt->salt_iter = ROUNDS_MD5CRYPT;
salt->salt_iter = hc_strtoul ((const char *) token.opt_buf + 7, NULL, 10); // 7 = "rounds="
}
if (input_len > (DISPLAY_LEN_MAX_500 + iterations_len)) return (PARSER_GLOBAL_LENGTH);
u8 *salt_pos = token.buf[1];
int salt_len = token.len[1];
u8 *hash_pos = (u8 *) strchr ((const char *) salt_pos, '$');
const bool parse_rc = parse_and_store_generic_salt ((u8 *) salt->salt_buf, (int *) &salt->salt_len, salt_pos, salt_len, hashconfig);
if (hash_pos == NULL) return (PARSER_SEPARATOR_UNMATCHED);
if (parse_rc == false) return (PARSER_SALT_LENGTH);
u32 salt_len = hash_pos - salt_pos;
if (salt_len > 8) return (PARSER_SALT_LENGTH);
memcpy ((u8 *) salt->salt_buf, salt_pos, salt_len);
salt->salt_len = salt_len;
hash_pos++;
u32 hash_len = input_len - 3 - iterations_len - salt_len - 1;
if (hash_len != 22) return (PARSER_HASH_LENGTH);
u8 *hash_pos = token.buf[2];
md5crypt_decode ((u8 *) digest, hash_pos);
@ -4029,53 +4075,48 @@ int md5crypt_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_U
int md5apr1_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UNUSED hashconfig_t *hashconfig)
{
if (memcmp (SIGNATURE_MD5APR1, input_buf, 6) != 0) return (PARSER_SIGNATURE_UNMATCHED);
u32 *digest = (u32 *) hash_buf->digest;
salt_t *salt = hash_buf->salt;
u8 *salt_pos = input_buf + 6;
token_t token;
u32 iterations_len = 0;
token.token_cnt = 3;
token.signature = SIGNATURE_MD5APR1;
if (memcmp (salt_pos, "rounds=", 7) == 0)
token.len[0] = 6;
token.attr[0] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_SIGNATURE;
token.len_min[1] = 0;
token.len_max[1] = 8;
token.sep[1] = '$';
token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_OPTIONAL_ROUNDS;
token.len[2] = 22;
token.attr[2] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_BASE64B;
const int rc_tokenizer = input_tokenizer (input_buf, input_len, &token);
if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
salt->salt_iter = ROUNDS_MD5CRYPT;
if (token.opt_len != -1)
{
salt_pos += 7;
for (iterations_len = 0; salt_pos[0] >= '0' && salt_pos[0] <= '9' && iterations_len < 7; iterations_len++, salt_pos += 1) continue;
if (iterations_len == 0 ) return (PARSER_SALT_ITERATION);
if (salt_pos[0] != '$') return (PARSER_SIGNATURE_UNMATCHED);
salt_pos[0] = 0x0;
salt->salt_iter = hc_strtoul ((const char *) (salt_pos - iterations_len), NULL, 10);
salt_pos += 1;
iterations_len += 8;
}
else
{
salt->salt_iter = ROUNDS_MD5CRYPT;
salt->salt_iter = hc_strtoul ((const char *) token.opt_buf + 7, NULL, 10); // 7 = "rounds="
}
if ((input_len < DISPLAY_LEN_MIN_1600) || (input_len > DISPLAY_LEN_MAX_1600 + iterations_len)) return (PARSER_GLOBAL_LENGTH);
u8 *salt_pos = token.buf[1];
int salt_len = token.len[1];
u8 *hash_pos = (u8 *) strchr ((const char *) salt_pos, '$');
const bool parse_rc = parse_and_store_generic_salt ((u8 *) salt->salt_buf, (int *) &salt->salt_len, salt_pos, salt_len, hashconfig);
if (hash_pos == NULL) return (PARSER_SEPARATOR_UNMATCHED);
if (parse_rc == false) return (PARSER_SALT_LENGTH);
u32 salt_len = hash_pos - salt_pos;
if (salt_len > 8) return (PARSER_SALT_LENGTH);
memcpy ((u8 *) salt->salt_buf, salt_pos, salt_len);
salt->salt_len = salt_len;
hash_pos++;
u8 *hash_pos = token.buf[2];
md5crypt_decode ((u8 *) digest, hash_pos);
@ -4084,35 +4125,48 @@ int md5apr1_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UN
int episerver_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_UNUSED hashconfig_t *hashconfig)
{
if ((input_len < DISPLAY_LEN_MIN_141) || (input_len > DISPLAY_LEN_MAX_141)) return (PARSER_GLOBAL_LENGTH);
if (memcmp (SIGNATURE_EPISERVER, input_buf, 14) != 0) return (PARSER_SIGNATURE_UNMATCHED);
u32 *digest = (u32 *) hash_buf->digest;
salt_t *salt = hash_buf->salt;
u8 *salt_pos = input_buf + 14;
token_t token;
u8 *hash_pos = (u8 *) strchr ((const char *) salt_pos, '*');
token.token_cnt = 4;
token.signature = SIGNATURE_EPISERVER;
if (hash_pos == NULL) return (PARSER_SEPARATOR_UNMATCHED);
token.len_min[0] = 11;
token.len_max[0] = 11;
token.sep[0] = '*';
token.attr[0] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_SIGNATURE;
hash_pos++;
token.len_min[1] = 1;
token.len_max[1] = 6;
token.sep[1] = '*';
token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_DIGIT;
u32 salt_len = hash_pos - salt_pos - 1;
token.len_min[2] = 0;
token.len_max[2] = 44;
token.sep[2] = '*';
token.attr[2] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_BASE64A;
u8 *salt_buf_ptr = (u8 *) salt->salt_buf;
token.len_min[3] = 27;
token.len_max[3] = 27;
token.attr[3] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_BASE64A;
salt_len = parse_and_store_salt_legacy (salt_buf_ptr, salt_pos, salt_len, hashconfig);
const int rc_tokenizer = input_tokenizer (input_buf, input_len, &token);
if (salt_len == UINT_MAX) return (PARSER_SALT_LENGTH);
if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
salt->salt_len = salt_len;
u8 *hash_pos = token.buf[3];
int hash_len = token.len[3];
u8 tmp_buf[100] = { 0 };
base64_decode (base64_to_int, (const u8 *) hash_pos, 27, tmp_buf);
base64_decode (base64_to_int, hash_pos, hash_len, tmp_buf);
memcpy (digest, tmp_buf, 20);
@ -4131,6 +4185,13 @@ int episerver_parse_hash (u8 *input_buf, u32 input_len, hash_t *hash_buf, MAYBE_
digest[4] -= SHA1M_E;
}
u8 *salt_pos = token.buf[2];
int salt_len = token.len[2];
const bool parse_rc = parse_and_store_generic_salt ((u8 *) salt->salt_buf, (int *) &salt->salt_len, salt_pos, salt_len, hashconfig);
if (parse_rc == false) return (PARSER_SALT_LENGTH);
return (PARSER_OK);
}
@ -17993,7 +18054,7 @@ int ascii_digest (hashcat_ctx_t *hashcat_ctx, char *out_buf, const size_t out_le
ptr_plain[27] = 0;
snprintf (out_buf, out_len - 1, "%s%s*%s", SIGNATURE_EPISERVER, ptr_salt, ptr_plain);
snprintf (out_buf, out_len - 1, "%s%s*%s", SIGNATURE_EPISERVER0, ptr_salt, ptr_plain);
}
else if (hash_mode == 400)
{