/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

#include "exception.hpp"
#include "cssmerr.h"
#include "misc.hpp"

#include "ibmcylinkcsp.hpp"
#include "dhkeygen.hpp"
#include "toolkit.h"
#include "dhkey.hpp"
#include <iostream.h>

/**********************************************************
 *
 *	DHKeyGenEngine class
 *
 **********************************************************/
DHKeyGenEngine::DHKeyGenEngine(Random* randSource)
:KeyGenEngine(CSSM_ALGID_DH, randSource)
{
}

DHKeyGenEngine::~DHKeyGenEngine() {
}

void DHKeyGenEngine::init(CssmData &seed, void *params) {
}

AlgorithmParams* DHKeyGenEngine::generateParams(void *paramsIn) {
	CssmData	rVal = CssmData(SHA_LENGTH);
	CssmData	q = CssmData(SHA_LENGTH);
	ushort		length;
	DHParams	*result = NULL;
	int			rc;

	if ((paramsIn == NULL) || 
		(*(ushort*)paramsIn < DH_LENGTH_MIN) ||
		(*(ushort*)paramsIn % sizeof(ord))) 
	{
		throw InputException(CSSM_CSP_PARAM_INVALID_VALUE);
	}

	length = *(ushort*)paramsIn;
	CssmData	base = CssmData(length);
	CssmData	modulus = CssmData(length);

	randSource->generateRandom(rVal);
	rc = GenDSSParameters(length, modulus.getData(), q.getData(), base.getData(), rVal.getData(), NULL);
	if (rc != SUCCESS) {
		throw InternalException(CSSM_CSP_KEYGEN_FAILED);
	}
	//this->generateDHParameters(length, base.getData(), modulus.getData(), rVal.getData());

	result = new DHParams(base, modulus);

	return(result);
}

void DHKeyGenEngine::generateDHParameters(ushort length, uchar *base, uchar *modulus, uchar *rVal) {
    uchar DH_base[DH_LENGTH] =
	 { 0xc9, 0x07, 0x86, 0xbf, 0x92, 0x6c, 0x1e, 0x51,
       0xa5, 0xb6, 0xe6, 0xe1, 0x9d, 0x0b, 0xc6, 0x50,
       0xab, 0x49, 0x77, 0xe6, 0x3c, 0xc7, 0x32, 0x1c,
       0x3f, 0x24, 0xb3, 0x2d, 0xd6, 0x22, 0x40, 0x01,
	   0x32, 0x19, 0x34, 0x35, 0x15, 0xdf, 0xa5, 0x63,
       0x33, 0xe1, 0x35, 0xc1, 0x7e, 0x98, 0xf1, 0x92,
       0x0f, 0xc5, 0x6c, 0xf4, 0x3f, 0x73, 0x4e, 0xf6,
       0x9d, 0x9d, 0xf5, 0xd0, 0xd6, 0x06, 0x9a, 0x3c};

    uchar DH_modulus[DH_LENGTH] =
     { 0xff, 0xe2, 0x14, 0x9a, 0xfd, 0xcd, 0x25, 0x47,
       0x1c, 0xaf, 0x1a, 0x7c, 0xd4, 0xeb, 0xdd, 0xf8,
       0xc0, 0x88, 0x66, 0xbe, 0xf2, 0x61, 0xb6, 0xe5,
       0x1f, 0x2b, 0xf0, 0x5c, 0xb4, 0x94, 0x9d, 0xa9,
       0x30, 0x85, 0xe4, 0xe4, 0xed, 0x4d, 0x4d, 0xcb,
       0x2a, 0xe4, 0x7e, 0x5f, 0x6e, 0xef, 0x39, 0xf9,
       0xb5, 0xb6, 0xca, 0x25, 0x5f, 0xcf, 0x3b, 0x2f,
	   0x70, 0x8b, 0xa0, 0x64, 0x72, 0xa8, 0x49, 0xfb};

	if (length != DH_LENGTH)
		throw InputException(CSSM_CSP_KEY_BAD_LENGTH);

	memcpy(base, DH_base, length);
	memcpy(modulus, DH_modulus, length);
}

void DHKeyGenEngine::generateKeyMat(Key *key, AlgorithmParams *algParams) {
	DHParams	*dhParams = NULL;

	if (key == NULL)
		throw InputException(CSSM_CSP_INVALID_KEY_POINTER);
	
	if (key->getAlgId() != this->getAlgId())
		throw InputException(CSSM_CSP_KEY_ALGID_NOTMATCH);

	if (key->getKeyClass() != CSSM_KEYCLASS_PRIVATE_KEY)
		throw InputException(CSSM_CSP_INVALID_KEYCLASS);
	
	//think about how to support default parameters (in which case
	//this pointer can be NULL)
	if (algParams == NULL)
		throw InputException(CSSM_CSP_KEY_NO_PARAM);

	if (algParams->getAlgId() != CSSM_ALGID_DH)
		throw InputException(CSSM_CSP_KEY_ALGID_NOTMATCH);

	if (algParams->getLength() < DH_LENGTH_MIN)
		throw InputException(CSSM_CSP_KEY_LENGTH_UNSUPPORTED);

	DHPrivateKey *tmpKeyMat = (DHPrivateKey*)instantiateKeyMat(*key);
	generateKeyMat(tmpKeyMat, algParams);
	key->importKeyMat(tmpKeyMat);
	delete tmpKeyMat;
}

/***********************************************************************
 *
 * Uses algParams to generate the key material, and then imports these
 * parameters into the keyMat object.
 *
 ***********************************************************************/
void DHKeyGenEngine::generateKeyMat(KeyMaterial *keyMat, AlgorithmParams* algParams) {
	DHParams	*dhParams = NULL;
	int			rc;

	if (keyMat == NULL)
		throw InputException(CSSM_CSP_INVALID_KEY_POINTER);

	if (keyMat->getAlgId() != this->getAlgId())
		throw InputException(CSSM_CSP_KEY_ALGID_NOTMATCH);

	if (keyMat->getKeyClass() != CSSM_KEYCLASS_PRIVATE_KEY)
		throw InputException(CSSM_CSP_INVALID_KEYCLASS);

	//think about how to support default parameters (in which case
	//this pointer can be NULL)
	if (algParams == NULL)
		throw InputException(CSSM_CSP_KEY_NO_PARAM);

	if (algParams->getAlgId() != CSSM_ALGID_DH)
		throw InputException(CSSM_CSP_KEY_ALGID_NOTMATCH);

	dhParams = (DHParams*)algParams;
	CssmData x = CssmData(dhParams->getLength());
	x.setDestroy(CSSM_TRUE);
	CssmData y = CssmData(dhParams->getLength());
	y.setDestroy(CSSM_TRUE);
	CssmData rand = CssmData(SHA_LENGTH);

	CssmData &tmpBase = dhParams->getBase();
	CssmData &tmpModulus = dhParams->getModulus();

	randSource->generateRandom(rand);
	rc = -1;
	rc = GenDHKey(dhParams->getLength(), //public and param length
				   x.getLength(), //secret length
                   x.getData(), //secret
				   y.getData(), //public
				   tmpBase.getData(),
				   tmpModulus.getData(),
                   rand.getData());

	delete &tmpBase;
	delete &tmpModulus;

	if (rc != SUCCESS)
		throw CryptoLibException(CSSM_CSP_KEYEXCH_PHASE1_FAILED);

	((DHPublicKey*)keyMat)->importAlgParams(algParams);
	((DHPublicKey*)keyMat)->setY(y);
	((DHPrivateKey*)keyMat)->setX(x);
}
