Milán Major

netscape-revival

1 branch
Code

security/cmd/rsaperf.c

#include "crypto.h"
#include "cert.h"
#include "secrng.h"
#include "secutil.h"
#include "prglobal.h"
#include "prlong.h"
#include "prtime.h"

#define MAX_RSA_MODULUS_BYTES (1024/8)
#define DEFAULT_ITERS 10

typedef struct TimingContextStr TimingContext;

struct TimingContextStr {
    int64 start;
    int64 end;
    int64 interval;
    long days;     
    int hours;    
    int minutes;  
    int seconds;  
    int millisecs;
};

TimingContext *CreateTimingContext(void) {
    return XP_ALLOC(sizeof(TimingContext));
}

void DestroyTimingContext(TimingContext *ctx) {
    XP_FREE(ctx);
}

void TimingBegin(TimingContext *ctx) {
    ctx->start = PR_Now();
}

static void timingUpdate(TimingContext *ctx) {
    int64 tmp, remaining;
    int64 L1000,L60,L24;

    LL_I2L(L1000,1000);
    LL_I2L(L60,60);
    LL_I2L(L24,24);

    LL_DIV(remaining, ctx->interval, L1000);
    LL_MOD(tmp, remaining, L1000);
    LL_L2I(ctx->millisecs, tmp);
    LL_DIV(remaining, remaining, L1000);
    LL_MOD(tmp, remaining, L60);
    LL_L2I(ctx->seconds, tmp);
    LL_DIV(remaining, remaining, L60);
    LL_MOD(tmp, remaining, L60);
    LL_L2I(ctx->minutes, tmp);
    LL_DIV(remaining, remaining, L60);
    LL_MOD(tmp, remaining, L24);
    LL_L2I(ctx->hours, tmp);
    LL_DIV(remaining, remaining, L24);
    LL_L2I(ctx->days, remaining);
}

void TimingEnd(TimingContext *ctx) {
    ctx->end = PR_Now();
    LL_SUB(ctx->interval, ctx->end, ctx->start);
    XP_ASSERT(LL_GE_ZERO(ctx->interval));
    timingUpdate(ctx);
}

void TimingDivide(TimingContext *ctx, int divisor) {
    int64 tmp;

    LL_I2L(tmp, divisor);
    LL_DIV(ctx->interval, ctx->interval, tmp);

    timingUpdate(ctx);
}

char *TimingGenerateString(TimingContext *ctx) {
    char *buf = NULL;

    if (ctx->days != 0) {
	buf = PR_sprintf_append(buf, "%d days", ctx->days);
    }
    if (ctx->hours != 0) {
	if (buf != NULL) buf = PR_sprintf_append(buf, ", ");
	buf = PR_sprintf_append(buf, "%d hours", ctx->hours);
    }
    if (ctx->minutes != 0) {
	if (buf != NULL) buf = PR_sprintf_append(buf, ", ");
	buf = PR_sprintf_append(buf, "%d minutes", ctx->minutes);
    }
    if (buf != NULL) buf = PR_sprintf_append(buf, ", and ");
    if (ctx->millisecs == 0) {
	buf = PR_sprintf_append(buf, "%d seconds", ctx->seconds);
    } else {
	buf = PR_sprintf_append(buf, "%d.%03d seconds",
				ctx->seconds, ctx->millisecs);
    }
    return buf;
}

void
Usage(char *progName)
{
    fprintf(stderr, "Usage: %s [-d certdir] [-i itterations] [-s | -e]"
	            " -n nickname\n",
	    progName);
    fprintf(stderr, "%-20s Cert database directory (default is ~/.netscape)\n",
	    "-d certdir");
    fprintf(stderr, "%-20s How many operations to perform\n", "-i itterations");
    fprintf(stderr, "%-20s Perform signing (private key) operations\n", "-s");
    fprintf(stderr, "%-20s Perform encryption (public key) operations\n", "-e");
    fprintf(stderr, "%-20s Nickname of certificate or key\n", "-n nickname");
    exit(-1);
}

SECStatus
DoRSAPublicOps(SECKEYLowPublicKey *key, unsigned char *data, int iters)
{
    int modulusLen;
    unsigned char input[MAX_RSA_MODULUS_BYTES];
    unsigned char output[MAX_RSA_MODULUS_BYTES];
    SECStatus rv;
    
    modulusLen = SECKEY_LowPublicModulusLen(key);

    XP_MEMCPY(input, data, modulusLen);

    while(iters--) {
	rv = RSA_PublicKeyOp(key, output, input, modulusLen);
	if (rv != SECSuccess) return rv;
	XP_MEMCPY(&output, &input, modulusLen);
    }
    return rv;
}

SECStatus
DoRSAPrivateOps(SECKEYLowPrivateKey *key, unsigned char *data, int iters)
{
    int modulusLen;
    unsigned char input[MAX_RSA_MODULUS_BYTES];
    unsigned char output[MAX_RSA_MODULUS_BYTES];
    SECStatus rv;
    
    modulusLen = SECKEY_LowPrivateModulusLen(key);

    XP_MEMCPY(input, data, modulusLen);

    while(iters--) {
	rv = RSA_PrivateKeyOp(key, output, input, modulusLen);
	if (rv != SECSuccess) return rv;
	XP_MEMCPY(&output, &input, modulusLen);
    }
    return rv;
}

int
main(int argc, char **argv)
{
    TimingContext *timeCtx;
    SECKEYLowPrivateKey *privKey;
    SECKEYPublicKey *pubHighKey;
    SECKEYLowPublicKey *pubKey;
    CERTCertificate *cert;
    int opt;
    char *secDir = NULL;
    char *nickname = NULL;
    long iters = DEFAULT_ITERS;
    PRBool doPriv = PR_FALSE, doPub = PR_FALSE;
    SECKEYKeyDBHandle *keydb;
    CERTCertDBHandle certdb;
    int rv;
    unsigned char buf[1024];
    unsigned int modulus_len;
    int i;
    
    while ((opt = getopt(argc, argv, "d:i:sen:")) != EOF) {
	switch (opt) {
	  case '?':
	    Usage(argv[0]);
	    break;
          case 'd':
	    secDir = XP_STRDUP(optarg);
	    break;
	  case 'i':
	    iters = atol(optarg);
	    break;
	  case 's':
	    doPriv = PR_TRUE;
	    break;
	  case 'e':
	    doPub = PR_TRUE;
	    break;
	  case 'n':
	    nickname = XP_STRDUP(optarg);
	    break;
	}
    }

    if ((doPriv && doPub) || (nickname == NULL)) Usage(argv[0]);

    if (!doPriv && !doPub) doPriv = PR_TRUE;

    PR_Init(argv[0], 1, 1, 0);
    SEC_Init();

    rv = CERT_OpenCertDBFilename(&certdb, NULL, PR_TRUE);
    if (rv != SECSuccess) {
	fprintf(stderr, "Can't open certificate database.\n");
	exit(1);
    }

    if (doPub) {
	cert = CERT_FindCertByNickname(&certdb, nickname);
	if (cert == NULL) {
	    fprintf(stderr,
		    "Can't find certificate by name \"%s\"\n", nickname);
	    exit(1);
	}
	pubHighKey = CERT_ExtractPublicKey(&cert->subjectPublicKeyInfo);
	pubKey = SECU_ConvHighToLow(pubHighKey);
	if (pubKey == NULL) {
	    fprintf(stderr, "Can't extract public key from certificate");
	    exit(1);
	}
	modulus_len = SECKEY_LowPublicModulusLen(pubKey);
    }

    if (doPriv) {
        keydb = SECU_OpenKeyDB();
      
	if (keydb == NULL) {
	    fprintf(stderr, "Can't open key database.\n");
	    exit(1);
	}
	privKey = SECU_FindLowPrivateKeyFromNickname(nickname);
	if (privKey == NULL) {
	    fprintf(stderr,
		    "Can't find private key by name \"%s\"\n", nickname);
	    exit(1);
	}
	modulus_len = SECKEY_LowPrivateModulusLen(privKey);
    }

    RNG_GenerateGlobalRandomBytes(buf, sizeof(buf));

    timeCtx = CreateTimingContext();
    TimingBegin(timeCtx);
    i = iters;
    while(i--) {
	buf[0] &= 0x3f;
	if (doPub) {
	    rv = RSA_PublicKeyOp(pubKey, buf, buf, modulus_len);
	} else if (doPriv) {
	    rv = RSA_PrivateKeyOp(privKey, buf, buf, modulus_len);
	}
	if (rv != SECSuccess) {
	    fprintf(stderr, "Error in RSA operation\n");
	    exit(1);
	}
    }
    TimingEnd(timeCtx);
    printf("%d iterations in %s\n",
	   iters, TimingGenerateString(timeCtx));
    TimingDivide(timeCtx, iters);
    printf("one operation every %s\n", TimingGenerateString(timeCtx));
    exit(0);
}