/*
 * This file is part of John the Ripper password cracker,
 * Copyright (c) 2012 magnum / JimF
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 */

#ifndef _COMMON_CRYPTSHA256_H
#define _COMMON_CRYPTSHA256_H


/* ------ Contains (at least) prepare(), valid() and split() ------ */
/* Prefix for optional rounds specification.  */
#define ROUNDS_PREFIX           "rounds="
/* Default number of rounds if not explicitly specified.  */
#define ROUNDS_DEFAULT          5000
/* Minimum number of rounds.  */
#define ROUNDS_MIN              1	/* Drepper has it as 1000 */
/* Maximum number of rounds.  */
#define ROUNDS_MAX              999999999

#define FORMAT_NAME		"crypt(3) $5$"
#define BENCHMARK_COMMENT	" (rounds=5000)"
#define BENCHMARK_LENGTH	-1
#define CIPHERTEXT_LENGTH		43

#define BINARY_SIZE				32
#define BINARY_ALIGN			4
#define SALT_LENGTH				16
#define SALT_ALIGN				4

/* ------- Check if the ciphertext if a valid SHA-256 crypt ------- */
static int valid(char * ciphertext, struct fmt_main * self) {
	char *pos, *start;

	if (strncmp(ciphertext, "$5$", 3))
			return 0;

	ciphertext += 3;

	if (!strncmp(ciphertext, ROUNDS_PREFIX,
			sizeof(ROUNDS_PREFIX) - 1)) {
		const char *num = ciphertext + sizeof(ROUNDS_PREFIX) - 1;
		char *endp;
		if (!strtoul(num, &endp, 10))
					return 0;
		if (*endp == '$')
			ciphertext = endp + 1;
			}
	for (pos = ciphertext; *pos && *pos != '$'; pos++);
	if (!*pos || pos < ciphertext) return 0;

	start = ++pos;
	while (atoi64[ARCH_INDEX(*pos)] != 0x7F) pos++;
	if (*pos || pos - start != CIPHERTEXT_LENGTH) return 0;
	return 1;
}

/* ------- To binary functions ------- */
#define TO_BINARY(b1, b2, b3) \
	value = (ARCH_WORD_32)atoi64[ARCH_INDEX(pos[0])] | \
		((ARCH_WORD_32)atoi64[ARCH_INDEX(pos[1])] << 6) | \
		((ARCH_WORD_32)atoi64[ARCH_INDEX(pos[2])] << 12) | \
		((ARCH_WORD_32)atoi64[ARCH_INDEX(pos[3])] << 18); \
	pos += 4; \
	out[b1] = value >> 16; \
	out[b2] = value >> 8; \
	out[b3] = value;

static void * get_binary(char * ciphertext) {
	static ARCH_WORD_32 outbuf[BINARY_SIZE/4];
	ARCH_WORD_32 value;
	char *pos = strrchr(ciphertext, '$') + 1;
	unsigned char *out = (unsigned char*)outbuf;
	int i=0;

	do {
		TO_BINARY(i, (i+10)%30, (i+20)%30);
		i = (i+21)%30;
	} while (i != 0);
	value = (ARCH_WORD_32)atoi64[ARCH_INDEX(pos[0])] |
		((ARCH_WORD_32)atoi64[ARCH_INDEX(pos[1])] << 6) |
		((ARCH_WORD_32)atoi64[ARCH_INDEX(pos[2])] << 12);
	out[31] = value >> 8;
	out[30] = value;
	return (void *)out;
}

// here are the 'current' lengths supported by the 3 different cryptsha256
// implementations:
//    opencl:  #define PLAINTEXT_LENGTH        35
//    CPU:     #define PLAINTEXT_LENGTH        24
//    cuda:    #define PLAINTEXT_LENGTH        23 (should be 24, bug somewhere)

/* here is our 'unified' tests array. */
#ifdef __CRYPTSHA256_CREATE_PROPER_TESTS_ARRAY__
static struct fmt_tests tests[] = {
	{"$5$LKO/Ute40T3FNF95$U0prpBQd4PloSGU0pnpM4z9wKn4vZ1.jsrzQfPqxph9", "U*U*U*U*"},
	{"$5$LKO/Ute40T3FNF95$fdgfoJEBoMajNxCv3Ru9LyQ0xZgv0OBMQoq80LQ/Qd.", "U*U***U"},
	{"$5$LKO/Ute40T3FNF95$8Ry82xGnnPI/6HtFYnvPBTYgOL23sdMXn8C29aO.x/A", "U*U***U*"},
	{"$5$9mx1HkCz7G1xho50$O7V7YgleJKLUhcfk9pgzdh3RapEaWqMtEp9UUBAKIPA", "*U*U*U*U"},
	{"$5$kc7lRD1fpYg0g.IP.ThisShouldBeTruncated.$d7CMTcEqJyTXyeq8hTdu/jB/I6DGkoo62NXbHIR7S43", ""},
	{"$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5", "Hello world!"},
	{"$5$V8UMZ8/8.j$GGzeGHZy60318qdLiocMj7DddCnfr7jIcLMDIRy9Tr0", "password"},

	// For the CPU implementation, this 35 char PW 'should' work, in 1 & 2 buffer code, but it changes the
	// benchmark timings, so has been removed.  Uncomment, test your build, then re-comment it.
	//{"$5$mTfUlwguIR0Gp2ed$nX5lzmEGAZQ.1.CcncGnSq/lxSF7t1P.YkVlljQfOC2", "01234567890123456789012345678901234"},

	// For the OpenCL/CPU implementation, this 24 char PW 'should' work
	//{"$5$fnJDgbSMK0ZQbj2j$xuV9QTbDdySL1tZxYKCL2OZRvR9G4acRXe1md0UbPmA", "123456789012345678901234"},

	// For the all implementations, this 15 char PW 'should' work
	//{"$5$saltstring$VxW44bFDcvixlQoTE4E.k5c8v1w0fGMyZ4tn8nGcWn0", "abcdefghijklmno"},


#ifdef DEBUG
#if PLAINTEXT_LENGTH > 35
	{"$5$aewWTiO8RzEz5FBF$CZ3I.vdWF4omQXMQOv1g3XarjhH0wwR29Jwzt6/gvV/", "012345678901234567890123456789012345"},
#endif
#if PLAINTEXT_LENGTH >= 35
	{"$5$mTfUlwguIR0Gp2ed$nX5lzmEGAZQ.1.CcncGnSq/lxSF7t1P.YkVlljQfOC2", "01234567890123456789012345678901234"},
#endif
#if PLAINTEXT_LENGTH >= 24
	{"$5$fnJDgbSMK0ZQbj2j$xuV9QTbDdySL1tZxYKCL2OZRvR9G4acRXe1md0UbPmA", "123456789012345678901234"},
#endif

	// Here is a test case for rounds=50000. Works, but slows down self test a lot
	{"$5$rounds=50000$LKO/Ute40T3FNF95$S51z7fjx29wblQAQbkqY7G8ExS18kQva39ur8FG5VS0", "U*U*U*U*"},

	//Special test cases. (from GPU implementations)
	{"$5$UOUBPEMKQRHHRFML$zicoLpMLhBsNGtEplY/ehM0NtiAqxijiBCrolt7WBW0", "jjti"},

	// all formats should handle this 15 byte password.
	{"$5$XSLWLBSQUCNOWXOB$i7Ho5wUAIjsH2e2zA.WarqYLWir5nmZbUEcjK//Or7.", "hgnirgayjnhvi"},
	{"$5$VDCTRFOIDQXRQVHR$uolqT0wEwU.pvI9jq5xU457JQpiwTTKX3PB/9RS4/h4", "o"},
	{"$5$WTYWNCYHNPMXPG$UwZyrq0irhWs4OcLKcqSbFdktZaNAD2by1CiNNw7oID", "tcepf"},
	{"$5$DQUHKJNMVOEBGBG$91u2d/jMN5QuW3/kBEPG0xC2G8y1TuDU7SGAUYTX.y0", "wbfhoc"},
	{"$5$saltstring$0Az3qME7zTXm78kfHrR2OtT8WOu2gd8bcVn/9Y.3l/7", "john"},

	{"$5$saltstring$7cz4bTeQ7MnNssphNhFVrITtuJYY/1tdvLL2uzLvOk8", "a"},
	{"$5$saltstring$4Wjlxdm/Hbpo8ZQzKFazuvfUZPVVUQn6v1oPTX3nwX/", "ab"},
	{"$5$saltstring$tDHA0KPsYQ8V.LDB1/fgW7cvROod5ZajSrx1tZU2JG9", "abc"},
	{"$5$saltstring$LfhGTHVGfbAkxy/xKLgvSfXyeE7hZheoMRKhjfvNF6.", "abcd"},
	{"$5$saltstring$Qg0Xm9f2VY.ePLAwNXnOPU/s8btLptK/tEU/gFnn8BD", "abcde"},
	{"$5$saltstring$2Snf.yaHnLnLI3Qhsk2S119X4vKbwQyiTMOHp3Oy7F5", "abcdef"},
	{"$5$saltstring$4Y5UR.6zwplRx6y93NJVyNkxqdlyT64EV68F2mCrZ16", "abcdefg"},
	{"$5$saltstring$bEM3iuUR.CTgy8Wygh4zu.CAgmlwx3uxm3dGA34.Ij4", "abcdefgh"},
	{"$5$saltstring$1/OrKXZSFlaEE2DKMhKKE8qCld5X0Ez0vtz5TvO3U3D", "abcdefghi"},
	{"$5$saltstring$1IbZU70/Wo9m1b40ha6Ao8d.v6Ja0.bAFg5/QFVzoX/", "abcdefghij"},
	{"$5$saltstring$S4gCgloAzqAXE5sRz9DShPvaXrwt4vjDJ4fYgIMbLo1", "abcdefghijk"},
	{"$5$saltstring$AFNSzsWaoMDvt7lk2bx0rPapzCz2zGahXDdFeoXrNE9", "abcdefghijkl"},
	{"$5$saltstring$QfHc8JBd2DfyloVL0YLDa23Dc67N9mbdYqyRJQlFqZ5", "abcdefghijklm"},
	{"$5$saltstring$XKHiS.SSJ545PvJJr2t.HyUpmPZDAIT8fVvzr/HGhd0", "abcdefghijklmn"},
	// all formats should handle this 15 byte password.
	{"$5$saltstring$VxW44bFDcvixlQoTE4E.k5c8v1w0fGMyZ4tn8nGcWn0", "abcdefghijklmno"},

	{"$5$QSTVVEKDIDYRNK$4j8TST.29P07GHASD.BUHd0UTaFz7h.Mz//zcHokoZ5", "cgyihfkqk"},

	// These were found in a bug #1077 https://github.com/magnumripper/JohnTheRipper/issues/1077
	// and created by pass_gen to test all lengths of salts. NOTE, I could
	// not get pass_gen.pl to do a null salt. Not sure it could be made anyway
	{"$5$1$EjlWWGGbmWXm00wmWG2EutReY7G/TA9awDah5IvTSy2", "short_salt"},
	{"$5$12$lhPEqohC1/lflYSl2juFZgDasZIiVdryUeIP/.XKRDA", "short_salt"},
	{"$5$123$KOc9ndqmAVjarsk6RvQu2bEca5o7qly.lG2gNTAvzYA", "short_salt"},
	{"$5$1234$LqOTc55Fc4K0O6h53GqAVINUCmtYuAW/8zNDoXE9zjA", "short_salt"},
	{"$5$12345$9fAbLJJamYElIPFc5Pb9S6XfteLYOEHjdBMwdy1oWp.", "short_salt"},
	{"$5$123456$qKfIMUCUvbINEaqXwe6LAvog3Ofj6YKXPpTXGWc5VPB", "short_salt"},
	{"$5$1234567$367DyB16D3vHEhYfZAPQPqynsKNgkClsdQiB/I3EfQ6", "short_salt"},
	{"$5$12345678$5Xt3LE6ogpAZvCXdQ/vPCwpzNYpABPINvsLiM5iJ9Z4", "short_salt"},
	{"$5$123456789$csTeZZS4O/WMMHBn9mgI9mrQC8xuffJvd/jdrvYRHV5", "short_salt"},
	{"$5$1234567890$ZS3MJOM5Rin821TVyDKq0QNTRnU6di94XhLwJc.BTj5", "short_salt"},
	{"$5$12345678901$QdspXWcGfNr9E/Y85tslyPjFt5yQzZLsnUTlFH5AXq4", "short_salt"},
	{"$5$123456789012$g4ldCaiyPo9fwJLJZV/oA1qux/hHElXYdgo//9UOqB6", "short_salt"},
	{"$5$1234567890123$rejKhy.g7TXlffFRqEgPxI1gTDbqt/LDuvfRPinDHs3", "short_salt"},
	{"$5$12345678901234$aKCh3GXmEudusN/fbNpSprqtwetjEGrEzNJdkAm9HF/", "short_salt"},
	{"$5$123456789012345$F0HVo5HW7oxYD6cYALYrLXPq.oILAyWpdjn9pdGw6M/", "short_salt"},

	// from a comment in the OpenCL implementation:
	//{"$5$EKt.VLXiPjwyv.xe$52wdOp9ixFXMsHDI1JcCw8KJ83IakDP6J7MIEV2OUk0", "1234567"},
#endif
	// from a comment in the CUDA implementaton:
	//{"$5$rounds=5000$abcdefghijklmnop$BAYQep7SsuSczAeXlks3F54SpxMUUludHi1C4JVOqpD","abcdefghijklmno"},
	{NULL}
};
#endif

#endif
