  // has to be the FIRST include !
#include "./../H/common.h"

  // contains just #include of "rsaeuro.h"
#include "./../RSAEuro/H/rsaref.h"
#include "./../RSAEuro/H/rsa.h"

#include "./H/cipherer.h"
#include "../H/labels.h"

/**
 * Generate symetric key.
 *
 * Generates one symetric key, in parameters we can insert what type
 * of key to generate. DES key is generated by default (because of
 * RSAEuro toolkit).
 *
 * @param   parameters What type of key to generate.
 * @return  GMessage Symetric key, NULL if generation failed:
 * <pre>
 *   GM_SYMETRIC_KEY			- ie. 8 random bytes of DES key
 *   GM_INITIALIZATION_VECTOR		- ie. 8 random bytes of DES iv
 *   GM_SYMETRIC_CIPHER_TYPE		- ie. "DES" by default
 * </pre>
 * @author  Pechy
 * @see     other crypthographic methods
 */
GMessage *Cipherer::GenerateSymetricKey(GMessage *parameters = NULL)
{
    // to shut up a warning message
  parameters = NULL;

  GMessage *symKey = new GMessage();
    // unsigned !!!
  unsigned char key[SYM_KEY_LEN], vector[SYM_KEY_LEN];

  for (int i = 0; i < SYM_KEY_LEN; ++i) {
    key[i] = GenerateRandomByte();
      // vector is not interesting for us for *NOW*
    vector[i] = GenerateRandomByte();
  }

  symKey->SetAsBytes(GM_SYMETRIC_KEY, (void *) key, SYM_KEY_LEN);
  symKey->SetAsBytes(GM_INITIALIZATION_VECTOR, (void *) vector, SYM_KEY_LEN);
  symKey->SetAsString(GM_SYMETRIC_CIPHER_TYPE, "");
    // EA_DES_CBC and int type from RSAEuro
  //symKey->SetAsBytes(GM_SYMETRIC_CIPHER_TYPE, EA_DES_CBC, sizeof(int));

  return symKey;
}

// Gets in parameters:
//   (now nothing, place for identification of requested key, now RSA only)
//
// Returns:
/**
 * Generate asymetric key pair.
 *
 * Generates one asymetric key pair, in parameters we can insert what type
 * of key to generate. RSA key is generated by default (because of
 * RSAEuro toolkit). For now, only RSA is supported
 *
 * @param   parameters What type of algorithm.
 * @return  GMessage with generated asymetric key.
 * <pre>
 *   GM_PUBLIC_KEY_INFO
 *     GM_PUBLIC_KEY			- native structure from RSAEuro
 *     GM_ASYMETRIC_CIPHER_TYPE		- ie. "RSA"
 *     GM_ASYMETRIC_CIPHER_VERSION	- obsolete, still supported, not used
 *   GM_PRIVATE_KEY_INFO
 *     GM_PRIVATE_KEY			- native structure from RSAEuro
 *     GM_ASYMETRIC_CIPHER_TYPE		- ie. "RSA"
 *     GM_ASYMETRIC_CIPHER_VERSION	- obsolete, still supported, not used
 * <pre>
 * @author  Pechy
 * @see     other crypthographic methods
 */
GMessage *Cipherer::GenerateAsymetricKey(GMessage *parameters = NULL)
{
    // to shut up a warning message
  parameters = NULL;

  R_RSA_PUBLIC_KEY publicKey; /* new RSA public key */
  R_RSA_PRIVATE_KEY privateKey; /* new RSA private key */

    // use system clock to initialize...
  R_RANDOM_STRUCT randomStruct; /* random structure */
  R_RandomCreate(&randomStruct);

  R_RSA_PROTO_KEY protoKey; /* RSA prototype key */
    // currently 512
  protoKey.bits = RSA_DEFAULT_MODULUS_BIT_LEN;
  protoKey.useFermat4 = 0;

  if (R_GeneratePEMKeys(&publicKey, &privateKey, &protoKey, 
                        &randomStruct) != 0) {
    WriteString(llWarning, __FILE__ ":%d:RSA key generation failed.",
                __LINE__);
    return NULL;
  }
  else {
    WriteString(llDebug, __FILE__ ":%d:RSA key generation OK, "
                "sizeof(privKey)=%d, sizeof(pubKey)=%d.", __LINE__,
                sizeof(privateKey), sizeof(publicKey));

    GMessage *asymKeyGMsg = new GMessage();
    GMessage *publicKeyGMsg = new GMessage();
    GMessage *privateKeyGMsg = new GMessage();
    
      // the same type for both !!
    publicKeyGMsg->SetAsString(GM_ASYMETRIC_CIPHER_TYPE, "RSA");
    publicKeyGMsg->SetAsString(GM_ASYMETRIC_CIPHER_VERSION, "");
    privateKeyGMsg->SetAsString(GM_ASYMETRIC_CIPHER_TYPE, "RSA");
    privateKeyGMsg->SetAsString(GM_ASYMETRIC_CIPHER_VERSION, "");

    publicKeyGMsg->SetAsBytes(GM_PUBLIC_KEY, (void *) &publicKey,
                          sizeof(publicKey));
    privateKeyGMsg->SetAsBytes(GM_PRIVATE_KEY, (void *) &privateKey,
                          sizeof(privateKey));
    asymKeyGMsg->SetAsGMessage(GM_PUBLIC_KEY_INFO, publicKeyGMsg);
    asymKeyGMsg->SetAsGMessage(GM_PRIVATE_KEY_INFO, privateKeyGMsg);

    DELETE(privateKeyGMsg);
    DELETE(publicKeyGMsg);

    return asymKeyGMsg;
  }
}
