Sample Code 3: Hashing, MAC

/*
 * Demonstration program for hashing and MACs
 */

#include <iostream.h>

#include "pk11pub.h"
#include "nss.h"

static void
printDigest(unsigned char *digest, unsigned int len)
{
  int i;

  cout << "length: " << len << endl;
  for(i = 0;i < len;i++) printf("%02x ", digest[i]);
  cout << endl;
}

/*
 * main
 */
int
main(int argc, const char *argv[])
{
  int status = 0;
  PK11SlotInfo *slot = 0;
  PK11SymKey *key = 0;
  PK11Context *context = 0;
  unsigned char data[80];
  unsigned char digest[20]; /*Is there a way to tell how large the output is?*/
  unsigned int len;
  SECStatus s;

  /* Initialize NSS
   * If your application code has already initialized NSS, you can skip it
   * here.
   * This code uses the simplest of the Init functions, which does not
   * require a NSS database to exist
   */
  NSS_NoDB_Init(".");

  /* Get a slot to use for the crypto operations */
  slot = PK11_GetInternalKeySlot();
  if (!slot)
  {
    cout << "GetInternalKeySlot failed" << endl;
    status = 1;
    goto done;
  }

  /*
   *  Part 1 - Simple hashing
   */
  cout << "Part 1 -- Simple hashing" << endl;

  /* Initialize data */
  memset(data, 0xbc, sizeof data);

  /* Create a context for hashing (digesting) */
  context = PK11_CreateDigestContext(SEC_OID_MD5);
  if (!context) { cout << "CreateDigestContext failed" << endl; goto done; }

  s = PK11_DigestBegin(context);
  if (s != SECSuccess) { cout << "DigestBegin failed" << endl; goto done; }

  s = PK11_DigestOp(context, data, sizeof data);
  if (s != SECSuccess) { cout << "DigestUpdate failed" << endl; goto done; }

  s = PK11_DigestFinal(context, digest, &len, sizeof digest);
  if (s != SECSuccess) { cout << "DigestFinal failed" << endl; goto done; }

  /* Print digest */
  printDigest(digest, len);

  PK11_DestroyContext(context, PR_TRUE);
  context = 0;

  /*
   *  Part 2 - Hashing with included secret key
   */
  cout << "Part 2 -- Hashing with included secret key" << endl;

  /* Initialize data */
  memset(data, 0xbc, sizeof data);

  /* Create a Key */
  key = PK11_KeyGen(slot, CKM_GENERIC_SECRET_KEY_GEN, 0, 128, 0);
  if (!key) { cout << "Create key failed" << endl; goto done; }

  cout << (void *)key << endl;

  /* Create parameters for crypto context */
  /* NOTE: params must be provided, but may be empty */
  SECItem noParams;
  noParams.type = siBuffer;
  noParams.data = 0;
  noParams.len = 0;

  /* Create context using the same slot as the key */
//  context = PK11_CreateDigestContext(SEC_OID_MD5);
  context = PK11_CreateContextBySymKey(CKM_MD5, CKA_DIGEST, key, &noParams);
  if (!context) { cout << "CreateDigestContext failed" << endl; goto done; }

  s = PK11_DigestBegin(context);
  if (s != SECSuccess) { cout << "DigestBegin failed" << endl; goto done; }

  s = PK11_DigestKey(context, key);
  if (s != SECSuccess) { cout << "DigestKey failed" << endl; goto done; }

  s = PK11_DigestOp(context, data, sizeof data);
  if (s != SECSuccess) { cout << "DigestUpdate failed" << endl; goto done; }

  s = PK11_DigestFinal(context, digest, &len, sizeof digest);
  if (s != SECSuccess) { cout << "DigestFinal failed" << endl; goto done; }

  /* Print digest */
  printDigest(digest, len);

  PK11_DestroyContext(context, PR_TRUE);
  context = 0;

  /*
   *  Part 3 - MAC (with secret key)
   */
  cout << "Part 3 -- MAC (with secret key)" << endl;

  /* Initialize data */
  memset(data, 0xbc, sizeof data);

  context = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, key, &noParams);
  if (!context) { cout << "CreateContextBySymKey failed" << endl; goto done; }

  s = PK11_DigestBegin(context);
  if (s != SECSuccess) { cout << "DigestBegin failed" << endl; goto done; }

  s = PK11_DigestOp(context, data, sizeof data);
  if (s != SECSuccess) { cout << "DigestOp failed" << endl; goto done; }

  s = PK11_DigestFinal(context, digest, &len, sizeof digest);
  if (s != SECSuccess) { cout << "DigestFinal failed" << endl; goto done; }

  /* Print digest */
  printDigest(digest, len);

  PK11_DestroyContext(context, PR_TRUE);
  context = 0;

done:
  if (context) PK11_DestroyContext(context, PR_TRUE);  /* freeit ?? */
  if (key) PK11_FreeSymKey(key);
  if (slot) PK11_FreeSlot(slot);

  return status;
}