/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * This file implements PKCS 11 on top of our existing security modules * * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. * This implementation has two slots: * slot 1 is our generic crypto support. It does not require login. * It supports Public Key ops, and all they bulk ciphers and hashes. * It can also support Private Key ops for imported Private keys. It does * not have any token storage. * slot 2 is our private key support. It requires a login before use. It * can store Private Keys and Certs as token objects. Currently only private * keys and their associated Certificates are saved on the token. * * In this implementation, session objects are only visible to the session * that created or generated them.
*/
#include <limits.h> /* for UINT_MAX and ULONG_MAX */
/* create a definition of SHA1 that's consistent
* with the rest of the CKM_SHAxxx hashes*/ #define CKM_SHA1 CKM_SHA_1 #define CKM_SHA1_HMAC CKM_SHA_1_HMAC #define CKM_SHA1_HMAC_GENERAL CKM_SHA_1_HMAC_GENERAL
/* * turn a CDMF key into a des key. CDMF is an old IBM scheme to export DES by * Deprecating a full des key to 40 bit key strenth.
*/ static CK_RV
sftk_cdmf2des(unsignedchar *cdmfkey, unsignedchar *deskey)
{ unsignedchar key1[8] = { 0xc4, 0x08, 0xb0, 0x54, 0x0b, 0xa1, 0xe0, 0xae }; unsignedchar key2[8] = { 0xef, 0x2c, 0x04, 0x1c, 0xe6, 0x38, 0x2f, 0xe6 }; unsignedchar enc_src[8]; unsignedchar enc_dest[8]; unsignedint leng, i;
DESContext *descx;
SECStatus rv;
CK_RV crv = CKR_OK;
/* zero the parity bits */ for (i = 0; i < 8; i++) {
enc_src[i] = cdmfkey[i] & 0xfe;
}
/* xor source with des, zero the parity bits and deprecate the key*/ for (i = 0; i < 8; i++) { if (i & 1) {
enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0xfe;
} else {
enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0x0e;
}
}
/* set the corret parity on our new des key */
sftk_FormatDESKey(deskey, 8);
done:
PORT_Memset(enc_src, 0, sizeof enc_src);
PORT_Memset(enc_dest, 0, sizeof enc_dest); return crv;
}
if (slot == NULL) { return CKR_SESSION_HANDLE_INVALID;
} /* * This whole block just makes sure we really can destroy the * requested object.
*/
session = sftk_SessionFromHandle(hSession); if (session == NULL) { return CKR_SESSION_HANDLE_INVALID;
}
/* don't destroy a private object if we aren't logged in */ if ((!slot->isLoggedIn) && (slot->needLogin) &&
(sftk_isTrue(object, CKA_PRIVATE))) {
sftk_FreeSession(session);
sftk_FreeObject(object); return CKR_USER_NOT_LOGGED_IN;
}
/* don't destroy a token object if we aren't in a rw session */
/* * get some indication if the object is destroyed. Note: this is not * 100%. Someone may have an object reference outstanding (though that * should not be the case by here. Also note that the object is "half" * destroyed. Our internal representation is destroyed, but it may still * be in the data base.
*/
status = sftk_FreeObject(object);
/* * Returns true if "params" contains a valid set of PSS parameters
*/ static PRBool
sftk_ValidatePssParams(const CK_RSA_PKCS_PSS_PARAMS *params)
{ if (!params) { return PR_FALSE;
} if (sftk_GetHashTypeFromMechanism(params->hashAlg) == HASH_AlgNULL ||
sftk_GetHashTypeFromMechanism(params->mgf) == HASH_AlgNULL) { return PR_FALSE;
} return PR_TRUE;
}
/* * Returns true if "params" contains a valid set of OAEP parameters
*/ static PRBool
sftk_ValidateOaepParams(const CK_RSA_PKCS_OAEP_PARAMS *params)
{ if (!params) { return PR_FALSE;
} /* The requirements of ulSourceLen/pSourceData come from PKCS #11, which * state: * If the parameter is empty, pSourceData must be NULL and * ulSourceDataLen must be zero.
*/ if (params->source != CKZ_DATA_SPECIFIED ||
(sftk_GetHashTypeFromMechanism(params->hashAlg) == HASH_AlgNULL) ||
(sftk_GetHashTypeFromMechanism(params->mgf) == HASH_AlgNULL) ||
(params->ulSourceDataLen == 0 && params->pSourceData != NULL) ||
(params->ulSourceDataLen != 0 && params->pSourceData == NULL)) { return PR_FALSE;
} return PR_TRUE;
}
/* * return a context based on the SFTKContext type.
*/
SFTKSessionContext *
sftk_ReturnContextByType(SFTKSession *session, SFTKContextType type)
{ switch (type) { case SFTK_ENCRYPT: case SFTK_DECRYPT: case SFTK_MESSAGE_ENCRYPT: case SFTK_MESSAGE_DECRYPT: return session->enc_context; case SFTK_HASH: return session->hash_context; case SFTK_SIGN: case SFTK_SIGN_RECOVER: case SFTK_VERIFY: case SFTK_VERIFY_RECOVER: case SFTK_MESSAGE_SIGN: case SFTK_MESSAGE_VERIFY: return session->hash_context;
} return NULL;
}
/* * change a context based on the SFTKContext type.
*/ void
sftk_SetContextByType(SFTKSession *session, SFTKContextType type,
SFTKSessionContext *context)
{ switch (type) { case SFTK_ENCRYPT: case SFTK_DECRYPT: case SFTK_MESSAGE_ENCRYPT: case SFTK_MESSAGE_DECRYPT:
session->enc_context = context; break; case SFTK_HASH:
session->hash_context = context; break; case SFTK_SIGN: case SFTK_SIGN_RECOVER: case SFTK_VERIFY: case SFTK_VERIFY_RECOVER: case SFTK_MESSAGE_SIGN: case SFTK_MESSAGE_VERIFY:
session->hash_context = context; break;
} return;
}
/* * code to grab the context. Needed by every C_XXXUpdate, C_XXXFinal, * and C_XXX function. The function takes a session handle, the context type, * and wether or not the session needs to be multipart. It returns the context, * and optionally returns the session pointer (if sessionPtr != NULL) if session * pointer is returned, the caller is responsible for freeing it.
*/
CK_RV
sftk_GetContext(CK_SESSION_HANDLE handle, SFTKSessionContext **contextPtr,
SFTKContextType type, PRBool needMulti, SFTKSession **sessionPtr)
{
SFTKSession *session;
SFTKSessionContext *context;
session = sftk_SessionFromHandle(handle); if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
context = sftk_ReturnContextByType(session, type); /* make sure the context is valid */ if ((context == NULL) || (context->type != type) || (needMulti && !(context->multi))) {
sftk_FreeSession(session); return CKR_OPERATION_NOT_INITIALIZED;
}
*contextPtr = context; if (sessionPtr != NULL) {
*sessionPtr = session;
} else {
sftk_FreeSession(session);
} return CKR_OK;
}
/** Terminate operation (in the PKCS#11 spec sense). * Intuitive name for FreeContext/SetNullContext pair.
*/ void
sftk_TerminateOp(SFTKSession *session, SFTKContextType ctype,
SFTKSessionContext *context)
{
session->lastOpWasFIPS = context->isFIPS;
sftk_FreeContext(context);
sftk_SetContextByType(session, ctype, NULL);
}
/* * All the NSC_InitXXX functions have a set of common checks and processing they * all need to do at the beginning. This is done here.
*/
CK_RV
sftk_InitGeneric(SFTKSession *session, CK_MECHANISM *pMechanism,
SFTKSessionContext **contextPtr,
SFTKContextType ctype, SFTKObject **keyPtr,
CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
{
SFTKObject *key = NULL;
SFTKAttribute *att;
SFTKSessionContext *context;
/* We can only init if there is not current context active */ if (sftk_ReturnContextByType(session, ctype) != NULL) { return CKR_OPERATION_ACTIVE;
}
/* find the key */ if (keyPtr) {
key = sftk_ObjectFromHandle(hKey, session); if (key == NULL) { return CKR_KEY_HANDLE_INVALID;
}
/* make sure it's a valid key for this operation */ if (((key->objclass != CKO_SECRET_KEY) &&
(key->objclass != pubKeyType)) ||
!sftk_isTrue(key, operation)) {
sftk_FreeObject(key); return CKR_KEY_TYPE_INCONSISTENT;
} /* get the key type */
att = sftk_FindAttribute(key, CKA_KEY_TYPE); if (att == NULL) {
sftk_FreeObject(key); return CKR_KEY_TYPE_INCONSISTENT;
}
PORT_Assert(att->attrib.ulValueLen == sizeof(CK_KEY_TYPE)); if (att->attrib.ulValueLen != sizeof(CK_KEY_TYPE)) {
sftk_FreeAttribute(att);
sftk_FreeObject(key); return CKR_ATTRIBUTE_VALUE_INVALID;
}
PORT_Memcpy(keyTypePtr, att->attrib.pValue, sizeof(CK_KEY_TYPE));
sftk_FreeAttribute(att);
*keyPtr = key;
}
#if NSS_SOFTOKEN_DOES_RC5 case CKM_RC5_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_RC5_ECB: case CKM_RC5_CBC: if (key_type != CKK_RC5) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_CBC_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
context->blockSize = rc5_param->ulWordsize * 2;
rc5Key.data = (unsignedchar *)att->attrib.pValue;
rc5Key.len = att->attrib.ulValueLen;
context->cipherInfo = RC5_CreateContext(&rc5Key, rc5_param->ulRounds,
rc5_param->ulWordsize, rc5_param->pIv,
pMechanism->mechanism == CKM_RC5_ECB ? NSS_RC5 : NSS_RC5_CBC);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
}
context->update = isEncrypt ? SFTKCipher_RC5_Encrypt : SFTKCipher_RC5_Decrypt;
context->destroy = SFTKCipher_RC5_DestroyContext; break; #endif case CKM_RC4: if (key_type != CKK_RC4) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
context->cipherInfo =
RC4_CreateContext((unsignedchar *)att->attrib.pValue,
att->attrib.ulValueLen);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; /* WRONG !!! */ break;
}
context->update = isEncrypt ? SFTKCipher_RC4_Encrypt : SFTKCipher_RC4_Decrypt;
context->destroy = SFTKCipher_RC4_DestroyContext; break; case CKM_CDMF_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_CDMF_ECB: case CKM_CDMF_CBC: if (key_type != CKK_CDMF) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = (pMechanism->mechanism == CKM_CDMF_ECB) ? NSS_DES : NSS_DES_CBC; goto finish_des; case CKM_DES_ECB: if (key_type != CKK_DES) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = NSS_DES; goto finish_des; case CKM_DES_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_DES_CBC: if (key_type != CKK_DES) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = NSS_DES_CBC; goto finish_des; case CKM_DES3_ECB: if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = NSS_DES_EDE3; goto finish_des; case CKM_DES3_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_DES3_CBC: if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = NSS_DES_EDE3_CBC;
finish_des: if ((t != NSS_DES && t != NSS_DES_EDE3) && (pMechanism->pParameter == NULL ||
pMechanism->ulParameterLen < 8)) {
crv = CKR_DOMAIN_PARAMS_INVALID; break;
}
context->blockSize = 8;
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
} if (key_type == CKK_DES2 &&
(t == NSS_DES_EDE3_CBC || t == NSS_DES_EDE3)) { /* extend DES2 key to DES3 key. */
memcpy(newdeskey, att->attrib.pValue, 16);
memcpy(newdeskey + 16, newdeskey, 8);
useNewKey = PR_TRUE;
} elseif (key_type == CKK_CDMF) {
crv = sftk_cdmf2des((unsignedchar *)att->attrib.pValue, newdeskey); if (crv != CKR_OK) {
sftk_FreeAttribute(att); break;
}
useNewKey = PR_TRUE;
}
context->cipherInfo = DES_CreateContext(
useNewKey ? newdeskey : (unsignedchar *)att->attrib.pValue,
(unsignedchar *)pMechanism->pParameter, t, isEncrypt); if (useNewKey)
memset(newdeskey, 0, sizeof newdeskey);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
}
context->update = isEncrypt ? SFTKCipher_DES_Encrypt : SFTKCipher_DES_Decrypt;
context->destroy = SFTKCipher_DES_DestroyContext; break; #ifndef NSS_DISABLE_DEPRECATED_SEED case CKM_SEED_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_SEED_CBC: if (!pMechanism->pParameter ||
pMechanism->ulParameterLen != 16) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
} /* fall thru */ case CKM_SEED_ECB:
context->blockSize = 16; if (key_type != CKK_SEED) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
context->cipherInfo = SEED_CreateContext(
(unsignedchar *)att->attrib.pValue,
(unsignedchar *)pMechanism->pParameter,
pMechanism->mechanism == CKM_SEED_ECB ? NSS_SEED : NSS_SEED_CBC,
isEncrypt);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
}
context->update = isEncrypt ? SFTKCipher_SEED_Encrypt : SFTKCipher_SEED_Decrypt;
context->destroy = SFTKCipher_SEED_DestroyContext; break; #endif/* NSS_DISABLE_DEPRECATED_SEED */ case CKM_CAMELLIA_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_CAMELLIA_CBC: if (!pMechanism->pParameter ||
pMechanism->ulParameterLen != 16) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
} /* fall thru */ case CKM_CAMELLIA_ECB:
context->blockSize = 16; if (key_type != CKK_CAMELLIA) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
context->cipherInfo = Camellia_CreateContext(
(unsignedchar *)att->attrib.pValue,
(unsignedchar *)pMechanism->pParameter,
pMechanism->mechanism ==
CKM_CAMELLIA_ECB
? NSS_CAMELLIA
: NSS_CAMELLIA_CBC,
isEncrypt, att->attrib.ulValueLen);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
}
context->update = isEncrypt ? SFTKCipher_Camellia_Encrypt : SFTKCipher_Camellia_Decrypt;
context->destroy = SFTKCipher_Camellia_DestroyContext; break;
case CKM_AES_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_AES_ECB: case CKM_AES_CBC:
context->blockSize = 16; case CKM_AES_CTS: case CKM_AES_CTR: case CKM_AES_GCM:
aes_param = pMechanism->pParameter; /* * Due to a mismatch between the documentation and the header * file, two different definitions for CK_GCM_PARAMS exist. * The header file is normative according to Oasis, but NSS used * the documentation. In PKCS #11 v3.0, this was reconciled in * favor of the header file definition. To maintain binary * compatibility, NSS now defines CK_GCM_PARAMS_V3 as the official * version v3 (V2.4 header file) and CK_NSS_GCM_PARAMS as the * legacy (V2.4 documentation, NSS version). CK_GCM_PARAMS * is defined as CK_GCM_PARAMS_V3 if NSS_PKCS11_2_0_COMPAT is not * defined and CK_NSS_GCM_PARAMS if it is. Internally * softoken continues to use the legacy version. The code below * automatically detects which parameter was passed in and * converts CK_GCM_PARAMS_V3 to the CK_NSS_GCM_PARAMS (legacy * version) on the fly. NSS proper will eventually start * using the CK_GCM_PARAMS_V3 version and fall back to the * CK_NSS_GCM_PARAMS if the CK_GCM_PARAMS_V3 version fails with * CKR_MECHANISM_PARAM_INVALID.
*/ if (pMechanism->mechanism == CKM_AES_GCM) { if (!aes_param) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
} if (pMechanism->ulParameterLen == sizeof(CK_GCM_PARAMS_V3)) { /* convert the true V3 parameters into the old NSS parameters */
CK_GCM_PARAMS_V3 *gcm_params = (CK_GCM_PARAMS_V3 *)aes_param; if (gcm_params->ulIvLen * 8 != gcm_params->ulIvBits) { /* only support byte aligned IV lengths */
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
aes_param = (void *)&nss_gcm_param;
nss_gcm_param.pIv = gcm_params->pIv;
nss_gcm_param.ulIvLen = gcm_params->ulIvLen;
nss_gcm_param.pAAD = gcm_params->pAAD;
nss_gcm_param.ulAADLen = gcm_params->ulAADLen;
nss_gcm_param.ulTagBits = gcm_params->ulTagBits;
} elseif (pMechanism->ulParameterLen != sizeof(CK_NSS_GCM_PARAMS)) { /* neither old nor new style params, must be invalid */
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
} elseif ((pMechanism->mechanism == CKM_AES_CTR && BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CTR_PARAMS))) ||
((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CTS) && BAD_PARAM_CAST(pMechanism, AES_BLOCK_SIZE))) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
/* make sure we don't overflow our parameters */ if ((sizeof(ctx->counter) < counter_len) ||
(sizeof(ctx->nonce) < nonce_len)) {
PORT_Free(ctx);
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
/* The counter is little endian. */ int i = 0; for (; i < counter_len; ++i) {
ctx->counter |= (PRUint32)counter[i] << (i * 8);
}
memcpy(ctx->nonce, nonce, nonce_len);
context->cipherInfo = ctx;
context->update = sftk_ChaCha20Ctr;
context->destroy = sftk_ChaCha20Ctr_DestroyContext; break;
}
case CKM_NSS_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_NSS_AES_KEY_WRAP: case CKM_AES_KEY_WRAP:
context->blockSize = 8; case CKM_AES_KEY_WRAP_KWP:
context->multi = PR_FALSE; if (key_type != CKK_AES) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
context->cipherInfo = AESKeyWrap_CreateContext(
(unsignedchar *)att->attrib.pValue,
(unsignedchar *)pMechanism->pParameter,
isEncrypt, att->attrib.ulValueLen);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
} if (pMechanism->mechanism == CKM_AES_KEY_WRAP_KWP) {
context->update = isEncrypt ? SFTKCipher_AESKeyWrap_EncryptKWP
: SFTKCipher_AESKeyWrap_DecryptKWP;
} else {
context->update = isEncrypt ? SFTKCipher_AESKeyWrap_Encrypt
: SFTKCipher_AESKeyWrap_Decrypt;
}
context->destroy = SFTKCipher_AESKeyWrap_DestroyContext; break;
/* do padding */ if (context->doPad) { /* deal with previous buffered data */ if (context->padDataLength != 0) { /* fill in the padded to a full block size */ for (i = context->padDataLength;
(ulPartLen != 0) && i < context->blockSize; i++) {
context->padBuf[i] = *pPart++;
ulPartLen--;
context->padDataLength++;
}
/* not enough data to encrypt yet? then return */ if (context->padDataLength != context->blockSize) {
*pulEncryptedPartLen = 0; return CKR_OK;
} /* encrypt the current padded data */
rv = (*context->update)(context->cipherInfo, pEncryptedPart,
&padoutlen, maxout, context->padBuf,
context->blockSize); if (rv != SECSuccess) { return sftk_MapCryptError(PORT_GetError());
}
pEncryptedPart += padoutlen;
maxout -= padoutlen;
} /* save the residual */
context->padDataLength = ulPartLen % context->blockSize; if (context->padDataLength) {
PORT_Memcpy(context->padBuf,
&pPart[ulPartLen - context->padDataLength],
context->padDataLength);
ulPartLen -= context->padDataLength;
} /* if we've exhausted our new buffer, we're done */ if (ulPartLen == 0) {
*pulEncryptedPartLen = padoutlen; return CKR_OK;
}
}
/* do it: NOTE: this assumes buf size in is >= buf size out! */
rv = (*context->update)(context->cipherInfo, pEncryptedPart,
&outlen, maxout, pPart, ulPartLen); if (rv != SECSuccess) { return sftk_MapCryptError(PORT_GetError());
}
*pulEncryptedPartLen = (CK_ULONG)(outlen + padoutlen); return CKR_OK;
}
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_ENCRYPT, PR_TRUE, &session); if (crv != CKR_OK) return crv;
*pulLastEncryptedPartLen = 0; if (!pLastEncryptedPart) { /* caller is checking the amount of remaining data */ if (context->blockSize > 0 && context->doPad) {
*pulLastEncryptedPartLen = context->blockSize;
contextFinished = PR_FALSE; /* still have padding to go */
} goto finish;
}
/* do padding */ if (context->doPad) { unsignedchar padbyte = (unsignedchar)(context->blockSize - context->padDataLength); /* fill out rest of pad buffer with pad magic*/ for (i = context->padDataLength; i < context->blockSize; i++) {
context->padBuf[i] = padbyte;
}
rv = (*context->update)(context->cipherInfo, pLastEncryptedPart,
&outlen, maxout, context->padBuf, context->blockSize); if (rv == SECSuccess)
*pulLastEncryptedPartLen = (CK_ULONG)outlen;
}
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_DECRYPT, PR_TRUE, NULL); if (crv != CKR_OK) return crv;
/* this can only happen on an NSS programming error */
PORT_Assert((context->padDataLength == 0) || context->padDataLength == context->blockSize);
if (context->doPad) { /* Check the data length for block ciphers. If we are padding, * then we must be using a block cipher. In the non-padding case * the error will be returned by the underlying decryption * function when we do the actual decrypt. We need to do the * check here to avoid returning a negative length to the caller * or reading before the beginning of the pEncryptedPart buffer.
*/ if ((ulEncryptedPartLen == 0) ||
(ulEncryptedPartLen % context->blockSize) != 0) { return CKR_ENCRYPTED_DATA_LEN_RANGE;
}
}
if (!pPart) { if (context->doPad) {
*pulPartLen =
ulEncryptedPartLen + context->padDataLength - context->blockSize; return CKR_OK;
} /* for stream ciphers there is are no constraints on ulEncryptedPartLen. * for block ciphers, it must be a multiple of blockSize. The error is * detected when this function is called again do decrypt the output.
*/
*pulPartLen = ulEncryptedPartLen; return CKR_OK;
}
if (context->doPad) { /* first decrypt our saved buffer */ if (context->padDataLength != 0) {
rv = (*context->update)(context->cipherInfo, pPart, &padoutlen,
maxout, context->padBuf, context->blockSize); if (rv != SECSuccess) return sftk_MapDecryptError(PORT_GetError());
pPart += padoutlen;
maxout -= padoutlen;
}
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.