uint32_t Cipher(uint8_t* out, const uint8_t* in, uint32_t len, uint8_t mode, const uint8_t* key, const uint8_t* IV, bool inverse) { Cipher_CTX ctx; CipherInit(&ctx, mode, key, IV); uint32_t ret = CipherUpdate(&ctx, out, in, len, inverse); ret += CipherFinal(&ctx, out, inverse); return ret; }
VLT_STS CipherDoFinal( VLT_PU8 pDataIn, VLT_U32 DataInLen, VLT_U32 dataInCapacity, VLT_PU8 pDataOut, VLT_PU32 pDataOutLen, VLT_U32 dataOutCapacity ) { VLT_STS status = VLT_FAIL; if ( ( ST_UNKNOWN == cipherState ) || ( ST_FINALISED == cipherState ) ) { return( ECPHDFNOTSUPPORTED ); } /** * Ensure we haven't been passed * null pointers by the caller. */ if( ( NULL == pDataIn )|| ( NULL == pDataOutLen ) || ( NULL == pDataOut ) ) { return( ECPHUPDNULLPARAM ); } /** * Apply the padding if we have been called to * encrypt data. */ if( ( VLT_ENCRYPT_MODE == operationalMode ) && ( PADDING_NONE != params.paddingScheme ) ) { status = PaddingAdd( params.paddingScheme, theCipher.cipherGetBlockSize(), pDataIn, &DataInLen, dataInCapacity ); } else { status = VLT_OK; } /** * Process the data, encrypt/decrypt */ if( VLT_OK == status ) { status = CipherUpdate( pDataIn, DataInLen, dataInCapacity, pDataOut, pDataOutLen, dataOutCapacity); } if( VLT_OK == status ) { if( VLT_DECRYPT_MODE == operationalMode ) { status = PaddingRemove( params.paddingScheme, theCipher.cipherGetBlockSize(), pDataOut, pDataOutLen ); } } /** * Set the appropriate cipher state; */ cipherState = ST_FINALISED; return( status ); }
VLT_STS SignerIso9797Update( VLT_PU8 pMessage, VLT_U32 messageLen, VLT_U32 messageCapacity ) { VLT_STS status = VLT_FAIL; VLT_U8 blockSize = 0; VLT_U32 byteCount = 0; VLT_U32 workingLen = 0; VLT_U8 workingBuffer[VLT_AES_CMAC_LENGTH]; if ( ( ST_UNKNOWN == signerState ) || ( ST_FINALISED == signerState ) ) { return( SIGNER_NOT_SETUP ); } /** * Ensure we haven't been passed * a null pointer by the caller. */ if ( NULL == pMessage ) { return( SIGNER_UPD_NULL_PARAMS ); } /** * Cache the block size, we'll use it * frequently. */ blockSize = (VLT_U8)CipherGetBlockSize( ); /** * For the SignerIso9797Update the capacity of * the buffer passed to us by the caller * should be equal or larger than that * of the data buffer length. */ if ( ( messageLen > messageCapacity ) || ( messageLen < blockSize ) || ( messageCapacity < blockSize ) ) { return( SIGNER_UPD_INVALID_CAP ); } /** * Update only deals with data lengths * multiple of the block size, if the * client has passed us anything else * other than that then we should exit * gracefully-ish! */ if( 0 != ( messageLen % blockSize ) ) { return( SIGNER_UPD_NON_MUL_BLK_SZ ); } while( 0 != ( messageLen - byteCount ) ) { /** * Right, the cipher requires the output buffer * to be as big as the message buffer, which * this method has no control over, so the signer * will send BLOCK_SIZED chunks to the cipher * and discard the answer for each block * until the last block in do final is processed. */ /* * No need to check the return type as pointer has been validated */ (void)host_memcpy(&workingBuffer[0], &pMessage[byteCount], blockSize); if( VLT_OK == ( status = CipherUpdate( workingBuffer, blockSize, messageCapacity, workingBuffer, &workingLen, NELEMS(workingBuffer)) ) ) { /** * It should be impossible for the cipher * to return a length not equal to * the blockSize, nevertheless if it does * exit with an appropriate error code. */ if( workingLen != blockSize ) { return( SIGNER_UPD_INVALID_BLOCK ); } } else { return( status ); } byteCount += blockSize; blockCounter++; } /** * Setup the IV in the IV buffer if the * do final is called with a message * shorter or equal to the block size. * In this case the cipher will be re- * initalized with a new algorithm. */ /* * No need to check the return type as pointer has been validated */ (void)host_memcpy(&aIv[0], &workingBuffer[0], params.ivSize); return( VLT_OK ); }
VLT_STS SignerIso9797DoFinal( VLT_PU8 pMessage, VLT_U32 messageLen, VLT_U32 messageCapacity, VLT_PU8 pMac, VLT_PU32 pMacLen, VLT_U32 macCapacity ) { VLT_STS status = VLT_FAIL; VLT_U8 blockSize = 0; VLT_U32 byteCount = 0; VLT_U32 workingLen = 0; VLT_U8 paddingPerformed = VLT_PAD_NOT_DONE; VLT_PU8 pMessageIt = &pMessage[byteCount]; VLT_U8 hasGrownByBlockSize = FALSE; /** * With padding the final block can be double the * block size, so double the size of the buffer. */ VLT_U8 workingBuffer[VLT_AES_CMAC_LENGTH * 2]; if ( ( ST_UNKNOWN == signerState ) || ( ST_FINALISED == signerState ) ) { return( SIGNER_NOT_SETUP ); } /** * Ensure we haven't been passed * a null pointer by the caller. */ if ( ( NULL == pMessage ) || ( NULL == pMac ) || ( NULL == pMacLen ) ) { return( SIGNER_DOF_NULL_PARAMS ); } /** * Cache the block size, we'll use it * frequently. */ workingLen = blockSize = (VLT_U8)CipherGetBlockSize( ); /** * For the SignerIso9797Update the capacity of * the buffer passed to us by the caller * should be equal or larger than that * of the data buffer length. */ if ( ( messageLen > messageCapacity ) || ( messageLen == 0 ) || ( blockSize > macCapacity) ) { return( SIGNER_DOF_INVALID_CAP ); } if ( ( blockCounter == 0 ) && ( messageLen < blockSize ) && ( params.paddingScheme == PADDING_NONE ) ) { /** * Can not process an empty do final * with no padding. */ return ( SIGNER_EMPT_DOFIN_NPAD ); } while( 0 != ( messageLen - byteCount ) ) { /** * The cipher requires the output buffer * to be as big as the message buffer, which * this method has no control over, so the signer * will send BLOCK_SIZED chunks to the cipher * and discard the answer for each block * until the last block in do final is processed. */ if ( ( messageLen - byteCount ) <= blockSize ) { if ( messageLen > blockSize ) { /** * Copy the last block, to setup the IV for the next if * MAC algo 1 is being used. */ /* * No need to check the return type as pointer has been validated */ (void)host_memcpy( &aIv[0], &workingBuffer[0], blockSize ); } /** * Check if Padding is needed */ if ( ( PADDING_NONE != params.paddingScheme ) && ( VLT_PAD_DONE != paddingPerformed ) ) { /** * Working in a small internal buffer so * the current count (byteCount) has to be * removed from the message size to ensure * the correct sizes are passed to padding * to ensure padding thinks there is enough * room in the working buffer. The working * length is left so the correct number of * remaining bytes are copied. */ messageLen = workingLen = messageLen - byteCount; if ( VLT_OK != ( status = PaddingAdd( params.paddingScheme, blockSize, &workingBuffer[0], &messageLen, /* Used because of the copying blockSize bytes at a time. */ NELEMS(workingBuffer) ) ) ) { return ( status ); } /** * Add the padding length onto the message. */ messageLen += byteCount; paddingPerformed = VLT_PAD_DONE; } /** * Padding can make the remaining bytes double * and result in two blocks remaining to be signed * Re-test the message length and take different * action if the message length has grown such * another block is required. */ if ( ( messageLen - byteCount ) <= blockSize ) { signerState = ST_FINALISED; /** * Get the cipher to perform a different * action on do final. Mac Alg3 switchs from DES to * TDES on the do final, and AES_CMAC can use one of * two different session keys on final! */ DoFinalSetup ( aIv, blockSize ); if ( ( VLT_PAD_DONE == paddingPerformed ) && ( hasGrownByBlockSize ) ) { /** * Setup the the latst block copy from the end * of the buffer to the start, no needed * but simpler than more logic later. */ pMessageIt = &workingBuffer[blockSize]; } } else { /** * Padding has added block size * more bytes so another round * is required. */ hasGrownByBlockSize = TRUE; } } /* * No need to check the return type as pointer has been validated */ (void)host_memcpy(&workingBuffer[0], pMessageIt, workingLen); if ( ST_FINALISED != signerState ) { if( VLT_OK == ( status = CipherUpdate( workingBuffer, blockSize, messageCapacity, workingBuffer, &workingLen, NELEMS(workingBuffer)) ) ) { /** * It is possible for the cipher * to return a length twice * the blockSize, or the blockSize, * if it is any other value exit * with an appropriate error code. */ if ( ( workingLen != blockSize ) && ( workingLen != ( blockSize * 2 ) ) ) { return( SIGNER_UPD_INVALID_BLOCK ); } } else { return( status ); } } else if ( ST_FINALISED == signerState ) { if( VLT_OK == ( status = CipherDoFinal( workingBuffer, blockSize, messageCapacity, workingBuffer, &workingLen, NELEMS(workingBuffer)) ) ) { /** * It is possible for the cipher * to return a length twice * the blockSize, or the blockSize, * if it is any other value exit * with an appropriate error code. */ if ( ( workingLen != blockSize ) && ( workingLen != ( blockSize * 2 ) ) ) { return( SIGNER_UPD_INVALID_BLOCK ); } } else { return( status ); } if ( workingLen == ( blockSize * 2 ) ) { workingLen = blockSize; } else { workingLen = 0; } /** * Take a block sized chunk and * copy it into the output buffer. */ /* * No need to check the return type as pointer has been validated */ (void)host_memcpy(pMac, &workingBuffer[workingLen], blockSize); /** * Set the length of the Mac */ *pMacLen = blockSize; break; } /** * Add block size to the byte count and * increment the message ptr by block size. */ byteCount += blockSize; pMessageIt += blockSize; blockCounter++; } return ( VLT_OK ); }
VLT_STS VltUnwrapKey( VLT_U8 u8KeyGroup, VLT_U8 u8KeyIndex, const VLT_FILE_PRIVILEGES *pKeyFilePrivileges, const VLT_KEY_OBJ_RAW* pKeyObj ) { #if( VLT_ENABLE_KEY_WRAPPING == VLT_ENABLE ) VLT_STS status = VLT_FAIL; VLT_U8 u8SecChnlState = VLT_USER_NOT_AUTHENTICATED; /* * Check the validity of the input parameters */ if( ( NULL == pKeyFilePrivileges ) || ( NULL == pKeyObj ) || ( NULL == pKeyObj->pu16ClearKeyObjectLen ) || ( NULL == pKeyObj->pu8KeyObject ) ) { return( EKWWKNULLPARAM ); } /* * Check that the key wrapping has been initialised */ if( ST_UNINIT == keyWrappingState ) { return ( EKWWKUNINIT ); } /* * Check if a Secure channel is enabled. If it is, don't allow the wrap */ if( VLT_OK == VltScpGetState( &u8SecChnlState ) ) { if( u8SecChnlState == VLT_USER_AUTHENTICATED ) { status = EKWWKSCPENBLD; } else { status = VLT_OK; } } else { /* * As Secure Channel hasn't been enabled the wrap call can proceed */ status = VLT_OK; } if( VLT_OK == status ) { /* * Initialise the Cipher */ status = CipherInit( VLT_ENCRYPT_MODE, &theKey, (VLT_PU8)&theWrapParams ); if( VLT_OK == status ) { /* * The cipher was initialised correctly so update the state */ keyWrappingState = ST_CIPHER_INIT; } } if( ( VLT_OK == status ) && ( WRAP_MODE != keyWrappingMode ) ) { /* * Call Initialize Algorithm on the VaultIC to set it up to unwrap the * wrapped key we are about to send down. Only do this if it hasn't * already been called */ VLT_ALGO_PARAMS algorithm; algorithm.u8AlgoID = theWrapParams.algoID; algorithm.data.SymCipher.u8Padding = theWrapParams.paddingScheme; algorithm.data.SymCipher.u8Mode = theWrapParams.chainMode; if (theWrapParams.pIV != NULL) { /* * No need to check the return type as pointer has been validated */ (void)host_memcpy( &(algorithm.data.SymCipher.u8Iv[0]), theWrapParams.pIV, CipherGetBlockSize() ); algorithm.data.SymCipher.u8IvLength = (VLT_U8)CipherGetBlockSize(); } else algorithm.data.SymCipher.u8IvLength = 0; status = VltInitializeAlgorithm( u8CachedKTSKeyGroup, u8CachedKTSKeyIndex, VLT_UNWRAP_KEY_MODE, &algorithm ); if( VLT_OK == status ) { /* * Update the mode to wrap */ keyWrappingMode = WRAP_MODE; } } if( VLT_OK == status ) { VLT_U16 u16Remaining = VLT_PUTKEY_FIXED_DATA_LENGTH + *pKeyObj->pu16ClearKeyObjectLen; VLT_U16 u16KeyBytesRemaining = *(pKeyObj->pu16ClearKeyObjectLen); VLT_U16 u16MaxChunk = VltCommsGetMaxSendSize(); VLT_U16 u16Offset = 0; while( 0 != u16Remaining ) { VLT_SW Sw = VLT_STATUS_NONE; VLT_U16 u16Avail = 0; VLT_U16 u16PartialKeyLen = 0; VLT_U32 u32CipherDataLen = 0; VLT_U8 u8Final = 0; /* * Set index at the start of the data portion of the buffer */ idx = VLT_APDU_DATA_OFFSET; /* * Build the data in */ if( 0 == u16Offset ) { /* * Add the Key Priviliges */ Command.pu8Data[idx++] = pKeyFilePrivileges->u8Read; Command.pu8Data[idx++] = pKeyFilePrivileges->u8Write; Command.pu8Data[idx++] = pKeyFilePrivileges->u8Delete; Command.pu8Data[idx++] = pKeyFilePrivileges->u8Execute; /* * Add the Key Length */ Command.pu8Data[idx++] = (VLT_U8)( (*pKeyObj->pu16ClearKeyObjectLen >> 8 ) & 0xFF ); Command.pu8Data[idx++] = (VLT_U8)( (*pKeyObj->pu16ClearKeyObjectLen >> 0 ) & 0xFF ); } u16Avail = NumBufferBytesAvail( u16MaxChunk, idx ); if(u16KeyBytesRemaining > u16Avail) { /* * There is more key data remaining than can be transferred * in one transaction */ u16PartialKeyLen = ( u16Avail / CipherGetBlockSize() ) * CipherGetBlockSize(); } else { /* * The remaining data might all be able to be transferred in * one transaction */ if( u16Avail >= (u16KeyBytesRemaining + CipherGetBlockSize() ) ) { u16PartialKeyLen = u16KeyBytesRemaining; /* * Flag that this will be the final block to be encrypted */ u8Final = 1; } else { u16PartialKeyLen = u16KeyBytesRemaining - CipherGetBlockSize(); } } /* * Copy the number of bytes of the partial key into the buffer */ /* * No need to check the return type as pointer has been validated */ (void)host_memcpy( &(Command.pu8Data[idx]), &( (pKeyObj->pu8KeyObject[u16Offset]) ), u16PartialKeyLen ); /* * Now encrypt the data in the buffer */ if( 1 == u8Final ) { status = CipherDoFinal( &(Command.pu8Data[idx]), u16PartialKeyLen, Command.u16Capacity - VLT_APDU_DATA_OFFSET, &(Command.pu8Data[idx]), &u32CipherDataLen, Command.u16Capacity - VLT_APDU_DATA_OFFSET ); } else { status = CipherUpdate( &(Command.pu8Data[idx]), u16PartialKeyLen, Command.u16Capacity - VLT_APDU_DATA_OFFSET, &(Command.pu8Data[idx]), &u32CipherDataLen, Command.u16Capacity - VLT_APDU_DATA_OFFSET ); } if( VLT_OK == status ) { /* * Update the index to reflect the data that has just been added */ idx += (VLT_U16)u32CipherDataLen; /* * Subtract the number of key bytes that have just been added to * the buffer from the number of key bytes remaining to be sent */ u16KeyBytesRemaining -= u16PartialKeyLen; /* * Decrement the remaining number of bytes to be sent. */ if( 0 == u16Offset ) { /* * The first time the File Privileges and the length are * included so include them plus the partial key length * which won't incude any padding bytes if some have been * added */ u16Remaining -= ( VLT_PUTKEY_FIXED_DATA_LENGTH - NUM_CRC_BYTES ) + u16PartialKeyLen; } else { /* * Subtract the partial key length that was added to * the buffer */ u16Remaining -= u16PartialKeyLen; } /* * Update the offset into the key */ u16Offset += u16PartialKeyLen; /* * We need two bytes free in the buffer for the wCRC field. */ if( ( NUM_CRC_BYTES == u16Remaining ) && ( NumBufferBytesAvail( u16MaxChunk, idx ) >= NUM_CRC_BYTES ) ) { Command.pu8Data[idx++] = (VLT_U8)( ( pKeyObj->u16Crc >> 8 ) & 0xFF ); Command.pu8Data[idx++] = (VLT_U8)( (pKeyObj->u16Crc >> 0 ) & 0xFF ); u16Remaining -= NUM_CRC_BYTES; }
uint32_t DecryptUpdate(Decrypt_CTX* ctx, uint8_t* out, const uint8_t* in, uint32_t len) { return CipherUpdate(ctx, out, in, len, true); }
uint32_t EncryptUpdate(Encrypt_CTX* ctx, uint8_t* out, const uint8_t* in, uint32_t len) { return CipherUpdate(ctx, out, in, len, false); }