Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Tue, 18 Sep 2007 06:25:06 +0200
From: andrea@...share.com
To: john-users@...ts.openwall.com
Cc: cpushare-devel@...share.com
Subject: CPUShare port of John MD5 brute force

Hello everyone,

I had to spend last weekend at home to recover from a flu, so I had
the opportunity to finish porting John 1.7.2 the MD5 crypto algorithms
of John to CPUShare.

There's lots of room for improvements still, but this effectively
makes John the first open source application capable of running on top
of CPUShare. It also makes CPUShare useful for the first time (and the
money connection with paypal and worldwide invoicing system are both
already fully enabled online, so theoretically you could start using
John right now and paying with real money for CPU usage).

I'm unsure about the license requirement, currently I used LGPL but it
may very well be I need to make the C part GPL, any advice is
welcome. I know LGPL may also be upgraded (or downgraded depending on
your point of view ;) to GPL at any time without my consent (this is a
property of the LGPL itself). Not sure if that matters in this case?

If I create cpushare_buy/pwd with an editor and I put the below line
as the first line inside it:

$1$12345678$xek.CpjQUVgdf/P2N9KQf/

After the client quits I get at the end of the logs:

2007-09-18 06:03:23+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:03:23+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:03:23+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:03:23+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:03:23+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:03:23+0200 [cpushare_protocol,client] Starting factory <cpushare.proto.cpushare_seccomp_factory instance at 0xc44bd8>
2007-09-18 06:03:23+0200 [Uninitialized] Pushing range :aaa
2007-09-18 06:03:23+0200 [Uninitialized] Pushing range aaa:baa
2007-09-18 06:03:23+0200 [Uninitialized] Pushing range baa:caa
2007-09-18 06:03:23+0200 [Uninitialized] Pushing range caa:daa
2007-09-18 06:03:23+0200 [Uninitialized] Pushing range daa:eaa
2007-09-18 06:03:24+0200 [cpushare_seccomp_protocol,client] --------------------------------------------------
2007-09-18 06:03:24+0200 [cpushare_seccomp_protocol,client] Decryption successful, cleartext is: ''
2007-09-18 06:03:24+0200 [cpushare_seccomp_protocol,client] --------------------------------------------------

If I instead put this in the pwd file (I created this one by typing
"passwd andrea" and cut-and-pasting the encrypted pwd from /etc/shadow
into the pwd file):

$1$2kUlsM5n$dt9OSEYNxcsGQcUae3zS..

I get:

2007-09-18 06:05:06+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:05:06+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:05:06+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:05:06+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:05:06+0200 [cpushare_protocol,client] 'start transaction: CPUCoins 0.10'
2007-09-18 06:05:06+0200 [cpushare_protocol,client] Starting factory <cpushare.proto.cpushare_seccomp_factory instance at 0xc44bd8>
2007-09-18 06:05:06+0200 [Uninitialized] Pushing range :aaa
2007-09-18 06:05:06+0200 [Uninitialized] Pushing range aaa:baa
2007-09-18 06:05:06+0200 [Uninitialized] Pushing range baa:caa
2007-09-18 06:05:06+0200 [Uninitialized] Pushing range caa:daa
2007-09-18 06:05:06+0200 [Uninitialized] Pushing range daa:eaa
2007-09-18 06:05:07+0200 [cpushare_seccomp_protocol,client] --------------------------------------------------
2007-09-18 06:05:07+0200 [cpushare_seccomp_protocol,client] Decryption successful, cleartext is: 'ab'
2007-09-18 06:05:07+0200 [cpushare_seccomp_protocol,client] --------------------------------------------------

Longer computations should work too ;). The code isn't heavily tested
though. It also fails to checkpoint the runtime, but that's a trivial
add-on for later and it doesn't worry me a single bit, only the
pending_ranges list and the start_range needs to be saved in a file
once in a while and re-read at startup. The only really important
thing is that the core of the seccomp computations are going ok.

I'd also like to know if something remotely like the below could be
merged into john of if it has to remain separated (I included the
patch it in the cpushare core package for now). It's not so
invasive. However CPUShare is still in alpha status, the buy protocol
may change a lot over time and that will require updates (it's already
decently clean, but the handling of those seccomp errors could have
some more layer of abstractions as well as few other bits, but in this
startup-mode that's frankly a low priority, no time for cleanups even
if they affect the visible buy-API).

The only mode implemented is actually a brute-force python-mode in
charset order (inferior to the john incremental mode), but the python
code can be changed to implement other modes, no change to the C code
should be required. Only the encryption code of john is being run remotely.

Hope somebody finds this useful ;), or if nothing else fun!!

The next app ported will be povray-pvm, I got life easy with john
because I didn't need to implement malloc in userland over a
preallocated mmap yet ;)

diff --git a/cpushare_buy/__init__.py b/cpushare_buy/__init__.py
new file mode 100644
--- /dev/null
+++ b/cpushare_buy/__init__.py
@@ -0,0 +1,20 @@
+# cpushare buy client core API
+# Copyright (C) 2005-2007  Andrea Arcangeli <andrea@...share.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation;
+# only version 2.1 of the License.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+from cpushare_buy.api import seccomp_gen_hash
+from cpushare_buy.api import checkpoint_sec
+from cpushare_buy.api import buy_state_machine_class
diff --git a/cpushare_buy/api.py b/cpushare_buy/api.py
new file mode 100644
--- /dev/null
+++ b/cpushare_buy/api.py
@@ -0,0 +1,206 @@
+# cpushare buy client core API
+# Copyright (C) 2005-2007  Andrea Arcangeli <andrea@...share.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation;
+# only version 2.1 of the License.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import os, struct, errno
+
+# local
+from cpushare.seccomp_gen import seccomp_gen_class
+from cpushare.proto_const import *
+from cpushare.exceptions import CompilationError
+
+# estimate of the max number of seconds that the sell client
+# will take to checkpoint and send its state back to us
+checkpoint_sec = 120
+
+seccomp_gen_hash = {}
+def build_seccomp_gen_hash():
+	_dir = os.path.join(os.readlink('cpushare_buy'), '../src')
+	if os.system('make CPUSHARE_CORE=`pwd` -C %s linux-cpushare' % _dir):
+		raise CompilationError()
+
+	x86 = seccomp_gen_hash['i686'] = seccomp_gen_class(os.path.join(_dir,
+									'bytecode.i686'),
+							   'i686')
+	x86.heap_kbytes = 1
+	x86.stack_kbytes = 8
+
+	ppc = seccomp_gen_hash['ppc'] = seccomp_gen_class(os.path.join(_dir,
+								       'bytecode.ppc'),
+							  'ppc')
+	ppc.heap_kbytes = 1
+	ppc.stack_kbytes = 8
+# build and prepare the bytecode at the first import
+if not seccomp_gen_hash:
+	build_seccomp_gen_hash()
+
+pwd = None
+def read_pwd():
+	f = file('cpushare_buy/pwd')
+	global pwd
+	pwd = f.readline()
+	pwd = pwd.strip()
+if not pwd:
+	read_pwd()
+
+charset = ''
+charset_next = {}
+def init_charset():
+	global charset
+	c = 'a'
+	while 1:
+		if c > 'z':
+			break
+		charset += c
+		c = chr(ord(c)+1)
+	c = 'A'
+	while 1:
+		if c > 'Z':
+			break
+		charset += c
+		c = chr(ord(c)+1)
+	c = '0'
+	while 1:
+		if c > '9':
+			break
+		charset += c
+		c = chr(ord(c)+1)
+	charset += '~!@...^&*()_+{}|":><?/.,;\'\\][=-`'
+	for i in xrange(len(charset)-1):
+		charset_next[charset[i]] = charset[i+1]
+	charset_next[charset[-1]] = charset[0]
+	charset_next[chr(0)] = charset[0]
+if not charset:
+	init_charset()
+
+class buy_state_machine_class(object):
+	max_cleartext_length = 15
+	depth = 8
+	depth_per_pass = 2
+	pending_ranges = []
+	start_range = ''.rjust(max_cleartext_length, chr(0))
+	end_range = (charset[0] * depth).rjust(max_cleartext_length, chr(0))
+	finish_mode = None
+	def __init__(self, protocol):
+		self.protocol = protocol
+		self.handler = self.stringReceived
+		self.cleartext = ''
+
+	def get_new_range(self):
+		if buy_state_machine_class.start_range == buy_state_machine_class.end_range:
+			return
+		start = buy_state_machine_class.start_range
+		end = list(start)
+		for i in xrange(self.max_cleartext_length-1, self.max_cleartext_length-1-self.depth_per_pass, -1):
+			if end[i] == chr(0):
+				end[i] = charset[0]
+		for i in xrange(self.max_cleartext_length-1-self.depth_per_pass, -1, -1):
+			old_end = end[i]
+			end[i] = charset_next[old_end]
+			if old_end == chr(0) or end[i] != charset[0]:
+				break
+		else:
+			raise Exception()
+		end = ''.join(end)
+		buy_state_machine_class.start_range = end
+		return start, end
+	def get_range(self):
+		try:
+			return buy_state_machine_class.pending_ranges.pop(0)
+		except IndexError:
+			return self.get_new_range()
+
+	def start(self):
+		self.protocol.sendString(PROTO_SECCOMP_FORWARD + chr(len(pwd)))
+		self.protocol.sendString(PROTO_SECCOMP_FORWARD + pwd)
+
+		self.protocol.sendString(PROTO_SECCOMP_FORWARD + chr(len(charset)))
+		self.protocol.sendString(PROTO_SECCOMP_FORWARD + charset)
+
+		self.push_range()
+
+	def push_range(self):
+		self.range = self.get_range()
+		if not self.range:
+			return
+
+		print 'Pushing range %s:%s' % (self.range[0].strip(chr(0)), self.range[1].strip(chr(0)))
+		assert len(self.range[0]) == self.max_cleartext_length, self.range[0]
+		assert len(self.range[1]) == self.max_cleartext_length, self.range[1]
+
+		self.protocol.sendString(PROTO_SECCOMP_FORWARD + self.range[0])
+		self.protocol.sendString(PROTO_SECCOMP_FORWARD + self.range[1])
+
+	def stringReceived(self, string):
+		control = string[0]
+		data = string[1:]
+
+		if control == PROTO_SECCOMP_FORWARD:
+			#print self, repr(data)
+			if self.finish_mode == 1:
+				self.cleartext += data
+				if len(self.cleartext) == self.max_cleartext_length:
+					self.protocol.sendString(PROTO_SECCOMP_SUCCESS)
+					print '-'*50
+					print 'Decryption successful, cleartext is: %r' % self.cleartext.strip(chr(0))
+					print '-'*50
+
+					from twisted.internet import reactor
+					reactor.iterate(1) # give a chance to the success to go out
+					reactor.stop()
+				if len(self.cleartext) > self.max_cleartext_length:
+					self.protocol.sendString(PROTO_SECCOMP_FAILURE)
+					self.protocol.transport.loseConnection()
+			else:
+				if data[0] == chr(0):
+					assert not self.finish_mode
+					self.push_range()
+				elif data[0] == chr(1):
+					self.finish_mode = 1
+					self.stringReceived(control+data[1:])
+				elif data[0] == chr(2):
+					assert self.finish_mode is None
+					assert len(data) == 1
+					self.finish_mode = 2
+					self.protocol.sendString(PROTO_SECCOMP_SUCCESS)
+				else:
+					print 'malicious client: unknown command %c' % data[0]
+					self.protocol.sendString(PROTO_SECCOMP_FAILURE)
+					self.protocol.transport.loseConnection()
+		elif control == PROTO_SECCOMP_SIGNAL:
+			print 'checkpoint starting'
+		elif control == PROTO_LOG:
+			print repr(data)
+		else:
+			if control == PROTO_SECCOMP_SUCCESS:
+				pass
+			elif control == PROTO_SECCOMP_FAILURE:
+				status = struct.unpack('!i', data)[0]
+				exit_code = status >> 8
+				signal = status & 0xff
+				_str = 'Seccomp failure: status %d, exit_code %d, signal %d.' % \
+				       (status, exit_code, signal)
+				print _str
+			else:
+				_str = 'Unknown buy api failure %d - %s' % (ord(control), repr(string))
+				self.protocol.sendString(PROTO_SECCOMP_FAILURE + _str)
+				print _str
+			self.protocol.sendString(PROTO_SECCOMP_FAILURE)
+			self.protocol.transport.loseConnection()
+
+	def connectionLost(self):
+		if not self.finish_mode:
+			self.pending_ranges.append(self.range)
diff --git a/cpushare_buy/linux-cpushare-i686-arch.h b/cpushare_buy/linux-cpushare-i686-arch.h
new file mode 100644
--- /dev/null
+++ b/cpushare_buy/linux-cpushare-i686-arch.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of John the Ripper password cracker,
+ * Copyright (c) 1996-2001 by Solar Designer
+ */
+
+/*
+ * Architecture specific parameters for x86.
+ */
+
+#ifndef _JOHN_ARCH_H
+#define _JOHN_ARCH_H
+
+#define ARCH_WORD			long
+#define ARCH_SIZE			4
+#define ARCH_BITS			32
+#define ARCH_BITS_LOG			5
+#define ARCH_BITS_STR			"32"
+#define ARCH_LITTLE_ENDIAN		1
+#define ARCH_INT_GT_32			0
+#define ARCH_ALLOWS_UNALIGNED		1
+#define ARCH_INDEX(x)			((unsigned int)(unsigned char)(x))
+
+#if defined(__CYGWIN32__) || defined(__BEOS__)
+#define OS_TIMER			0
+#else
+#define OS_TIMER			1
+#endif
+#define OS_FLOCK			1
+
+#define CPU_DETECT			1
+#define CPU_REQ				0
+
+#define DES_ASM				1
+#define DES_128K			0
+#define DES_X2				0
+#define DES_MASK			1
+#define DES_SCALE			0
+#define DES_EXTB			0
+#define DES_COPY			1
+#define DES_BS_ASM			0
+#define DES_BS				0
+#define DES_BS_VECTOR			0
+#define DES_BS_EXPAND			0
+
+#define MD5_ASM				1
+#define MD5_X2				0
+#define MD5_IMM				1
+
+#define BF_ASM				1
+#define BF_SCALE			1
+
+#endif
diff --git a/cpushare_buy/linux-cpushare-ppc-arch.h b/cpushare_buy/linux-cpushare-ppc-arch.h
new file mode 100644
--- /dev/null
+++ b/cpushare_buy/linux-cpushare-ppc-arch.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of John the Ripper password cracker,
+ * Copyright (c) 1996-2001 by Solar Designer
+ */
+
+/*
+ * Architecture specific parameters for x86.
+ */
+
+#ifndef _JOHN_ARCH_H
+#define _JOHN_ARCH_H
+
+#define ARCH_WORD			long
+#define ARCH_SIZE			4
+#define ARCH_BITS			32
+#define ARCH_BITS_LOG			5
+#define ARCH_BITS_STR			"32"
+#define ARCH_LITTLE_ENDIAN		0
+#define ARCH_INT_GT_32			0
+#define ARCH_ALLOWS_UNALIGNED		1
+#define ARCH_INDEX(x)			((unsigned int)(unsigned char)(x))
+
+#if defined(__CYGWIN32__) || defined(__BEOS__)
+#define OS_TIMER			0
+#else
+#define OS_TIMER			1
+#endif
+#define OS_FLOCK			1
+
+#define CPU_DETECT			1
+#define CPU_REQ				0
+
+#define DES_ASM				1
+#define DES_128K			0
+#define DES_X2				0
+#define DES_MASK			1
+#define DES_SCALE			0
+#define DES_EXTB			0
+#define DES_COPY			1
+#define DES_BS_ASM			0
+#define DES_BS				0
+#define DES_BS_VECTOR			0
+#define DES_BS_EXPAND			0
+
+#define MD5_ASM				0
+#define MD5_X2				0
+#define MD5_IMM				0
+
+#define BF_ASM				0
+#define BF_SCALE			0
+
+#endif
diff --git a/src/Makefile b/src/Makefile
--- a/src/Makefile
+++ b/src/Makefile
@@ -88,6 +88,7 @@ default:
 	@echo "linux-ppc32              Linux, PowerPC 32-bit"
 #	@echo "linux-ppc64-altivec      Linux, PowerPC 64-bit w/AltiVec"
 	@echo "linux-ppc64              Linux, PowerPC 64-bit"
+	@echo "linux-cpushare           Linux, CPUShare"
 	@echo "freebsd-x86-sse2         FreeBSD, x86 with SSE2 (best)"
 	@echo "freebsd-x86-mmx          FreeBSD, x86 with MMX"
 	@echo "freebsd-x86-any          FreeBSD, x86"
@@ -136,6 +137,22 @@ default:
 	@echo "beos-x86-any             BeOS, x86"
 	@echo "generic                  Any other Unix-like system with gcc"
 
+ifeq ($(CPUSHARE_CORE),)
+linux-cpushare:
+	@echo Make manual invocation error: CPUSHARE_CORE is missing.
+	@echo Use: \'make CPUSHARE_CORE=/wherever_it_is/cpushare cpushare\'
+else
+# OBJS is needed by Makefile.cpushare
+export CFLAGS
+linux-cpushare: $(CPUSHARE_CORE)/seccomp-loader.h
+	make _clean
+	cp ../cpushare_buy/linux-cpushare-ppc-arch.h arch.h
+	$(MAKE) CPUSHARE_PROJECT=`pwd` -f $(CPUSHARE_CORE)/Makefile.ppc OBJS="MD5_fmt.o MD5_std.o common.o misc.o"
+	make _clean
+	cp ../cpushare_buy/linux-cpushare-i686-arch.h arch.h
+	$(MAKE) CPUSHARE_PROJECT=`pwd` -f $(CPUSHARE_CORE)/Makefile.i686  OBJS="MD5_fmt.o MD5_std.o x86.o common.o misc.o"
+endif
+
 linux-x86-sse2:
 	$(LN) x86-sse.h arch.h
 	$(MAKE) $(PROJ) \
@@ -738,11 +755,14 @@ depend:
 depend:
 	makedepend -fMakefile.dep -Y *.c 2>> /dev/null
 
-clean:
+_clean:
 	$(RM) $(PROJ) $(PROJ_DOS) $(PROJ_WIN32)
 	$(RM) ../run/john.exe *.o *.bak core
 	$(RM) detect bench generic.h arch.h sparc.h tmp.s
 	$(RM) DES_bs_s.c DES_bs_n.c DES_bs_a.c
 	$(CP) $(NULL) Makefile.dep
 
+clean: _clean
+	-$(RM) bytecode.i686 bytecode.ppc bytecode.lds bytecode.lds.s *.{text,data,seccomp}.bin
+
 include Makefile.dep
diff --git a/src/Makefile.cpushare b/src/Makefile.cpushare
new file mode 100644
--- /dev/null
+++ b/src/Makefile.cpushare
@@ -0,0 +1,9 @@
+# this is called back from the cpushare/projects/Makefile.$(ARCH)
+
+ifeq ($(CPUSHARE_CORE),)
+all:
+	@echo Make manual invocation error: CPUSHARE_CORE is missing.
+else
+bytecode.$(ARCH).o: cpushare.c $(OBJS) $(CPUSHARE_CORE)/seccomp-loader.h
+	$(CC) -c $(CFLAGS) $< -o $@
+endif
diff --git a/src/cpushare.c b/src/cpushare.c
new file mode 100644
--- /dev/null
+++ b/src/cpushare.c
@@ -0,0 +1,197 @@
+/*
+  bytecode: invoked by CPUShare
+  Copyright (C) 2004-2007  Andrea Arcangeli <andrea@...share.com>
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation;
+  only version 2.1 of the License.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <signal.h>
+#include <math.h>
+#include <string.h>
+
+#include <seccomp-loader.h>
+
+#include "MD5_std.h"
+#include "formats.h"
+
+#if !defined(__i386__) && (!defined(__powerpc__) || defined(__powerpc64__))
+#error "only x86 and ppc are supported, not enough resources to port to other archs yet"
+#endif
+
+volatile unsigned int quit;
+
+void sighandler(int signal)
+{
+	if (signal != SIGQUIT)
+		sys_exit(200);
+	quit = 1;
+}
+
+#define MAX_CLEARTEXT_LENGTH 15
+#define ENCRYPTED_PWD_LENGTH 34
+
+static char crypto[ENCRYPTED_PWD_LENGTH+1];
+static char charset_length;
+static unsigned char_start, char_end;
+static unsigned char start[MAX_CLEARTEXT_LENGTH+1], end[MAX_CLEARTEXT_LENGTH+1];
+static unsigned char charset[sizeof(char)<<8], charset_next[sizeof(char)<<8], charset_prev[sizeof(char)<<8];
+
+static int inc_cleartext(void)
+{
+	int i;
+	for (i = MAX_CLEARTEXT_LENGTH-1;;) {
+		unsigned char old;
+		old = start[i];
+		start[i] = charset_next[old];
+		if (!old || start[i] != char_start)
+			break;
+		i--;
+		if (i < 0)
+			sys_exit(100); /* overflow? */
+	}
+	if (!memcmp(start, end, MAX_CLEARTEXT_LENGTH))
+		return 0;
+	else
+		return 1;
+}
+
+static void dec_cleartext(void)
+{
+	int i;
+	for (i = MAX_CLEARTEXT_LENGTH-1;;) {
+		start[i] = charset_prev[start[i]];
+		if (start[i] == char_end && (i == 0 || start[i-i] == 0))
+			start[i] = 0;
+		if (!start[i] || start[i] != char_end)
+			break;
+		i--;
+		if (i < 0)
+			sys_exit(101); /* overflow? */
+	}
+}
+
+static int _check(void)
+{
+	int ret = 0, i;
+	for (i = 0; i < MD5_N; i++) {
+		int j = 0;
+		char * s = (char *) start;
+		while (!*s && j++ < MAX_CLEARTEXT_LENGTH)
+			s++;
+		MD5_std_set_key(s, i);
+		if (!inc_cleartext())
+			ret = 2;
+	}
+	MD5_std_crypt();
+	for (i = 0; i < MD5_N; i++) {
+		if (!memcmp(MD5_std_get_binary(crypto), MD5_out[i], sizeof(MD5_binary))) {
+			i = MD5_N-i;
+			while (i--)
+				dec_cleartext();
+			return 1;
+		}
+	}
+	return ret;
+}
+
+static int check(void)
+{
+	for (;;) {
+		int ret = _check();
+		if (ret == 1)
+			return 1;
+		if (ret == 2)
+			/* reached end */
+			break;
+	}
+	return 0;
+}
+
+void bytecode(unsigned char * mem, int heap_size, int stack_size)
+{
+	extern struct fmt_main fmt_MD5;
+	unsigned char c, crypto_length;
+	char x;
+
+	common_init();
+	MD5_std_init();
+
+	if (sys_read(0, (char *) &crypto_length, 1) != 1)
+		sys_exit(1);
+	if (sys_read(0, crypto, crypto_length) != crypto_length)
+		sys_exit(2);
+	if (crypto_length > ENCRYPTED_PWD_LENGTH)
+		sys_exit(3);
+	if (!fmt_MD5.methods.valid(crypto))
+		sys_exit(4);
+
+	MD5_std_set_salt(MD5_std_get_salt(crypto));
+
+	if (sys_read(0, &charset_length, 1) != 1)
+		sys_exit(5);
+	if (charset_length < 2)
+		sys_exit(6);
+	if (sys_read(0, (char *) &charset, charset_length) != charset_length)
+		sys_exit(7);
+	/* 0 is magic */
+	if (memchr(charset, 0, charset_length))
+		sys_exit(8);
+	for (c = 0; c < charset_length-1; c++)
+		charset_next[charset[c]] = charset[c+1];
+	char_start = charset[0];
+	charset_next[charset[charset_length-1]] = char_start;
+	charset_next[0] = char_start;
+
+	for (c = 1; c < charset_length; c++)
+		charset_prev[charset[c]] = charset[c-1];
+	char_end = charset[charset_length-1];
+	charset_prev[charset[0]] = char_end;
+
+	for (;;) {
+		if (sys_read(0, (char *) start, MAX_CLEARTEXT_LENGTH) !=
+		    MAX_CLEARTEXT_LENGTH)
+			sys_exit(10);
+		if (sys_read(0, (char *) end, MAX_CLEARTEXT_LENGTH) !=
+		    MAX_CLEARTEXT_LENGTH)
+			sys_exit(11);
+
+		if (check()) {
+			x = 1;
+			if (sys_write(1, &x, 1) != 1)
+				sys_exit(12);
+			if (sys_write(1, (char *) start, MAX_CLEARTEXT_LENGTH) !=
+			    MAX_CLEARTEXT_LENGTH)
+				sys_exit(13);
+			for(;;);
+		}
+
+		if (quit)
+			break;
+
+		x = 0;
+		if (sys_write(1, &x, 1) != 1)
+			sys_exit(14);
+	}
+	x = 2;
+	if (sys_write(1, &x, 1) != 1)
+		sys_exit(15);
+	for(;;);
+}
+
+void log_event(char * f, ...) {}
+void log_done(void) {}
+
+char * fmt_default_split(char * c, int i) { return NULL; }
+void fmt_default_clear_keys(void) {}

-- 
To unsubscribe, e-mail john-users-unsubscribe@...ts.openwall.com and reply
to the automated confirmation request that will be sent to you.

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.