tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

index.rst (40973B)


      1 .. _mozilla_projects_nss_encrypt_decrypt_mac_using_token:
      2 
      3 Encrypt and decrypt MAC using token
      4 ===================================
      5 
      6 .. _nss_sample_code_3_encryptiondecryption_and_mac_using_token_object.:
      7 
      8 `NSS sample code 3: encryption/decryption and MAC using token object. <#nss_sample_code_3_encryptiondecryption_and_mac_using_token_object.>`__
      9 ----------------------------------------------------------------------------------------------------------------------------------------------
     10 
     11 .. container::
     12 
     13   Generates encryption/mac keys and uses token for storing.
     14 
     15   .. code:: c
     16 
     17      /* This Source Code Form is subject to the terms of the Mozilla Public
     18       * License, v. 2.0. If a copy of the MPL was not distributed with this
     19       * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
     20 
     21      /* NSPR Headers */
     22      #include
     23      #include
     24      #include
     25      #include
     26      #include
     27      #include
     28      #include
     29 
     30      /* NSS headers */
     31      #include
     32      #include
     33 
     34      /* our samples utilities */
     35      #include "util.h"
     36 
     37      #define BUFFERSIZE            80
     38      #define DIGESTSIZE            16
     39      #define PTEXT_MAC_BUFFER_SIZE 96
     40      #define CIPHERSIZE            96
     41      #define BLOCKSIZE             32
     42 
     43      #define CIPHER_HEADER         "-----BEGIN CIPHER-----"
     44      #define CIPHER_TRAILER        "-----END CIPHER-----"
     45      #define ENCKEY_HEADER         "-----BEGIN AESKEY CKAID-----"
     46      #define ENCKEY_TRAILER        "-----END AESKEY CKAID-----"
     47      #define MACKEY_HEADER         "-----BEGIN MACKEY CKAID-----"
     48      #define MACKEY_TRAILER        "-----END MACKEY CKAID-----"
     49      #define IV_HEADER             "-----BEGIN IV-----"
     50      #define IV_TRAILER            "-----END IV-----"
     51      #define MAC_HEADER            "-----BEGIN MAC-----"
     52      #define MAC_TRAILER           "-----END MAC-----"
     53      #define PAD_HEADER            "-----BEGIN PAD-----"
     54      #define PAD_TRAILER           "-----END PAD-----"
     55 
     56      typedef enum {
     57          ENCRYPT,
     58          DECRYPT,
     59          UNKNOWN
     60      } CommandType;
     61 
     62      typedef enum {
     63         SYMKEY = 0,
     64         MACKEY = 1,
     65         IV     = 2,
     66         MAC    = 3,
     67         PAD    = 4
     68      } HeaderType;
     69 
     70 
     71      /*
     72       * Print usage message and exit
     73       */
     74      static void
     75      Usage(const char *progName)
     76      {
     77          fprintf(stderr, "\nUsage:  %s -c  -d  [-z ] "
     78                  "[-p  | -f ] -i  -o \n\n",
     79                  progName);
     80          fprintf(stderr, "%-20s  Specify 'a' for encrypt operation\n\n",
     81                   "-c ");
     82          fprintf(stderr, "%-20s  Specify 'b' for decrypt operation\n\n",
     83                   " ");
     84          fprintf(stderr, "%-20s  Specify db directory path\n\n",
     85                   "-d ");
     86          fprintf(stderr, "%-20s  Specify db password [optional]\n\n",
     87                   "-p ");
     88          fprintf(stderr, "%-20s  Specify db password file [optional]\n\n",
     89                   "-f ");
     90          fprintf(stderr, "%-20s  Specify noise file name [optional]\n\n",
     91                   "-z ");
     92          fprintf(stderr, "%-21s Specify an input file name\n\n",
     93                   "-i ");
     94          fprintf(stderr, "%-21s Specify an output file name\n\n",
     95                   "-o ");
     96          fprintf(stderr, "%-7s For encrypt, it takes  as an input file and produces\n",
     97                   "Note :");
     98          fprintf(stderr, "%-7s .enc and .header as intermediate output files.\n\n",
     99                   "");
    100          fprintf(stderr, "%-7s For decrypt, it takes .enc and .header\n",
    101                   "");
    102          fprintf(stderr, "%-7s as input files and produces  as a final output file.\n\n",
    103                   "");
    104          exit(-1);
    105      }
    106 
    107      /*
    108       * Gather a CKA_ID
    109       */
    110      SECStatus
    111      GatherCKA_ID(PK11SymKey* key, SECItem* buf)
    112      {
    113          SECStatus rv = PK11_ReadRawAttribute(PK11_TypeSymKey, key, CKA_ID, buf);
    114          if (rv != SECSuccess) {
    115              PR_fprintf(PR_STDERR, "PK11_ReadRawAttribute returned (%d)\n", rv);
    116              PR_fprintf(PR_STDERR, "Could not read SymKey CKA_ID attribute\n");
    117              return rv;
    118          }
    119          return rv;
    120      }
    121 
    122      /*
    123       * Generate a Symmetric Key
    124       */
    125      PK11SymKey *
    126      GenerateSYMKey(PK11SlotInfo  *slot, CK_MECHANISM_TYPE mechanism,
    127                     int keySize, SECItem *keyID, secuPWData *pwdata)
    128      {
    129          SECStatus      rv;
    130          PK11SymKey    *key;
    131 
    132          if (PK11_NeedLogin(slot)) {
    133              rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
    134              if (rv != SECSuccess) {
    135                  PR_fprintf(PR_STDERR, "Could not authenticate to token %s.\n",
    136                             PK11_GetTokenName(slot));
    137                  return NULL;
    138              }
    139          }
    140 
    141          /* Generate the symmetric key */
    142          key = PK11_TokenKeyGen(slot, mechanism,
    143                                 NULL, keySize, keyID, PR_TRUE, pwdata);
    144 
    145          if (!key) {
    146              PR_fprintf(PR_STDERR, "Symmetric Key Generation Failed \n");
    147          }
    148 
    149          return key;
    150      }
    151 
    152      /*
    153       * MacInit
    154       */
    155      SECStatus
    156      MacInit(PK11Context *ctx)
    157      {
    158          SECStatus rv = PK11_DigestBegin(ctx);
    159          if (rv != SECSuccess) {
    160              PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestBegin()\n");
    161          }
    162          return rv;
    163      }
    164 
    165      /*
    166       * MacUpdate
    167       */
    168      SECStatus
    169      MacUpdate(PK11Context *ctx,
    170                unsigned char *msg, unsigned int msgLen)
    171      {
    172          SECStatus rv = PK11_DigestOp(ctx, msg, msgLen);
    173          if (rv != SECSuccess) {
    174              PR_fprintf(PR_STDERR, "Compute MAC Failed : DigestOp()\n");
    175          }
    176          return rv;
    177      }
    178 
    179      /*
    180       * Finalize MACing
    181       */
    182      SECStatus
    183      MacFinal(PK11Context *ctx,
    184               unsigned char *mac, unsigned int *macLen, unsigned int maxLen)
    185      {
    186          SECStatus rv = PK11_DigestFinal(ctx, mac, macLen, maxLen);
    187          if (rv != SECSuccess) {
    188              PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestFinal()\n");
    189          }
    190          return SECSuccess;
    191      }
    192 
    193      /*
    194       * Compute Mac
    195       */
    196      SECStatus
    197      ComputeMac(PK11Context *ctxmac,
    198                 unsigned char *ptext, unsigned int ptextLen,
    199                 unsigned char *mac, unsigned int *macLen,
    200                 unsigned int maxLen)
    201      {
    202          SECStatus rv = MacInit(ctxmac);
    203          if (rv != SECSuccess) return rv;
    204          rv = MacUpdate(ctxmac, ptext, ptextLen);
    205          if (rv != SECSuccess) return rv;
    206          rv = MacFinal(ctxmac, mac, macLen, maxLen);
    207          return rv;
    208      }
    209 
    210      /*
    211       * WriteToHeaderFile
    212       */
    213      SECStatus
    214      WriteToHeaderFile(const char *buf, unsigned int len, HeaderType type,
    215                        PRFileDesc *outFile)
    216      {
    217          SECStatus      rv;
    218          char           header[40];
    219          char           trailer[40];
    220          char          *outString = NULL;
    221 
    222          switch (type) {
    223          case SYMKEY:
    224              strcpy(header, ENCKEY_HEADER);
    225              strcpy(trailer, ENCKEY_TRAILER);
    226              break;
    227          case MACKEY:
    228              strcpy(header, MACKEY_HEADER);
    229              strcpy(trailer, MACKEY_TRAILER);
    230              break;
    231          case IV:
    232              strcpy(header, IV_HEADER);
    233              strcpy(trailer, IV_TRAILER);
    234              break;
    235          case MAC:
    236              strcpy(header, MAC_HEADER);
    237              strcpy(trailer, MAC_TRAILER);
    238              break;
    239          case PAD:
    240              strcpy(header, PAD_HEADER);
    241              strcpy(trailer, PAD_TRAILER);
    242              break;
    243          }
    244 
    245          PR_fprintf(outFile, "%s\n", header);
    246          PrintAsHex(outFile, buf, len);
    247          PR_fprintf(outFile, "%s\n\n", trailer);
    248          return SECSuccess;
    249      }
    250 
    251      /*
    252       * Initialize for encryption or decryption - common code
    253       */
    254      PK11Context *
    255      CryptInit(PK11SymKey *key,
    256                unsigned char *iv, unsigned int ivLen,
    257                CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation)
    258      {
    259          SECItem ivItem = { siBuffer, iv, ivLen };
    260          PK11Context *ctx = NULL;
    261 
    262          SECItem *secParam = PK11_ParamFromIV(CKM_AES_CBC, &ivItem);
    263          if (secParam == NULL) {
    264              PR_fprintf(PR_STDERR, "Crypt Failed : secParam NULL\n");
    265              return NULL;
    266          }
    267          ctx = PK11_CreateContextBySymKey(CKM_AES_CBC, operation, key, secParam);
    268          if (ctx == NULL) {
    269              PR_fprintf(PR_STDERR, "Crypt Failed : can't create a context\n");
    270              goto cleanup;
    271 
    272          }
    273      cleanup:
    274          if (secParam) {
    275              SECITEM_FreeItem(secParam, PR_TRUE);
    276          }
    277          return ctx;
    278      }
    279 
    280      /*
    281       * Common encryption and decryption code
    282       */
    283      SECStatus
    284      Crypt(PK11Context *ctx,
    285            unsigned char *out, unsigned int *outLen, unsigned int maxOut,
    286            unsigned char *in, unsigned int inLen)
    287      {
    288          SECStatus rv;
    289 
    290          rv = PK11_CipherOp(ctx, out, outLen, maxOut, in, inLen);
    291          if (rv != SECSuccess) {
    292              PR_fprintf(PR_STDERR, "Crypt Failed : PK11_CipherOp returned %d\n", rv);
    293              goto cleanup;
    294          }
    295 
    296      cleanup:
    297          if (rv != SECSuccess) {
    298              return rv;
    299          }
    300          return SECSuccess;
    301      }
    302 
    303      /*
    304       * Decrypt
    305       */
    306      SECStatus
    307      Decrypt(PK11Context *ctx,
    308              unsigned char *out, unsigned int *outLen, unsigned int maxout,
    309              unsigned char *in, unsigned int inLen)
    310      {
    311          return Crypt(ctx, out, outLen, maxout, in, inLen);
    312      }
    313 
    314      /*
    315       * Encrypt
    316       */
    317      SECStatus
    318      Encrypt(PK11Context* ctx,
    319              unsigned char *out, unsigned int *outLen, unsigned int maxout,
    320              unsigned char *in, unsigned int inLen)
    321      {
    322          return Crypt(ctx, out, outLen, maxout, in, inLen);
    323      }
    324 
    325      /*
    326       * EncryptInit
    327       */
    328      PK11Context *
    329      EncryptInit(PK11SymKey *ek, unsigned char *iv, unsigned int ivLen,
    330                  CK_MECHANISM_TYPE type)
    331      {
    332          return CryptInit(ek, iv, ivLen, type, CKA_ENCRYPT);
    333      }
    334 
    335      /*
    336       * DecryptInit
    337       */
    338      PK11Context *
    339      DecryptInit(PK11SymKey *dk, unsigned char *iv, unsigned int ivLen,
    340                  CK_MECHANISM_TYPE type)
    341      {
    342          return CryptInit(dk, iv, ivLen, type, CKA_DECRYPT);
    343      }
    344 
    345      /*
    346       * Read cryptographic parameters from the header file
    347       */
    348      SECStatus
    349      ReadFromHeaderFile(const char *fileName, HeaderType type,
    350                         SECItem *item, PRBool isHexData)
    351      {
    352          SECStatus      rv;
    353          PRFileDesc*    file;
    354          SECItem        filedata;
    355          SECItem        outbuf;
    356          unsigned char *nonbody;
    357          unsigned char *body;
    358          char           header[40];
    359          char           trailer[40];
    360 
    361          outbuf.type = siBuffer;
    362          file = PR_Open(fileName, PR_RDONLY, 0);
    363          if (!file) {
    364              PR_fprintf(PR_STDERR, "Failed to open %s\n", fileName);
    365              return SECFailure;
    366          }
    367          switch (type) {
    368          case SYMKEY:
    369              strcpy(header, ENCKEY_HEADER);
    370              strcpy(trailer, ENCKEY_TRAILER);
    371              break;
    372          case MACKEY:
    373              strcpy(header, MACKEY_HEADER);
    374              strcpy(trailer, MACKEY_TRAILER);
    375              break;
    376          case IV:
    377              strcpy(header, IV_HEADER);
    378              strcpy(trailer, IV_TRAILER);
    379              break;
    380          case MAC:
    381              strcpy(header, MAC_HEADER);
    382              strcpy(trailer, MAC_TRAILER);
    383              break;
    384          case PAD:
    385              strcpy(header, PAD_HEADER);
    386              strcpy(trailer, PAD_TRAILER);
    387              break;
    388          }
    389 
    390          rv = FileToItem(&filedata, file);
    391          nonbody = (char *)filedata.data;
    392          if (!nonbody) {
    393              PR_fprintf(PR_STDERR, "unable to read data from input file\n");
    394              rv = SECFailure;
    395              goto cleanup;
    396          }
    397 
    398          /* check for headers and trailers and remove them */
    399          if ((body = strstr(nonbody, header)) != NULL) {
    400              char *trail = NULL;
    401              nonbody = body;
    402              body = PORT_Strchr(body, '\n');
    403              if (!body)
    404                  body = PORT_Strchr(nonbody, '\r'); /* maybe this is a MAC file */
    405              if (body)
    406                  trail = strstr(++body, trailer);
    407              if (trail != NULL) {
    408                  *trail = '\0';
    409              } else {
    410                  PR_fprintf(PR_STDERR,  "input has header but no trailer\n");
    411                  PORT_Free(filedata.data);
    412                  return SECFailure;
    413              }
    414          } else {
    415              body = nonbody;
    416          }
    417 
    418      cleanup:
    419          PR_Close(file);
    420          HexToBuf(body, item, isHexData);
    421          return SECSuccess;
    422      }
    423 
    424      /*
    425       * EncryptAndMac
    426       */
    427      SECStatus
    428      EncryptAndMac(PRFileDesc *inFile,
    429                    PRFileDesc *headerFile,
    430                    PRFileDesc *encFile,
    431                    PK11SymKey *ek,
    432                    PK11SymKey *mk,
    433                    unsigned char *iv, unsigned int ivLen,
    434                    PRBool ascii)
    435      {
    436          SECStatus      rv;
    437          unsigned char  ptext[BLOCKSIZE];
    438          unsigned int   ptextLen;
    439          unsigned char  mac[DIGESTSIZE];
    440          unsigned int   macLen;
    441          unsigned int   nwritten;
    442          unsigned char  encbuf[BLOCKSIZE];
    443          unsigned int   encbufLen;
    444          SECItem        noParams = { siBuffer, NULL, 0 };
    445          PK11Context   *ctxmac = NULL;
    446          PK11Context   *ctxenc = NULL;
    447          unsigned int   pad[1];
    448          SECItem        padItem;
    449          unsigned int   paddingLength;
    450 
    451          static unsigned int firstTime = 1;
    452          int j;
    453 
    454          ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams);
    455          if (ctxmac == NULL) {
    456              PR_fprintf(PR_STDERR, "Can't create MAC context\n");
    457              rv = SECFailure;
    458              goto cleanup;
    459          }
    460          rv = MacInit(ctxmac);
    461          if (rv != SECSuccess) {
    462              goto cleanup;
    463          }
    464 
    465          ctxenc = EncryptInit(ek, iv, ivLen, CKM_AES_CBC);
    466 
    467          /* read a buffer of plaintext from input file */
    468          while ((ptextLen = PR_Read(inFile, ptext, sizeof(ptext))) > 0) {
    469 
    470              /* Encrypt using it using CBC, using previously created IV */
    471              if (ptextLen != BLOCKSIZE) {
    472                  paddingLength = BLOCKSIZE - ptextLen;
    473                  for ( j=0; j < paddingLength; j++) {
    474                      ptext[ptextLen+j] = (unsigned char)paddingLength;
    475                  }
    476                  ptextLen = BLOCKSIZE;
    477              }
    478              rv  = Encrypt(ctxenc,
    479                      encbuf, &encbufLen, sizeof(encbuf),
    480                      ptext, ptextLen);
    481              if (rv != SECSuccess) {
    482                  PR_fprintf(PR_STDERR, "Encrypt Failure\n");
    483                  goto cleanup;
    484              }
    485 
    486              /* save the last block of ciphertext as the next IV */
    487              iv = encbuf;
    488              ivLen = encbufLen;
    489 
    490              /* write the cipher text to intermediate file */
    491              nwritten = PR_Write(encFile, encbuf, encbufLen);
    492              /*PR_Assert(nwritten == encbufLen);*/
    493 
    494              rv = MacUpdate(ctxmac, ptext, ptextLen);
    495          }
    496 
    497          rv = MacFinal(ctxmac, mac, &macLen, DIGESTSIZE);
    498          if (rv != SECSuccess) {
    499              PR_fprintf(PR_STDERR, "MacFinal Failure\n");
    500              goto cleanup;
    501          }
    502          if (macLen == 0) {
    503              PR_fprintf(PR_STDERR, "Bad MAC length\n");
    504              rv = SECFailure;
    505              goto cleanup;
    506          }
    507          WriteToHeaderFile(mac, macLen, MAC, headerFile);
    508          if (rv != SECSuccess) {
    509              PR_fprintf(PR_STDERR, "Write MAC Failure\n");
    510              goto cleanup;
    511          }
    512 
    513          pad[0] = paddingLength;
    514          padItem.type = siBuffer;
    515          padItem.data = (unsigned char *)pad;
    516          padItem.len  = sizeof(pad[0]);
    517 
    518          WriteToHeaderFile(padItem.data, padItem.len, PAD, headerFile);
    519          if (rv != SECSuccess) {
    520              PR_fprintf(PR_STDERR, "Write PAD Failure\n");
    521              goto cleanup;
    522          }
    523 
    524          rv = SECSuccess;
    525 
    526      cleanup:
    527          if (ctxmac != NULL) {
    528              PK11_DestroyContext(ctxmac, PR_TRUE);
    529          }
    530          if (ctxenc != NULL) {
    531              PK11_DestroyContext(ctxenc, PR_TRUE);
    532          }
    533 
    534          return rv;
    535      }
    536 
    537      /*
    538       * Find the Key for the given mechanism
    539       */
    540      PK11SymKey*
    541      FindKey(PK11SlotInfo *slot,
    542              CK_MECHANISM_TYPE mechanism,
    543              SECItem *keyBuf, secuPWData *pwdata)
    544      {
    545          SECStatus      rv;
    546          PK11SymKey    *key;
    547 
    548          if (PK11_NeedLogin(slot)) {
    549              rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
    550              if (rv != SECSuccess) {
    551                  PR_fprintf(PR_STDERR,
    552                             "Could not authenticate to token %s.\n",
    553                             PK11_GetTokenName(slot));
    554                  if (slot) {
    555                      PK11_FreeSlot(slot);
    556                  }
    557                  return NULL;
    558              }
    559          }
    560 
    561          key = PK11_FindFixedKey(slot, mechanism, keyBuf, 0);
    562          if (!key) {
    563              PR_fprintf(PR_STDERR,
    564                         "PK11_FindFixedKey failed (err %d)\n",
    565                         PR_GetError());
    566              PK11_FreeSlot(slot);
    567              return NULL;
    568          }
    569          return key;
    570      }
    571 
    572      /*
    573       * Decrypt and Verify MAC
    574       */
    575      SECStatus
    576      DecryptAndVerifyMac(const char* outFileName,
    577          char *encryptedFileName,
    578          SECItem *cItem, SECItem *macItem,
    579          PK11SymKey* ek, PK11SymKey* mk, SECItem *ivItem, SECItem *padItem)
    580      {
    581          SECStatus      rv;
    582          PRFileDesc*    inFile;
    583          PRFileDesc*    outFile;
    584 
    585          unsigned char  decbuf[64];
    586          unsigned int   decbufLen;
    587 
    588          unsigned char  ptext[BLOCKSIZE];
    589          unsigned int   ptextLen = 0;
    590          unsigned char  ctext[64];
    591          unsigned int   ctextLen;
    592          unsigned char  newmac[DIGESTSIZE];
    593          unsigned int   newmacLen                 = 0;
    594          unsigned int   newptextLen               = 0;
    595          unsigned int   count                     = 0;
    596          unsigned int   temp                      = 0;
    597          unsigned int   blockNumber               = 0;
    598          SECItem        noParams = { siBuffer, NULL, 0 };
    599          PK11Context   *ctxmac = NULL;
    600          PK11Context   *ctxenc = NULL;
    601 
    602          unsigned char iv[BLOCKSIZE];
    603          unsigned int ivLen = ivItem->len;
    604          unsigned int fileLength;
    605          unsigned int paddingLength;
    606          int j;
    607 
    608          memcpy(iv, ivItem->data, ivItem->len);
    609          paddingLength = (unsigned int)padItem->data[0];
    610 
    611          ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams);
    612          if (ctxmac == NULL) {
    613              PR_fprintf(PR_STDERR, "Can't create MAC context\n");
    614              rv = SECFailure;
    615              goto cleanup;
    616          }
    617 
    618          /*  Open the input file.  */
    619          inFile = PR_Open(encryptedFileName, PR_RDONLY , 0);
    620          if (!inFile) {
    621              PR_fprintf(PR_STDERR,
    622                         "Unable to open \"%s\" for writing.\n",
    623                         encryptedFileName);
    624              return SECFailure;
    625          }
    626          /*  Open the output file.  */
    627          outFile = PR_Open(outFileName,
    628                            PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR , 00660);
    629          if (!outFile) {
    630              PR_fprintf(PR_STDERR,
    631                         "Unable to open \"%s\" for writing.\n",
    632                         outFileName);
    633              return SECFailure;
    634          }
    635 
    636          rv = MacInit(ctxmac);
    637          if (rv != SECSuccess) goto cleanup;
    638 
    639          ctxenc = DecryptInit(ek, iv, ivLen, CKM_AES_CBC);
    640          fileLength = FileSize(encryptedFileName);
    641 
    642          while ((ctextLen = PR_Read(inFile, ctext, sizeof(ctext))) > 0) {
    643 
    644              count += ctextLen;
    645 
    646              /* decrypt cipher text buffer using CBC and IV */
    647 
    648              rv = Decrypt(ctxenc, decbuf, &decbufLen, sizeof(decbuf),
    649                           ctext, ctextLen);
    650 
    651              if (rv != SECSuccess) {
    652                  PR_fprintf(PR_STDERR, "Decrypt Failure\n");
    653                  goto cleanup;
    654              }
    655 
    656              if (decbufLen == 0) break;
    657 
    658              rv = MacUpdate(ctxmac, decbuf, decbufLen);
    659              if (rv != SECSuccess) { goto cleanup; }
    660              if (count == fileLength) {
    661                  decbufLen = decbufLen-paddingLength;
    662              }
    663 
    664              /* write the plain text to out file */
    665              temp = PR_Write(outFile, decbuf, decbufLen);
    666              if (temp != decbufLen) {
    667                  PR_fprintf(PR_STDERR, "write error\n");
    668                  rv = SECFailure;
    669                  break;
    670              }
    671 
    672              /* save last block of ciphertext */
    673              memcpy(iv, decbuf, decbufLen);
    674              ivLen = decbufLen;
    675              blockNumber++;
    676          }
    677 
    678          if (rv != SECSuccess) { goto cleanup; }
    679 
    680          rv = MacFinal(ctxmac, newmac, &newmacLen, sizeof(newmac));
    681          if (rv != SECSuccess) { goto cleanup; }
    682 
    683          if (PORT_Memcmp(macItem->data, newmac, newmacLen) == 0) {
    684              rv = SECSuccess;
    685          } else {
    686              PR_fprintf(PR_STDERR, "Check MAC : Failure\n");
    687              PR_fprintf(PR_STDERR, "Extracted : ");
    688              PrintAsHex(PR_STDERR, macItem->data, macItem->len);
    689              PR_fprintf(PR_STDERR, "Computed  : ");
    690              PrintAsHex(PR_STDERR, newmac, newmacLen);
    691              rv = SECFailure;
    692          }
    693      cleanup:
    694          if (ctxmac) {
    695              PK11_DestroyContext(ctxmac, PR_TRUE);
    696          }
    697          if (ctxenc) {
    698              PK11_DestroyContext(ctxenc, PR_TRUE);
    699          }
    700          if (outFile) {
    701              PR_Close(outFile);
    702          }
    703 
    704          return rv;
    705      }
    706 
    707      /*
    708       * Gets IV and CKAIDS From Header File
    709       */
    710      SECStatus
    711      GetIVandCKAIDSFromHeader(const char *cipherFileName,
    712                  SECItem *ivItem, SECItem *encKeyItem, SECItem *macKeyItem)
    713      {
    714          SECStatus      rv;
    715 
    716          /* open intermediate file, read in header, get IV and CKA_IDs of two keys
    717           * from it
    718           */
    719          rv = ReadFromHeaderFile(cipherFileName, IV, ivItem, PR_TRUE);
    720          if (rv != SECSuccess) {
    721              PR_fprintf(PR_STDERR, "Could not retrieve IV from cipher file\n");
    722              goto cleanup;
    723          }
    724 
    725          rv = ReadFromHeaderFile(cipherFileName, SYMKEY, encKeyItem, PR_TRUE);
    726          if (rv != SECSuccess) {
    727              PR_fprintf(PR_STDERR,
    728              "Could not retrieve AES CKA_ID from cipher file\n");
    729              goto cleanup;
    730          }
    731          rv = ReadFromHeaderFile(cipherFileName, MACKEY, macKeyItem, PR_TRUE);
    732          if (rv != SECSuccess) {
    733              PR_fprintf(PR_STDERR,
    734                         "Could not retrieve MAC CKA_ID from cipher file\n");
    735              goto cleanup;
    736          }
    737      cleanup:
    738          return rv;
    739      }
    740 
    741      /*
    742       * DecryptFile
    743       */
    744      SECStatus
    745      DecryptFile(PK11SlotInfo *slot,
    746                   const char   *dbdir,
    747                   const char   *outFileName,
    748                   const char   *headerFileName,
    749                   char         *encryptedFileName,
    750                   secuPWData   *pwdata,
    751                   PRBool       ascii)
    752      {
    753          /*
    754           * The DB is open read only and we have authenticated to it
    755           * open input file, read in header, get IV and CKA_IDs of two keys from it
    756           * find those keys in the DB token
    757           * Open output file
    758           * loop until EOF(input):
    759           *     read a buffer of ciphertext from input file,
    760           *     Save last block of ciphertext
    761           *     decrypt ciphertext buffer using CBC and IV,
    762           *     compute and check MAC, then remove MAC from plaintext
    763           *     replace IV with saved last block of ciphertext
    764           *     write the plain text to output file
    765           * close files
    766           * report success
    767           */
    768 
    769          SECStatus           rv;
    770          SECItem             ivItem;
    771          SECItem             encKeyItem;
    772          SECItem             macKeyItem;
    773          SECItem             cipherItem;
    774          SECItem             macItem;
    775          SECItem             padItem;
    776          PK11SymKey         *encKey              = NULL;
    777          PK11SymKey         *macKey              = NULL;
    778 
    779 
    780          /* open intermediate file, read in header, get IV and CKA_IDs of two keys
    781           * from it
    782           */
    783          rv = GetIVandCKAIDSFromHeader(headerFileName,
    784                     &ivItem, &encKeyItem, &macKeyItem);
    785          if (rv != SECSuccess) {
    786              goto cleanup;
    787          }
    788 
    789          /* find those keys in the DB token */
    790          encKey = FindKey(slot, CKM_AES_CBC, &encKeyItem, pwdata);
    791          if (encKey == NULL) {
    792              PR_fprintf(PR_STDERR, "Can't find the encryption key\n");
    793              rv = SECFailure;
    794              goto cleanup;
    795          }
    796          /* CKM_MD5_HMAC or CKM_EXTRACT_KEY_FROM_KEY */
    797          macKey = FindKey(slot, CKM_MD5_HMAC, &macKeyItem, pwdata);
    798          if (macKey == NULL) {
    799              rv = SECFailure;
    800              goto cleanup;
    801          }
    802 
    803          /* Read in the Mac into item from the intermediate file */
    804          rv = ReadFromHeaderFile(headerFileName, MAC, &macItem, PR_TRUE);
    805          if (rv != SECSuccess) {
    806              PR_fprintf(PR_STDERR,
    807                         "Could not retrieve MAC from cipher file\n");
    808              goto cleanup;
    809          }
    810          if (macItem.data == NULL) {
    811              PR_fprintf(PR_STDERR, "MAC has NULL data\n");
    812              rv = SECFailure;
    813              goto cleanup;
    814          }
    815          if (macItem.len == 0) {
    816              PR_fprintf(PR_STDERR, "MAC has data has 0 length\n");
    817              /*rv = SECFailure;
    818              goto cleanup;*/
    819          }
    820 
    821          rv = ReadFromHeaderFile(headerFileName, PAD, &padItem, PR_TRUE);
    822          if (rv != SECSuccess) {
    823              PR_fprintf(PR_STDERR,
    824                         "Could not retrieve PAD detail from header file\n");
    825              goto cleanup;
    826          }
    827 
    828          if (rv == SECSuccess) {
    829              /* Decrypt and Remove Mac */
    830              rv = DecryptAndVerifyMac(outFileName, encryptedFileName,
    831                      &cipherItem, &macItem, encKey, macKey, &ivItem, &padItem);
    832              if (rv != SECSuccess) {
    833                  PR_fprintf(PR_STDERR, "Failed while decrypting and removing MAC\n");
    834              }
    835          }
    836 
    837      cleanup:
    838          if (slot) {
    839              PK11_FreeSlot(slot);
    840          }
    841          if (encKey) {
    842              PK11_FreeSymKey(encKey);
    843          }
    844          if (macKey) {
    845              PK11_FreeSymKey(macKey);
    846          }
    847 
    848          return rv;
    849      }
    850 
    851      /*
    852       * EncryptFile
    853       */
    854      SECStatus
    855      EncryptFile(PK11SlotInfo *slot,
    856                   const char   *dbdir,
    857                   const char   *inFileName,
    858                   const char   *headerFileName,
    859                   const char   *encryptedFileName,
    860                   const char   *noiseFileName,
    861                   secuPWData   *pwdata,
    862                   PRBool       ascii)
    863      {
    864          /*
    865           * The DB is open for read/write and we have authenticated to it.
    866           * generate a symmetric AES key as a token object.
    867           * generate a second key to use for MACing, also a token object.
    868           * get their  CKA_IDs
    869           * generate a random value to use as IV for AES CBC
    870           * open an input file and an output file,
    871           * write a header to the output that identifies the two keys by
    872           *  their CKA_IDs, May include original file name and length.
    873           * loop until EOF(input)
    874           *    read a buffer of plaintext from input file,
    875           *    MAC it, append the MAC to the plaintext
    876           *    encrypt it using CBC, using previously created IV,
    877           *    store the last block of ciphertext as the new IV,
    878           *    write the cipher text to intermediate file
    879           *    close files
    880           *    report success
    881           */
    882          SECStatus           rv;
    883          PRFileDesc         *inFile;
    884          PRFileDesc         *headerFile;
    885          PRFileDesc         *encFile;
    886 
    887          unsigned char      *encKeyId = (unsigned char *) "Encrypt Key";
    888          unsigned char      *macKeyId = (unsigned char *) "MAC Key";
    889          SECItem encKeyID = { siAsciiString, encKeyId, PL_strlen(encKeyId) };
    890          SECItem macKeyID = { siAsciiString, macKeyId, PL_strlen(macKeyId) };
    891 
    892          SECItem             encCKAID;
    893          SECItem             macCKAID;
    894          unsigned char       iv[BLOCKSIZE];
    895          SECItem             ivItem;
    896          PK11SymKey         *encKey = NULL;
    897          PK11SymKey         *macKey = NULL;
    898          SECItem             temp;
    899          unsigned char       c;
    900 
    901          /* generate a symmetric AES key as a token object. */
    902          encKey = GenerateSYMKey(slot, CKM_AES_KEY_GEN, 128/8, &encKeyID, pwdata);
    903          if (encKey == NULL) {
    904              PR_fprintf(PR_STDERR, "GenerateSYMKey for AES returned NULL.\n");
    905              rv = SECFailure;
    906              goto cleanup;
    907          }
    908 
    909          /* generate a second key to use for MACing, also a token object. */
    910          macKey = GenerateSYMKey(slot, CKM_GENERIC_SECRET_KEY_GEN, 160/8,
    911                                  &macKeyID, pwdata);
    912          if (macKey == NULL) {
    913              PR_fprintf(PR_STDERR, "GenerateSYMKey for MACing returned NULL.\n");
    914              rv = SECFailure;
    915              goto cleanup;
    916          }
    917 
    918          /* get the encrypt key CKA_ID */
    919          rv = GatherCKA_ID(encKey, &encCKAID);
    920          if (rv != SECSuccess) {
    921              PR_fprintf(PR_STDERR, "Error while wrapping encrypt key\n");
    922              goto cleanup;
    923          }
    924 
    925          /* get the MAC key CKA_ID */
    926          rv = GatherCKA_ID(macKey, &macCKAID);
    927          if (rv != SECSuccess) {
    928              PR_fprintf(PR_STDERR, "Can't get the MAC key CKA_ID.\n");
    929              goto cleanup;
    930          }
    931 
    932          if (noiseFileName) {
    933              rv = SeedFromNoiseFile(noiseFileName);
    934              if (rv != SECSuccess) {
    935                  PORT_SetError(PR_END_OF_FILE_ERROR);
    936                  return SECFailure;
    937              }
    938              rv = PK11_GenerateRandom(iv, BLOCKSIZE);
    939              if (rv != SECSuccess) {
    940                  goto cleanup;
    941              }
    942 
    943          } else {
    944              /* generate a random value to use as IV for AES CBC */
    945              GenerateRandom(iv, BLOCKSIZE);
    946          }
    947 
    948          headerFile = PR_Open(headerFileName,
    949                               PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660);
    950          if (!headerFile) {
    951              PR_fprintf(PR_STDERR,
    952                         "Unable to open \"%s\" for writing.\n",
    953                         headerFileName);
    954              return SECFailure;
    955          }
    956          encFile = PR_Open(encryptedFileName,
    957                            PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660);
    958          if (!encFile) {
    959              PR_fprintf(PR_STDERR,
    960                         "Unable to open \"%s\" for writing.\n",
    961                         encryptedFileName);
    962              return SECFailure;
    963          }
    964          /* write to a header file the IV and the CKA_IDs
    965           * identifying the two keys
    966           */
    967          ivItem.type = siBuffer;
    968          ivItem.data = iv;
    969          ivItem.len = BLOCKSIZE;
    970 
    971          rv = WriteToHeaderFile(iv, BLOCKSIZE, IV, headerFile);
    972          if (rv != SECSuccess) {
    973              PR_fprintf(PR_STDERR, "Error writing IV to cipher file - %s\n",
    974                         headerFileName);
    975              goto cleanup;
    976          }
    977 
    978          rv = WriteToHeaderFile(encCKAID.data, encCKAID.len, SYMKEY, headerFile);
    979          if (rv != SECSuccess) {
    980              PR_fprintf(PR_STDERR, "Error writing AES CKA_ID to cipher file - %s\n",
    981              encryptedFileName);
    982              goto cleanup;
    983          }
    984          rv = WriteToHeaderFile(macCKAID.data, macCKAID.len, MACKEY, headerFile);
    985          if (rv != SECSuccess) {
    986              PR_fprintf(PR_STDERR, "Error writing MAC CKA_ID to cipher file - %s\n",
    987                         headerFileName);
    988              goto cleanup;
    989          }
    990 
    991          /*  Open the input file.  */
    992          inFile = PR_Open(inFileName, PR_RDONLY, 0);
    993          if (!inFile) {
    994              PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n",
    995                         inFileName);
    996              return SECFailure;
    997          }
    998 
    999          /* Macing and Encryption */
   1000          if (rv == SECSuccess) {
   1001              rv = EncryptAndMac(inFile, headerFile, encFile,
   1002                                 encKey, macKey, ivItem.data, ivItem.len, ascii);
   1003              if (rv != SECSuccess) {
   1004                  PR_fprintf(PR_STDERR, "Failed : Macing and Encryption\n");
   1005                  goto cleanup;
   1006              }
   1007          }
   1008 
   1009      cleanup:
   1010          if (inFile) {
   1011              PR_Close(inFile);
   1012          }
   1013          if (headerFile) {
   1014              PR_Close(headerFile);
   1015          }
   1016          if (encFile) {
   1017              PR_Close(encFile);
   1018          }
   1019          if (slot) {
   1020              PK11_FreeSlot(slot);
   1021          }
   1022          if (encKey) {
   1023              PK11_FreeSymKey(encKey);
   1024          }
   1025          if (macKey) {
   1026              PK11_FreeSymKey(macKey);
   1027          }
   1028 
   1029          return rv;
   1030      }
   1031 
   1032      /*
   1033       * This example illustrates basic encryption/decryption and MACing
   1034       * Generates the encryption/mac keys and uses token for storing.
   1035       * Encrypts the input file and appends MAC before storing in intermediate
   1036       * header file.
   1037       * Writes the CKA_IDs of the encryption keys into intermediate header file.
   1038       * Reads the intermediate headerfile for CKA_IDs and encrypted
   1039       * contents and decrypts into output file.
   1040       */
   1041      int
   1042      main(int argc, char **argv)
   1043      {
   1044          SECStatus           rv;
   1045          SECStatus           rvShutdown;
   1046          PK11SlotInfo        *slot = NULL;
   1047          PLOptState          *optstate;
   1048          PLOptStatus         status;
   1049          char                headerFileName[50];
   1050          char                encryptedFileName[50];
   1051          PRFileDesc         *inFile;
   1052          PRFileDesc         *outFile;
   1053          PRBool              ascii = PR_FALSE;
   1054          CommandType         cmd = UNKNOWN;
   1055          const char         *command             = NULL;
   1056          const char         *dbdir               = NULL;
   1057          const char         *inFileName          = NULL;
   1058          const char         *outFileName         = NULL;
   1059          const char         *noiseFileName       = NULL;
   1060          secuPWData          pwdata              = { PW_NONE, 0 };
   1061 
   1062          char * progName = strrchr(argv[0], '/');
   1063          progName = progName ? progName + 1 : argv[0];
   1064 
   1065          /* Parse command line arguments */
   1066          optstate = PL_CreateOptState(argc, argv, "c:d:i:o:f:p:z:a");
   1067          while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
   1068              switch (optstate->option) {
   1069              case 'a':
   1070                  ascii = PR_TRUE;
   1071                  break;
   1072              case 'c':
   1073                  command = strdup(optstate->value);
   1074                  break;
   1075              case 'd':
   1076                  dbdir = strdup(optstate->value);
   1077                  break;
   1078              case 'f':
   1079                  pwdata.source = PW_FROMFILE;
   1080                  pwdata.data = strdup(optstate->value);
   1081                  break;
   1082              case 'p':
   1083                  pwdata.source = PW_PLAINTEXT;
   1084                  pwdata.data = strdup(optstate->value);
   1085                  break;
   1086              case 'i':
   1087                  inFileName = strdup(optstate->value);
   1088                  break;
   1089              case 'o':
   1090                  outFileName = strdup(optstate->value);
   1091                  break;
   1092              case 'z':
   1093                  noiseFileName = strdup(optstate->value);
   1094                  break;
   1095              default:
   1096                  Usage(progName);
   1097                  break;
   1098              }
   1099          }
   1100          PL_DestroyOptState(optstate);
   1101 
   1102          if (!command || !dbdir || !inFileName || !outFileName)
   1103              Usage(progName);
   1104          if (PL_strlen(command)==0)
   1105              Usage(progName);
   1106 
   1107          cmd = command[0] == 'a' ? ENCRYPT : command[0] == 'b' ? DECRYPT : UNKNOWN;
   1108 
   1109          /*  Open the input file.  */
   1110          inFile = PR_Open(inFileName, PR_RDONLY, 0);
   1111          if (!inFile) {
   1112              PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n",
   1113                         inFileName);
   1114              return SECFailure;
   1115          }
   1116          PR_Close(inFile);
   1117 
   1118          /* For intermediate header file, choose filename as inputfile name
   1119             with extension ".header" */
   1120          strcpy(headerFileName, inFileName);
   1121          strcat(headerFileName, ".header");
   1122 
   1123          /* For intermediate encrypted file, choose filename as inputfile name
   1124             with extension ".enc" */
   1125          strcpy(encryptedFileName, inFileName);
   1126          strcat(encryptedFileName, ".enc");
   1127 
   1128          PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
   1129 
   1130          switch (cmd) {
   1131          case ENCRYPT:
   1132              /* If the intermediate header file already exists, delete it */
   1133              if (PR_Access(headerFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
   1134                  PR_Delete(headerFileName);
   1135              }
   1136              /* If the intermediate encrypted  already exists, delete it */
   1137              if (PR_Access(encryptedFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
   1138                  PR_Delete(encryptedFileName);
   1139              }
   1140 
   1141              /* Open DB for read/write and authenticate to it. */
   1142              rv = NSS_InitReadWrite(dbdir);
   1143              if (rv != SECSuccess) {
   1144                  PR_fprintf(PR_STDERR, "NSS_InitReadWrite Failed\n");
   1145                  goto cleanup;
   1146              }
   1147 
   1148              PK11_SetPasswordFunc(GetModulePassword);
   1149              slot = PK11_GetInternalKeySlot();
   1150              if (PK11_NeedLogin(slot)) {
   1151                  rv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
   1152                  if (rv != SECSuccess) {
   1153                      PR_fprintf(PR_STDERR, "Could not authenticate to token %s.\n",
   1154                                 PK11_GetTokenName(slot));
   1155                      goto cleanup;
   1156                  }
   1157              }
   1158              rv = EncryptFile(slot, dbdir,
   1159                                inFileName, headerFileName, encryptedFileName,
   1160                                noiseFileName, &pwdata, ascii);
   1161              if (rv != SECSuccess) {
   1162                  PR_fprintf(PR_STDERR, "EncryptFile : Failed\n");
   1163                  return SECFailure;
   1164              }
   1165              break;
   1166          case DECRYPT:
   1167              /* Open DB read only, authenticate to it */
   1168              PK11_SetPasswordFunc(GetModulePassword);
   1169 
   1170              rv = NSS_Init(dbdir);
   1171              if (rv != SECSuccess) {
   1172                  PR_fprintf(PR_STDERR, "NSS_Init Failed\n");
   1173                  return SECFailure;
   1174              }
   1175 
   1176              slot = PK11_GetInternalKeySlot();
   1177              if (PK11_NeedLogin(slot)) {
   1178                  rv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
   1179                  if (rv != SECSuccess) {
   1180                      PR_fprintf(PR_STDERR, "Could not authenticate to token %s.\n",
   1181                                 PK11_GetTokenName(slot));
   1182                      goto cleanup;
   1183                  }
   1184              }
   1185 
   1186              rv = DecryptFile(slot, dbdir,
   1187                               outFileName, headerFileName,
   1188                               encryptedFileName, &pwdata, ascii);
   1189              if (rv != SECSuccess) {
   1190                  PR_fprintf(PR_STDERR, "DecryptFile : Failed\n");
   1191                  return SECFailure;
   1192              }
   1193              break;
   1194          }
   1195 
   1196      cleanup:
   1197          rvShutdown = NSS_Shutdown();
   1198          if (rvShutdown != SECSuccess) {
   1199              PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown()\n");
   1200              rv = SECFailure;
   1201          }
   1202 
   1203          PR_Cleanup();
   1204 
   1205          return rv;
   1206      }