Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Sun, 28 Oct 2012 17:44:37 +0530
From: Dhiru Kholia <dhiru.kholia@...il.com>
To: john-dev@...ts.openwall.com
Subject: Re: ssh_fmt / privkey without using high level OpenSSL functions

On Sun, Oct 28, 2012 at 4:03 PM, Dhiru Kholia <dhiru.kholia@...il.com> wrote:
> Hi,
>
> I tried to re-implement ssh / privkey format without using high level
> OpenSSL functions. However I didn't get a speed-up over JtR's existing
> ssh format :-(. Code is attached. Feel free to re-use it.

Update: after some hacks, it seems that it is possible to get 4.5X
speedup over existing code. Attaching latest code.

However, I am getting some false positives (during actual cracking).

✗ ../run/john -fo:fastssh crackme

Loaded 1 password hash (fast SSH RSA / DSA [32/64])
rdlwny           (rsa.key)
22282576         (rsa.key)
0brlops          (rsa.key)
rith390          (rsa.key)
jbrred!          (rsa.key)
Trcky            (rsa.key)
Bjntb            (rsa.key)
binghase         (rsa.key)
msacis17         (rsa.key)
53472211         (rsa.key)
kj83gE           (rsa.key)
bcep3u           (rsa.key)
ps6o             (rsa.key)

When I put these passwords in a dictionary, they don't work. Even
changing compiler to clang, results in different set of false
positives. There seems to be a bug in my code but I can't find it.

magnum,

Can you please take a look?

-- 
Cheers,
Dhiru

/* Cracker for SSH RSA key files. Hacked together during September of 2012 by 
 * Dhiru Kholia <dhiru.kholia at gmail.com>.
 *
 * This software is Copyright (c) 2012, Dhiru Kholia <dhiru.kholia at gmail.com>,
 * 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 <string.h>
#include <openssl/aes.h>
#include <openssl/des.h>
#include <openssl/asn1.h>
#include <assert.h>
#include <errno.h>
#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 <omp.h>
#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$1$16$570F498F6FF732775EE38648130F600D$1200$1777f12047d4ebab06d052d52946e5e0e73b41d5077b20e1ffe1c97ef9459b8c6844fecc24fdf63314c8889398fa140026339c85336278600e299c0f4c236648ca684f0c122e66d3e860e19eab8b46a564eb101def1c6a38f2f1800040c6b59a66e7b86e145e180f8a126e46544be1e17dd32e4e72f735c9e6b0ca4bbbb32ccf34ba0a7827858b0be32f9e53f13466e2ac78c3fecdf2a51cd7871286a3a91f9c71ae9e857a74bcc06071af6f60d827f7e13ccf6c1be722246c0796f509744c2b1b1452315ea6f86a1c8765d1f0c1d795349b4ea1ba229318b392fe505292cd0c6b4e3e9b2acc13b96943d92fa5635e05b7795989906274b0fb1894102d07facdd8f2122299960e1490823d62bbd5bf6d6c92ed26e68cc2edc93fbffec557a5d187fffe085ded9408ac63293851a684ca10d6e9a4ee9b5c552c827caee1f1c41870fe2d0e79bc4a0b85478fa82a58f947d345122c8ac7c80ba2ae8452b093dda70e2a4329fce70af9cf98e19477a622083664d1e62393a01b20371fc5be9390059f1c4af75d5448a2fbe1aaa46701c696afec927c67d15c046036531d9252faa08bbf9ea0e019ea574e6af94edd7ec17c83c0f87e34c7456e19bc53b2de04dafa83267694c1f61d038e0fc5f8f1b8ce573da470e6db6d38c0e8f7141ad9e9609ea408e3823271e987766039d484bc88f23f2f2a1175636ece950c7d82f43726287fef37da945ec6ad6adc04cb59f66087f68a3e84e8cc39c578bcbce3aaf67f1325d3d20dbd5872cc88ab72fc0bda05bf969eca08f8cafb306424a1597ba5d612e155b4723c2c1bee9a8e3d195be3b798ea417008a2340a919e23ac899ea4dbc4ef05af2cf6b12293eeb293584b37d3f8465e36a62d65b21f68725603e11dc14acf4e3855e25980387a34a34919fdd49844ed888e37199bb26df1bbbc303e895615fcbb0aa9ddc8a2aa685da942a1e68dc3a355d27236f74220d404d25e0ac64ae9203bb04296b4d67481a4f516fd22e47092073c9c44fa098670d736c5c509e55d6b40d3bf346ea5bb0007e32e9d8290c2633621fd84c2f5f428a5649ff3a16d00fec21381543202f2ee12078ddea8a371935f2ffa15aafa644e111a29c1c4703bf8e9cf1397356e296c5484558b96639b9cf3703aabff0cf42864dab91b1e09c6439159bc95374da7a5d416402286390e76cb766cd94e7a002596e8862b8d7e46c1fc6f7bdd0b93c73d2dc3cf58ea31bc549086209f450bb7460d5e9ba0d0f7b80337651f45bf83bef1783c3a15631c82428bfe167dc0692402d7f15144fff01ad8596970439ce8a2df0107c85a23ef93edd19f62de499ab58ada581886494c3e52dd5ec53c191f6d62729729a252c2c0d8024950d1637cfd7c61a4fe64ce41cde76fe00fa2607af66a44d3b4b8836820f40c03669f08b4e986f4d03c09e3c026a910f83be623d7f68ff80d81662f020f433f7a896e10134a278cd9a8517d3bcd77c5287f7d41bc52d2f8db79b5f8f9ed6d6f45a482b13cb91ecdef43ebe38f5ad71836185ae6faf1dd11c50cc1759e4834fcab2b3523d4224a32d2eaba224a2c950dac7524afc74f02f17b511f3b22d577a6928d40909bed64f6ed27096dff591a8fbee3f32733fd2b36c0c4708a5224f165af000d93832e211ae52465f680e7a4fd66bb5eb210c4402eb58f6ebfde", "strongpassword"},
	{"$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] = {0};
	int keyidx = 0;
	int digest_inited = 0;
	int size = 0;;
	int i = 0;

	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] = {0};
	char *res = NULL;
	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)
		goto bad;
	BIO_gets(outfile, (char*)output, 8192);
	res = memmem(output, 128, ":00", 3);
	if (!res)
		goto bad;
	BIO_free(outfile);
	return 0;
bad:
	BIO_free(outfile);
	return -1;

}


static void crypt_all(int count)
{
	int index = 0;
#ifdef _OPENMP
#pragma omp parallel for
	for (index = 0; index < count; index++)
#endif
	{
		if (cur_salt->cipher == 0) {
			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, cur_salt->ctl);
			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;
		}
		else {
			unsigned char key[16] = {0};
			unsigned char out[cur_salt->ctl];
			AES_KEY akey;
			unsigned char iv[16];
			memcpy(iv, cur_salt->salt, 16);
			memset(out, 0, 32);
			memset(out + cur_salt->ctl - 32, 0, 32);
			generate_key_bytes(16, (unsigned char*)saved_key[index], key);
			AES_set_decrypt_key(key, 128, &akey);
			//AES_cbc_encrypt(cur_salt->ct, out, cur_salt->ctl, &akey, iv, AES_DECRYPT);
			// dirty hack!
			AES_cbc_encrypt(cur_salt->ct, out, 16, &akey, iv, AES_DECRYPT); // are starting 16 bytes enough?
			// 2 blocks (32 bytes) are enough to self-recover from bad IV, required for correct padding check
			AES_cbc_encrypt(cur_salt->ct + cur_salt->ctl - 32, out + cur_salt->ctl - 32, 32, &akey, iv, AES_DECRYPT);
			if (check_padding_3des(out, cur_salt->ctl) == 0)
				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 | FMT_NOT_EXACT,
		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
	}
};

[ CONTENT OF TYPE application/octet-stream SKIPPED ]

Powered by blists - more mailing lists

Your e-mail address:

Powered by Openwall GNU/*/Linux - Powered by OpenVZ