| RSA BSAFE Crypto-C |
Cryptographic Components for C |
| Search |
/* $Id: bslite.c,v 1.4 2004/12/03 02:08:35 sparki Exp $ */ /* * Copyright (C) 1998-2004 RSA Security Inc. * * This file shall only be used to demonstrate how to interface to an * RSA Security Inc. licensed development product. * * You have a royalty-free right to use, reproduce and distribute this * demonstration file, provided that you agree that RSA Security Inc. * has no warranty, implied or otherwise, or liability for this * demonstration file (including any modified version). This software * is provided "as is" without warranties or representations of any * kind. RSA Security disclaims all conditions and warranties, statutory * and otherwise, both express and implied, with respect to the software, * its quality and performance, including but not limited to, all * implied warranties of merchantability, fitness for a particular * purpose, title and noninfringement of third party rights. Without * limiting the foregoing, RSA Security does not warrant that the * software is error-free or that errors in the product will be * corrected. You agree that RSA Security shall not be liable for any * direct, indirect, incidental, special, consequential, punitive or * other damages whatsoever resulting from your use of this software * or any modified version. * * */ #include "aglobal.h" #include "bsafe.h" #include "bslite.h" #include "demochos.h" /***********************************************************************/ /* symmetric key generation, block and stream cipher */ /***********************************************************************/ int BSL_MakeKeyFromSeed(unsigned char *key, unsigned int keyLen, unsigned char *seed, unsigned int seedLen) { B_ALGORITHM_OBJ randomAlgorithmObj = NULL_PTR; int status; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create random algorithm object and set algorithm info */ status = B_CreateAlgorithmObject (&randomAlgorithmObj); if (status != 0) break; status = B_SetAlgorithmInfo (randomAlgorithmObj, AI_MD2Random, NULL_PTR); if (status != 0) break; /****************************************************************** NOTE: The choice of MD2 for hashing random numbers is arbitrary. AI_MD5Random may also be used. See Internet RFC1319 and RFC1321. ******************************************************************/ /* call random init, update with supplied seed bytes */ status = B_RandomInit (randomAlgorithmObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_RandomUpdate (randomAlgorithmObj, seed, seedLen, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* generate random bytes for key */ status = B_GenerateRandomBytes (randomAlgorithmObj, key, keyLen, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup object */ B_DestroyAlgorithmObject (&randomAlgorithmObj); return (status); } /***********************************************************************/ int BSL_BlockEncryptSetup(B_ALGORITHM_OBJ *algorithmObject, unsigned char *key, unsigned char *IV, int algorithm) { A_RC2_CBC_PARAMS rc2Params; B_KEY_OBJ secretKeyObj = NULL_PTR; ITEM keyItem; int status; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create symmetric encryption algorithm object */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; /* set algorithm object according to supplied algorithm */ switch (algorithm) { case EA_DES_CBC: status = B_SetAlgorithmInfo (*algorithmObject, AI_DES_CBCPadIV8, (POINTER)IV); break; case EA_RC2_CBC_64: rc2Params.iv = IV; rc2Params.effectiveKeyBits = 64; status = B_SetAlgorithmInfo (*algorithmObject, AI_RC2_CBCPad, (POINTER)&rc2Params); break; default: status = BE_ALG_OPERATION_UNKNOWN; break; } if (status != 0) break; /* create key object */ status = B_CreateKeyObject (&secretKeyObj); if (status != 0) break; /* setup key item (always 8 bytes) and set key info */ keyItem.data = key; keyItem.len = 8; status = B_SetKeyInfo (secretKeyObj, KI_Item, (POINTER)&keyItem); if (status != 0) break; /* call the encrypt init */ status = B_EncryptInit (*algorithmObject, secretKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); /* cleanup object */ B_DestroyKeyObject (&secretKeyObj); return (status); } /***********************************************************************/ int BSL_BlockEncrypt(B_ALGORITHM_OBJ *algorithmObject, unsigned char *outputData, unsigned int *outputDataLen, unsigned char *inputData, unsigned int inputDataLen) { int status; /* if last call (inputData == NULL_PTR) finish up */ if (inputData == (unsigned char *)NULL_PTR) { status = B_EncryptFinal (*algorithmObject, outputData, outputDataLen, BLOCK_OUT_BYTES(0), (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup object */ B_DestroyAlgorithmObject (algorithmObject); return (status); } /* if not final call, process this input chunk */ status = B_EncryptUpdate (*algorithmObject, outputData, outputDataLen, BLOCK_OUT_BYTES(inputDataLen), inputData, inputDataLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ int BSL_BlockDecryptSetup(B_ALGORITHM_OBJ *algorithmObject, unsigned char *key, unsigned char *IV, int algorithm) { A_RC2_CBC_PARAMS rc2Params; B_KEY_OBJ secretKeyObj = NULL_PTR; ITEM keyItem; int status; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create symmetric encryption algorithm object */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; /* set algorithm object according to supplied algorithm */ switch (algorithm) { case EA_DES_CBC: status = B_SetAlgorithmInfo (*algorithmObject, AI_DES_CBCPadIV8, (POINTER)IV); break; case EA_RC2_CBC_64: rc2Params.iv = IV; rc2Params.effectiveKeyBits = 64; status = B_SetAlgorithmInfo (*algorithmObject, AI_RC2_CBCPad, (POINTER)&rc2Params); break; default: status = BE_ALG_OPERATION_UNKNOWN; break; } if (status != 0) break; /* create key object */ status = B_CreateKeyObject (&secretKeyObj); if (status != 0) break; /* setup key item (always 8 bytes) and set key info */ keyItem.data = key; keyItem.len = 8; status = B_SetKeyInfo (secretKeyObj, KI_Item, (POINTER)&keyItem); if (status != 0) break; /* call the decrypt init */ status = B_DecryptInit (*algorithmObject, secretKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); /* cleanup object */ B_DestroyKeyObject (&secretKeyObj); return (status); } /***********************************************************************/ int BSL_BlockDecrypt(B_ALGORITHM_OBJ *algorithmObject, unsigned char *outputData, unsigned int *outputDataLen, unsigned char *inputData, unsigned int inputDataLen) { int status; /* if last call (inputData == NULL_PTR) finish up */ if (inputData == (unsigned char *)NULL_PTR) { status = B_DecryptFinal (*algorithmObject, outputData, outputDataLen, BLOCK_OUT_BYTES(0), (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup object */ B_DestroyAlgorithmObject (algorithmObject); return (status); } /* if not final call, process this input chunk */ status = B_DecryptUpdate (*algorithmObject, outputData, outputDataLen, BLOCK_OUT_BYTES(inputDataLen), inputData, inputDataLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ int BSL_RC4CipherSetup(B_ALGORITHM_OBJ *algorithmObject, unsigned char *key, unsigned int keyLen) { B_KEY_OBJ secretKeyObj = NULL_PTR; ITEM keyItem; int status; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create symmetric encryption algorithm object */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; status = B_SetAlgorithmInfo (*algorithmObject, AI_RC4, NULL_PTR); if (status != 0) break; /* create key object */ status = B_CreateKeyObject (&secretKeyObj); if (status != 0) break; /* setup key item and set key info */ keyItem.data = key; keyItem.len = keyLen; status = B_SetKeyInfo (secretKeyObj, KI_Item, (POINTER)&keyItem); if (status != 0) break; /* call the encrypt init */ status = B_EncryptInit (*algorithmObject, secretKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); /* cleanup object */ B_DestroyKeyObject (&secretKeyObj); return (status); } /***********************************************************************/ int BSL_RC4Cipher(B_ALGORITHM_OBJ *algorithmObject, unsigned char *data, unsigned int dataLen) { int status; unsigned int outLen; /* if last call (data == NULL_PTR) finish up */ if (data == (unsigned char *)NULL_PTR) { /* call the encrypt final. For RC4, expect zero output bytes from final. Note that the result placed in outLen is ignored. */ status = B_EncryptFinal (*algorithmObject, data, &outLen, 0, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup object */ B_DestroyAlgorithmObject (algorithmObject); return (status); } /* otherwise, process this input chunk, encrypting "in place" by providing 'data' as the input and output part. Note that the result placed in outLen is ignored.*/ status = B_EncryptUpdate (*algorithmObject, data, &outLen, dataLen, data, dataLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ /* Diffie-Hellman parameter generation and 2 phase key negotiation */ /***********************************************************************/ int BSL_MakeDHParamsFromSeed(unsigned char *params, unsigned int *paramsLen, unsigned int paramSizeBits, unsigned char *seed, unsigned int seedLen) { A_DH_PARAM_GEN_PARAMS paramGenParams; B_ALGORITHM_OBJ generateAlgorithmObj = NULL_PTR; B_ALGORITHM_OBJ randomAlgorithmObj = NULL_PTR; B_ALGORITHM_OBJ resultAlgorithmObj = NULL_PTR; ITEM *paramsItem; int status; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create random algorithm objects and set algorithm info */ status = B_CreateAlgorithmObject (&randomAlgorithmObj); if (status != 0) break; status = B_SetAlgorithmInfo (randomAlgorithmObj, AI_MD2Random, NULL_PTR); if (status != 0) break; /****************************************************************** NOTE: The choice of MD2 for hashing random numbers is arbitrary. AI_MD5Random may also be used. See Internet RFC1319 and RFC1321. ******************************************************************/ /* call random init, update with supplied seed bytes */ status = B_RandomInit (randomAlgorithmObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_RandomUpdate (randomAlgorithmObj, seed, seedLen, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* create generate algorithm object */ status = B_CreateAlgorithmObject (&generateAlgorithmObj); if (status != 0) break; /* set up key generation parameters and set algorithm object */ paramGenParams.primeBits = paramSizeBits; paramGenParams.exponentBits = paramSizeBits - 1; status = B_SetAlgorithmInfo (generateAlgorithmObj, AI_DHParamGen, (POINTER)¶mGenParams); if (status != 0) break; /****************************************************************** NOTE: The choice of paramSizeBits - 1 for the exponent size in bits is arbitrary and may have security considerations. See PKCS #3. ******************************************************************/ /* generate init */ status = B_GenerateInit (generateAlgorithmObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* create algorithm object to hold resulting parameters */ status = B_CreateAlgorithmObject (&resultAlgorithmObj); if (status != 0) break; /* actual DH parameter generation (may take a long time) */ status = B_GenerateParameters (generateAlgorithmObj, resultAlgorithmObj, randomAlgorithmObj, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* get the Distinguished Encoding (DER) of the DH parameters See PKCS #3. */ status = B_GetAlgorithmInfo ((POINTER *)¶msItem, resultAlgorithmObj, AI_DHKeyAgreeBER); if (status != 0) break; /* copy paramters to supplied buffers */ T_memcpy ((POINTER)params, (POINTER)paramsItem->data, paramsItem->len); *paramsLen = paramsItem->len; } while (0); /* cleanup objects */ B_DestroyAlgorithmObject (&generateAlgorithmObj); B_DestroyAlgorithmObject (&randomAlgorithmObj); B_DestroyAlgorithmObject (&resultAlgorithmObj); return (status); } /***********************************************************************/ int BSL_DiffieHellman1(B_ALGORITHM_OBJ *algorithmObject, unsigned char *output, unsigned int *outputLen, unsigned char *seed, unsigned int seedLen, unsigned char *params, unsigned int paramsLen) { B_ALGORITHM_OBJ randomAlgorithmObj = NULL_PTR; ITEM paramsItem; int status; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create Diffie-Hellman algorithm object */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; /* setup parameters item and use it to set algorithm info */ paramsItem.data = params; paramsItem.len = paramsLen; status = B_SetAlgorithmInfo (*algorithmObject, AI_DHKeyAgreeBER, (POINTER)¶msItem); if (status != 0) break; /* call the key agreement init */ status = B_KeyAgreeInit (*algorithmObject, (B_KEY_OBJ)NULL_PTR, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* create random algorithm object and set algorithm info */ status = B_CreateAlgorithmObject (&randomAlgorithmObj); if (status != 0) break; status = B_SetAlgorithmInfo (randomAlgorithmObj, AI_MD2Random, NULL_PTR); if (status != 0) break; /****************************************************************** NOTE: The choice of MD2 for hashing random numbers is arbitrary. AI_MD5Random may also be used. See Internet RFC1319 and RFC1321. ******************************************************************/ /* call random init, update with supplied seed bytes */ status = B_RandomInit (randomAlgorithmObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_RandomUpdate (randomAlgorithmObj, seed, seedLen, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* call the Key Agree Phase 1 */ status = B_KeyAgreePhase1 (*algorithmObject, output, outputLen, MAX_DH_OUTPUT_BYTES, randomAlgorithmObj, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup DH algorithm only if an error occured */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); /* cleanup object */ B_DestroyAlgorithmObject (&randomAlgorithmObj); return (status); } /***********************************************************************/ int BSL_DiffieHellman2(B_ALGORITHM_OBJ *algorithmObject, unsigned char *output, unsigned int *outputLen, unsigned char *input, unsigned int inputLen) { int status; /* call the Key Agree Phase 2 */ status = B_KeyAgreePhase2 (*algorithmObject, output, outputLen, MAX_DH_OUTPUT_BYTES, input, inputLen, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup object */ B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ /* MD2 or MD5 message digest calculation */ /***********************************************************************/ int BSL_ComputeDigestInit(B_ALGORITHM_OBJ *algorithmObject, int digestAlgorithm) { int status; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create digest algorithm object */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; /* set algorithm info according to desired digest algorithm */ switch (digestAlgorithm) { case DA_MD2: status = B_SetAlgorithmInfo (*algorithmObject, AI_MD2, NULL_PTR); break; case DA_MD5: status = B_SetAlgorithmInfo (*algorithmObject, AI_MD5, NULL_PTR); break; default: status = BE_ALG_OPERATION_UNKNOWN; break; } if (status != 0) break; /* call the digest init */ status = B_DigestInit (*algorithmObject, (B_KEY_OBJ)NULL_PTR, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ int BSL_ComputeDigestUpdate(B_ALGORITHM_OBJ *algorithmObject, unsigned char *input, unsigned int inputLen) { int status; /* call the digest update with the supplied input. Note that B_DigestUpdate requires a B_ALGORITHM_OBJ, not a pointer to one, so we pass *algorithmObject. */ status = B_DigestUpdate (*algorithmObject, input, inputLen, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ int BSL_ComputeDigestFinal(B_ALGORITHM_OBJ *algorithmObject, unsigned char *digest) { int status; unsigned int digestLen; status = B_DigestFinal (*algorithmObject, digest, &digestLen, 16, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup object */ B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ /* RSA key generation, password-based private key protection, */ /* digital signatures and digital envelopes */ /***********************************************************************/ /* the public key encryption exponent Fermat 4 (F4) = 65537 */ unsigned char EXPONENT_F4[3] = {0x1, 0x0, 0x1}; /* define parameters for password-based encryption */ #define PBE_ITERATION_COUNT 1000 int BSL_MakeRSAKeyPairFromSeed(unsigned char *publicKey, unsigned int *publicKeyLen, unsigned char *ppPrivateKey, unsigned int *ppPrivateKeyLen, unsigned char *pbeParams, unsigned int *pbeParamsLen, unsigned int keySizeBits, unsigned char *seed, unsigned int seedLen, unsigned char *password, unsigned int passwordLen) { A_RSA_KEY_GEN_PARAMS keyGenParams; B_ALGORITHM_OBJ generateAlgorithmObj = NULL_PTR; B_ALGORITHM_OBJ pbEncryptionAlgorithmObj = NULL_PTR; B_ALGORITHM_OBJ randomAlgorithmObj = NULL_PTR; B_ALGORITHM_OBJ saltDigestAlgorithmObj = NULL_PTR; B_KEY_OBJ passwordKeyObj = NULL_PTR; B_KEY_OBJ privateKeyObj = NULL_PTR; B_KEY_OBJ publicKeyObj = NULL_PTR; B_PBE_PARAMS pbeParamsStruct; ITEM passwordItem, *keyItemPtr, *pbeBERItemPtr; int status; unsigned char pbeSaltBuf[16]; unsigned int digestLen, outputLen; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create random algorithm objects and set algorithm info */ status = B_CreateAlgorithmObject (&randomAlgorithmObj); if (status != 0) break; status = B_SetAlgorithmInfo (randomAlgorithmObj, AI_MD2Random, NULL_PTR); if (status != 0) break; /****************************************************************** NOTE: The choice of MD2 for hashing random numbers is arbitrary. AI_MD5Random may also be used. See Internet RFC1319 and RFC1321. ******************************************************************/ /* call random init, update with supplied seed bytes */ status = B_RandomInit (randomAlgorithmObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_RandomUpdate (randomAlgorithmObj, seed, seedLen, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* create generate algorithm object */ status = B_CreateAlgorithmObject (&generateAlgorithmObj); if (status != 0) break; /* set up key generation parameters and set algorithm object */ keyGenParams.modulusBits = keySizeBits; keyGenParams.publicExponent.data = EXPONENT_F4; keyGenParams.publicExponent.len = sizeof (EXPONENT_F4); status = B_SetAlgorithmInfo (generateAlgorithmObj, AI_RSAKeyGen, (POINTER)&keyGenParams); if (status != 0) break; /****************************************************************** NOTE: The choice of F4 (65537) for a public exponent is arbitrary. The value 3 or other value may also be used. See PKCS #1. ******************************************************************/ /* generate init */ status = B_GenerateInit (generateAlgorithmObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* create private and public key objects */ status = B_CreateKeyObject (&privateKeyObj); if (status != 0) break; status = B_CreateKeyObject (&publicKeyObj); if (status != 0) break; /* generate keys and store in key objects (may take a few moments) */ status = B_GenerateKeypair (generateAlgorithmObj, publicKeyObj, privateKeyObj, randomAlgorithmObj, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* request the Distinguished Encoding (DER) of the public key (see PKCS #1) and store it in the supplied buffer */ status = B_GetKeyInfo ((POINTER *)&keyItemPtr, publicKeyObj, KI_RSAPublicBER); if (status != 0) break; T_memcpy ((POINTER)publicKey, (POINTER)keyItemPtr->data, keyItemPtr->len); *publicKeyLen = keyItemPtr->len; /* request the Distinguished Encoding (DER) of the private key info (see PKCS #8) */ status = B_GetKeyInfo ((POINTER *)&keyItemPtr, privateKeyObj, KI_PKCS_RSAPrivateBER); if (status != 0) break; /* if supplied password is NULL, copy unencrypted private key info to the supplied buffer */ if (password == (unsigned char *)NULL_PTR) { T_memcpy ((POINTER)ppPrivateKey, (POINTER)keyItemPtr->data, keyItemPtr->len); *ppPrivateKeyLen = keyItemPtr->len; } /* otherwise; encrypt the private key under the supplied password */ else { /* first, generate a password-based encryption salt value by digesting the private key and the supplied password */ status = B_CreateAlgorithmObject (&saltDigestAlgorithmObj); if (status != 0) break; status = B_SetAlgorithmInfo (saltDigestAlgorithmObj, AI_MD2, NULL_PTR); if (status != 0) break; /****************************************************************** Note: The choice of MD2 creating a password-based encryption salt value is arbitrary. AI_MD5 may also be used. In general, it is advantageous to use the same digest algorithm that is used in the actual password-based encryption operation. See PKCS #5. ******************************************************************/ status = B_DigestInit (saltDigestAlgorithmObj, NULL_PTR, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_DigestUpdate (saltDigestAlgorithmObj, password, passwordLen, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_DigestUpdate (saltDigestAlgorithmObj, keyItemPtr->data, keyItemPtr->len, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_DigestFinal (saltDigestAlgorithmObj, pbeSaltBuf, &digestLen, sizeof(pbeSaltBuf), (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* create password-based encryption algorithm object */ status = B_CreateAlgorithmObject (&pbEncryptionAlgorithmObj); if (status != 0) break; /* setup password-based encryption parameters */ pbeParamsStruct.salt = pbeSaltBuf; pbeParamsStruct.iterationCount = PBE_ITERATION_COUNT; /****************************************************************** Note: The password-based encryption iteration count supplied is hard-coded above. The chosen value is arbitrary and may have security ramifications. See PKCS #5. ******************************************************************/ /* set algorithm object */ status = B_SetAlgorithmInfo (pbEncryptionAlgorithmObj, AI_MD2WithDES_CBCPad, (POINTER)&pbeParamsStruct); if (status != 0) break; /* get the PBE parameters in their BER encoded form */ status = B_GetAlgorithmInfo ((POINTER *)&pbeBERItemPtr, pbEncryptionAlgorithmObj, AI_MD2WithDES_CBCPadBER); if (status != 0) break; /****************************************************************** Note: The choice of MD2 with DES for password-based private key protection is arbitrary. AI_MD2WithRC2_CBCPad, AI_MD5WithDES_CBCPad, or AI_MD5WithRC2_CBCPad may also be used. See PKCS #5. ******************************************************************/ /* return encoded pbe parameters and length to the caller in the supplied args. */ T_memcpy ((POINTER)pbeParams, (POINTER)pbeBERItemPtr->data, pbeBERItemPtr->len); *pbeParamsLen = pbeBERItemPtr->len; /* create key object */ status = B_CreateKeyObject (&passwordKeyObj); if (status != 0) break; /* setup password item and set key info */ passwordItem.data = password; passwordItem.len = passwordLen; status = B_SetKeyInfo (passwordKeyObj, KI_Item, (POINTER)&passwordItem); if (status != 0) break; /* encrypt the private key DER */ status = B_EncryptInit (pbEncryptionAlgorithmObj, passwordKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_EncryptUpdate (pbEncryptionAlgorithmObj, ppPrivateKey, &outputLen, PP_PRIV_KEY_BYTES(keySizeBits), keyItemPtr->data, keyItemPtr->len, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; *ppPrivateKeyLen = outputLen; status = B_EncryptFinal (pbEncryptionAlgorithmObj, ppPrivateKey + *ppPrivateKeyLen, &outputLen, PP_PRIV_KEY_BYTES(keySizeBits) - *ppPrivateKeyLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; *ppPrivateKeyLen += outputLen; } } while (0); /* cleanup objects */ B_DestroyAlgorithmObject (&generateAlgorithmObj); B_DestroyAlgorithmObject (&pbEncryptionAlgorithmObj); B_DestroyAlgorithmObject (&randomAlgorithmObj); B_DestroyAlgorithmObject (&saltDigestAlgorithmObj); B_DestroyKeyObject (&passwordKeyObj); B_DestroyKeyObject (&privateKeyObj); B_DestroyKeyObject (&publicKeyObj); return (status); } /***********************************************************************/ int BSL_MD5WithRSASignInit(B_ALGORITHM_OBJ *algorithmObject, unsigned char *ppPrivateKey, unsigned int ppPrivateKeyLen, unsigned char *password, unsigned int passwordLen, unsigned char *pbeParams, unsigned int pbeParamsLen) { B_ALGORITHM_OBJ pbEncryptionAlgorithmObj = NULL_PTR; B_KEY_OBJ passwordKeyObj = NULL_PTR; B_KEY_OBJ privateKeyObj = NULL_PTR; ITEM passwordItem, privateKeyItem, pbEncryptionInfoItem; int status; unsigned char *privateKeyBuf = NULL_PTR; unsigned int outputLen, privateKeyBufLen; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* set up an algorithm to create signature */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; /* set algorithm info to make signature with MD5 and RSA */ status = B_SetAlgorithmInfo (*algorithmObject, AI_MD5WithRSAEncryption, NULL_PTR); if (status != 0) break; /****************************************************************** Note: The choice of MD5 with RSA for signature computation is arbitrary. AI_MD2WithRSAEncryption may also be used. See PKCS #1. ******************************************************************/ /* create a key object for the private key */ status = B_CreateKeyObject (&privateKeyObj); if (status != 0) break; /* if supplied password is NULL, use the private key data supplied */ if (password == (unsigned char *)NULL_PTR) { privateKeyItem.data = ppPrivateKey; privateKeyItem.len = ppPrivateKeyLen; } else { /* otherwise, a password is supplied, so decrypt the private key with the password and set the key info with the result */ /* create password-based encryption algorithm object */ status = B_CreateAlgorithmObject (&pbEncryptionAlgorithmObj); if (status != 0) break; /* set up the ITEM which supplies the password-based encryption algorithm info. This contains the salt and iteration count which were specified when the private key was password-encrypted. */ pbEncryptionInfoItem.data = pbeParams; pbEncryptionInfoItem.len = pbeParamsLen; /* set algorithm object */ status = B_SetAlgorithmInfo (pbEncryptionAlgorithmObj, AI_MD2WithDES_CBCPadBER, (POINTER)&pbEncryptionInfoItem); if (status != 0) break; /****************************************************************** Note: The choice of MD2 with DES for password-based private key decryption corresponds to the password-based encryption algorithm used by the BSL_MakeRSAKeyPairFromSeed() routine above. The call to SetAlgorithmInfo() will return BE_WRONG_ALGORITHM_INFO if the algorithm information conveyed in the pbeParams argument is other than MD2 and DES. In this case it would be necessary to call SetAlgorithmInfo() with other candidate algorithm info choices (such as AI_MD5WithDES_CBCPadBER or AI_MD2WithRC2_CBCBER) until the call is successful. ******************************************************************/ /* create key object */ status = B_CreateKeyObject (&passwordKeyObj); if (status != 0) break; /* setup password item and set key info */ passwordItem.data = password; passwordItem.len = passwordLen; status = B_SetKeyInfo (passwordKeyObj, KI_Item, (POINTER)&passwordItem); if (status != 0) break; /* allocate a buffer to hold the decrypted private key. Since the decrypted size will be smaller than the encrypted size, we can allocate a buffer of the size of the encrypted key. */ if ((privateKeyBuf = (unsigned char *)T_malloc (ppPrivateKeyLen)) == (unsigned char *)NULL_PTR) { status = BE_ALLOC; break; } /* decrypt the private key DER */ status = B_DecryptInit (pbEncryptionAlgorithmObj, passwordKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_DecryptUpdate (pbEncryptionAlgorithmObj, privateKeyBuf, &outputLen, ppPrivateKeyLen, ppPrivateKey, ppPrivateKeyLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; privateKeyBufLen = outputLen; status = B_DecryptFinal (pbEncryptionAlgorithmObj, privateKeyBuf + privateKeyBufLen, &outputLen, ppPrivateKeyLen - privateKeyBufLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; privateKeyBufLen += outputLen; /* use the decrypted private key bytes */ privateKeyItem.data = privateKeyBuf; privateKeyItem.len = privateKeyBufLen; } /* set the private key info */ status = B_SetKeyInfo (privateKeyObj, KI_PKCS_RSAPrivateBER, (POINTER)&privateKeyItem); if (status != 0) break; /* call the signature init */ status = B_SignInit (*algorithmObject, privateKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); /* cleanup objects */ B_DestroyAlgorithmObject (&pbEncryptionAlgorithmObj); B_DestroyKeyObject (&passwordKeyObj); B_DestroyKeyObject (&privateKeyObj); /* if privateKeyBuf is not NULL, zeroize and free memory */ if (privateKeyBuf != (unsigned char *)NULL_PTR) { T_memset ((POINTER)privateKeyBuf, 0, ppPrivateKeyLen); T_free ((POINTER)privateKeyBuf); } return (status); } /***********************************************************************/ int BSL_MD5WithRSASignUpdate(B_ALGORITHM_OBJ *algorithmObject, unsigned char *input, unsigned int inputLen) { int status; /* call sign update to process input data */ status = B_SignUpdate (*algorithmObject, input, inputLen, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ int BSL_MD5WithRSASignFinal(B_ALGORITHM_OBJ *algorithmObject, unsigned char *signature, unsigned int *signatureLen) { int status; status = B_SignFinal (*algorithmObject, signature, signatureLen, MAX_RSA_OUTPUT_BYTES, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup object */ B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ int BSL_MD5WithRSAVerifyInit(B_ALGORITHM_OBJ *algorithmObject, unsigned char *publicKey, unsigned int publicKeyLen) { B_KEY_OBJ publicKeyObj = NULL_PTR; ITEM publicKeyItem; int status; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create algorithm object for verifying signature */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; /* set algorithm object to MD5 with RSA signature */ status = B_SetAlgorithmInfo (*algorithmObject, AI_MD5WithRSAEncryption, NULL_PTR); if (status != 0) break; /****************************************************************** Note: The choice of MD5 with RSA for signature verification corresponds to the use of MD5 and RSA for signature creation in the BSL_MD5WithRSASignInit() routine above. If this routine were intended to handle other signature algorithms, such as MD2 with RSA, it would be necessary to pass around algorithm identifier information with the signature. ******************************************************************/ /* create and set up a key object for public key decryption */ status = B_CreateKeyObject (&publicKeyObj); if (status != 0) break; publicKeyItem.data = publicKey; publicKeyItem.len = publicKeyLen; status = B_SetKeyInfo (publicKeyObj, KI_RSAPublicBER, (POINTER)&publicKeyItem); if (status != 0) break; /* call the verify init */ status = B_VerifyInit (*algorithmObject, publicKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); /* cleanup object */ B_DestroyKeyObject (&publicKeyObj); return (status); } /***********************************************************************/ int BSL_MD5WithRSAVerifyUpdate(B_ALGORITHM_OBJ *algorithmObject, unsigned char *input, unsigned int inputLen) { int status; /* call the verify update */ status = B_VerifyUpdate (*algorithmObject, input, inputLen, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ int BSL_MD5WithRSAVerifyFinal(B_ALGORITHM_OBJ *algorithmObject, unsigned char *signature, unsigned int signatureLen) { int status; /* call the verify final */ status = B_VerifyFinal (*algorithmObject, signature, signatureLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); /* cleanup object */ B_DestroyAlgorithmObject (algorithmObject); return (status); } /***********************************************************************/ int BSL_SealDESWithRSAEnvelopeSetup(B_ALGORITHM_OBJ *algorithmObject, unsigned char *encryptedKey, unsigned int *encryptedKeyLen, unsigned char *IV, unsigned char *seed, unsigned int seedLen, unsigned char *publicKey, unsigned int publicKeyLen) { B_ALGORITHM_OBJ keyEncryptionAlgorithmObj = NULL_PTR; B_ALGORITHM_OBJ randomAlgorithmObj = NULL_PTR; B_KEY_OBJ publicKeyObj = NULL_PTR; B_KEY_OBJ secretKeyObj = NULL_PTR; ITEM publicKeyItem; int status; unsigned char secretKeyBuf[8], *secretKeyPtr; unsigned int outLen; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create random algorithm object and set algorithm info */ status = B_CreateAlgorithmObject (&randomAlgorithmObj); if (status != 0) break; status = B_SetAlgorithmInfo (randomAlgorithmObj, AI_MD2Random, NULL_PTR); if (status != 0) break; /****************************************************************** NOTE: The choice of MD2 for hashing random numbers is arbitrary. AI_MD5Random may also be used. See Internet RFC1319 and RFC1321. ******************************************************************/ /* call random init, update with supplied seed bytes */ status = B_RandomInit (randomAlgorithmObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_RandomUpdate (randomAlgorithmObj, seed, seedLen, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* generate 8 random bytes for secret DES key */ status = B_GenerateRandomBytes (randomAlgorithmObj, secretKeyBuf, 8, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* create key object for data encryption */ status = B_CreateKeyObject (&secretKeyObj); if (status != 0) break; /* set the data encryption key object with the DES key and request to have the parity automatically adjusted */ status = B_SetKeyInfo (secretKeyObj, KI_DES8, (POINTER)secretKeyBuf); if (status != 0) break; /* request a pointer to the same DES key with parity adjusted See FIPS 46-1 */ status = B_GetKeyInfo ((POINTER *)&secretKeyPtr, secretKeyObj, KI_DES8); if (status != 0) break; /* generate 8 random bytes for Initialization Vector (IV) */ status = B_GenerateRandomBytes (randomAlgorithmObj, IV, 8, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; /* create an algorithm for encrypting the data encryption key */ status = B_CreateAlgorithmObject (&keyEncryptionAlgorithmObj); if (status != 0) break; /* set up algorithm for PKCS public key encryption */ status = B_SetAlgorithmInfo (keyEncryptionAlgorithmObj, AI_PKCS_RSAPublic, NULL_PTR); if (status != 0) break; /* create public key object */ status = B_CreateKeyObject (&publicKeyObj); if (status != 0) break; /* set up public key */ publicKeyItem.data = publicKey; publicKeyItem.len = publicKeyLen; status = B_SetKeyInfo (publicKeyObj, KI_RSAPublicBER, (POINTER)&publicKeyItem); if (status != 0) break; /* encrypt the data encryption key */ status = B_EncryptInit (keyEncryptionAlgorithmObj, publicKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_EncryptUpdate (keyEncryptionAlgorithmObj, encryptedKey, &outLen, MAX_RSA_OUTPUT_BYTES, secretKeyPtr, 8, randomAlgorithmObj, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; *encryptedKeyLen = outLen; status = B_EncryptFinal (keyEncryptionAlgorithmObj, encryptedKey + *encryptedKeyLen, &outLen, MAX_RSA_OUTPUT_BYTES - *encryptedKeyLen, randomAlgorithmObj, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; *encryptedKeyLen += outLen; /* create algorithm object for data encryption */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; /* set up algorithm for DES CBC data encryption */ status = B_SetAlgorithmInfo (*algorithmObject, AI_DES_CBCPadIV8, (POINTER)IV); if (status != 0) break; /****************************************************************** Note: The choice of DES CBC for envelope data encryption is arbitrary and may have security considerations. RC2 CBC may also be used. ******************************************************************/ /* call the encrypt init with the data encryption key */ status = B_EncryptInit (*algorithmObject, secretKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); /* cleanup objects */ B_DestroyAlgorithmObject (&keyEncryptionAlgorithmObj); B_DestroyAlgorithmObject (&randomAlgorithmObj); B_DestroyKeyObject (&publicKeyObj); B_DestroyKeyObject (&secretKeyObj); /* zeroize secret key buffer */ T_memset ((POINTER)secretKeyBuf, 0, sizeof (secretKeyBuf)); return (status); } /***********************************************************************/ int BSL_OpenDESWithRSAEnvelopeSetup(B_ALGORITHM_OBJ *algorithmObject, unsigned char *encryptedKey, unsigned int encryptedKeyLen, unsigned char *IV, unsigned char *ppPrivateKey, unsigned int ppPrivateKeyLen, unsigned char *password, unsigned int passwordLen, unsigned char *pbeParams, unsigned int pbeParamsLen) { B_ALGORITHM_OBJ keyDecryptAlgorithmObj = NULL_PTR; B_ALGORITHM_OBJ pbEncryptionAlgorithmObj = NULL_PTR; B_KEY_OBJ passwordKeyObj = NULL_PTR; B_KEY_OBJ privateKeyObj = NULL_PTR; B_KEY_OBJ secretKeyObj = NULL_PTR; ITEM dataKeyItem, passwordItem, privateKeyItem, pbEncryptionInfoItem; int status; unsigned char *dataKeyBuf = NULL_PTR; unsigned char *privateKeyBuf = NULL_PTR; unsigned int dataKeyBufLen, outputLen, privateKeyBufLen; /* initialize algorithm object to NULL pointer */ *algorithmObject = NULL_PTR; /* do {} while(0); provides convenient way to ensure cleanup upon error */ do { /* create a key object for the private key */ status = B_CreateKeyObject (&privateKeyObj); if (status != 0) break; /* if supplied password is NULL, use the private key data supplied */ if (password == (unsigned char *)NULL_PTR) { privateKeyItem.data = ppPrivateKey; privateKeyItem.len = ppPrivateKeyLen; } else { /* otherwise, the password is supplied, so use it to decrypt the private key and set the key info with the result */ /* create password-based encryption algorithm object */ status = B_CreateAlgorithmObject (&pbEncryptionAlgorithmObj); if (status != 0) break; /* set up the ITEM which supplies the password-based encryption algorithm info. This contains the salt and iteration count which were specified when the private key was password-encrypted. */ pbEncryptionInfoItem.data = pbeParams; pbEncryptionInfoItem.len = pbeParamsLen; /* set algorithm object */ status = B_SetAlgorithmInfo (pbEncryptionAlgorithmObj, AI_MD2WithDES_CBCPadBER, (POINTER)&pbEncryptionInfoItem); if (status != 0) break; /****************************************************************** Note: The choice of MD2 with DES for password-based private key decryption corresponds to the password-based encryption algorithm used by the BSL_MakeRSAKeyPairFromSeed() routine above. The call to SetAlgorithmInfo() will return BE_WRONG_ALGORITHM_INFO if the algorithm information conveyed in the pbeParams argument is other than MD2 and DES. In this case it would be necessary to call SetAlgorithmInfo() with other candidate algorithm info choices (such as AI_MD5WithDES_CBCPadBER or AI_MD2WithRC2_CBCBER) until the call is successful. ******************************************************************/ /* create key object */ status = B_CreateKeyObject (&passwordKeyObj); if (status != 0) break; /* setup password item and set key info */ passwordItem.data = password; passwordItem.len = passwordLen; status = B_SetKeyInfo (passwordKeyObj, KI_Item, (POINTER)&passwordItem); if (status != 0) break; /* allocate a buffer to hold the decrypted private key. Since the decrypted size will be smaller than the encrypted size, we can allocate a buffer of the size of the encrypted key. */ if ((privateKeyBuf = (unsigned char *)T_malloc (ppPrivateKeyLen)) == (unsigned char *)NULL_PTR) { status = BE_ALLOC; break; } /* decrypt the private key DER */ status = B_DecryptInit (pbEncryptionAlgorithmObj, passwordKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_DecryptUpdate (pbEncryptionAlgorithmObj, privateKeyBuf, &outputLen, ppPrivateKeyLen, ppPrivateKey, ppPrivateKeyLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; privateKeyBufLen = outputLen; status = B_DecryptFinal (pbEncryptionAlgorithmObj, privateKeyBuf + privateKeyBufLen, &outputLen, ppPrivateKeyLen - privateKeyBufLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; privateKeyBufLen += outputLen; /* use the decrypted private key bytes */ privateKeyItem.data = privateKeyBuf; privateKeyItem.len = privateKeyBufLen; } /* set the private key info */ status = B_SetKeyInfo (privateKeyObj, KI_PKCS_RSAPrivateBER, (POINTER)&privateKeyItem); if (status != 0) break; /* create algorithm object for decrypting key */ status = B_CreateAlgorithmObject (&keyDecryptAlgorithmObj); if (status != 0) break; /* set algorithm object to RSA private key decryption */ status = B_SetAlgorithmInfo (keyDecryptAlgorithmObj, AI_PKCS_RSAPrivate, NULL_PTR); if (status != 0) break; /* allocate a buffer to hold the decrypted data encryption key. Since the decrypted size will be smaller than the encrypted size, we can allocate a buffer of the size of the encrypted key. */ if ((dataKeyBuf = (unsigned char *)T_malloc (encryptedKeyLen)) == (unsigned char *)NULL_PTR) { status = BE_ALLOC; break; } /* now, decrypt the data encryption key with the private key */ status = B_DecryptInit (keyDecryptAlgorithmObj, privateKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; status = B_DecryptUpdate (keyDecryptAlgorithmObj, dataKeyBuf, &outputLen, encryptedKeyLen, encryptedKey, encryptedKeyLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; dataKeyBufLen = outputLen; status = B_DecryptFinal (keyDecryptAlgorithmObj, dataKeyBuf + dataKeyBufLen, &outputLen, encryptedKeyLen - dataKeyBufLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; dataKeyBufLen += outputLen; /* create key object for secret key decryption */ status = B_CreateKeyObject (&secretKeyObj); if (status != 0) break; /* use the decrypted data encryption key bytes */ dataKeyItem.data = dataKeyBuf; dataKeyItem.len = dataKeyBufLen; /* set the data encryption key info */ status = B_SetKeyInfo (secretKeyObj, KI_Item, (POINTER)&dataKeyItem); if (status != 0) break; /* set up an algorithm object for data decryption */ status = B_CreateAlgorithmObject (algorithmObject); if (status != 0) break; /* set algorithm info for decrypting DES CBC with padding */ status = B_SetAlgorithmInfo (*algorithmObject, AI_DES_CBCPadIV8, (POINTER)IV); if (status != 0) break; /****************************************************************** Note: The choice of DES CBC for envelope data decryption corresponds to the use of DES CBC for envelope data encryption in the BSL_SealDESRSAEnvelopeSetup() routine above. If this routine were intended to handle other signature algorithms, such as RC2 CBC, it would be necessary to pass around algorithm identifier information with the encrypted data. ******************************************************************/ /* call the decrypt init with the data encryption key */ status = B_DecryptInit (*algorithmObject, secretKeyObj, DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR); if (status != 0) break; } while (0); /* cleanup only if an error occurred */ if (status != 0) B_DestroyAlgorithmObject (algorithmObject); /* cleanup objects */ B_DestroyAlgorithmObject (&keyDecryptAlgorithmObj); B_DestroyAlgorithmObject (&pbEncryptionAlgorithmObj); B_DestroyKeyObject (&passwordKeyObj); B_DestroyKeyObject (&privateKeyObj); B_DestroyKeyObject (&secretKeyObj); /* if dataKeyBuf is not NULL, zeroize and free memory */ if (dataKeyBuf != (unsigned char *)NULL_PTR) { T_memset ((POINTER)dataKeyBuf, 0, encryptedKeyLen); T_free ((POINTER)dataKeyBuf); } /* if privateKeyBuf is not NULL, zeroize and free memory */ if (privateKeyBuf != (unsigned char *)NULL_PTR) { T_memset ((POINTER)privateKeyBuf, 0, ppPrivateKeyLen); T_free ((POINTER)privateKeyBuf); } return (status); }