#include <crypto/rsaes.h>

NTL_CLIENT


RSAES :: RSAES(REM& R, int len) : rem(R), logfile(0)
{
	if (len < 20)
		throw General_error();
		
        ZZ p = GenPrime_ZZ(len, 80);
        ZZ q = GenPrime_ZZ(len, 80);
        ZZ phi;

        while(p == q)
                q = GenPrime_ZZ(len, 80);

        e = (1L << 16) + 1;
        n = p*q;
        phi = (p-1)*(q-1);
        d = InvMod(e, phi);

	_MaxMsgLen = NumBytes(n) - rem.Bound;
	if (_MaxMsgLen < 0) 
		throw Init_error();
}

RSAES :: RSAES(REM& R, istream& ifile) : rem(R), logfile(0)
{
	ifile >> n >> e >> d;

	_MaxMsgLen = NumBytes(n) - rem.Bound;
	if (_MaxMsgLen < 0) 
		throw Init_error();
}

void RSAES :: PrettyPrint(ostream& tofile)
{
	tofile << "\n===============";
	tofile << "\nRSAES";
	tofile << "\n===============";
	tofile << "\nRem=";
	rem.PrettyPrint(tofile);
	tofile << "\n\n-----\n";
	tofile << "\nPublic Key";
	tofile << "\n\nn = " << n << "\n\ne = " << e;
	tofile << "\n\n-----\n";
	tofile << "\nPrivate Key";
	tofile << "\n\nn = " << n << "\n\nd = " << d;
	tofile << "\n";
}

void RSAES :: writetofile(ostream& ofile)
{
	ofile << n << "\n" << e << "\n" << d;
}

ostring RSAES :: rsatransform(const ostring& X, ZZ& a)
{
	long l = NumBytes(n);
	ZZ x, y;
	ostring Y;

	if(X.size() != l)
		throw Decrypt_error();

	x = os2ip(X);

	if(!(x < n))
		throw Decrypt_error();

	y = PowerMod(x,a,n);

	Y = i2osp(y,l);

	return Y;
}

ostring RSAES :: encrypt(const ostring& L, const ostring& M)
{
	ostring E, C;

	rem.logfile = logfile;

	if (*logfile != NULL)
	{
		*logfile << "\n===============================";
		*logfile << "\nTrace for RSAES encrypt";
		*logfile << "\n===============================";
	}

	E = rem.encode(M, L, NumBytes(n));

	C = rsatransform(E, e);

	if (*logfile != NULL)
	{
		*logfile << "\n\nE = ";
		prettyprint(*logfile, E);
		*logfile << "\n\nC = ";
		prettyprint(*logfile, C);
		*logfile << "\n";
	}

	return C;
}

ostring RSAES :: decrypt(const ostring& L, const ostring& C)
{
	ostring E, M;

	E = rsatransform(C, d);

	M = rem.decode(E, L);

	return M;
}

