/***************************************************************************
  *     Copyright (C) 2005 by hal9000 <hal9000@evilscientists.de>                                           *
  *    Copyright (C) 2005 by Maurice Massar <vpnc@unix-ag.uni-kl.de>                                           *
  *    Copyright (C) 2005 by Christoph Thielecke <crissi99@gmx.de>                                           *
  *                                                                                                             *
  *    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; either version 2 of the License, or       *
  *    (at your option) any later version.                                                    *
  *                                                                                                             *
  *    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.,                                                          *
  *    59 Temple Place - Suite 330, Boston, MA   02111-1307, USA.                   *
  ***************************************************************************/
#include "ciscopasswddecoder.h"

#include <qfile.h>
#include <qtextstream.h>
#include <kmessagebox.h>
#include <klocale.h>

CiscoPasswdDecoder::CiscoPasswdDecoder(QString& profileFile)
{
	profile = profileFile;
}

CiscoPasswdDecoder::~CiscoPasswdDecoder()
{}

/* read hex strings for "enc_GroupPwd" and "enc_UserPassword" from profile file */
void CiscoPasswdDecoder::readProfileData(QString& profile, QString& userData, QString& groupData)
{
	QFile PcfFile(profile);
	QTextStream stream ( &PcfFile );

	if ( PcfFile.open(IO_ReadOnly))
	{
		QString line = "";
		while ( !stream.atEnd() )
		{
			line = stream.readLine(); // line of text excluding '\n' and replace all white chars with one blank
			if ( !line.startsWith("#") )
			{
				if (line.startsWith("enc_GroupPwd") || line.startsWith("enc_GroupPwd") )
					groupData=line.section('=',1,1).stripWhiteSpace();
				if (line.startsWith("enc_UserPassword") || line.startsWith("enc_GroupPwd") )
					userData=line.section('=',1,1).stripWhiteSpace();
			}
		}
		PcfFile.close();
	}
	else
	{
		KMessageBox::error ( 0, i18n ( "Reading of \"%1\" has been failed!" ).arg ( PcfFile.name() ) );
	}
}

int CiscoPasswdDecoder::hex2bin_c(unsigned int c)
{
	if ((c >= '0')&&(c <= '9'))
		return c - '0';
	if ((c >= 'A')&&(c <= 'F'))
		return c - 'A' + 10;
	if ((c >= 'a')&&(c <= 'f'))
		return c - 'a' + 10;
	return -1;
}

int CiscoPasswdDecoder::hex2bin(QString str, QString& bin, int& len)
{
QString p;
	int i, l;

	for (i = 0; str[i] != '\0'; i++)
		if (hex2bin_c(QChar(str[i]).unicode()) == -1)
			return EINVAL;

	l = i;
	if ((l & 1) != 0)
		return EINVAL;
	l /= 2;

	for (i = 0; i < l; i++)
		p+= hex2bin_c(QChar(str[i*2]).unicode()) << 4 | hex2bin_c(QChar(str[i*2+1]).unicode());

	bin = p;
	if (len)
		len = l;

	return 0;
}

int CiscoPasswdDecoder::c_decrypt(QString ct, int len, char **resp, int reslenp)
{
	QString h1  = ct;
	const char *h4  = ct.ascii() + 20;
	const char *enc = ct.ascii() + 40;

	char ht[20], h2[20], h3[20], key[24];
	const char *iv = h1.ascii();
	char *res;
	gcry_cipher_hd_t ctx;
	int reslen;

	if (len < 48)
		return 0;
	len -= 40;

	memcpy(ht, h1.ascii(), 20);

	ht[19]++;
	gcry_md_hash_buffer(GCRY_MD_SHA1, h2, ht, 20);

	ht[19] += 2;
	gcry_md_hash_buffer(GCRY_MD_SHA1, h3, ht, 20);

	memcpy(key, h2, 20);
	memcpy(key+20, h3, 4);
	/* who cares about parity anyway? */

	gcry_md_hash_buffer(GCRY_MD_SHA1, ht, enc, len);

	if (memcmp(h4, ht, 20) != 0)
		return -1;

	res = (char *)malloc(len);
	if (res == NULL)
		return -1;

	gcry_cipher_open(&ctx, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
	gcry_cipher_setkey(ctx, key, 24);
	gcry_cipher_setiv(ctx, iv, 8);
	gcry_cipher_decrypt(ctx, (unsigned char *)res, len, (unsigned char *)enc, len);
	gcry_cipher_close(ctx);

	reslen = len - res[len-1];
	res[reslen] = '\0';

	if (resp)
		*resp = res;

		reslenp = reslen;
	return 0;
}

bool CiscoPasswdDecoder::decodePasswords(QString& userPasswd, QString& groupPasswd)
{
	QString encUserPasswd="";
	QString encGroupPasswd="";
	int i, len, ret = 0;
	char *pw, *pw2;
	QString bin,bin2;
	int len2=0;
	bool success=true;

	readProfileData(profile, encUserPasswd, encGroupPasswd);


	if (!encGroupPasswd.isEmpty())
	{
		ret = hex2bin( encGroupPasswd, bin, len);


		if (ret != 0)
		{
			perror("error: groupPasswd: decoding input");
			success=false;
		}
		ret = c_decrypt(bin, len, &pw, 0);

		if (ret != 0)
		{
			perror("error: groupPasswd: decrypting input");
			success=false;
		}
		else
		{
// 		printf("groupPasswd: %s\n", pw);
// 			std::cout << "groupPasswd: " << QString::fromLocal8Bit(pw) << std::endl;
			

		groupPasswd = QString::fromLocal8Bit(pw);
		//free(pw);
		}
	}
	if (!encUserPasswd.isEmpty() )
	{
		i=0;
		len2=0;
	 	ret = 0;
		ret = hex2bin( encUserPasswd, bin2, len2);

		if (ret != 0)
		{
			perror("error: userPasswd: decoding input");
			success=false;
		}
		ret = c_decrypt(bin2, len2, &pw2, 0);
		//free(bin2);
		if (ret != 0)
		{
			perror("error: userPasswd: decrypting input");
			success=false;
		}
		else
		{

// // 		printf("userPasswd: %s\n", pw2);
// 		std::cout << "userPasswd " << QString::fromLocal8Bit(pw2) << std::endl;
		userPasswd = QString::fromLocal8Bit(pw2);


		//free(pw);
		}
	}

	

	return success;

}
