static int nss_encrypt_decrypt_init(struct crypto_mech_data *mech_props, bool do_encrypt, struct sss_nss_crypto_ctx *cctx) { CK_ATTRIBUTE_TYPE op; int ret; op = do_encrypt ? CKA_ENCRYPT : CKA_DECRYPT; /* turn the raw key into a key object */ cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher, PK11_OriginUnwrap, op, cctx->key, NULL); if (cctx->keyobj == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to import key into NSS (err %d)\n", PR_GetError()); ret = EIO; goto done; } /* turn the raw IV into a initialization vector object */ cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv); if (cctx->sparam == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to set up PKCS11 param (err %d)\n", PR_GetError()); ret = EIO; goto done; } /* Create cipher context */ cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op, cctx->keyobj, cctx->sparam); if (cctx->ectx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create cipher context (err %d)\n", PORT_GetError()); ret = EIO; goto done; } ret = EOK; done: return ret; }
int Pk11StoreGetPin(char **out, Pk11PinStore *store) { int err = PIN_SUCCESS; unsigned char *plain; SECStatus rv = SECSuccess; PK11Context *ctx = 0; int outLen; do { plain = (unsigned char *)malloc(store->length); if (!plain) { err = PIN_NOMEMORY; break; } ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_DECRYPT, store->key, store->params); if (!ctx) { err = PIN_SYSTEMERROR; break; } rv = PK11_CipherOp(ctx, plain, &outLen, store->length, store->crypt, store->length); if (rv) break; rv = PK11_Finalize(ctx); if (rv) break; } while(0); if (ctx) PK11_DestroyContext(ctx, PR_TRUE); if (rv) { err = PIN_SYSTEMERROR; memset(plain, 0, store->length); free(plain); plain = 0; } *out = (char *)plain; return err; }
SVRCOREError SVRCORE_Pk11StoreGetPin(char **out, SVRCOREPk11PinStore *store) { SVRCOREError err = SVRCORE_Success; unsigned char *plain; SECStatus rv; PK11Context *ctx = 0; int outLen; do { plain = (unsigned char *)malloc(store->length); if (!plain) { err = SVRCORE_NoMemory_Error; break; } ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_DECRYPT, store->key, store->params); if (!ctx) { err = SVRCORE_System_Error; break; } rv = PK11_CipherOp(ctx, plain, &outLen, store->length, store->crypt, store->length); if (rv) break; rv = PK11_Finalize(ctx); if (rv) break; } while(0); if (ctx) PK11_DestroyContext(ctx, PR_TRUE); if (rv) { err = SVRCORE_System_Error; memset(plain, 0, store->length); free(plain); plain = 0; } *out = (char *)plain; return err; }
/* * put together the various PK11_Create_Context calls used by different * parts of libsec. */ PK11Context * __PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, SECItem *param, void *wincx) { PK11SymKey *symKey = NULL; PK11Context *context = NULL; /* first get a slot */ if (slot == NULL) { slot = PK11_GetBestSlot(type, wincx); if (slot == NULL) { PORT_SetError(SEC_ERROR_NO_MODULE); goto loser; } } else { PK11_ReferenceSlot(slot); } /* now import the key */ symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx); if (symKey == NULL) goto loser; context = PK11_CreateContextBySymKey(type, operation, symKey, param); loser: if (symKey) { PK11_FreeSymKey(symKey); } if (slot) { PK11_FreeSlot(slot); } return context; }
/* * CreatePk11PinStore */ int CreatePk11PinStore(Pk11PinStore **out, const char *tokenName, const char *pin) { int err = PIN_SUCCESS; Pk11PinStore *store; do { store = (Pk11PinStore*)malloc(sizeof(Pk11PinStore)); if (store == 0) { err = PIN_NOMEMORY; break; } /* Low-level init */ store->key = 0; store->params = 0; store->crypt = 0; /* Use the tokenName to find a PKCS11 slot */ store->slot = PK11_FindSlotByName((char *)tokenName); if (store->slot == 0) { err = PIN_NOSUCHTOKEN; break; } /* Check the password/PIN. This allows access to the token */ { SECStatus rv = PK11_CheckUserPassword(store->slot, (char *)pin); if (rv == SECSuccess) ; else if (rv == SECWouldBlock) { /* NSS returns a blocking error when the pin is wrong */ err = PIN_INCORRECTPW; break; } else { err = PIN_SYSTEMERROR; break; } } /* Find the mechanism that this token can do */ { const mech_item *tp; store->mech = 0; for(tp = table;tp < &table[MECH_TABLE_SIZE];tp++) { if (PK11_DoesMechanism(store->slot, tp->type)) { store->mech = (mech_item *)tp; break; } } /* Default to a mechanism (probably on the internal token */ if (store->mech == 0) { store->mech = &dflt_mech; } } /* Generate a key and parameters to do the encryption */ #if NSS_VMAJOR >= 3 && (NSS_VMINOR <= 9 || (NSS_VMINOR <= 10 && NSS_VPATCH == 0)) store->key = PK11_KeyGen(store->slot, store->mech->type, 0, 0, 0); #else store->key = PK11_TokenKeyGenWithFlags(store->slot, store->mech->type, NULL, 0, NULL, CKF_ENCRYPT|CKF_DECRYPT, PR_FALSE, NULL); #endif if (store->key == 0) { /* PR_SetError(xxx); */ err = PIN_SYSTEMERROR; break; } store->params = PK11_GenerateNewParam(store->mech->type, store->key); if (store->params == 0) { err = PIN_SYSTEMERROR; break; } /* Compute the size of the encrypted data including necessary padding */ { int blocksize = PK11_GetBlockSize(store->mech->type, 0); store->length = strlen(pin)+1; /* Compute padded size - 0 means stream cipher */ if (blocksize != 0) { store->length += blocksize - (store->length % blocksize); } store->crypt = (unsigned char *)malloc(store->length); if (!store->crypt) { err = PIN_NOMEMORY; break; } } /* Encrypt */ { unsigned char *plain; PK11Context *ctx; SECStatus rv; int outLen; plain = (unsigned char *)malloc(store->length); if (!plain) { err = PIN_NOMEMORY; break; } /* Pad with 0 bytes */ memset(plain, 0, store->length); strcpy((char *)plain, pin); ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_ENCRYPT, store->key, store->params); if (!ctx) { err = PIN_SYSTEMERROR; break; } do { rv = PK11_CipherOp(ctx, store->crypt, &outLen, store->length, plain, store->length); if (rv) break; rv = PK11_Finalize(ctx); } while(0); PK11_DestroyContext(ctx, PR_TRUE); memset(plain, 0, store->length); free(plain); if (rv) err = PIN_SYSTEMERROR; } } while(0); if (err) { DestroyPk11PinStore(store); store = 0; } *out = store; return err; }
static int calculate_nss_hash( knet_handle_t knet_h, const unsigned char *buf, const size_t buf_len, unsigned char *hash) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; PK11Context* hash_context = NULL; SECItem hash_param; unsigned int hash_tmp_outlen = 0; int err = -1; /* Now do the digest */ hash_param.type = siBuffer; hash_param.data = 0; hash_param.len = 0; hash_context = PK11_CreateContextBySymKey(hash_to_nss[instance->crypto_hash_type], CKA_SIGN, instance->nss_sym_key_sign, &hash_param); if (!hash_context) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CreateContext failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestBegin(hash_context) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestBegin failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestOp(hash_context, buf, buf_len) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestOp failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestFinal(hash_context, hash, &hash_tmp_outlen, hash_len[instance->crypto_hash_type]) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestFinale failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } err = 0; out: if (hash_context) { PK11_DestroyContext(hash_context, PR_TRUE); } return err; }
/* the content of an encrypted data content info is decrypted. * it is assumed that for encrypted data, that the data has already * been set and is in the "encContent" field of the content info. * * cinfo is the content info to decrypt * * key is the key with which to perform the decryption. if the * algorithm is a password based encryption algorithm, the * key is actually a password which will be processed per * PKCS #5. * * in the event of an error, SECFailure is returned. SECSuccess * indicates a success. */ SECStatus SEC_PKCS7DecryptContents(PRArenaPool *poolp, SEC_PKCS7ContentInfo *cinfo, SECItem *key, void *wincx) { SECAlgorithmID *algid = NULL; SECStatus rv = SECFailure; SECItem *result = NULL, *dest, *src; void *mark; PK11SymKey *eKey = NULL; PK11SlotInfo *slot = NULL; CK_MECHANISM_TYPE cryptoMechType; void *cx; SECItem *c_param = NULL; int bs; if((cinfo == NULL) || (key == NULL)) return SECFailure; if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA) return SECFailure; algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo); if(algid == NULL) return SECFailure; if(poolp == NULL) poolp = cinfo->poolp; mark = PORT_ArenaMark(poolp); src = &cinfo->content.encryptedData->encContentInfo.encContent; dest = &cinfo->content.encryptedData->encContentInfo.plainContent; dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64)); dest->len = (src->len + 64); if(dest->data == NULL) { rv = SECFailure; goto loser; } slot = PK11_GetInternalKeySlot(); if(slot == NULL) { rv = SECFailure; goto loser; } eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx); if(eKey == NULL) { rv = SECFailure; goto loser; } cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key); if (cryptoMechType == CKM_INVALID_MECHANISM) { rv = SECFailure; goto loser; } cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, eKey, c_param); if(cx == NULL) { rv = SECFailure; goto loser; } rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), (int)(src->len + 64), src->data, (int)src->len); PK11_DestroyContext((PK11Context *)cx, PR_TRUE); bs = PK11_GetBlockSize(cryptoMechType, c_param); if(bs) { /* check for proper badding in block algorithms. this assumes * RC2 cbc or a DES cbc variant. and the padding is thus defined */ if(((int)dest->data[dest->len-1] <= bs) && ((int)dest->data[dest->len-1] > 0)) { dest->len -= (int)dest->data[dest->len-1]; } else { rv = SECFailure; /* set an error ? */ } } loser: /* let success fall through */ if(result != NULL) SECITEM_ZfreeItem(result, PR_TRUE); if(rv == SECFailure) PORT_ArenaRelease(poolp, mark); else PORT_ArenaUnmark(poolp, mark); if(eKey != NULL) PK11_FreeSymKey(eKey); if(slot != NULL) PK11_FreeSlot(slot); if(c_param != NULL) SECITEM_ZfreeItem(c_param, PR_TRUE); return rv; }
/* * Create a cipher object to do decryption, based on the given bulk * encryption key and algorithm identifier (which may include an iv). * * XXX This interface, or one similar, would be really nice available * in general... I tried to keep the pkcs7-specific stuff (mostly * having to do with padding) out of here. * * XXX Once both are working, it might be nice to combine this and the * function below (for starting up encryption) into one routine, and just * have two simple cover functions which call it. */ sec_PKCS7CipherObject * sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid) { sec_PKCS7CipherObject *result; SECOidTag algtag; void *ciphercx; CK_MECHANISM_TYPE cryptoMechType; PK11SlotInfo *slot; SECItem *param = NULL; result = (struct sec_pkcs7_cipher_object*) PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object)); if (result == NULL) return NULL; ciphercx = NULL; algtag = SECOID_GetAlgorithmTag (algid); if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { SECItem *pwitem; pwitem = (SECItem *)PK11_GetSymKeyUserData(key); if (!pwitem) { PORT_Free(result); return NULL; } cryptoMechType = PK11_GetPBECryptoMechanism(algid, ¶m, pwitem); if (cryptoMechType == CKM_INVALID_MECHANISM) { PORT_Free(result); SECITEM_FreeItem(param,PR_TRUE); return NULL; } } else { cryptoMechType = PK11_AlgtagToMechanism(algtag); param = PK11_ParamFromAlgid(algid); if (param == NULL) { PORT_Free(result); return NULL; } } result->pad_size = PK11_GetBlockSize(cryptoMechType, param); slot = PK11_GetSlotFromKey(key); result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size; PK11_FreeSlot(slot); ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, key, param); SECITEM_FreeItem(param,PR_TRUE); if (ciphercx == NULL) { PORT_Free (result); return NULL; } result->cx = ciphercx; result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp; result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext; result->encrypt = PR_FALSE; result->pending_count = 0; return result; }
/* * NSS_CMSCipherContext_StartDecrypt - create a cipher context to do decryption * based on the given bulk encryption key and algorithm identifier (which * may include an iv). * * XXX Once both are working, it might be nice to combine this and the * function below (for starting up encryption) into one routine, and just * have two simple cover functions which call it. */ NSSCMSCipherContext * NSS_CMSCipherContext_StartDecrypt(PK11SymKey *key, SECAlgorithmID *algid) { NSSCMSCipherContext *cc; void *ciphercx; CK_MECHANISM_TYPE cryptoMechType; PK11SlotInfo *slot; SECOidTag algtag; SECItem *param = NULL; algtag = SECOID_GetAlgorithmTag(algid); /* set param and mechanism */ if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { SECItem *pwitem; pwitem = PK11_GetSymKeyUserData(key); if (!pwitem) return NULL; cryptoMechType = PK11_GetPBECryptoMechanism(algid, ¶m, pwitem); if (cryptoMechType == CKM_INVALID_MECHANISM) { SECITEM_FreeItem(param,PR_TRUE); return NULL; } } else { cryptoMechType = PK11_AlgtagToMechanism(algtag); if ((param = PK11_ParamFromAlgid(algid)) == NULL) return NULL; } cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext)); if (cc == NULL) { SECITEM_FreeItem(param,PR_TRUE); return NULL; } /* figure out pad and block sizes */ cc->pad_size = PK11_GetBlockSize(cryptoMechType, param); slot = PK11_GetSlotFromKey(key); cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; PK11_FreeSlot(slot); /* create PK11 cipher context */ ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, key, param); SECITEM_FreeItem(param, PR_TRUE); if (ciphercx == NULL) { PORT_Free (cc); return NULL; } cc->cx = ciphercx; cc->doit = (nss_cms_cipher_function) PK11_CipherOp; cc->destroy = (nss_cms_cipher_destroy) PK11_DestroyContext; cc->encrypt = PR_FALSE; cc->pending_count = 0; return cc; }
/* encrypt a block (XMLSEC_NSS_AES_BLOCK_SIZE), in and out can overlap */ static void xmlSecNssAesOp(PK11SymKey *aeskey, const xmlSecByte *in, xmlSecByte *out, int enc) { CK_MECHANISM_TYPE cipherMech; SECItem* SecParam = NULL; PK11Context* EncContext = NULL; SECStatus rv; int tmp1_outlen; unsigned int tmp2_outlen; xmlSecAssert(in != NULL); xmlSecAssert(out != NULL); cipherMech = CKM_AES_ECB; SecParam = PK11_ParamFromIV(cipherMech, NULL); if (SecParam == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_ParamFromIV", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } EncContext = PK11_CreateContextBySymKey(cipherMech, enc ? CKA_ENCRYPT : CKA_DECRYPT, aeskey, SecParam); if (EncContext == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CreateContextBySymKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } tmp1_outlen = tmp2_outlen = 0; rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, XMLSEC_NSS_AES_BLOCK_SIZE, (unsigned char *)in, XMLSEC_NSS_AES_BLOCK_SIZE); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CipherOp", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, &tmp2_outlen, XMLSEC_NSS_AES_BLOCK_SIZE-tmp1_outlen); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_DigestFinal", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } done: if (SecParam) { SECITEM_FreeItem(SecParam, PR_TRUE); } if (EncContext) { PK11_DestroyContext(EncContext, PR_TRUE); } }
int main(int argc, char **argv) { CK_MECHANISM_TYPE hashMech; PK11SlotInfo* slot = NULL; PK11SymKey* SymKey = NULL; SECItem SecParam; PK11Context* HashContext = NULL; SECItem keyItem; SECStatus rv, rv1, rv2; unsigned char buf1[1024], buf2[1024]; char data[1024]; int i; unsigned int tmp2_outlen; /* Initialize NSS * * If your application code has already initialized NSS, you can skip it * * here. * * This code uses the simplest of the Init functions, which does not * * require a NSS database to exist * */ rv = NSS_NoDB_Init("."); if (rv != SECSuccess) { fprintf(stderr, "NSS initialization failed (err %d)\n", PR_GetError()); goto out; } /* choose mechanism: CKM_DES_CBC_PAD, CKM_DES3_ECB, CKM_DES3_CBC..... * * Note that some mechanisms (*_PAD) imply the padding is handled for you * * by NSS. If you choose something else, then data padding is the * * application's responsibility * */ hashMech = CKM_SHA_1_HMAC; slot = PK11_GetBestSlot(hashMech, NULL); /* slot = PK11_GetInternalKeySlot(); is a simpler alternative but in * * theory, it *may not* return the optimal slot for the operation. For * * DES ops, Internal slot is typically the best slot * */ if (slot == NULL) { fprintf(stderr, "Unable to find security device (err %d)\n", PR_GetError()); goto out; } /* NSS passes blobs around as SECItems. These contain a pointer to * * data and a length. Turn the raw key into a SECItem. */ keyItem.type = siBuffer; keyItem.data = gKey; keyItem.len = sizeof(gKey); /* Turn the raw key into a key object. We use PK11_OriginUnwrap * * to indicate the key was unwrapped - which is what should be done * * normally anyway - using raw keys isn't a good idea */ SymKey = PK11_ImportSymKey(slot, hashMech, PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); if (SymKey == NULL) { fprintf(stderr, "Failure to import key into NSS (err %d)\n", PR_GetError()); goto out; } SecParam.type = siBuffer; SecParam.data = 0; SecParam.len = 0; /* sample data we'll hash */ strcpy(data, "Hash me!"); fprintf(stderr, "Clear Data: %s\n", data); /* ========================= START SECTION ============================= */ /* If using the the same key and iv over and over, stuff before this */ /* section and after this section needs to be done only ONCE */ /* Create cipher context */ HashContext = PK11_CreateContextBySymKey(hashMech, CKA_SIGN, SymKey, &SecParam); if (!HashContext) { fprintf(stderr, "no hash context today?\n"); goto out; } if (PK11_DigestBegin(HashContext) != SECSuccess) { fprintf(stderr, "hash doesn't begin?\n"); goto out; } rv1 = PK11_DigestOp(HashContext, (unsigned char *)data, strlen(data)+1); rv2 = PK11_DigestFinal(HashContext, buf2, &tmp2_outlen, SHA1_BLOCK_LENGTH); PK11_DestroyContext(HashContext, PR_TRUE); if (rv1 != SECSuccess || rv2 != SECSuccess) goto out; fprintf(stderr, "Hash Data: "); for (i=0; i<tmp2_outlen; i++) fprintf(stderr, "%02x ", buf2[i]); fprintf(stderr, "\n"); /* =========================== END SECTION ============================= */ /* ========================= START SECTION ============================= */ /* If using the the same key and iv over and over, stuff before this */ /* section and after this section needs to be done only ONCE */ memset(buf1, 0, sizeof(buf1)); memset(buf2, 0, sizeof(buf2)); /* Create cipher context */ HashContext = PK11_CreateContextBySymKey(hashMech, CKA_SIGN, SymKey, &SecParam); if (!HashContext) { fprintf(stderr, "no hash context today?\n"); goto out; } if (PK11_DigestBegin(HashContext) != SECSuccess) { fprintf(stderr, "hash doesn't begin?\n"); goto out; } rv1 = PK11_DigestOp(HashContext, (unsigned char *)data, 5); rv1 = PK11_DigestOp(HashContext, (unsigned char *)data+5, 4); rv2 = PK11_DigestFinal(HashContext, buf2, &tmp2_outlen, SHA1_BLOCK_LENGTH); PK11_DestroyContext(HashContext, PR_TRUE); if (rv1 != SECSuccess || rv2 != SECSuccess) goto out; fprintf(stderr, "Hash Data: "); for (i=0; i<tmp2_outlen; i++) fprintf(stderr, "%02x ", buf2[i]); fprintf(stderr, "\n"); /* =========================== END SECTION ============================= */ out: if (SymKey) PK11_FreeSymKey(SymKey); return 0; }
void do_3des_nss(u_int8_t *buf, size_t buf_len, PK11SymKey *symkey, u_int8_t *iv, bool enc) { u_int8_t *tmp_buf; u_int8_t *new_iv; CK_MECHANISM_TYPE ciphermech; SECItem ivitem; SECItem *secparam; PK11Context *enccontext = NULL; SECStatus rv; int outlen; DBG(DBG_CRYPT, DBG_log("NSS: do_3des init start")); ciphermech = CKM_DES3_CBC; /* libreswan provides padding */ if (symkey == NULL) { loglog(RC_LOG_SERIOUS, "do_3des: NSS derived enc key is NULL"); abort(); } ivitem.type = siBuffer; ivitem.data = iv; ivitem.len = DES_CBC_BLOCK_SIZE; secparam = PK11_ParamFromIV(ciphermech, &ivitem); if (secparam == NULL) { loglog(RC_LOG_SERIOUS, "do_3des: Failure to set up PKCS11 param (err %d)", PR_GetError()); abort(); } outlen = 0; tmp_buf = PR_Malloc((PRUint32)buf_len); new_iv = (u_int8_t*)PR_Malloc((PRUint32)DES_CBC_BLOCK_SIZE); if (!enc) memcpy(new_iv, (char*) buf + buf_len - DES_CBC_BLOCK_SIZE, DES_CBC_BLOCK_SIZE); enccontext = PK11_CreateContextBySymKey(ciphermech, enc ? CKA_ENCRYPT : CKA_DECRYPT, symkey, secparam); if (enccontext == NULL) { loglog(RC_LOG_SERIOUS, "do_3des: PKCS11 context creation failure (err %d)", PR_GetError()); abort(); } rv = PK11_CipherOp(enccontext, tmp_buf, &outlen, buf_len, buf, buf_len); if (rv != SECSuccess) { loglog(RC_LOG_SERIOUS, "do_3des: PKCS11 operation failure (err %d)", PR_GetError()); abort(); } if (enc) memcpy(new_iv, (char*) tmp_buf + buf_len - DES_CBC_BLOCK_SIZE, DES_CBC_BLOCK_SIZE); memcpy(buf, tmp_buf, buf_len); memcpy(iv, new_iv, DES_CBC_BLOCK_SIZE); PK11_DestroyContext(enccontext, PR_TRUE); PR_Free(tmp_buf); PR_Free(new_iv); if (secparam != NULL) SECITEM_FreeItem(secparam, PR_TRUE); DBG(DBG_CRYPT, DBG_log("NSS: do_3des init end")); }
char * crypto_encrypt (const char *cipher, const guint8 *data, gsize data_len, const char *iv, gsize iv_len, const char *key, gsize key_len, gsize *out_len, GError **error) { SECStatus ret; CK_MECHANISM_TYPE cipher_mech = CKM_DES3_CBC_PAD; PK11SlotInfo *slot = NULL; SECItem key_item = { .data = (unsigned char *) key, .len = key_len }; SECItem iv_item = { .data = (unsigned char *) iv, .len = iv_len }; PK11SymKey *sym_key = NULL; SECItem *sec_param = NULL; PK11Context *ctx = NULL; unsigned char *output, *padded_buf; gsize output_len; int encrypted_len = 0, i; gboolean success = FALSE; gsize padded_buf_len, pad_len; if (!crypto_init (error)) return NULL; if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) cipher_mech = CKM_DES3_CBC_PAD; else if (!strcmp (cipher, CIPHER_AES_CBC)) cipher_mech = CKM_AES_CBC_PAD; else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), cipher); return NULL; } /* If data->len % ivlen == 0, then we add another complete block * onto the end so that the decrypter knows there's padding. */ pad_len = iv_len - (data_len % iv_len); output_len = padded_buf_len = data_len + pad_len; padded_buf = g_malloc0 (padded_buf_len); memcpy (padded_buf, data, data_len); for (i = 0; i < pad_len; i++) padded_buf[data_len + i] = (guint8) (pad_len & 0xFF); output = g_malloc0 (output_len); slot = PK11_GetBestSlot (cipher_mech, NULL); if (!slot) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Failed to initialize the encryption cipher slot.")); goto out; } sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); if (!sym_key) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to set symmetric key for encryption.")); goto out; } sec_param = PK11_ParamFromIV (cipher_mech, &iv_item); if (!sec_param) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to set IV for encryption.")); goto out; } ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_ENCRYPT, sym_key, sec_param); if (!ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to initialize the encryption context.")); goto out; } ret = PK11_CipherOp (ctx, output, &encrypted_len, output_len, padded_buf, padded_buf_len); if (ret != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to encrypt: %d."), PORT_GetError ()); goto out; } if (encrypted_len != output_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Unexpected amount of data after encrypting.")); goto out; } *out_len = encrypted_len; success = TRUE; out: if (ctx) PK11_DestroyContext (ctx, PR_TRUE); if (sym_key) PK11_FreeSymKey (sym_key); if (sec_param) SECITEM_FreeItem (sec_param, PR_TRUE); if (slot) PK11_FreeSlot (slot); memset (padded_buf, 0, padded_buf_len); g_free (padded_buf); if (!success) { memset (output, 0, output_len); g_free (output); output = NULL; } return (char *) output; } NMCryptoFileFormat crypto_verify_cert (const unsigned char *data, gsize len, GError **error) { CERTCertificate *cert; if (!crypto_init (error)) return NM_CRYPTO_FILE_FORMAT_UNKNOWN; /* Try DER/PEM first */ cert = CERT_DecodeCertFromPackage ((char *) data, len); if (!cert) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Couldn't decode certificate: %d"), PORT_GetError()); return NM_CRYPTO_FILE_FORMAT_UNKNOWN; } CERT_DestroyCertificate (cert); return NM_CRYPTO_FILE_FORMAT_X509; } gboolean crypto_verify_pkcs12 (const guint8 *data, gsize data_len, const char *password, GError **error) { SEC_PKCS12DecoderContext *p12ctx = NULL; SECItem pw = { 0 }; PK11SlotInfo *slot = NULL; SECStatus s; gunichar2 *ucs2_password; glong ucs2_chars = 0; #ifndef WORDS_BIGENDIAN guint16 *p; #endif /* WORDS_BIGENDIAN */ if (error) g_return_val_if_fail (*error == NULL, FALSE); if (!crypto_init (error)) return FALSE; /* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do * any conversions for us. */ if (password && *password) { if (!g_utf8_validate (password, -1, NULL)) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_PASSWORD, _("Password must be UTF-8")); return FALSE; } ucs2_password = g_utf8_to_utf16 (password, strlen (password), NULL, &ucs2_chars, NULL); /* Can't fail if g_utf8_validate() succeeded */ g_return_val_if_fail (ucs2_password != NULL && ucs2_chars != 0, FALSE); ucs2_chars *= 2; /* convert # UCS2 characters -> bytes */ pw.data = PORT_ZAlloc(ucs2_chars + 2); memcpy (pw.data, ucs2_password, ucs2_chars); pw.len = ucs2_chars + 2; /* include terminating NULL */ memset (ucs2_password, 0, ucs2_chars); g_free (ucs2_password); #ifndef WORDS_BIGENDIAN for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++) *p = GUINT16_SWAP_LE_BE (*p); #endif /* WORDS_BIGENDIAN */ } else { /* NULL password */ pw.data = NULL; pw.len = 0; } slot = PK11_GetInternalKeySlot(); p12ctx = SEC_PKCS12DecoderStart (&pw, slot, NULL, NULL, NULL, NULL, NULL, NULL); if (!p12ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Couldn't initialize PKCS#12 decoder: %d"), PORT_GetError()); goto error; } s = SEC_PKCS12DecoderUpdate (p12ctx, (guint8 *)data, data_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Couldn't decode PKCS#12 file: %d"), PORT_GetError()); goto error; } s = SEC_PKCS12DecoderVerify (p12ctx); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Couldn't verify PKCS#12 file: %d"), PORT_GetError()); goto error; } SEC_PKCS12DecoderFinish (p12ctx); SECITEM_ZfreeItem (&pw, PR_FALSE); return TRUE; error: if (p12ctx) SEC_PKCS12DecoderFinish (p12ctx); if (slot) PK11_FreeSlot(slot); SECITEM_ZfreeItem (&pw, PR_FALSE); return FALSE; }
/* * SVRCORE_CreatePk11PinStore */ SVRCOREError SVRCORE_CreatePk11PinStore( SVRCOREPk11PinStore **out, const char *tokenName, const char *pin) { SVRCOREError err; SVRCOREPk11PinStore *store; do { err = SVRCORE_Success; store = (SVRCOREPk11PinStore*)malloc(sizeof *store); if (store == 0) { err = SVRCORE_NoMemory_Error; break; } /* Low-level init */ store->slot = 0; store->key = 0; store->params = 0; store->crypt = 0; /* Use the tokenName to find a PKCS11 slot */ store->slot = PK11_FindSlotByName((char *)tokenName); if (store->slot == 0) { err = SVRCORE_NoSuchToken_Error; break; } /* Check the password/PIN. This allows access to the token */ { SECStatus rv = PK11_CheckUserPassword(store->slot, (char *)pin); if (rv == SECSuccess) ; else if (rv == SECWouldBlock) { err = SVRCORE_IncorrectPassword_Error; break; } else { err = SVRCORE_System_Error; break; } } /* Find the mechanism that this token can do */ { const mech_item *tp; store->mech = 0; for(tp = table;tp < &table[MECH_TABLE_SIZE];tp++) { if (PK11_DoesMechanism(store->slot, tp->type)) { store->mech = tp; break; } } /* Default to a mechanism (probably on the internal token */ if (store->mech == 0) store->mech = &dflt_mech; } /* Generate a key and parameters to do the encryption */ store->key = PK11_TokenKeyGenWithFlags(store->slot, store->mech->type, 0, 0, 0, CKF_ENCRYPT|CKF_DECRYPT, 0, 0); if (store->key == 0) { /* PR_SetError(xxx); */ err = SVRCORE_System_Error; break; } store->params = PK11_GenerateNewParam(store->mech->type, store->key); if (store->params == 0) { err = SVRCORE_System_Error; break; } /* Compute the size of the encrypted data including necessary padding */ { int blocksize = PK11_GetBlockSize(store->mech->type, 0); store->length = strlen(pin)+1; /* Compute padded size - 0 means stream cipher */ if (blocksize != 0) { store->length += blocksize - (store->length % blocksize); } store->crypt = (unsigned char *)malloc(store->length); if (!store->crypt) { err = SVRCORE_NoMemory_Error; break; } } /* Encrypt */ { unsigned char *plain; PK11Context *ctx; SECStatus rv; int outLen; plain = (unsigned char *)malloc(store->length); if (!plain) { err = SVRCORE_NoMemory_Error; break; } /* Pad with 0 bytes */ memset(plain, 0, store->length); strcpy((char *)plain, pin); ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_ENCRYPT, store->key, store->params); if (!ctx) { err = SVRCORE_System_Error; break; } do { rv = PK11_CipherOp(ctx, store->crypt, &outLen, store->length, plain, store->length); if (rv) break; rv = PK11_Finalize(ctx); } while(0); PK11_DestroyContext(ctx, PR_TRUE); memset(plain, 0, store->length); free(plain); if (rv) err = SVRCORE_System_Error; } } while(0); if (err) { SVRCORE_DestroyPk11PinStore(store); store = 0; } *out = store; return err; }
TPS_PUBLIC PRStatus Util::ComputeKeyCheck(const Buffer& newKey, Buffer& output) { PK11SymKey *key = NULL; PRStatus status = PR_FAILURE ; PK11SlotInfo *slot = PK11_GetInternalKeySlot(); PK11Context *context = NULL; SECStatus s = SECFailure; int len; static SECItem noParams = { siBuffer, 0, 0 }; #ifdef DES2_WORKAROUND unsigned char keyData[24]; #else unsigned char keyData[16]; #endif SECItem keyItem = {siBuffer, keyData, sizeof(keyData) }; unsigned char value[8]; // convert 16-byte to 24-byte triple-DES key memcpy(keyData, newKey, 16); #ifdef DES2_WORKAROUND memcpy(keyData+16, newKey, 8); #endif memset(value, 0, sizeof value); key = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, PK11_OriginGenerated, CKA_ENCRYPT, &keyItem, CKF_ENCRYPT, PR_FALSE, 0); if( ! key ) { goto done; } context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, key, &noParams); if (!context) { goto done; } s = PK11_CipherOp(context, &value[0], &len, 8, &value[0], 8); if (s != SECSuccess) { goto done; } output.resize(3); output.replace(0, value, 3); status = PR_SUCCESS; done: memset(keyData, 0, sizeof keyData); if( context != NULL ) { PK11_DestroyContext( context, PR_TRUE ); context = NULL; } if( slot != NULL ) { PK11_FreeSlot( slot ); slot = NULL; } if( key != NULL ) { PK11_FreeSymKey( key ); key = NULL; } return status; }
TPS_PUBLIC PRStatus Util::EncryptData(Buffer &kek_key, Buffer &input, Buffer &output) { PRStatus rv = PR_FAILURE; PK11SymKey *master = NULL; PK11SlotInfo *slot = PK11_GetInternalKeySlot(); PK11Context *context = NULL; int i; SECStatus s = SECFailure; int len; static SECItem noParams = { siBuffer, 0, 0 }; #ifdef DES2_WORKAROUND unsigned char masterKeyData[24]; #else unsigned char masterKeyData[16]; #endif SECItem masterKeyItem = {siBuffer, masterKeyData, sizeof(masterKeyData) }; unsigned char result[8]; // convert 16-byte to 24-byte triple-DES key memcpy(masterKeyData, (BYTE*)kek_key, 16); #ifdef DES2_WORKAROUND memcpy(masterKeyData+16, (BYTE*)kek_key, 8); #endif master = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, PK11_OriginGenerated, CKA_ENCRYPT, &masterKeyItem, CKF_ENCRYPT, PR_FALSE, 0); if( ! master ) { goto done; } context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, master, &noParams); if (!context) { goto done; } for(i = 0;i < (int)input.size();i += 8) { s = PK11_CipherOp(context, result, &len, 8, (unsigned char *)(((BYTE*)input)+i), 8); if (s != SECSuccess) { goto done; } output.replace(i, result, 8); } rv = PR_SUCCESS; done: memset(masterKeyData, 0, sizeof masterKeyData); if( context != NULL ) { PK11_DestroyContext( context, PR_TRUE ); context = NULL; } if( slot != NULL ) { PK11_FreeSlot( slot ); slot = NULL; } if( master != NULL ) { PK11_FreeSymKey( master ); master = NULL; } return rv; }
TPS_PUBLIC PK11SymKey *Util::DeriveKey(const Buffer& permKey, const Buffer& hostChallenge, const Buffer& cardChallenge) { PK11SymKey *key = NULL, *master = NULL; PK11SlotInfo *slot = PK11_GetInternalKeySlot(); PK11Context *context = NULL; unsigned char derivationData[16]; #ifdef DES2_WORKAROUND unsigned char keyData[24]; #else unsigned char keyData[16]; #endif int i; SECStatus s; int len; SECItem keyItem = { siBuffer, keyData, sizeof keyData }; static SECItem noParams = { siBuffer, 0, 0 }; BYTE masterKeyData[24]; SECItem masterKeyItem = {siBuffer, masterKeyData, sizeof(masterKeyData) }; // convert 16-byte to 24-byte triple-DES key memcpy(masterKeyData, permKey, 16); memcpy(masterKeyData+16, permKey, 8); master = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, PK11_OriginGenerated, CKA_ENCRYPT, &masterKeyItem, CKF_ENCRYPT, PR_FALSE, 0); if( ! master ) goto done; for(i = 0;i < 4;i++) { derivationData[i] = cardChallenge[i+4]; derivationData[i+4] = hostChallenge[i]; derivationData[i+8] = cardChallenge[i]; derivationData[i+12] = hostChallenge[i+4]; } context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, master, &noParams); if (!context) goto done; /* Part 1 */ s = PK11_CipherOp(context, &keyData[0], &len, 8, &derivationData[0], 8); if (s != SECSuccess) goto done; /* Part 2 */ s = PK11_CipherOp(context, &keyData[8], &len, 8, &derivationData[8], 8); if (s != SECSuccess) goto done; #ifdef DES2_WORKAROUND /* Part 3 */ for(i = 0;i < 8;i++) { keyData[i+16] = keyData[i]; } #endif key = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, PK11_OriginGenerated, CKA_ENCRYPT, &keyItem, CKF_SIGN | CKF_ENCRYPT, PR_FALSE, 0); done: memset(keyData, 0, sizeof keyData); if( context != NULL ) { PK11_DestroyContext( context, PR_TRUE ); context = NULL; } if( slot != NULL ) { PK11_FreeSlot( slot ); slot = NULL; } if( master != NULL ) { PK11_FreeSymKey( master ); master = NULL; } return key; }
TPS_PUBLIC PRStatus Util::ComputeMAC(PK11SymKey *key, Buffer &x_input, const Buffer &icv, Buffer &output) { PRStatus rv = PR_SUCCESS; PK11Context *context = NULL; // NetkeyICV temp; unsigned char result[8]; int i; SECStatus s; int len; #ifdef USE_DESMAC CK_ULONG macLen = sizeof result; SECItem params = { siBuffer, (unsigned char *)&macLen, sizeof macLen }; #endif static SECItem noParams = { siBuffer, 0, 0 }; static unsigned char macPad[] = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; BYTE *input = (BYTE *) x_input; int inputLen = x_input.size(); #ifdef USE_DESMAC context = PK11_CreateContextBySymKey(CKM_DES3_MAC_GENERAL, CKA_SIGN, key, ¶ms); if (!context) { rv = PR_FAILURE; goto done; } s = PK11_DigestBegin(context); if (s != SECSuccess) { rv = PR_FAILURE; goto done; } s = PK11_DigestOp(context, icv, 8); if (s != SECSuccess) { rv = PR_FAILURE; goto done; } while(inputLen >= 8) { s = PK11_DigestOp(context, input, 8); if (s != SECSuccess) { rv = PR_FAILURE; goto done; } input += 8; inputLen -= 8; } for (i = 0;i < inputLen;i++) { result[i] = input[i]; } input = macPad; for(;i < 8;i++) { result[i] = *input++; } s = PK11_DigestOp(context, result, sizeof result); if (s != SECSuccess) { rv = PR_FAILURE; goto done; } s = PK11_DigestFinal(context, output, (unsigned int *)&len, sizeof output); if (1 != SECSuccess) { rv = PR_FAILURE; goto done; } #else context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, key, &noParams); if (!context) { rv = PR_FAILURE; goto done; } memcpy(result, icv, sizeof result); /* Process whole blocks */ while(inputLen >= 8) { for(i = 0;i < 8;i++) { result[i] ^= input[i]; } s = PK11_CipherOp(context, result, &len, sizeof result, result, sizeof result); if (s != SECSuccess) { rv = PR_FAILURE; goto done; } if (len != sizeof result) /* assert? */ { //PR_SetError(PR_UNKNOWN_ERROR, 0); rv = PR_FAILURE; goto done; } input += 8; inputLen -= 8; } /* * Fold in remaining data (if any) * Set i to number of bytes processed */ for(i = 0;i < inputLen;i++) { result[i] ^= input[i]; } /* * Fill remainder of last block. There * will be at least one byte handled here. */ input = macPad; while(i < 8) { result[i] ^= *input++; i++; } s = PK11_CipherOp(context, result, &len, sizeof result, result, sizeof result); if (s != SECSuccess) { rv = PR_FAILURE; goto done; } if (len != sizeof result) { //PR_SetError(PR_UNKNOWN_ERROR, 0); rv = PR_FAILURE; goto done; } output.replace(0, result, sizeof result); #endif done: if( context != NULL ) { PK11_Finalize( context ); PK11_DestroyContext( context, PR_TRUE ); context = NULL; } memset(result, 0, sizeof result); return rv; } /* ComputeMAC */
size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res) { #define CIPHER_MECH CKM_DES3_CBC #define MAX_OUTPUT_LEN 72 int len1; unsigned int len2; PK11Context *ctx = NULL; PK11SlotInfo *slot = NULL; SECItem keyItem; SECItem ivItem; SECItem *secParam = NULL; PK11SymKey *symKey = NULL; size_t rc; SECStatus rv; if (!initialized) { ssl_init(); } keyItem.data = (unsigned char *)key; keyItem.len = key_len; slot = PK11_GetBestSlot(CIPHER_MECH, NULL); if (slot == NULL) { fprintf(stderr, "PK11_GetBestSlot failed (err %d)\n", PR_GetError()); rc = 0; goto out; } symKey = PK11_ImportSymKey(slot, CIPHER_MECH, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL); if (symKey == NULL) { fprintf(stderr, "PK11_ImportSymKey failed (err %d)\n", PR_GetError()); rc = 0; goto out; } ivItem.data = (unsigned char *)iv; /* See msn_soap_passport_sso_handle_response in protocols/msn/soap.c */ ivItem.len = 8; secParam = PK11_ParamFromIV(CIPHER_MECH, &ivItem); if (secParam == NULL) { fprintf(stderr, "PK11_ParamFromIV failed (err %d)\n", PR_GetError()); rc = 0; goto out; } ctx = PK11_CreateContextBySymKey(CIPHER_MECH, CKA_ENCRYPT, symKey, secParam); if (ctx == NULL) { fprintf(stderr, "PK11_CreateContextBySymKey failed (err %d)\n", PR_GetError()); rc = 0; goto out; } *res = g_new0(unsigned char, MAX_OUTPUT_LEN); rv = PK11_CipherOp(ctx, *res, &len1, MAX_OUTPUT_LEN, (unsigned char *)input, input_len); if (rv != SECSuccess) { fprintf(stderr, "PK11_CipherOp failed (err %d)\n", PR_GetError()); rc = 0; goto out; } assert(len1 <= MAX_OUTPUT_LEN); rv = PK11_DigestFinal(ctx, *res + len1, &len2, (unsigned int)MAX_OUTPUT_LEN - len1); if (rv != SECSuccess) { fprintf(stderr, "PK11_DigestFinal failed (err %d)\n", PR_GetError()); rc = 0; goto out; } rc = len1 + len2; out: if (ctx) PK11_DestroyContext(ctx, PR_TRUE); if (symKey) PK11_FreeSymKey(symKey); if (secParam) SECITEM_FreeItem(secParam, PR_TRUE); if (slot) PK11_FreeSlot(slot); return rc; }
/** * @brief Initialise a context for encrypting arbitrary data using the given key. * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If * *ctx is not NULL, *ctx must point at a previously created structure. * @param ctx The block context returned, see note. * @param iv Optional initialisation vector. If the buffer pointed to is NULL, * an IV will be created at random, in space allocated from the pool. * If the buffer pointed to is not NULL, the IV in the buffer will be * used. * @param key The key structure. * @param blockSize The block size of the cipher. * @param p The pool to use. * @return Returns APR_ENOIV if an initialisation vector is required but not specified. * Returns APR_EINIT if the backend failed to initialise the context. Returns * APR_ENOTIMPL if not implemented. */ static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx, const unsigned char **iv, const apr_crypto_key_t *key, apr_size_t *blockSize, apr_pool_t *p) { PRErrorCode perr; SECItem * secParam; SECItem ivItem; unsigned char * usedIv; apr_crypto_block_t *block = *ctx; if (!block) { *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); } if (!block) { return APR_ENOMEM; } block->f = key->f; block->pool = p; block->provider = key->provider; apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, apr_pool_cleanup_null); if (key->ivSize) { if (iv == NULL) { return APR_ENOIV; } if (*iv == NULL) { SECStatus s; usedIv = apr_pcalloc(p, key->ivSize); if (!usedIv) { return APR_ENOMEM; } apr_crypto_clear(p, usedIv, key->ivSize); s = PK11_GenerateRandom(usedIv, key->ivSize); if (s != SECSuccess) { return APR_ENOIV; } *iv = usedIv; } else { usedIv = (unsigned char *) *iv; } ivItem.data = usedIv; ivItem.len = key->ivSize; secParam = PK11_ParamFromIV(key->cipherMech, &ivItem); } else { secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey); } block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam); block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_ENCRYPT, key->symKey, secParam); /* did an error occur? */ perr = PORT_GetError(); if (perr || !block->ctx) { key->f->result->rc = perr; key->f->result->msg = PR_ErrorToName(perr); return APR_EINIT; } if (blockSize) { *blockSize = PK11_GetBlockSize(key->cipherMech, secParam); } return APR_SUCCESS; }
char * crypto_decrypt (const char *cipher, int key_type, const guint8 *data, gsize data_len, const char *iv, const gsize iv_len, const char *key, const gsize key_len, gsize *out_len, GError **error) { char *output = NULL; int decrypted_len = 0; CK_MECHANISM_TYPE cipher_mech; PK11SlotInfo *slot = NULL; SECItem key_item; PK11SymKey *sym_key = NULL; SECItem *sec_param = NULL; PK11Context *ctx = NULL; SECStatus s; gboolean success = FALSE; unsigned int pad_len = 0, extra = 0; guint32 i, real_iv_len = 0; if (!crypto_init (error)) return NULL; if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { cipher_mech = CKM_DES3_CBC_PAD; real_iv_len = 8; } else if (!strcmp (cipher, CIPHER_DES_CBC)) { cipher_mech = CKM_DES_CBC_PAD; real_iv_len = 8; } else if (!strcmp (cipher, CIPHER_AES_CBC)) { cipher_mech = CKM_AES_CBC_PAD; real_iv_len = 16; } else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), cipher); return NULL; } if (iv_len < real_iv_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Invalid IV length (must be at least %d)."), real_iv_len); return NULL; } output = g_malloc0 (data_len); slot = PK11_GetBestSlot (cipher_mech, NULL); if (!slot) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Failed to initialize the decryption cipher slot.")); goto out; } key_item.data = (unsigned char *) key; key_item.len = key_len; sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL); if (!sym_key) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to set symmetric key for decryption.")); goto out; } key_item.data = (unsigned char *) iv; key_item.len = real_iv_len; sec_param = PK11_ParamFromIV (cipher_mech, &key_item); if (!sec_param) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to set IV for decryption.")); goto out; } ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_DECRYPT, sym_key, sec_param); if (!ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to initialize the decryption context.")); goto out; } s = PK11_CipherOp (ctx, (unsigned char *) output, &decrypted_len, data_len, data, data_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: %d."), PORT_GetError ()); goto out; } if (decrypted_len > data_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: decrypted data too large.")); goto out; } s = PK11_DigestFinal (ctx, (unsigned char *) (output + decrypted_len), &extra, data_len - decrypted_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to finalize decryption of the private key: %d."), PORT_GetError ()); goto out; } decrypted_len += extra; pad_len = data_len - decrypted_len; /* Check if the padding at the end of the decrypted data is valid */ if (pad_len == 0 || pad_len > real_iv_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: unexpected padding length.")); goto out; } /* Validate tail padding; last byte is the padding size, and all pad bytes * should contain the padding size. */ for (i = pad_len; i > 0; i--) { if (output[data_len - i] != pad_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key.")); goto out; } } *out_len = decrypted_len; success = TRUE; out: if (ctx) PK11_DestroyContext (ctx, PR_TRUE); if (sym_key) PK11_FreeSymKey (sym_key); if (sec_param) SECITEM_FreeItem (sec_param, PR_TRUE); if (slot) PK11_FreeSlot (slot); if (!success) { if (output) { /* Don't expose key material */ memset (output, 0, data_len); g_free (output); output = NULL; } } return output; }
/* * SecCmsCipherContextStartDecrypt - create a cipher context to do decryption * based on the given bulk * encryption key and algorithm identifier (which may include an iv). * * XXX Once both are working, it might be nice to combine this and the * function below (for starting up encryption) into one routine, and just * have two simple cover functions which call it. */ SecCmsCipherContext * SecCmsCipherContextStartDecrypt(SecSymmetricKeyRef key, SECAlgorithmID *algid) { return SecCmsCipherContextStart(NULL, key, algid, PR_FALSE); #if 0 SecCmsCipherContext *cc; void *ciphercx; CK_MECHANISM_TYPE mechanism; CSSM_DATA *param; PK11SlotInfo *slot; SECOidTag algtag; algtag = SECOID_GetAlgorithmTag(algid); /* set param and mechanism */ if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { CK_MECHANISM pbeMech, cryptoMech; CSSM_DATA *pbeParams; SEC_PKCS5KeyAndPassword *keyPwd; PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM)); PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM)); /* HACK ALERT! * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword * */ keyPwd = (SEC_PKCS5KeyAndPassword *)key; key = keyPwd->key; /* find correct PK11 mechanism and parameters to initialize pbeMech */ pbeMech.mechanism = PK11_AlgtagToMechanism(algtag); pbeParams = PK11_ParamFromAlgid(algid); if (!pbeParams) return NULL; pbeMech.pParameter = pbeParams->Data; pbeMech.ulParameterLen = pbeParams->Length; /* now map pbeMech to cryptoMech */ if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem, PR_FALSE) != CKR_OK) { SECITEM_ZfreeItem(pbeParams, PR_TRUE); return NULL; } SECITEM_ZfreeItem(pbeParams, PR_TRUE); /* and use it to initialize param & mechanism */ if ((param = (CSSM_DATA *)PORT_ZAlloc(sizeof(CSSM_DATA))) == NULL) return NULL; param->Data = (unsigned char *)cryptoMech.pParameter; param->Length = cryptoMech.ulParameterLen; mechanism = cryptoMech.mechanism; } else { mechanism = PK11_AlgtagToMechanism(algtag); if ((param = PK11_ParamFromAlgid(algid)) == NULL) return NULL; } cc = (SecCmsCipherContext *)PORT_ZAlloc(sizeof(SecCmsCipherContext)); if (cc == NULL) { SECITEM_FreeItem(param,PR_TRUE); return NULL; } /* figure out pad and block sizes */ cc->pad_size = PK11_GetBlockSize(mechanism, param); slot = PK11_GetSlotFromKey(key); cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; PK11_FreeSlot(slot); /* create PK11 cipher context */ ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_DECRYPT, key, param); SECITEM_FreeItem(param, PR_TRUE); if (ciphercx == NULL) { PORT_Free (cc); return NULL; } cc->cx = ciphercx; cc->doit = (nss_cms_cipher_function) PK11_CipherOp; cc->destroy = (nss_cms_cipher_destroy) PK11_DestroyContext; cc->encrypt = PR_FALSE; cc->pending_count = 0; return cc; #endif }
static int xmlSecNssKWAesOp(const xmlSecByte *key, xmlSecSize keySize, const xmlSecByte *in, xmlSecSize inSize, xmlSecByte *out, xmlSecSize outSize, int enc) { CK_MECHANISM_TYPE cipherMech; PK11SlotInfo* slot = NULL; PK11SymKey* aeskey = NULL; SECItem* SecParam = NULL; PK11Context* EncContext = NULL; SECItem keyItem; SECStatus rv; int result_len = -1; int tmp1_outlen; unsigned int tmp2_outlen; xmlSecAssert2(key != NULL, -1); xmlSecAssert2(keySize > 0, -1); xmlSecAssert2(in != NULL, -1); xmlSecAssert2(inSize > 0, -1); xmlSecAssert2(out != NULL, -1); xmlSecAssert2(outSize >= inSize + 8, -1); cipherMech = CKM_NETSCAPE_AES_KEY_WRAP; slot = PK11_GetBestSlot(cipherMech, NULL); if (slot == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_GetBestSlot", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } keyItem.data = (unsigned char *)key; keyItem.len = keySize; aeskey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, enc ? CKA_ENCRYPT : CKA_DECRYPT, &keyItem, NULL); if (aeskey == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_ImportSymKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } SecParam = PK11_ParamFromIV(cipherMech, NULL); if (SecParam == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_ParamFromIV", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } EncContext = PK11_CreateContextBySymKey(cipherMech, enc ? CKA_ENCRYPT : CKA_DECRYPT, aeskey, SecParam); if (EncContext == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CreateContextBySymKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } tmp1_outlen = tmp2_outlen = 0; rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, outSize, (unsigned char *)in, inSize); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CipherOp", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, &tmp2_outlen, outSize-tmp1_outlen); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_DigestFinal", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } result_len = tmp1_outlen + tmp2_outlen; done: if (slot) { PK11_FreeSlot(slot); } if (aeskey) { PK11_FreeSymKey(aeskey); } if (SecParam) { SECITEM_FreeItem(SecParam, PR_TRUE); } if (EncContext) { PK11_DestroyContext(EncContext, PR_TRUE); } return(result_len); }
/* * SecCmsCipherContextStartEncrypt - create a cipher object to do encryption, * based on the given bulk encryption key and algorithm tag. Fill in the algorithm * identifier (which may include an iv) appropriately. * * XXX Once both are working, it might be nice to combine this and the * function above (for starting up decryption) into one routine, and just * have two simple cover functions which call it. */ SecCmsCipherContext * SecCmsCipherContextStartEncrypt(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid) { return SecCmsCipherContextStart(poolp, key, algid, PR_TRUE); #if 0 SecCmsCipherContext *cc; void *ciphercx; CSSM_DATA *param; OSStatus rv; CK_MECHANISM_TYPE mechanism; PK11SlotInfo *slot; PRBool needToEncodeAlgid = PR_FALSE; SECOidTag algtag = SECOID_GetAlgorithmTag(algid); /* set param and mechanism */ if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { CK_MECHANISM pbeMech, cryptoMech; CSSM_DATA *pbeParams; SEC_PKCS5KeyAndPassword *keyPwd; PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM)); PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM)); /* HACK ALERT! * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword * */ keyPwd = (SEC_PKCS5KeyAndPassword *)key; key = keyPwd->key; /* find correct PK11 mechanism and parameters to initialize pbeMech */ pbeMech.mechanism = PK11_AlgtagToMechanism(algtag); pbeParams = PK11_ParamFromAlgid(algid); if (!pbeParams) return NULL; pbeMech.pParameter = pbeParams->Data; pbeMech.ulParameterLen = pbeParams->Length; /* now map pbeMech to cryptoMech */ if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem, PR_FALSE) != CKR_OK) { SECITEM_ZfreeItem(pbeParams, PR_TRUE); return NULL; } SECITEM_ZfreeItem(pbeParams, PR_TRUE); /* and use it to initialize param & mechanism */ if ((param = (CSSM_DATA *)PORT_ZAlloc(sizeof(CSSM_DATA))) == NULL) return NULL; param->Data = (unsigned char *)cryptoMech.pParameter; param->Length = cryptoMech.ulParameterLen; mechanism = cryptoMech.mechanism; } else { mechanism = PK11_AlgtagToMechanism(algtag); if ((param = PK11_GenerateNewParam(mechanism, key)) == NULL) return NULL; needToEncodeAlgid = PR_TRUE; } cc = (SecCmsCipherContext *)PORT_ZAlloc(sizeof(SecCmsCipherContext)); if (cc == NULL) return NULL; /* now find pad and block sizes for our mechanism */ cc->pad_size = PK11_GetBlockSize(mechanism,param); slot = PK11_GetSlotFromKey(key); cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; PK11_FreeSlot(slot); /* and here we go, creating a PK11 cipher context */ ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT, key, param); if (ciphercx == NULL) { PORT_Free(cc); cc = NULL; goto loser; } /* * These are placed after the CreateContextBySymKey() because some * mechanisms have to generate their IVs from their card (i.e. FORTEZZA). * Don't move it from here. * XXX is that right? the purpose of this is to get the correct algid * containing the IVs etc. for encoding. this means we need to set this up * BEFORE encoding the algid in the contentInfo, right? */ if (needToEncodeAlgid) { rv = PK11_ParamToAlgid(algtag, param, poolp, algid); if(rv != SECSuccess) { PORT_Free(cc); cc = NULL; goto loser; } } cc->cx = ciphercx; cc->doit = (nss_cms_cipher_function)PK11_CipherOp; cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext; cc->encrypt = PR_TRUE; cc->pending_count = 0; loser: SECITEM_FreeItem(param, PR_TRUE); return cc; #endif }
/* * Create a cipher object to do encryption, based on the given bulk * encryption key and algorithm tag. Fill in the algorithm identifier * (which may include an iv) appropriately. * * XXX This interface, or one similar, would be really nice available * in general... I tried to keep the pkcs7-specific stuff (mostly * having to do with padding) out of here. * * XXX Once both are working, it might be nice to combine this and the * function above (for starting up decryption) into one routine, and just * have two simple cover functions which call it. */ sec_PKCS7CipherObject * sec_PKCS7CreateEncryptObject (PRArenaPool *poolp, PK11SymKey *key, SECOidTag algtag, SECAlgorithmID *algid) { sec_PKCS7CipherObject *result; void *ciphercx; SECStatus rv; CK_MECHANISM_TYPE cryptoMechType; PK11SlotInfo *slot; SECItem *param = NULL; PRBool needToEncodeAlgid = PR_FALSE; result = (struct sec_pkcs7_cipher_object*) PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object)); if (result == NULL) return NULL; ciphercx = NULL; if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { SECItem *pwitem; pwitem = (SECItem *)PK11_GetSymKeyUserData(key); if (!pwitem) { PORT_Free(result); return NULL; } cryptoMechType = PK11_GetPBECryptoMechanism(algid, ¶m, pwitem); if (cryptoMechType == CKM_INVALID_MECHANISM) { PORT_Free(result); SECITEM_FreeItem(param,PR_TRUE); return NULL; } } else { cryptoMechType = PK11_AlgtagToMechanism(algtag); param = PK11_GenerateNewParam(cryptoMechType, key); if (param == NULL) { PORT_Free(result); return NULL; } needToEncodeAlgid = PR_TRUE; } result->pad_size = PK11_GetBlockSize(cryptoMechType,param); slot = PK11_GetSlotFromKey(key); result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size; PK11_FreeSlot(slot); ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, key, param); if (ciphercx == NULL) { PORT_Free (result); SECITEM_FreeItem(param,PR_TRUE); return NULL; } /* * These are placed after the CreateContextBySymKey() because some * mechanisms have to generate their IVs from their card (i.e. FORTEZZA). * Don't move it from here. */ if (needToEncodeAlgid) { rv = PK11_ParamToAlgid(algtag,param,poolp,algid); if(rv != SECSuccess) { PORT_Free (result); SECITEM_FreeItem(param,PR_TRUE); return NULL; } } SECITEM_FreeItem(param,PR_TRUE); result->cx = ciphercx; result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp; result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext; result->encrypt = PR_TRUE; result->pending_count = 0; return result; }
static void ike_alg_nss_cbc(const struct encrypt_desc *alg, u_int8_t *in_buf, size_t in_buf_len, PK11SymKey *symkey, u_int8_t *iv, bool enc) { DBG(DBG_CRYPT, DBG_log("NSS ike_alg_nss_cbc: %s - enter", alg->common.name)); if (symkey == NULL) { PASSERT_FAIL("%s - NSS derived enc key in NULL", alg->common.name); } SECItem ivitem; ivitem.type = siBuffer; ivitem.data = iv; ivitem.len = alg->enc_blocksize; SECItem *secparam = PK11_ParamFromIV(alg->common.nss_mechanism, &ivitem); if (secparam == NULL) { PASSERT_FAIL("%s - Failure to set up PKCS11 param (err %d)", alg->common.name, PR_GetError()); } PK11Context *enccontext; enccontext = PK11_CreateContextBySymKey(alg->common.nss_mechanism, enc ? CKA_ENCRYPT : CKA_DECRYPT, symkey, secparam); if (enccontext == NULL) { PASSERT_FAIL("%s - PKCS11 context creation failure (err %d)", alg->common.name, PR_GetError()); } /* Output buffer for transformed data. */ u_int8_t *out_buf = PR_Malloc((PRUint32)in_buf_len); int out_buf_len = 0; SECStatus rv = PK11_CipherOp(enccontext, out_buf, &out_buf_len, in_buf_len, in_buf, in_buf_len); if (rv != SECSuccess) { PASSERT_FAIL("%s - PKCS11 operation failure (err %d)", alg->common.name, PR_GetError()); } PK11_DestroyContext(enccontext, PR_TRUE); /* * Update the IV ready for the next call to this function. */ u_int8_t *new_iv; if (enc) { /* * The IV for the next encryption call is the last * block of encrypted output data. */ new_iv = out_buf + out_buf_len - alg->enc_blocksize; } else { /* * The IV for the next decryption call is the last * block of the encrypted input data. */ new_iv = in_buf + in_buf_len - alg->enc_blocksize; } memcpy(iv, new_iv, alg->enc_blocksize); /* * Finally, copy the transformed data back to the buffer. Do * this after extracting the IV. */ memcpy(in_buf, out_buf, in_buf_len); PR_Free(out_buf); if (secparam != NULL) SECITEM_FreeItem(secparam, PR_TRUE); DBG(DBG_CRYPT, DBG_log("NSS ike_alg_nss_cbc: %s - exit", alg->common.name)); }
/* * NSS_CMSCipherContext_StartEncrypt - create a cipher object to do encryption, * based on the given bulk encryption key and algorithm tag. Fill in the * algorithm identifier (which may include an iv) appropriately. * * XXX Once both are working, it might be nice to combine this and the * function above (for starting up decryption) into one routine, and just * have two simple cover functions which call it. */ NSSCMSCipherContext * NSS_CMSCipherContext_StartEncrypt(PLArenaPool *poolp, PK11SymKey *key, SECAlgorithmID *algid) { NSSCMSCipherContext *cc; void *ciphercx; SECStatus rv; CK_MECHANISM_TYPE cryptoMechType; PK11SlotInfo *slot; SECItem *param = NULL; PRBool needToEncodeAlgid = PR_FALSE; SECOidTag algtag = SECOID_GetAlgorithmTag(algid); /* set param and mechanism */ if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { SECItem *pwitem; pwitem = PK11_GetSymKeyUserData(key); if (!pwitem) return NULL; cryptoMechType = PK11_GetPBECryptoMechanism(algid, ¶m, pwitem); if (cryptoMechType == CKM_INVALID_MECHANISM) { SECITEM_FreeItem(param,PR_TRUE); return NULL; } } else { cryptoMechType = PK11_AlgtagToMechanism(algtag); if ((param = PK11_GenerateNewParam(cryptoMechType, key)) == NULL) return NULL; needToEncodeAlgid = PR_TRUE; } cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext)); if (cc == NULL) { goto loser; } /* now find pad and block sizes for our mechanism */ cc->pad_size = PK11_GetBlockSize(cryptoMechType, param); slot = PK11_GetSlotFromKey(key); cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; PK11_FreeSlot(slot); /* and here we go, creating a PK11 cipher context */ ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, key, param); if (ciphercx == NULL) { PORT_Free(cc); cc = NULL; goto loser; } /* * These are placed after the CreateContextBySymKey() because some * mechanisms have to generate their IVs from their card (i.e. FORTEZZA). * Don't move it from here. * XXX is that right? the purpose of this is to get the correct algid * containing the IVs etc. for encoding. this means we need to set this up * BEFORE encoding the algid in the contentInfo, right? */ if (needToEncodeAlgid) { rv = PK11_ParamToAlgid(algtag, param, poolp, algid); if(rv != SECSuccess) { PORT_Free(cc); cc = NULL; goto loser; } } cc->cx = ciphercx; cc->doit = (nss_cms_cipher_function)PK11_CipherOp; cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext; cc->encrypt = PR_TRUE; cc->pending_count = 0; loser: SECITEM_FreeItem(param, PR_TRUE); return cc; }
static gboolean purple_aes_cipher_nss_crypt(const guchar *input, guchar *output, size_t len, guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size, CK_ATTRIBUTE_TYPE operation) { PurpleAESCipherNSSContext context; CK_MECHANISM_TYPE cipher_mech = CKM_AES_CBC; SECItem key_item, iv_item; SECStatus ret; int outlen = 0; unsigned int outlen_tmp = 0; memset(&context, 0, sizeof(PurpleAESCipherNSSContext)); if (NSS_NoDB_Init(NULL) != SECSuccess) { purple_debug_error("cipher-aes", "NSS_NoDB_Init failed: %d\n", PR_GetError()); return FALSE; } context.slot = PK11_GetBestSlot(cipher_mech, NULL); if (context.slot == NULL) { purple_debug_error("cipher-aes", "PK11_GetBestSlot failed: %d\n", PR_GetError()); return FALSE; } key_item.type = siBuffer; key_item.data = key; key_item.len = key_size; context.sym_key = PK11_ImportSymKey(context.slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); if (context.sym_key == NULL) { purple_debug_error("cipher-aes", "PK11_ImportSymKey failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } iv_item.type = siBuffer; iv_item.data = iv; iv_item.len = PURPLE_AES_BLOCK_SIZE; context.sec_param = PK11_ParamFromIV(cipher_mech, &iv_item); if (context.sec_param == NULL) { purple_debug_error("cipher-aes", "PK11_ParamFromIV failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } context.enc_context = PK11_CreateContextBySymKey(cipher_mech, operation, context.sym_key, context.sec_param); if (context.enc_context == NULL) { purple_debug_error("cipher-aes", "PK11_CreateContextBySymKey failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } ret = PK11_CipherOp(context.enc_context, output, &outlen, len, (guchar *)input, len); if (ret != SECSuccess) { purple_debug_error("cipher-aes", "PK11_CipherOp failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } ret = PK11_DigestFinal(context.enc_context, output + outlen, &outlen_tmp, len - outlen); if (ret != SECSuccess) { purple_debug_error("cipher-aes", "PK11_DigestFinal failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } purple_aes_cipher_nss_cleanup(&context); outlen += outlen_tmp; if (outlen != (int)len) { purple_debug_error("cipher-aes", "resulting length doesn't match: %d (expected: %lu)\n", outlen, len); return FALSE; } return TRUE; }
int nss_crypto_init(struct crypto_mech_data *mech_props, enum crypto_mech_op crypto_op, struct sss_nss_crypto_ctx *cctx) { CK_ATTRIBUTE_TYPE op; int ret; switch (crypto_op) { case op_encrypt: op = CKA_ENCRYPT; break; case op_decrypt: op = CKA_DECRYPT; break; case op_sign: op = CKA_SIGN; break; default: return EFAULT; } /* turn the raw key into a key object */ cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher, PK11_OriginUnwrap, op, cctx->key, NULL); if (cctx->keyobj == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to import key into NSS (err %d)\n", PR_GetError()); ret = EIO; goto done; } if (crypto_op == op_encrypt || crypto_op == op_decrypt) { /* turn the raw IV into a initialization vector object */ cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv); if (cctx->sparam == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to set up PKCS11 param (err %d)\n", PR_GetError()); ret = EIO; goto done; } } else { cctx->sparam = SECITEM_AllocItem(NULL, NULL, 0); if (cctx->sparam == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to allocate SECItem\n"); ret = EIO; goto done; } MAKE_SECITEM(NULL, 0, cctx->sparam); } /* Create cipher context */ cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op, cctx->keyobj, cctx->sparam); if (cctx->ectx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create cipher context (err %d)\n", PORT_GetError()); ret = EIO; goto done; } ret = EOK; done: return ret; }
/* the content of an encrypted data content info is encrypted. * it is assumed that for encrypted data, that the data has already * been set and is in the "plainContent" field of the content info. * * cinfo is the content info to encrypt * * key is the key with which to perform the encryption. if the * algorithm is a password based encryption algorithm, the * key is actually a password which will be processed per * PKCS #5. * * in the event of an error, SECFailure is returned. SECSuccess * indicates a success. */ SECStatus SEC_PKCS7EncryptContents(PRArenaPool *poolp, SEC_PKCS7ContentInfo *cinfo, SECItem *key, void *wincx) { SECAlgorithmID *algid = NULL; SECItem * result = NULL; SECItem * src; SECItem * dest; SECItem * blocked_data = NULL; void * mark; void * cx; PK11SymKey * eKey = NULL; PK11SlotInfo * slot = NULL; CK_MECHANISM_TYPE cryptoMechType; int bs; SECStatus rv = SECFailure; SECItem *c_param = NULL; if((cinfo == NULL) || (key == NULL)) return SECFailure; if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA) return SECFailure; algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo); if(algid == NULL) return SECFailure; if(poolp == NULL) poolp = cinfo->poolp; mark = PORT_ArenaMark(poolp); src = &cinfo->content.encryptedData->encContentInfo.plainContent; dest = &cinfo->content.encryptedData->encContentInfo.encContent; dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64)); dest->len = (src->len + 64); if(dest->data == NULL) { rv = SECFailure; goto loser; } slot = PK11_GetInternalKeySlot(); if(slot == NULL) { rv = SECFailure; goto loser; } eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx); if(eKey == NULL) { rv = SECFailure; goto loser; } cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key); if (cryptoMechType == CKM_INVALID_MECHANISM) { rv = SECFailure; goto loser; } /* block according to PKCS 8 */ bs = PK11_GetBlockSize(cryptoMechType, c_param); rv = SECSuccess; if(bs) { char pad_char; pad_char = (char)(bs - (src->len % bs)); if(src->len % bs) { rv = SECSuccess; blocked_data = PK11_BlockData(src, bs); if(blocked_data) { PORT_Memset((blocked_data->data + blocked_data->len - (int)pad_char), pad_char, (int)pad_char); } else { rv = SECFailure; goto loser; } } else { blocked_data = SECITEM_DupItem(src); if(blocked_data) { blocked_data->data = (unsigned char*)PORT_Realloc( blocked_data->data, blocked_data->len + bs); if(blocked_data->data) { blocked_data->len += bs; PORT_Memset((blocked_data->data + src->len), (char)bs, bs); } else { rv = SECFailure; goto loser; } } else { rv = SECFailure; goto loser; } } } else { blocked_data = SECITEM_DupItem(src); if(!blocked_data) { rv = SECFailure; goto loser; } } cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, eKey, c_param); if(cx == NULL) { rv = SECFailure; goto loser; } rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), (int)(src->len + 64), blocked_data->data, (int)blocked_data->len); PK11_DestroyContext((PK11Context*)cx, PR_TRUE); loser: /* let success fall through */ if(blocked_data != NULL) SECITEM_ZfreeItem(blocked_data, PR_TRUE); if(result != NULL) SECITEM_ZfreeItem(result, PR_TRUE); if(rv == SECFailure) PORT_ArenaRelease(poolp, mark); else PORT_ArenaUnmark(poolp, mark); if(eKey != NULL) PK11_FreeSymKey(eKey); if(slot != NULL) PK11_FreeSlot(slot); if(c_param != NULL) SECITEM_ZfreeItem(c_param, PR_TRUE); return rv; }