/* Example code to illustrate PKI crypto ops (encrypt with public key, * decrypt with private key) * * Code assumes that you have set up a NSS database with a certificate * and a private key. The db password should be "test" and the cert * nickname should be "TestCA" * Here is one way of doing it: * # create CA cert db, if -f not provided, prompts for passwd * $ certutil -N -d . * # create CA cert, self-signed, generates key-pair, prompts for key * # type, cert type etc * # answers for prompts: 5,9,n,y,-1,n,5,6,7,9,n * $ certutil -S -s "CN=Test CA, O=BOGUS Inc, L=Mtn View, ST=CA, C=US" \ * -n TestCA -t CTu,CTu,CTu -v 60 -x -d . -1 -2 -5 * * There are many ways to setup a public/private key to use - this * example shows one of them. * * This example does not do any padding. It simply encrypts/decrypts a block * of length equal to modulus length of the public/private key. */ #include <string.h> #include <nss.h> #include <pk11pub.h> #include <cert.h> #include <keyhi.h> #include <prtypes.h> #include <nspr.h> #include <prprf.h> #include <prlog.h> /* this callback is responsible for returning the password to the NSS * key database. for example purposes, this function hardcodes the password. * In a real app, this function should obtain the password using secure means * such as prompting an operator, or retrieving it over a secure communication * channel */ char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg); int main(int argc, char **argv) { SECStatus rv; PRBool nssInitialized = PR_FALSE; CERTCertificate *cert = NULL; SECKEYPublicKey *pubKey = NULL; SECKEYPrivateKey *pvtkey = NULL; unsigned int modulusLen, outLen; unsigned char *buf1 = NULL; unsigned char *buf2 = NULL; unsigned char *buf3 = NULL; int i; do { /* Initialize NSS */ PK11_SetPasswordFunc(passwdcb); rv = NSS_Init("."); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "NSS initialization failed (err %d)\n", PR_GetError()); break; } nssInitialized = PR_TRUE; cert = PK11_FindCertFromNickname("TestCA", NULL); if (!cert) { PR_fprintf(PR_STDERR, "Couldn't find cert TestCA in NSS db (err %d)\n", PR_GetError()); break; } pubKey = CERT_ExtractPublicKey(cert); if (!pubKey) { PR_fprintf(PR_STDERR, "Couldn't extract public key from cert TestCA (err %d)\n", PR_GetError()); break; } modulusLen = SECKEY_PublicKeyStrength(pubKey); PR_fprintf(PR_STDOUT, "Public Key Modulus %d bytes\n", modulusLen); buf1 = PR_Malloc(modulusLen); buf2 = PR_Malloc(modulusLen); buf3 = PR_Malloc(modulusLen); /* initialize buf1 */ for (i = 0; i < modulusLen; i++) { buf1[i]= (i % 26) + 'A'; } buf1[modulusLen-1] = '\0'; PR_fprintf(PR_STDOUT, "Buffer being encrypted = \n%s\n", buf1); /* encrypt buf1, result will be in buf2 */ rv = PK11_PubEncryptRaw(pubKey, buf2, buf1, modulusLen, NULL); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Encrypt with Public Key failed (err %d)\n", PR_GetError()); break; } pvtkey = PK11_FindKeyByAnyCert(cert, NULL); if (!pvtkey) { rv = PR_GetError(); PR_fprintf(PR_STDERR, "Couldn't find private key for cert TestCA (err %d)\n", rv); break; } /* decrypt buf2, result will be in buf3 */ rv = PK11_PubDecryptRaw(pvtkey, buf3, &outLen, modulusLen, buf3, modulusLen); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Decrypt with Private Key failed (err %d)\n", PR_GetError()); break; } /* the recovered data better match the original */ PR_ASSERT(memcmp(buf1, buf3, outLen) == 0); PR_fprintf(PR_STDOUT, "Result of decryption, outLen = %d\n", outLen); PR_fprintf(PR_STDOUT, "Result of decryption, buf = \n%s\n", buf3); rv = SECSuccess; } while (0); /*cleanup:*/ /* Pretend this is sensitive data and clear * our buffers before releasing them */ if (buf1) { (void) memset(buf1, 0, modulusLen); PR_Free(buf1); } if (buf2) { (void) memset(buf2, 0, modulusLen); PR_Free(buf2); } if (buf3) { (void) memset(buf3, 0, modulusLen); PR_Free(buf2); } /* * Have NSS free what it allocated for us. */ if (cert) CERT_DestroyCertificate(cert); if (pubKey) SECKEY_DestroyPublicKey(pubKey); if (pvtkey) SECKEY_DestroyPrivateKey(pvtkey); /* The last thing we do is shutdown nss */ if (nssInitialized) { (void) NSS_Shutdown(); /* ignoring the result code */ } return rv; } /* Returns the password the firstime its called or NULL otherwise, no retry */ char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg) { return (retry) ? NULL : PL_strdup("test"); }