/* saltdecode.c  --  Decode a given password salt into a readable format
 *
 *  GPLv2 only - Copyright (C) 2009 - 2012
 *               David Sommerseth <dazo@users.sourceforge.net>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; version 2
 *  of the License.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

/**
 * @file   eurephia_saltdecode.c
 * @author David Sommerseth <dazo@users.sourceforge.net>
 * @date   2009-03-29
 *
 * @brief   Simple utility which decodes a eurephia SHA512 hash salt
 *
 */

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/param.h>

#include <eurephia_nullsafe.h>
#include <get_console_input.h>

#define ROUNDS_MIN 1000	         /**< Minimum hashing rounds to acknowledge */
#define ROUNDS_MAX 999999999     /**< Maximum hashing rounds to acknowledge */


/**
 * Generates a phase2 salt value from a password.
 *
 * @param pwd  Input hash
 *
 * @return Returns an int value containing the phase2 salt information
 */
static unsigned int get_salt_p2(const char *pwd) {
        int n = 0;
        long int saltinfo_p2 = 0, t = 0;

        for( n = 0; n < strlen_nullsafe(pwd); n++ ) {
                t += pwd[n];
        }

        for( n = 0; n < 4; n++ ) {
                saltinfo_p2 <<= 8;
                saltinfo_p2 += (strlen_nullsafe(pwd) ^ (t % 0xff));
        }
        return saltinfo_p2;
}


/**
 * This function will unpack the salt information and "unscramble" it with a given password
 *
 * @param insalt  Input eurephia SHA512 salt string
 * @param pwd     Users password
 *
 * @return Returns the decoded salt information, containing hashing rounds and salt length.
 */
unsigned int unpack_saltinfo(const char *insalt, const char *pwd) {
        unsigned int in_salt_prefix = 0;

        assert(insalt != NULL && pwd != NULL);

        if( sscanf(insalt, "%08x", &in_salt_prefix) > -1 ) {
                long int regen_p2 = in_salt_prefix ^ get_salt_p2(pwd);
                return regen_p2 ^ 0xAAAAAAAA;
        } else {
                return -1;
        }
}


/**
 * saltdecode main function
 *
 * @param argc argument counter
 * @param argv argument table
 *
 * @return Returns 0 on success, otherwise 1.
 */
int main(int argc, char **argv) {
        char key[258];
        unsigned int saltinfo = 0;
        size_t rounds = 0, salt_len = 0;

        if( argc != 2 ) {
                fprintf(stderr, "Usage: %s <password salt>\n", argv[0]);
                return 1;
        }

        memset(&key, 0, 258);
        printf("\nYou will need to give the correct password for this salt.\n");
        printf("If you give the wrong password, the decoded information will be wrong.\n\n");
        get_console_input(key, 256, "Password:", 1);
        saltinfo = unpack_saltinfo(argv[1], key);
        memset(&key, 0, 258);

        salt_len = saltinfo & 0x000000ff;
        rounds = MAX(ROUNDS_MIN, MIN(((saltinfo & 0xffffff00) >> 8), ROUNDS_MAX));

        printf("\nSalt length: %ld\nHash rounds: %ld\n\n",
	       (unsigned long int) salt_len,
	       (unsigned long int) rounds);

        return 0;
}
