#include <crypto/crypto.h>
#include <crypto/dem.h>

NTL_CLIENT


void DEM1 :: PrettyPrint(ostream& tofile)
{
	tofile << "\n-------------";
	tofile << "\nDEM1";
	tofile << "\n-------------";
	tofile << "\n\nSC=";
	s.PrettyPrint(tofile);
	tofile << "\nMAC=";
	m.PrettyPrint(tofile);	
	tofile << "\n";
}


// Variable-names as in document with following change in name
// Here C is C1 and k1 is k-prime.
ostring DEM1 :: encrypt(const ostring& key, const ostring& label, const ostring& mssg)
{
	if (key.size() != keylen)
		throw General_error();

	ostring C, T, k, k1, c, MAC;

	k = key.substr(0, s.keylen);
	k1 = key.substr(s.keylen, m.keylen);

	c = s.encrypt(k, mssg);

	T = c + label + i2osp(to_ZZ(8*label.size()), 8);

	MAC = m.eval(k1, T);

	C = c + MAC;

	if (logfile != NULL)
	{
		*logfile << "\n-------------------------------";
		*logfile << "\nTrace for DEM1 encrypt ";
		*logfile << "\n-------------------------------";
		*logfile << "\n\nMessage in ASCII = \"";
		printostring(*logfile, mssg);
		*logfile << "\"\n\nMessage as octet string = ";
		prettyprint(*logfile, mssg);
		*logfile << "\n\nLabel in ASCII = \"";
		printostring(*logfile, label);
		*logfile << "\"\n\nLabel as octet string = ";
		prettyprint(*logfile, label);
		*logfile << "\n\nk = ";
		prettyprint(*logfile, k);
		*logfile << "\n\nk' = ";
		prettyprint(*logfile, k1);
		*logfile << "\n\nc = ";
		prettyprint(*logfile, c);
		*logfile << "\n\nT = ";
		prettyprint(*logfile, T);
		*logfile << "\n\nMAC = ";
		prettyprint(*logfile, MAC);
		*logfile << "\n\nC1 = ";
		prettyprint(*logfile, C);
		*logfile << "\n\n";
	}

	return C;
}


ostring DEM1 :: decrypt(const ostring& key, const ostring& label, const ostring& cipher)
{
	if (key.size() != keylen)
		throw General_error();

	ostring mssg, k, k1, MAC, mac1, T, c;

	k = key.substr(0, s.keylen);
	k1 = key.substr(s.keylen, m.keylen);

	if(cipher.size() < m.outlen)
		throw Decrypt_error();

	c = cipher.substr(0, cipher.size() - m.outlen);
	MAC = cipher.substr(cipher.size() - m.outlen, m.outlen);

	T = c + label + i2osp(to_ZZ(8*label.size()), 8);

	mac1 = m.eval(k1, T);

	if(MAC != mac1)
		throw Decrypt_error();

	mssg = s.decrypt(k, c);

	return mssg;
}

