Back to index

lightning-sunbird  0.9+nobinonly
rsaperf.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "seccomon.h"
00038 #include "cert.h"
00039 #include "secutil.h"
00040 #include "nspr.h"
00041 #include "nss.h"
00042 #include "blapi.h"
00043 #include "plgetopt.h"
00044 #include "lowkeyi.h"
00045 #include "pk11pub.h"
00046 
00047 
00048 #define DEFAULT_ITERS           10
00049 #define DEFAULT_DURATION        10
00050 #define DEFAULT_KEY_BITS        1024
00051 #define MIN_KEY_BITS            512
00052 #define MAX_KEY_BITS            65536
00053 #define BUFFER_BYTES            MAX_KEY_BITS / 8
00054 #define DEFAULT_THREADS         1
00055 #define DEFAULT_EXPONENT        0x10001
00056 
00057 extern NSSLOWKEYPrivateKey * getDefaultRSAPrivateKey(void);
00058 extern NSSLOWKEYPublicKey  * getDefaultRSAPublicKey(void);
00059 
00060 secuPWData pwData = { PW_NONE, NULL };
00061 
00062 typedef struct TimingContextStr TimingContext;
00063 
00064 struct TimingContextStr {
00065     PRTime start;
00066     PRTime end;
00067     PRTime interval;
00068 
00069     long  days;     
00070     int   hours;    
00071     int   minutes;  
00072     int   seconds;  
00073     int   millisecs;
00074 };
00075 
00076 TimingContext *CreateTimingContext(void) {
00077     return PORT_Alloc(sizeof(TimingContext));
00078 }
00079 
00080 void DestroyTimingContext(TimingContext *ctx) {
00081     PORT_Free(ctx);
00082 }
00083 
00084 void TimingBegin(TimingContext *ctx, PRTime begin) {
00085     ctx->start = begin;
00086 }
00087 
00088 static void timingUpdate(TimingContext *ctx) {
00089     PRInt64 tmp, remaining;
00090     PRInt64 L1000,L60,L24;
00091 
00092     LL_I2L(L1000,1000);
00093     LL_I2L(L60,60);
00094     LL_I2L(L24,24);
00095 
00096     LL_DIV(remaining, ctx->interval, L1000);
00097     LL_MOD(tmp, remaining, L1000);
00098     LL_L2I(ctx->millisecs, tmp);
00099     LL_DIV(remaining, remaining, L1000);
00100     LL_MOD(tmp, remaining, L60);
00101     LL_L2I(ctx->seconds, tmp);
00102     LL_DIV(remaining, remaining, L60);
00103     LL_MOD(tmp, remaining, L60);
00104     LL_L2I(ctx->minutes, tmp);
00105     LL_DIV(remaining, remaining, L60);
00106     LL_MOD(tmp, remaining, L24);
00107     LL_L2I(ctx->hours, tmp);
00108     LL_DIV(remaining, remaining, L24);
00109     LL_L2I(ctx->days, remaining);
00110 }
00111 
00112 void TimingEnd(TimingContext *ctx, PRTime end) {
00113     ctx->end = end;
00114     LL_SUB(ctx->interval, ctx->end, ctx->start);
00115     PORT_Assert(LL_GE_ZERO(ctx->interval));
00116     timingUpdate(ctx);
00117 }
00118 
00119 void TimingDivide(TimingContext *ctx, int divisor) {
00120     PRInt64 tmp;
00121 
00122     LL_I2L(tmp, divisor);
00123     LL_DIV(ctx->interval, ctx->interval, tmp);
00124 
00125     timingUpdate(ctx);
00126 }
00127 
00128 char *TimingGenerateString(TimingContext *ctx) {
00129     char *buf = NULL;
00130 
00131     if (ctx->days != 0) {
00132        buf = PR_sprintf_append(buf, "%d days", ctx->days);
00133     }
00134     if (ctx->hours != 0) {
00135        if (buf != NULL) buf = PR_sprintf_append(buf, ", ");
00136        buf = PR_sprintf_append(buf, "%d hours", ctx->hours);
00137     }
00138     if (ctx->minutes != 0) {
00139        if (buf != NULL) buf = PR_sprintf_append(buf, ", ");
00140        buf = PR_sprintf_append(buf, "%d minutes", ctx->minutes);
00141     }
00142     if (buf != NULL) buf = PR_sprintf_append(buf, ", and ");
00143     if (!buf && ctx->seconds == 0) {
00144        int interval;
00145        LL_L2I(interval, ctx->interval);
00146        if (ctx->millisecs < 100) 
00147            buf = PR_sprintf_append(buf, "%d microseconds", interval);
00148        else
00149            buf = PR_sprintf_append(buf, "%d milliseconds", ctx->millisecs);
00150     } else if (ctx->millisecs == 0) {
00151        buf = PR_sprintf_append(buf, "%d seconds", ctx->seconds);
00152     } else {
00153        buf = PR_sprintf_append(buf, "%d.%03d seconds",
00154                             ctx->seconds, ctx->millisecs);
00155     }
00156     return buf;
00157 }
00158 
00159 void
00160 Usage(char *progName)
00161 {
00162     fprintf(stderr, "Usage: %s [-s | -e] [-i iterations | -p period] "
00163             "[-t threads]\n[-n none [-k keylength] [ [-g] -x exponent] |\n"
00164             " -n token:nickname [-d certdir] [-w password] |\n"
00165             " -h token [-d certdir] [-w password] [-g] [-k keylength] "
00166             "[-x exponent] ]\n",
00167            progName);
00168     fprintf(stderr, "%-20s Cert database directory (default is ~/.netscape)\n",
00169            "-d certdir");
00170     fprintf(stderr, "%-20s How many operations to perform\n", "-i iterations");
00171     fprintf(stderr, "%-20s How many seconds to run\n", "-p period");
00172     fprintf(stderr, "%-20s Perform signing (private key) operations\n", "-s");
00173     fprintf(stderr, "%-20s Perform encryption (public key) operations\n","-e");
00174     fprintf(stderr, "%-20s Nickname of certificate or key, prefixed "
00175             "by optional token name\n", "-n nickname");
00176     fprintf(stderr, "%-20s PKCS#11 token to perform operation with.\n",
00177             "-h token");
00178     fprintf(stderr, "%-20s key size in bits, from %d to %d\n", "-k keylength",
00179             MIN_KEY_BITS, MAX_KEY_BITS);
00180     fprintf(stderr, "%-20s token password\n", "-w password");
00181     fprintf(stderr, "%-20s temporary key generation. Not for token keys.\n",
00182             "-g");
00183     fprintf(stderr, "%-20s set public exponent for keygen\n", "-x");
00184     fprintf(stderr, "%-20s Number of execution threads (default 1)\n",
00185             "-t threads");
00186     exit(-1);
00187 }
00188 
00189 static void
00190 dumpBytes( unsigned char * b, int l)
00191 {
00192     int i;
00193     if (l <= 0)
00194         return;
00195     for (i = 0; i < l; ++i) {
00196         if (i % 16 == 0)
00197             printf("\t");
00198         printf(" %02x", b[i]);
00199         if (i % 16 == 15)
00200             printf("\n");
00201     }
00202     if ((i % 16) != 0)
00203         printf("\n");
00204 }
00205 
00206 static void
00207 dumpItem( SECItem * item, const char * description)
00208 {
00209     if (item->len & 1 && item->data[0] == 0) {
00210        printf("%s: (%d bytes)\n", description, item->len - 1);
00211        dumpBytes(item->data + 1, item->len - 1);
00212     } else {
00213        printf("%s: (%d bytes)\n", description, item->len);
00214        dumpBytes(item->data, item->len);
00215     }
00216 }
00217 
00218 void
00219 printPrivKey(NSSLOWKEYPrivateKey * privKey)
00220 {
00221     RSAPrivateKey *rsa = &privKey->u.rsa;
00222 
00223     dumpItem( &rsa->modulus,              "n");
00224     dumpItem( &rsa->publicExponent,       "e");
00225     dumpItem( &rsa->privateExponent,      "d");
00226     dumpItem( &rsa->prime1,               "P");
00227     dumpItem( &rsa->prime2,               "Q");
00228     dumpItem( &rsa->exponent1,             "d % (P-1)");
00229     dumpItem( &rsa->exponent2,             "d % (Q-1)");
00230     dumpItem( &rsa->coefficient,   "(Q ** -1) % P");
00231     puts("");
00232 }
00233 
00234 typedef SECStatus (* RSAOp)(void *               key, 
00235                          unsigned char *      output,
00236                           unsigned char *      input);
00237 
00238 typedef struct {
00239     SECKEYPublicKey* pubKey;
00240     SECKEYPrivateKey* privKey;
00241 } PK11Keys;
00242 
00243 
00244 SECStatus PK11_PublicKeyOp (SECKEYPublicKey*     key,
00245                          unsigned char *      output,
00246                           unsigned char *      input)
00247 {
00248     return PK11_PubEncryptRaw(key, output, input, key->u.rsa.modulus.len,
00249                               NULL);
00250 }
00251 
00252 SECStatus PK11_PrivateKeyOp (PK11Keys*            keys,
00253                           unsigned char *      output,
00254                            unsigned char *      input)
00255 {
00256     unsigned outLen = 0;
00257     return PK11_PrivDecryptRaw(keys->privKey,
00258                                output, &outLen,
00259                                keys->pubKey->u.rsa.modulus.len, input,
00260                                keys->pubKey->u.rsa.modulus.len);
00261 }
00262 typedef struct ThreadRunDataStr ThreadRunData;
00263 
00264 struct ThreadRunDataStr {
00265     const PRBool        *doIters;
00266     const void          *rsaKey;
00267     const unsigned char *buf;
00268     RSAOp                fn;
00269     int                  seconds;
00270     long                 iters;
00271     long                 iterRes;
00272     PRErrorCode          errNum;
00273     SECStatus            status;
00274 };
00275 
00276 
00277 void ThreadExecFunction(void *data)
00278 {
00279     ThreadRunData *tdata = (ThreadRunData*)data;
00280     unsigned char buf2[BUFFER_BYTES];
00281 
00282     tdata->status = SECSuccess;
00283     if (*tdata->doIters) {
00284         long i = tdata->iters;
00285         tdata->iterRes = 0;
00286         while (i--) {
00287             SECStatus rv = tdata->fn((void*)tdata->rsaKey, buf2,
00288                                      (unsigned char*)tdata->buf);
00289             if (rv != SECSuccess) {
00290                 tdata->errNum = PORT_GetError();
00291                 tdata->status = rv;
00292                 break;
00293             }
00294             tdata->iterRes++;
00295         }
00296     } else {
00297         PRIntervalTime total = PR_SecondsToInterval(tdata->seconds);
00298         PRIntervalTime start = PR_IntervalNow();
00299         tdata->iterRes = 0;
00300         while (PR_IntervalNow() - start < total) {
00301             SECStatus rv = tdata->fn((void*)tdata->rsaKey, buf2,
00302                                      (unsigned char*)tdata->buf);
00303             if (rv != SECSuccess) {
00304                 tdata->errNum = PORT_GetError();
00305                 tdata->status = rv;
00306                 break;
00307             }
00308             tdata->iterRes++;
00309         }
00310     }
00311 }
00312 
00313 #define INT_ARG(arg,def) atol(arg)>0?atol(arg):def
00314 
00315 int
00316 main(int argc, char **argv)
00317 {
00318     TimingContext *    timeCtx       = NULL;
00319     SECKEYPublicKey *         pubHighKey    = NULL;
00320     SECKEYPrivateKey *    privHighKey   = NULL;
00321     NSSLOWKEYPrivateKey * privKey       = NULL;
00322     NSSLOWKEYPublicKey *  pubKey        = NULL;
00323     CERTCertificate *         cert          = NULL;
00324     char *             progName      = NULL;
00325     char *             secDir      = NULL;
00326     char *             nickname    = NULL;
00327     char *                slotname      = NULL;
00328     char *                password      = NULL;
00329     long                  keybits     = 0;
00330     RSAOp                 fn;
00331     void *                rsaKey        = NULL;
00332     PLOptState *          optstate;
00333     PLOptStatus           optstatus;
00334     long               iters       = DEFAULT_ITERS;
00335     int                       i;
00336     PRBool             doPriv      = PR_FALSE;
00337     PRBool             doPub       = PR_FALSE;
00338     int                rv;
00339     unsigned char      buf[BUFFER_BYTES];
00340     unsigned char      buf2[BUFFER_BYTES];
00341     int                   seconds       = DEFAULT_DURATION;
00342     PRBool                doIters       = PR_FALSE;
00343     PRBool                doTime        = PR_FALSE;
00344     PRBool                useTokenKey   = PR_FALSE; /* use PKCS#11 token
00345                                                        object key */
00346     PRBool                useSessionKey = PR_FALSE; /* use PKCS#11 session
00347                                                        object key */
00348     PRBool                useBLKey = PR_FALSE;      /* use freebl */
00349     PK11SlotInfo*         slot          = NULL;     /* slot for session
00350                                                        object key operations */
00351     PRBool                doKeyGen      = PR_FALSE;
00352     int                   publicExponent  = DEFAULT_EXPONENT;
00353     PK11Keys keys;
00354     int peCount = 0;
00355     CK_BYTE pubEx[4];
00356     SECItem pe;
00357     RSAPublicKey          pubKeyStr;
00358     int                   threadNum     = DEFAULT_THREADS;
00359     ThreadRunData      ** runDataArr = NULL;
00360     PRThread           ** threadsArr = NULL;
00361     int                   calcThreads = 0;
00362 
00363     progName = strrchr(argv[0], '/');
00364     if (!progName)
00365        progName = strrchr(argv[0], '\\');
00366     progName = progName ? progName+1 : argv[0];
00367 
00368     optstate = PL_CreateOptState(argc, argv, "d:i:sen:p:t:h:k:w:gx:");
00369     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
00370        switch (optstate->option) {
00371        case '?':
00372            Usage(progName);
00373            break;
00374        case 'd':
00375            secDir = PORT_Strdup(optstate->value);
00376            break;
00377        case 'i':
00378            iters = INT_ARG(optstate->value, DEFAULT_ITERS);
00379            doIters = PR_TRUE;
00380            break;
00381        case 's':
00382            doPriv = PR_TRUE;
00383            break;
00384        case 'e':
00385            doPub = PR_TRUE;
00386            break;
00387        case 'g':
00388            doKeyGen = PR_TRUE;
00389            break;
00390        case 'n':
00391            nickname = PORT_Strdup(optstate->value);
00392             /* for compatibility, nickname of "none" means go to freebl */
00393             if (nickname && strcmp(nickname, "none")) {
00394                useTokenKey = PR_TRUE;
00395             } else {
00396                 useBLKey = PR_TRUE;
00397             }
00398            break;
00399        case 'p':
00400            seconds = INT_ARG(optstate->value, DEFAULT_DURATION);
00401            doTime = PR_TRUE;
00402             break;
00403        case 'h':
00404            slotname = PORT_Strdup(optstate->value);
00405            useSessionKey = PR_TRUE;
00406            break;
00407        case 'k':
00408            keybits = INT_ARG(optstate->value, DEFAULT_KEY_BITS);
00409            break;
00410        case 'w':
00411            password = PORT_Strdup(optstate->value);
00412            pwData.data = password;
00413            pwData.source = PW_PLAINTEXT;
00414            break;
00415        case 'x':
00416            /*  -x public exponent (for RSA keygen)  */
00417            publicExponent = INT_ARG(optstate->value, DEFAULT_EXPONENT);
00418            break;
00419        case 't':
00420            threadNum = INT_ARG(optstate->value, DEFAULT_THREADS);
00421            break;
00422        }
00423     }
00424     if (optstatus == PL_OPT_BAD)
00425        Usage(progName);
00426 
00427     if ((doPriv && doPub) || (doIters && doTime) ||
00428         ((useTokenKey + useSessionKey + useBLKey) != PR_TRUE) ||
00429         (useTokenKey && keybits) || (useTokenKey && doKeyGen) ||
00430         (keybits && (keybits<MIN_KEY_BITS || keybits>MAX_KEY_BITS))) {
00431         Usage(progName);
00432     }
00433 
00434     if (!doPriv && !doPub) doPriv = PR_TRUE;
00435 
00436     if (doIters && doTime) Usage(progName);
00437 
00438     if (!doTime) {
00439         doIters = PR_TRUE;
00440     }
00441 
00442     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
00443 
00444     PK11_SetPasswordFunc(SECU_GetModulePassword);
00445     secDir = SECU_ConfigDirectory(secDir);
00446 
00447     if (useTokenKey || useSessionKey) {
00448        rv = NSS_Init(secDir);
00449        if (rv != SECSuccess) {
00450            fprintf(stderr, "NSS_Init failed.\n");
00451            exit(1);
00452        }
00453     } else {
00454        rv = NSS_NoDB_Init(NULL);
00455        if (rv != SECSuccess) {
00456            fprintf(stderr, "NSS_NoDB_Init failed.\n");
00457            exit(1);
00458        }
00459     }
00460 
00461     if (useTokenKey) {
00462         CK_OBJECT_HANDLE kh = CK_INVALID_HANDLE;
00463         CERTCertDBHandle* certdb = NULL;
00464        certdb = CERT_GetDefaultCertDB();
00465         
00466         cert = PK11_FindCertFromNickname(nickname, &pwData);
00467         if (cert == NULL) {
00468             fprintf(stderr,
00469                     "Can't find certificate by name \"%s\"\n", nickname);
00470             exit(1);
00471         }
00472         pubHighKey = CERT_ExtractPublicKey(cert);
00473         if (pubHighKey == NULL) {
00474             fprintf(stderr, "Can't extract public key from certificate");
00475             exit(1);
00476         }
00477 
00478         if (doPub) {
00479             /* do public key ops */
00480             fn = (RSAOp)PK11_PublicKeyOp;
00481             rsaKey = (void *) pubHighKey;
00482                 
00483             kh = PK11_ImportPublicKey(cert->slot, pubHighKey, PR_FALSE);
00484             if (CK_INVALID_HANDLE == kh) {
00485                 fprintf(stderr,
00486                         "Unable to import public key to certificate slot.");
00487                 exit(1);
00488             }
00489             pubHighKey->pkcs11Slot = PK11_ReferenceSlot(cert->slot);
00490             pubHighKey->pkcs11ID = kh;
00491             printf("Using PKCS#11 for RSA encryption with token %s.\n",
00492                    PK11_GetTokenName(cert->slot));
00493         } else {
00494             /* do private key ops */
00495             privHighKey = PK11_FindKeyByAnyCert(cert, &pwData);
00496             if (privHighKey == NULL) {
00497                 fprintf(stderr,
00498                         "Can't find private key by name \"%s\"\n", nickname);
00499                 exit(1);
00500             }
00501     
00502             SECKEY_CacheStaticFlags(privHighKey);
00503             fn = (RSAOp)PK11_PrivateKeyOp;
00504             keys.privKey = privHighKey;
00505             keys.pubKey = pubHighKey;
00506             rsaKey = (void *) &keys;
00507             printf("Using PKCS#11 for RSA decryption with token %s.\n",
00508                    PK11_GetTokenName(privHighKey->pkcs11Slot));
00509         }        
00510     } else
00511 
00512     if (useSessionKey) {
00513         /* use PKCS#11 session key objects */
00514         PK11RSAGenParams   rsaparams;
00515         void             * params;
00516 
00517         slot = PK11_FindSlotByName(slotname); /* locate target slot */
00518         if (!slot) {
00519             fprintf(stderr, "Can't find slot \"%s\"\n", slotname);
00520             exit(1);
00521         }
00522 
00523         doKeyGen = PR_TRUE; /* Always do a keygen for session keys.
00524                                Import of hardcoded key is not supported */
00525         /* do a temporary keygen in selected slot */        
00526         if (!keybits) {
00527             keybits = DEFAULT_KEY_BITS;
00528         }
00529 
00530         printf("Using PKCS#11 with %ld bits session key in token %s.\n",
00531                keybits, PK11_GetTokenName(slot));
00532 
00533         rsaparams.keySizeInBits = keybits;
00534         rsaparams.pe = publicExponent;
00535         params = &rsaparams;
00536 
00537         fprintf(stderr,"\nGenerating RSA key. This may take a few moments.\n");
00538 
00539         privHighKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
00540                                            params, &pubHighKey, PR_FALSE,
00541                                            PR_FALSE, (void*)&pwData);
00542         if (!privHighKey) {
00543             fprintf(stderr,
00544                     "Key generation failed in token \"%s\"\n",
00545                     PK11_GetTokenName(slot));
00546             exit(1);
00547         }
00548 
00549         SECKEY_CacheStaticFlags(privHighKey);
00550         
00551         fprintf(stderr,"Keygen completed.\n");
00552 
00553         if (doPub) {
00554             /* do public key operations */
00555             fn = (RSAOp)PK11_PublicKeyOp;
00556             rsaKey = (void *) pubHighKey;
00557         } else {
00558             /* do private key operations */
00559             fn = (RSAOp)PK11_PrivateKeyOp;
00560             keys.privKey = privHighKey;
00561             keys.pubKey = pubHighKey;
00562             rsaKey = (void *) &keys;
00563         }        
00564     } else
00565         
00566     {
00567         /* use freebl directly */
00568         if (!keybits) {
00569             keybits = DEFAULT_KEY_BITS;
00570         }
00571         if (!doKeyGen) {
00572             if (keybits != DEFAULT_KEY_BITS) {
00573                 doKeyGen = PR_TRUE;
00574             }
00575         }
00576         printf("Using freebl with %ld bits key.\n", keybits);
00577         if (doKeyGen) {
00578             fprintf(stderr,"\nGenerating RSA key. "
00579                     "This may take a few moments.\n");
00580             for (i=0; i < 4; i++) {
00581                 if (peCount || (publicExponent & ((unsigned long)0xff000000L >>
00582                                                   (i*8)))) {
00583                     pubEx[peCount] =  (CK_BYTE)((publicExponent >>
00584                                                  (3-i)*8) & 0xff);
00585                     peCount++;
00586                 }
00587             }
00588             pe.len = peCount;
00589             pe.data = &pubEx[0];
00590             pe.type = siBuffer;
00591 
00592             rsaKey = RSA_NewKey(keybits, &pe);
00593             fprintf(stderr,"Keygen completed.\n");
00594         } else {
00595             /* use a hardcoded key */
00596             printf("Using hardcoded %ld bits key.\n", keybits);
00597             if (doPub) {
00598                 pubKey = getDefaultRSAPublicKey();
00599             } else {
00600                 privKey = getDefaultRSAPrivateKey();
00601             }
00602         }
00603 
00604         if (doPub) {
00605             /* do public key operations */
00606             fn = (RSAOp)RSA_PublicKeyOp;
00607             if (rsaKey) {
00608                 /* convert the RSAPrivateKey to RSAPublicKey */
00609                 pubKeyStr.arena = NULL;
00610                 pubKeyStr.modulus = ((RSAPrivateKey*)rsaKey)->modulus;
00611                 pubKeyStr.publicExponent =
00612                     ((RSAPrivateKey*)rsaKey)->publicExponent;
00613                 rsaKey = &pubKeyStr;
00614             } else {
00615                 /* convert NSSLOWKeyPublicKey to RSAPublicKey */
00616                 rsaKey = (void *)(&pubKey->u.rsa);
00617             }
00618             PORT_Assert(rsaKey);
00619         } else {
00620             /* do private key operations */
00621             fn = (RSAOp)RSA_PrivateKeyOp;
00622             if (privKey) {
00623                 /* convert NSSLOWKeyPrivateKey to RSAPrivateKey */
00624                 rsaKey = (void *)(&privKey->u.rsa);
00625             }
00626             PORT_Assert(rsaKey);
00627         }
00628     }
00629 
00630     memset(buf, 1, sizeof buf);
00631     rv = fn(rsaKey, buf2, buf);
00632     if (rv != SECSuccess) {
00633        PRErrorCode errNum;
00634        const char * errStr = NULL;
00635 
00636        errNum = PORT_GetError();
00637        if (errNum)
00638            errStr = SECU_Strerror(errNum);
00639        else
00640            errNum = rv;
00641        if (!errStr)
00642            errStr = "(null)";
00643        fprintf(stderr, "Error in RSA operation: %d : %s\n", errNum, errStr);
00644        exit(1);
00645     }
00646 
00647     threadsArr = (PRThread**)PORT_Alloc(threadNum*sizeof(PRThread*));
00648     runDataArr = (ThreadRunData**)PORT_Alloc(threadNum*sizeof(ThreadRunData*));
00649     timeCtx = CreateTimingContext();
00650     TimingBegin(timeCtx, PR_Now());
00651     for (i = 0;i < threadNum;i++) {
00652         runDataArr[i] = (ThreadRunData*)PORT_Alloc(sizeof(ThreadRunData));
00653         runDataArr[i]->fn = fn;
00654         runDataArr[i]->buf = buf;
00655         runDataArr[i]->doIters = &doIters;
00656         runDataArr[i]->rsaKey = rsaKey;
00657         runDataArr[i]->seconds = seconds;
00658         runDataArr[i]->iters = iters;
00659         threadsArr[i] = 
00660             PR_CreateThread(PR_USER_THREAD,
00661                  ThreadExecFunction,
00662                  (void*) runDataArr[i],
00663                  PR_PRIORITY_NORMAL,
00664                  PR_GLOBAL_THREAD,
00665                  PR_JOINABLE_THREAD,
00666                  0);
00667     }
00668     iters = 0;
00669     calcThreads = 0;
00670     for (i = 0;i < threadNum;i++, calcThreads++)
00671     {
00672         PR_JoinThread(threadsArr[i]);
00673         if (runDataArr[i]->status != SECSuccess) {
00674             const char * errStr = SECU_Strerror(runDataArr[i]->errNum);
00675             fprintf(stderr, "Thread %d: Error in RSA operation: %d : %s\n",
00676                     i, runDataArr[i]->errNum, errStr);
00677             calcThreads -= 1;
00678         } else {
00679             iters += runDataArr[i]->iterRes;
00680         }
00681         PORT_Free((void*)runDataArr[i]);
00682     }
00683     PORT_Free(runDataArr);
00684     PORT_Free(threadsArr);
00685 
00686     TimingEnd(timeCtx, PR_Now());
00687     
00688     printf("%ld iterations in %s\n",
00689           iters, TimingGenerateString(timeCtx));
00690     printf("%.2f operations/s .\n", ((double)(iters)*(double)1000000.0) /
00691            (double)timeCtx->interval );
00692     TimingDivide(timeCtx, iters);
00693     printf("one operation every %s\n", TimingGenerateString(timeCtx));
00694 
00695     if (pubHighKey) {
00696         SECKEY_DestroyPublicKey(pubHighKey);
00697     }
00698 
00699     if (privHighKey) {
00700          SECKEY_DestroyPrivateKey(privHighKey);
00701     }
00702 
00703     if (cert) {
00704         CERT_DestroyCertificate(cert);
00705     }
00706 
00707     if (NSS_Shutdown() != SECSuccess) {
00708         exit(1);
00709     }
00710 
00711     return 0;
00712 }