/* Cracker for SSH RSA key files. Hacked together during September of 2012 by * Dhiru Kholia . * * This software is Copyright (c) 2012, Dhiru Kholia , * and it is hereby released to the general public under the following terms: * Redistribution and use in source and binary forms, with or without modification, * are permitted. */ #define _GNU_SOURCE #include "md5.h" #include #include #include #include #include #include #include "arch.h" #include "misc.h" #include "common.h" #include "formats.h" #include "params.h" #include "options.h" #ifdef _OPENMP static int omp_t = 1; #include #define OMP_SCALE 64 #endif #define FORMAT_LABEL "fastssh" #define FORMAT_NAME "fast SSH RSA / DSA" #define ALGORITHM_NAME "32/" ARCH_BITS_STR #define BENCHMARK_COMMENT "" #define BENCHMARK_LENGTH -1 #define PLAINTEXT_LENGTH 32 #define BINARY_SIZE 16 #define SALT_SIZE sizeof(struct custom_salt) #define MIN_KEYS_PER_CRYPT 1 #define MAX_KEYS_PER_CRYPT 1 static struct fmt_tests fastssh_tests[] = { {"$fastssh$0$8$DAA422E8A5A8EFB7$608$fa7b2c1c699697dd487261a213a0dd088a86bc03f4e2db8b87ad302e3581bdd8ed17d0a3ced3e7179ef17beea9064ee862017f472de293d655f6b1cd7115e27c328cf5caf1b5896952590cd82d123fcf6c5da3b43f5435c829ebb595300c828e04d57c7ade57efe006305b32fe79afd0d14cadba681b4dc3a69b25a1e71ddbd353465217c311d11721f1cba05d1226ff0e7d261156f0837753bcaaddfec383591f61470a4318cf679046d43490a1eef33014a90865917ccaa16f986724b8ee421d990327a46410362b4992406af41a88e3c5e5bbb7707ba08517e7ac8295ad0b934c38968f05fd372f1ee29e24eddcbbacba5b3e1b7150e51ba4e17b4f54319630e2d5372adc46e4de437f64b3d11670eb25fc94c7e9bd0579806bbf16c6cfe529a4bc0d3918ca4777f8418e789163660d9bbe0aa297857ee4922dffe310e6967fba2ee2e06707d9bbd9c8601bad7ccfdcb8a948074de511be7d588b7b71d4b5f0b1e19020b54efc4d626b2e4d85c0a40682517128b9ecc29f882996f4f6b655bb1986e293cb5271fe98c61d8b2e6e8338fee42f22674fc8b2da475663ba19644e7de76927cd9e333b533ad7617cc7a9f19dc7c00c240ed92c2fb1aaf6495bd16ab9fae4650567ad8b175d02f9e6a9737362168035670017fd9ad87cf4e916f47baa5efe0d04939295fba608f83fa811b946d12afe77836dc6d0d398824a355926ce5848dace776c7a7ab7109be495894bc98a2cf04107368d5d8777a1d0ef19782ebb1527b564ac0f5d4ac91e81f435cc21f5905b9753ee1a79913306957589943da161a6f5dc3082b80930553769ce11d82d9cb12d8a12bb4e56eb3f1200eb", "television"}, {NULL} }; static char (*saved_key)[PLAINTEXT_LENGTH + 1]; static int *cracked; static struct custom_salt { char unsigned salt[16]; char unsigned ct[8192]; int cipher; int ctl; int sl; } *cur_salt; static void init(struct fmt_main *self) { #ifdef _OPENMP omp_t = omp_get_max_threads(); self->params.min_keys_per_crypt *= omp_t; omp_t *= OMP_SCALE; self->params.max_keys_per_crypt *= omp_t; #endif saved_key = mem_calloc_tiny(sizeof(*saved_key) * self->params.max_keys_per_crypt, MEM_ALIGN_NONE); cracked = mem_calloc_tiny(sizeof(*cracked) * self->params.max_keys_per_crypt, MEM_ALIGN_WORD); } static int valid(char *ciphertext, struct fmt_main *self) { return !strncmp(ciphertext, "$fastssh$", 9); } #ifdef DEBUG static void print_hex(unsigned char *str, int len) { int i; for (i = 0; i < len; ++i) printf("%02x", str[i]); printf("\n"); } #endif static void *get_salt(char *ciphertext) { char *ctcopy = strdup(ciphertext); char *keeptr = ctcopy; char *p; int i; static struct custom_salt cs; ctcopy += 9; /* skip over "$fastssh$" */ p = strtok(ctcopy, "$"); cs.cipher = atoi(p); p = strtok(NULL, "$"); cs.sl = atoi(p); p = strtok(NULL, "$"); for (i = 0; i < cs.sl; i++) cs.salt[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])]; p = strtok(NULL, "$"); cs.ctl = atoi(p); p = strtok(NULL, "$"); for (i = 0; i < cs.ctl; i++) cs.ct[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])]; MEM_FREE(keeptr); return (void *)&cs; } static void set_salt(void *salt) { cur_salt = (struct custom_salt *)salt; } void generate_key_bytes(int nbytes, unsigned char *password, unsigned char *key) { unsigned char digest[16]; int keyidx = 0; int digest_inited = 0; int size; int i; while (nbytes > 0) { MD5_CTX ctx; MD5_Init(&ctx); if (digest_inited) { MD5_Update(&ctx, digest, 16); } MD5_Update(&ctx, password, strlen((const char*)password)); /* use first 8 bytes of salt */ MD5_Update(&ctx, cur_salt->salt, 8); MD5_Final(digest, &ctx); digest_inited = 1; if (nbytes > 16) size = 16; else size = nbytes; /* copy part of digest to keydata */ for(i = 0; i < size; i++) key[keyidx++] = digest[i]; nbytes -= size; } } int check_padding_3des(unsigned char *out, int length) { int pad; int i; int n; unsigned char output[8192]; char *res; BIO * outfile; // now check padding pad = out[length - 1]; if(pad > 8) // "Bad padding byte. You probably have a wrong password" return -1; n = length - pad; for(i = n; i < length; i++) if(out[i] != pad) return -1; /* check BER decoding */ outfile = BIO_new(BIO_s_mem()); ASN1_parse(outfile, out, cur_salt->ctl, 0); BIO_gets(outfile, (char*)output, 8192); res = memmem(output, 128, "SEQUENCE", 8); if (!res) return -1; BIO_gets(outfile, (char*)output, 8192); res = memmem(output, 128, ":00", 3); if (!res) return -1; return 0; } static void crypt_all(int count) { int index = 0; #ifdef _OPENMP #pragma omp parallel for for (index = 0; index < count; index++) #endif { unsigned char key[24] = {0}; unsigned char out[cur_salt->ctl]; DES_cblock key1, key2, key3; DES_cblock ivec; DES_key_schedule ks1, ks2, ks3; generate_key_bytes(24, (unsigned char*)saved_key[index], key); memset(out, 0, sizeof(out)); memcpy(key1, key, 8); memcpy(key2, key + 8, 8); memcpy(key3, key + 16, 8); DES_set_key((C_Block *) key1, &ks1); DES_set_key((C_Block *) key2, &ks2); DES_set_key((C_Block *) key3, &ks3); memcpy(ivec, cur_salt->salt, 8); DES_ede3_cbc_encrypt(cur_salt->ct, out, cur_salt->ctl, &ks1, &ks2, &ks3, &ivec, DES_DECRYPT); if (check_padding_3des(out, cur_salt->ctl) == 0) cracked[index] = 1; else cracked[index] = 0; } /* AES_set_decrypt_key(key, 192, &akey); AES_cbc_encrypt(cur_salt->ct + 16, pt + 16, 32, &akey, iv, AES_DECRYPT); if (!memcmp(pt + 40, "\x08\x08\x08\x08\x08\x08\x08\x08", 8)) { cracked[index] = 1; } else cracked[index] = 0; */ } static int cmp_all(void *binary, int count) { int index; for (index = 0; index < count; index++) if (cracked[index]) return 1; return 0; } static int cmp_one(void *binary, int index) { return cracked[index]; } static int cmp_exact(char *source, int index) { return 1; } static void fastssh_set_key(char *key, int index) { int saved_key_length = strlen(key); if (saved_key_length > PLAINTEXT_LENGTH) saved_key_length = PLAINTEXT_LENGTH; memcpy(saved_key[index], key, saved_key_length); saved_key[index][saved_key_length] = 0; } static char *get_key(int index) { return saved_key[index]; } struct fmt_main fastssh_fmt = { { FORMAT_LABEL, FORMAT_NAME, ALGORITHM_NAME, BENCHMARK_COMMENT, BENCHMARK_LENGTH, PLAINTEXT_LENGTH, BINARY_SIZE, #if FMT_MAIN_VERSION > 9 DEFAULT_ALIGN, #endif SALT_SIZE, #if FMT_MAIN_VERSION > 9 DEFAULT_ALIGN, #endif MIN_KEYS_PER_CRYPT, MAX_KEYS_PER_CRYPT, FMT_CASE | FMT_8_BIT | FMT_OMP, fastssh_tests }, { init, fmt_default_prepare, valid, fmt_default_split, fmt_default_binary, get_salt, #if FMT_MAIN_VERSION > 9 fmt_default_source, #endif { fmt_default_binary_hash }, fmt_default_salt_hash, set_salt, fastssh_set_key, get_key, fmt_default_clear_keys, crypt_all, { fmt_default_get_hash }, cmp_all, cmp_one, cmp_exact } };