You are currently viewing a snapshot of www.mozilla.org taken on April 21, 2008. Most of this content is highly out of date (some pages haven't been updated since the project began in 1998) and exists for historical purposes only. If there are any pages on this archive site that you think should be added back to www.mozilla.org, please file a bug.




/* Example code to illustrate generation of a secret symmetric key ring
 * that PERSISTS in the NSS database. The symmetric keys can then be used
 * without ever exposing them in the clear.
 *
 * To encrypt, you need the id of the key to use.
 * To decrypt, you need the ciphertext and the id of the key that was used
 * to encrypt
 *
 * Before running this example, create the NSS database
 *     certutil -N -d .
 * (enter "test" when prompted for password)
 */


#include "nss.h"
#include "pk11func.h"

/* the key id can be any sequence of bytes. this example happens to use an
 * integer */
void genkey(int id);

/* this callback is responsible for returning the password to the NSS
 * key database. for example purposes, this function hardcodes the password.
 * In a real app, this function should obtain the password using secure means
 * such as prompting an operator, or retrieving it over a secure communication
 * channel
 */
char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg);


int main(int argc, char **argv)
{
  SECStatus rv;

  /* Initialize NSS */
  PK11_SetPasswordFunc(passwdcb);

  /* The NSS db must be initialized read-write since we'll be creating
   * keys in it. Once keys are generated, it can be opened without read-write
   * subsequently (NSS_Init).
   */
  rv = NSS_InitReadWrite(".");
  if (rv != SECSuccess)
  {
    fprintf(stderr, "NSS initialization failed (err %d)\n",
            PR_GetError());
    exit(1);
  }

  /* generate a key with id 1. should succeed on first run on a fresh db,
   * should fail on successive runs because key with that id already exists */
  genkey(1);

  /* generate a key with id 2. should succeed on first run on a fresh db,
   * should fail on successive runs because key with that id already exists */
  genkey(2);

  /* generate a key with id 1 - this will fail because key with that id
   * already exists */
  genkey(1);
}


void genkey(int id)
{
  PK11SlotInfo*  slot = NULL;
  PK11SymKey*    key = NULL;
  SECItem        keyiditem;
  int            keyid[1];
  CK_MECHANISM_TYPE cipherMech;
 
  /* using CKM_AES_CBC_PAD mechanism for example */
  cipherMech = CKM_AES_CBC_PAD;
 
   slot = PK11_GetInternalKeySlot();
  /* slot = PK11_GetBestSlot(cipherMech, NULL); didn't work.
   * Error code: token is read-only. ??
   */
  if (slot == NULL)
  {
    fprintf(stderr, "Unable to find security device (err %d)\n",
            PR_GetError());
    return;
  }

  keyid[0] = id;
  keyiditem.type = 0;
  keyiditem.data = (void *)keyid;
  keyiditem.len = sizeof(keyid[0]);

  /* Note: keysize must be 0 for fixed key-length algorithms like DES.
   *       Since we're using AES in this example, we're specifying
   *       one of the valid keysizes (16, 24, 32)
   */
  key = PK11_TokenKeyGen(slot, cipherMech, 0, 32 /*keysize*/,
                         &keyiditem, PR_TRUE, 0);
  if (key == NULL)
  {
    fprintf(stderr, "PK11_TokenKeyGen failed (err %d)\n",
            PR_GetError());
    PK11_FreeSlot(slot);
    return;
  }

  fprintf(stderr, "key length of generated key is %d\n",
          PK11_GetKeyLength(key));
  fprintf(stderr, "mechanism of key is %d (asked for %d)\n",
          PK11_GetMechanism(key), cipherMech);

  PK11_FreeSymKey(key);


  key = PK11_FindFixedKey(slot, cipherMech, &keyiditem, 0);
  if (key == NULL)
  {
    fprintf(stderr, "PK11_FindFixedKey failed (err %d)\n",
            PR_GetError());
    PK11_FreeSlot(slot);
    return;
  }

  fprintf(stderr, "Found key!\n");
  fprintf(stderr, "key length of generated key is %d\n",
          PK11_GetKeyLength(key));
  fprintf(stderr, "mechanism of key is %d (asked for %d)\n",
          PK11_GetMechanism(key), cipherMech);

  PK11_FreeSymKey(key);

  PK11_FreeSlot(slot);
}

char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg)
{
  if (!retry)
    return PL_strdup("test");
  else
    return NULL;
}