1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1998-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
48 #define DEFAULT_ITERS 10
49 #define DEFAULT_DURATION 10
50 #define DEFAULT_KEY_BITS 1024
51 #define MIN_KEY_BITS 512
52 #define MAX_KEY_BITS 65536
53 #define BUFFER_BYTES MAX_KEY_BITS / 8
54 #define DEFAULT_THREADS 1
55 #define DEFAULT_EXPONENT 0x10001
57 extern NSSLOWKEYPrivateKey
* getDefaultRSAPrivateKey(void);
58 extern NSSLOWKEYPublicKey
* getDefaultRSAPublicKey(void);
60 secuPWData pwData
= { PW_NONE
, NULL
};
62 typedef struct TimingContextStr TimingContext
;
64 struct TimingContextStr
{
76 TimingContext
*CreateTimingContext(void) {
77 return PORT_Alloc(sizeof(TimingContext
));
80 void DestroyTimingContext(TimingContext
*ctx
) {
84 void TimingBegin(TimingContext
*ctx
, PRTime begin
) {
88 static void timingUpdate(TimingContext
*ctx
) {
89 PRInt64 tmp
, remaining
;
90 PRInt64 L1000
,L60
,L24
;
96 LL_DIV(remaining
, ctx
->interval
, L1000
);
97 LL_MOD(tmp
, remaining
, L1000
);
98 LL_L2I(ctx
->millisecs
, tmp
);
99 LL_DIV(remaining
, remaining
, L1000
);
100 LL_MOD(tmp
, remaining
, L60
);
101 LL_L2I(ctx
->seconds
, tmp
);
102 LL_DIV(remaining
, remaining
, L60
);
103 LL_MOD(tmp
, remaining
, L60
);
104 LL_L2I(ctx
->minutes
, tmp
);
105 LL_DIV(remaining
, remaining
, L60
);
106 LL_MOD(tmp
, remaining
, L24
);
107 LL_L2I(ctx
->hours
, tmp
);
108 LL_DIV(remaining
, remaining
, L24
);
109 LL_L2I(ctx
->days
, remaining
);
112 void TimingEnd(TimingContext
*ctx
, PRTime end
) {
114 LL_SUB(ctx
->interval
, ctx
->end
, ctx
->start
);
115 PORT_Assert(LL_GE_ZERO(ctx
->interval
));
119 void TimingDivide(TimingContext
*ctx
, int divisor
) {
122 LL_I2L(tmp
, divisor
);
123 LL_DIV(ctx
->interval
, ctx
->interval
, tmp
);
128 char *TimingGenerateString(TimingContext
*ctx
) {
131 if (ctx
->days
!= 0) {
132 buf
= PR_sprintf_append(buf
, "%d days", ctx
->days
);
134 if (ctx
->hours
!= 0) {
135 if (buf
!= NULL
) buf
= PR_sprintf_append(buf
, ", ");
136 buf
= PR_sprintf_append(buf
, "%d hours", ctx
->hours
);
138 if (ctx
->minutes
!= 0) {
139 if (buf
!= NULL
) buf
= PR_sprintf_append(buf
, ", ");
140 buf
= PR_sprintf_append(buf
, "%d minutes", ctx
->minutes
);
142 if (buf
!= NULL
) buf
= PR_sprintf_append(buf
, ", and ");
143 if (!buf
&& ctx
->seconds
== 0) {
145 LL_L2I(interval
, ctx
->interval
);
146 if (ctx
->millisecs
< 100)
147 buf
= PR_sprintf_append(buf
, "%d microseconds", interval
);
149 buf
= PR_sprintf_append(buf
, "%d milliseconds", ctx
->millisecs
);
150 } else if (ctx
->millisecs
== 0) {
151 buf
= PR_sprintf_append(buf
, "%d seconds", ctx
->seconds
);
153 buf
= PR_sprintf_append(buf
, "%d.%03d seconds",
154 ctx
->seconds
, ctx
->millisecs
);
160 Usage(char *progName
)
162 fprintf(stderr
, "Usage: %s [-s | -e] [-i iterations | -p period] "
163 "[-t threads]\n[-n none [-k keylength] [ [-g] -x exponent] |\n"
164 " -n token:nickname [-d certdir] [-w password] |\n"
165 " -h token [-d certdir] [-w password] [-g] [-k keylength] "
168 fprintf(stderr
, "%-20s Cert database directory (default is ~/.netscape)\n",
170 fprintf(stderr
, "%-20s How many operations to perform\n", "-i iterations");
171 fprintf(stderr
, "%-20s How many seconds to run\n", "-p period");
172 fprintf(stderr
, "%-20s Perform signing (private key) operations\n", "-s");
173 fprintf(stderr
, "%-20s Perform encryption (public key) operations\n","-e");
174 fprintf(stderr
, "%-20s Nickname of certificate or key, prefixed "
175 "by optional token name\n", "-n nickname");
176 fprintf(stderr
, "%-20s PKCS#11 token to perform operation with.\n",
178 fprintf(stderr
, "%-20s key size in bits, from %d to %d\n", "-k keylength",
179 MIN_KEY_BITS
, MAX_KEY_BITS
);
180 fprintf(stderr
, "%-20s token password\n", "-w password");
181 fprintf(stderr
, "%-20s temporary key generation. Not for token keys.\n",
183 fprintf(stderr
, "%-20s set public exponent for keygen\n", "-x");
184 fprintf(stderr
, "%-20s Number of execution threads (default 1)\n",
190 dumpBytes( unsigned char * b
, int l
)
195 for (i
= 0; i
< l
; ++i
) {
198 printf(" %02x", b
[i
]);
207 dumpItem( SECItem
* item
, const char * description
)
209 if (item
->len
& 1 && item
->data
[0] == 0) {
210 printf("%s: (%d bytes)\n", description
, item
->len
- 1);
211 dumpBytes(item
->data
+ 1, item
->len
- 1);
213 printf("%s: (%d bytes)\n", description
, item
->len
);
214 dumpBytes(item
->data
, item
->len
);
219 printPrivKey(NSSLOWKEYPrivateKey
* privKey
)
221 RSAPrivateKey
*rsa
= &privKey
->u
.rsa
;
223 dumpItem( &rsa
->modulus
, "n");
224 dumpItem( &rsa
->publicExponent
, "e");
225 dumpItem( &rsa
->privateExponent
, "d");
226 dumpItem( &rsa
->prime1
, "P");
227 dumpItem( &rsa
->prime2
, "Q");
228 dumpItem( &rsa
->exponent1
, "d % (P-1)");
229 dumpItem( &rsa
->exponent2
, "d % (Q-1)");
230 dumpItem( &rsa
->coefficient
, "(Q ** -1) % P");
234 typedef SECStatus (* RSAOp
)(void * key
,
235 unsigned char * output
,
236 unsigned char * input
);
239 SECKEYPublicKey
* pubKey
;
240 SECKEYPrivateKey
* privKey
;
244 SECStatus
PK11_PublicKeyOp (SECKEYPublicKey
* key
,
245 unsigned char * output
,
246 unsigned char * input
)
248 return PK11_PubEncryptRaw(key
, output
, input
, key
->u
.rsa
.modulus
.len
,
252 SECStatus
PK11_PrivateKeyOp (PK11Keys
* keys
,
253 unsigned char * output
,
254 unsigned char * input
)
257 return PK11_PrivDecryptRaw(keys
->privKey
,
259 keys
->pubKey
->u
.rsa
.modulus
.len
, input
,
260 keys
->pubKey
->u
.rsa
.modulus
.len
);
262 typedef struct ThreadRunDataStr ThreadRunData
;
264 struct ThreadRunDataStr
{
265 const PRBool
*doIters
;
267 const unsigned char *buf
;
277 void ThreadExecFunction(void *data
)
279 ThreadRunData
*tdata
= (ThreadRunData
*)data
;
280 unsigned char buf2
[BUFFER_BYTES
];
282 tdata
->status
= SECSuccess
;
283 if (*tdata
->doIters
) {
284 long i
= tdata
->iters
;
287 SECStatus rv
= tdata
->fn((void*)tdata
->rsaKey
, buf2
,
288 (unsigned char*)tdata
->buf
);
289 if (rv
!= SECSuccess
) {
290 tdata
->errNum
= PORT_GetError();
297 PRIntervalTime total
= PR_SecondsToInterval(tdata
->seconds
);
298 PRIntervalTime start
= PR_IntervalNow();
300 while (PR_IntervalNow() - start
< total
) {
301 SECStatus rv
= tdata
->fn((void*)tdata
->rsaKey
, buf2
,
302 (unsigned char*)tdata
->buf
);
303 if (rv
!= SECSuccess
) {
304 tdata
->errNum
= PORT_GetError();
313 #define INT_ARG(arg,def) atol(arg)>0?atol(arg):def
316 main(int argc
, char **argv
)
318 TimingContext
* timeCtx
= NULL
;
319 SECKEYPublicKey
* pubHighKey
= NULL
;
320 SECKEYPrivateKey
* privHighKey
= NULL
;
321 NSSLOWKEYPrivateKey
* privKey
= NULL
;
322 NSSLOWKEYPublicKey
* pubKey
= NULL
;
323 CERTCertificate
* cert
= NULL
;
324 char * progName
= NULL
;
325 char * secDir
= NULL
;
326 char * nickname
= NULL
;
327 char * slotname
= NULL
;
328 char * password
= NULL
;
331 void * rsaKey
= NULL
;
332 PLOptState
* optstate
;
333 PLOptStatus optstatus
;
334 long iters
= DEFAULT_ITERS
;
336 PRBool doPriv
= PR_FALSE
;
337 PRBool doPub
= PR_FALSE
;
339 unsigned char buf
[BUFFER_BYTES
];
340 unsigned char buf2
[BUFFER_BYTES
];
341 int seconds
= DEFAULT_DURATION
;
342 PRBool doIters
= PR_FALSE
;
343 PRBool doTime
= PR_FALSE
;
344 PRBool useTokenKey
= PR_FALSE
; /* use PKCS#11 token
346 PRBool useSessionKey
= PR_FALSE
; /* use PKCS#11 session
348 PRBool useBLKey
= PR_FALSE
; /* use freebl */
349 PK11SlotInfo
* slot
= NULL
; /* slot for session
350 object key operations */
351 PRBool doKeyGen
= PR_FALSE
;
352 int publicExponent
= DEFAULT_EXPONENT
;
357 RSAPublicKey pubKeyStr
;
358 int threadNum
= DEFAULT_THREADS
;
359 ThreadRunData
** runDataArr
= NULL
;
360 PRThread
** threadsArr
= NULL
;
363 progName
= strrchr(argv
[0], '/');
365 progName
= strrchr(argv
[0], '\\');
366 progName
= progName
? progName
+1 : argv
[0];
368 optstate
= PL_CreateOptState(argc
, argv
, "d:i:sen:p:t:h:k:w:gx:");
369 while ((optstatus
= PL_GetNextOpt(optstate
)) == PL_OPT_OK
) {
370 switch (optstate
->option
) {
375 secDir
= PORT_Strdup(optstate
->value
);
378 iters
= INT_ARG(optstate
->value
, DEFAULT_ITERS
);
391 nickname
= PORT_Strdup(optstate
->value
);
392 /* for compatibility, nickname of "none" means go to freebl */
393 if (nickname
&& strcmp(nickname
, "none")) {
394 useTokenKey
= PR_TRUE
;
400 seconds
= INT_ARG(optstate
->value
, DEFAULT_DURATION
);
404 slotname
= PORT_Strdup(optstate
->value
);
405 useSessionKey
= PR_TRUE
;
408 keybits
= INT_ARG(optstate
->value
, DEFAULT_KEY_BITS
);
411 password
= PORT_Strdup(optstate
->value
);
412 pwData
.data
= password
;
413 pwData
.source
= PW_PLAINTEXT
;
416 /* -x public exponent (for RSA keygen) */
417 publicExponent
= INT_ARG(optstate
->value
, DEFAULT_EXPONENT
);
420 threadNum
= INT_ARG(optstate
->value
, DEFAULT_THREADS
);
424 if (optstatus
== PL_OPT_BAD
)
427 if ((doPriv
&& doPub
) || (doIters
&& doTime
) ||
428 ((useTokenKey
+ useSessionKey
+ useBLKey
) != PR_TRUE
) ||
429 (useTokenKey
&& keybits
) || (useTokenKey
&& doKeyGen
) ||
430 (keybits
&& (keybits
<MIN_KEY_BITS
|| keybits
>MAX_KEY_BITS
))) {
434 if (!doPriv
&& !doPub
) doPriv
= PR_TRUE
;
436 if (doIters
&& doTime
) Usage(progName
);
442 PR_Init( PR_SYSTEM_THREAD
, PR_PRIORITY_NORMAL
, 1);
444 PK11_SetPasswordFunc(SECU_GetModulePassword
);
445 secDir
= SECU_ConfigDirectory(secDir
);
447 if (useTokenKey
|| useSessionKey
) {
448 rv
= NSS_Init(secDir
);
449 if (rv
!= SECSuccess
) {
450 fprintf(stderr
, "NSS_Init failed.\n");
454 rv
= NSS_NoDB_Init(NULL
);
455 if (rv
!= SECSuccess
) {
456 fprintf(stderr
, "NSS_NoDB_Init failed.\n");
462 CK_OBJECT_HANDLE kh
= CK_INVALID_HANDLE
;
463 CERTCertDBHandle
* certdb
= NULL
;
464 certdb
= CERT_GetDefaultCertDB();
466 cert
= PK11_FindCertFromNickname(nickname
, &pwData
);
469 "Can't find certificate by name \"%s\"\n", nickname
);
472 pubHighKey
= CERT_ExtractPublicKey(cert
);
473 if (pubHighKey
== NULL
) {
474 fprintf(stderr
, "Can't extract public key from certificate");
479 /* do public key ops */
480 fn
= (RSAOp
)PK11_PublicKeyOp
;
481 rsaKey
= (void *) pubHighKey
;
483 kh
= PK11_ImportPublicKey(cert
->slot
, pubHighKey
, PR_FALSE
);
484 if (CK_INVALID_HANDLE
== kh
) {
486 "Unable to import public key to certificate slot.");
489 pubHighKey
->pkcs11Slot
= PK11_ReferenceSlot(cert
->slot
);
490 pubHighKey
->pkcs11ID
= kh
;
491 printf("Using PKCS#11 for RSA encryption with token %s.\n",
492 PK11_GetTokenName(cert
->slot
));
494 /* do private key ops */
495 privHighKey
= PK11_FindKeyByAnyCert(cert
, &pwData
);
496 if (privHighKey
== NULL
) {
498 "Can't find private key by name \"%s\"\n", nickname
);
502 SECKEY_CacheStaticFlags(privHighKey
);
503 fn
= (RSAOp
)PK11_PrivateKeyOp
;
504 keys
.privKey
= privHighKey
;
505 keys
.pubKey
= pubHighKey
;
506 rsaKey
= (void *) &keys
;
507 printf("Using PKCS#11 for RSA decryption with token %s.\n",
508 PK11_GetTokenName(privHighKey
->pkcs11Slot
));
513 /* use PKCS#11 session key objects */
514 PK11RSAGenParams rsaparams
;
517 slot
= PK11_FindSlotByName(slotname
); /* locate target slot */
519 fprintf(stderr
, "Can't find slot \"%s\"\n", slotname
);
523 doKeyGen
= PR_TRUE
; /* Always do a keygen for session keys.
524 Import of hardcoded key is not supported */
525 /* do a temporary keygen in selected slot */
527 keybits
= DEFAULT_KEY_BITS
;
530 printf("Using PKCS#11 with %ld bits session key in token %s.\n",
531 keybits
, PK11_GetTokenName(slot
));
533 rsaparams
.keySizeInBits
= keybits
;
534 rsaparams
.pe
= publicExponent
;
537 fprintf(stderr
,"\nGenerating RSA key. This may take a few moments.\n");
539 privHighKey
= PK11_GenerateKeyPair(slot
, CKM_RSA_PKCS_KEY_PAIR_GEN
,
540 params
, &pubHighKey
, PR_FALSE
,
541 PR_FALSE
, (void*)&pwData
);
544 "Key generation failed in token \"%s\"\n",
545 PK11_GetTokenName(slot
));
549 SECKEY_CacheStaticFlags(privHighKey
);
551 fprintf(stderr
,"Keygen completed.\n");
554 /* do public key operations */
555 fn
= (RSAOp
)PK11_PublicKeyOp
;
556 rsaKey
= (void *) pubHighKey
;
558 /* do private key operations */
559 fn
= (RSAOp
)PK11_PrivateKeyOp
;
560 keys
.privKey
= privHighKey
;
561 keys
.pubKey
= pubHighKey
;
562 rsaKey
= (void *) &keys
;
567 /* use freebl directly */
569 keybits
= DEFAULT_KEY_BITS
;
572 if (keybits
!= DEFAULT_KEY_BITS
) {
576 printf("Using freebl with %ld bits key.\n", keybits
);
578 fprintf(stderr
,"\nGenerating RSA key. "
579 "This may take a few moments.\n");
580 for (i
=0; i
< 4; i
++) {
581 if (peCount
|| (publicExponent
& ((unsigned long)0xff000000L
>>
583 pubEx
[peCount
] = (CK_BYTE
)((publicExponent
>>
592 rsaKey
= RSA_NewKey(keybits
, &pe
);
593 fprintf(stderr
,"Keygen completed.\n");
595 /* use a hardcoded key */
596 printf("Using hardcoded %ld bits key.\n", keybits
);
598 pubKey
= getDefaultRSAPublicKey();
600 privKey
= getDefaultRSAPrivateKey();
605 /* do public key operations */
606 fn
= (RSAOp
)RSA_PublicKeyOp
;
608 /* convert the RSAPrivateKey to RSAPublicKey */
609 pubKeyStr
.arena
= NULL
;
610 pubKeyStr
.modulus
= ((RSAPrivateKey
*)rsaKey
)->modulus
;
611 pubKeyStr
.publicExponent
=
612 ((RSAPrivateKey
*)rsaKey
)->publicExponent
;
615 /* convert NSSLOWKeyPublicKey to RSAPublicKey */
616 rsaKey
= (void *)(&pubKey
->u
.rsa
);
620 /* do private key operations */
621 fn
= (RSAOp
)RSA_PrivateKeyOp
;
623 /* convert NSSLOWKeyPrivateKey to RSAPrivateKey */
624 rsaKey
= (void *)(&privKey
->u
.rsa
);
630 memset(buf
, 1, sizeof buf
);
631 rv
= fn(rsaKey
, buf2
, buf
);
632 if (rv
!= SECSuccess
) {
634 const char * errStr
= NULL
;
636 errNum
= PORT_GetError();
638 errStr
= SECU_Strerror(errNum
);
643 fprintf(stderr
, "Error in RSA operation: %d : %s\n", errNum
, errStr
);
647 threadsArr
= (PRThread
**)PORT_Alloc(threadNum
*sizeof(PRThread
*));
648 runDataArr
= (ThreadRunData
**)PORT_Alloc(threadNum
*sizeof(ThreadRunData
*));
649 timeCtx
= CreateTimingContext();
650 TimingBegin(timeCtx
, PR_Now());
651 for (i
= 0;i
< threadNum
;i
++) {
652 runDataArr
[i
] = (ThreadRunData
*)PORT_Alloc(sizeof(ThreadRunData
));
653 runDataArr
[i
]->fn
= fn
;
654 runDataArr
[i
]->buf
= buf
;
655 runDataArr
[i
]->doIters
= &doIters
;
656 runDataArr
[i
]->rsaKey
= rsaKey
;
657 runDataArr
[i
]->seconds
= seconds
;
658 runDataArr
[i
]->iters
= iters
;
660 PR_CreateThread(PR_USER_THREAD
,
662 (void*) runDataArr
[i
],
670 for (i
= 0;i
< threadNum
;i
++, calcThreads
++)
672 PR_JoinThread(threadsArr
[i
]);
673 if (runDataArr
[i
]->status
!= SECSuccess
) {
674 const char * errStr
= SECU_Strerror(runDataArr
[i
]->errNum
);
675 fprintf(stderr
, "Thread %d: Error in RSA operation: %d : %s\n",
676 i
, runDataArr
[i
]->errNum
, errStr
);
679 iters
+= runDataArr
[i
]->iterRes
;
681 PORT_Free((void*)runDataArr
[i
]);
683 PORT_Free(runDataArr
);
684 PORT_Free(threadsArr
);
686 TimingEnd(timeCtx
, PR_Now());
688 printf("%ld iterations in %s\n",
689 iters
, TimingGenerateString(timeCtx
));
690 printf("%.2f operations/s .\n", ((double)(iters
)*(double)1000000.0) /
691 (double)timeCtx
->interval
);
692 TimingDivide(timeCtx
, iters
);
693 printf("one operation every %s\n", TimingGenerateString(timeCtx
));
696 SECKEY_DestroyPublicKey(pubHighKey
);
700 SECKEY_DestroyPrivateKey(privHighKey
);
704 CERT_DestroyCertificate(cert
);
707 if (NSS_Shutdown() != SECSuccess
) {