Esempio n. 1
0
VLT_U16 SignerIso9797GetBlockSize( void )
{
    if( ST_UNKNOWN != signerState )
    {
        return( CipherGetBlockSize() );
    }
    return( SIGNER_GMS_BLK_SZ_NOT_SUP );
}
Esempio n. 2
0
void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount)
{
	byte *data = dataPtr;
	size_t blockSize = CipherGetBlockSize (cipher);
	while (blockCount-- > 0)
	{
		DecipherBlock (cipher, data, ks);
		data += blockSize;
	}
}
Esempio n. 3
0
// For descriptions of the input parameters, see the 64-bit version of EncryptBufferXTS().
void DecryptBufferXTS (unsigned __int8 *buffer,
					   GST_LARGEST_COMPILER_UINT length,
					   const UINT64_STRUCT *startDataUnitNo,
					   unsigned int startCipherBlockNo,
					   unsigned __int8 *ks,
					   unsigned __int8 *ks2,
					   int cipher)
{
	// Decrypt all ciphertext blocks in the buffer
	if (CipherGetBlockSize(cipher) == 8)
		DecryptBufferXTS8Byte(buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
	else
		EncryptDecryptBufferXTS32 (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher, TRUE);
}
Esempio n. 4
0
// length: number of bytes to encrypt; may be larger than one data unit and must be divisible by the cipher block size
// ks: the primary key schedule
// ks2: the secondary key schedule
// startDataUnitNo: The sequential number of the data unit with which the buffer starts.
// startCipherBlockNo: The sequential number of the first plaintext block to encrypt inside the data unit startDataUnitNo.
//                     When encrypting the data unit from its first block, startCipherBlockNo is 0. 
//                     The startCipherBlockNo value applies only to the first data unit in the buffer; each successive
//                     data unit is encrypted from its first block. The start of the buffer does not have to be
//                     aligned with the start of a data unit. If it is aligned, startCipherBlockNo must be 0; if it
//                     is not aligned, startCipherBlockNo must reflect the misalignment accordingly.
void EncryptBufferXTS (unsigned __int8 *buffer,
					   GST_LARGEST_COMPILER_UINT length,
					   const UINT64_STRUCT *startDataUnitNo,
					   unsigned int startCipherBlockNo,
					   unsigned __int8 *ks,
					   unsigned __int8 *ks2,
					   int cipher)
{
	if (CipherGetBlockSize(cipher) == 8)
		EncryptBufferXTS8Byte(buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
	else if (CipherSupportsIntraDataUnitParallelization (cipher))
		EncryptBufferXTSParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
	else
		EncryptBufferXTSNonParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
}
Esempio n. 5
0
BOOL EAInitMode (PCRYPTO_INFO ci)
{
	switch (ci->mode)
	{
	case XTS:
		// Secondary key schedule
		if (EAInit (ci->ea, ci->k2, ci->ks2) != ERR_SUCCESS)
			return FALSE;

		/* Note: XTS mode could potentially be initialized with a weak key causing all blocks in one data unit
		on the volume to be tweaked with zero tweaks (i.e. 512 bytes of the volume would be encrypted in ECB
		mode). However, to create a GostCrypt volume with such a weak key, each human being on Earth would have
		to create approximately 11,378,125,361,078,862 (about eleven quadrillion) GostCrypt volumes (provided 
		that the size of each of the volumes is 1024 terabytes). */
		break;

	case LRW:
		switch (CipherGetBlockSize (EAGetFirstCipher (ci->ea)))
		{
		case 8:
			/* Deprecated/legacy */
			return Gf64TabInit (ci->k2, &ci->gf_ctx);

		case 16:
			return Gf128Tab64Init (ci->k2, &ci->gf_ctx);

		default:
			GST_THROW_FATAL_EXCEPTION;
		}

		break;

	case CBC:
	case INNER_CBC:
	case OUTER_CBC:
		// The mode does not need to be initialized or is initialized elsewhere 
		return TRUE;

	default:		
		// Unknown/wrong ID
		GST_THROW_FATAL_EXCEPTION;
	}
	return TRUE;
}
Esempio n. 6
0
void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount)
{
	byte *data = dataPtr;
#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
	KFLOATING_SAVE floatingPointState;
#endif

	if (cipher == AES
		&& (blockCount & (32 - 1)) == 0
		&& IsAesHwCpuSupported()
#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
		&& NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState))
#endif
		)
	{
		while (blockCount > 0)
		{
			aes_hw_cpu_decrypt_32_blocks ((byte *) ks + sizeof (aes_encrypt_ctx), data);

			data += 32 * 16;
			blockCount -= 32;
		}

#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
		KeRestoreFloatingPointState (&floatingPointState);
#endif
	}
	else
	{
		size_t blockSize = CipherGetBlockSize (cipher);
		while (blockCount-- > 0)
		{
			DecipherBlock (cipher, data, ks);
			data += blockSize;
		}
	}
}
Esempio n. 7
0
static void
EncryptBufferCBC (unsigned __int32 *data, 
		 unsigned int len,
		 unsigned __int8 *ks,
		 unsigned __int32 *iv,
		 unsigned __int32 *whitening,
		 int ea,
		 int cipher)
{
	/* IMPORTANT: This function has been deprecated (legacy) */

	unsigned __int32 bufIV[4];
	unsigned __int64 i;
	int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher);

	if (len % blockSize)
		GST_THROW_FATAL_EXCEPTION;

	//  IV
	bufIV[0] = iv[0];
	bufIV[1] = iv[1];
	if (blockSize == 16)
	{
		bufIV[2] = iv[2];
		bufIV[3] = iv[3];
	}

	// Encrypt each block
	for (i = 0; i < len/blockSize; i++)
	{
		// CBC
		data[0] ^= bufIV[0];
		data[1] ^= bufIV[1];
		if (blockSize == 16)
		{
			data[2] ^= bufIV[2];
			data[3] ^= bufIV[3];
		}

		if (ea != 0)
		{
			// Outer-CBC
			for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher))
			{
				EncipherBlock (cipher, data, ks);
				ks += CipherGetKeyScheduleSize (cipher);
			}
			ks -= EAGetKeyScheduleSize (ea);
		}
		else
		{
			// CBC/inner-CBC
			EncipherBlock (cipher, data, ks);
		}

		// CBC
		bufIV[0] = data[0];
		bufIV[1] = data[1];
		if (blockSize == 16)
		{
			bufIV[2] = data[2];
			bufIV[3] = data[3];
		}

		// Whitening
		data[0] ^= whitening[0];
		data[1] ^= whitening[1];
		if (blockSize == 16)
		{
			data[2] ^= whitening[0];
			data[3] ^= whitening[1];
		}

		data += blockSize / sizeof(*data);
	}
}
Esempio n. 8
0
void DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, GST_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci)
#endif // !GST_WINDOWS_BOOT
{
	int ea = ci->ea;
	unsigned __int8 *ks = ci->ks;
	unsigned __int8 *ks2 = ci->ks2;
	int cipher;

#ifndef GST_NO_COMPILER_INT64
	void *iv = ci->k2;									// Deprecated/legacy
	unsigned __int64 unitNo = structUnitNo->Value;
	unsigned __int64 *iv64 = (unsigned __int64 *) iv;	// Deprecated/legacy
	unsigned __int32 sectorIV[4];						// Deprecated/legacy
	unsigned __int32 secWhitening[2];					// Deprecated/legacy
#endif	// #ifndef GST_NO_COMPILER_INT64


	switch (ci->mode)
	{
	case XTS:
		ks += EAGetKeyScheduleSize (ea);
		ks2 += EAGetKeyScheduleSize (ea);

		for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher))
		{
			ks -= CipherGetKeyScheduleSize (cipher);
			ks2 -= CipherGetKeyScheduleSize (cipher);

			DecryptBufferXTS (buf,
				nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
				structUnitNo,
				0,
				ks,
				ks2,
				cipher);
		}
		break;

#ifndef GST_NO_COMPILER_INT64
	case LRW:

		/* Deprecated/legacy */

		switch (CipherGetBlockSize (EAGetFirstCipher (ea)))
		{
		case 8:
			DecryptBufferLRW64 (buf,
				(unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
				DataUnit2LRWIndex (unitNo, 8, ci),
				ci);
			break;

		case 16:
			DecryptBufferLRW128 (buf,
				(unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
				DataUnit2LRWIndex (unitNo, 16, ci),
				ci);
			break;

		default:
			GST_THROW_FATAL_EXCEPTION;
		}
		break;

	case CBC:
	case INNER_CBC:

		/* Deprecated/legacy */

		while (nbrUnits--)
		{
			ks += EAGetKeyScheduleSize (ea);
			for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher))
			{
				InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening);

				ks -= CipherGetKeyScheduleSize (cipher);

				DecryptBufferCBC ((unsigned __int32 *) buf,
					ENCRYPTION_DATA_UNIT_SIZE,
					ks,
					sectorIV,
					secWhitening,
					0,
					cipher);
			}
			buf += ENCRYPTION_DATA_UNIT_SIZE;
			unitNo++;
		}
		break;

	case OUTER_CBC:

		/* Deprecated/legacy */

		while (nbrUnits--)
		{
			InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening);

			DecryptBufferCBC ((unsigned __int32 *) buf,
				ENCRYPTION_DATA_UNIT_SIZE,
				ks,
				sectorIV,
				secWhitening,
				ea,
				0);

			buf += ENCRYPTION_DATA_UNIT_SIZE;
			unitNo++;
		}
		break;
#endif // #ifndef GST_NO_COMPILER_INT64

	default:		
		// Unknown/wrong ID
		GST_THROW_FATAL_EXCEPTION;
	}
}
Esempio n. 9
0
// DecryptBuffer
//
// buf:  data to be decrypted; the start of the buffer is assumed to be aligned with the start of a data unit.
// len:  number of bytes to decrypt; must be divisible by the block size (for cascaded ciphers, divisible 
//       by the largest block size used within the cascade)
void DecryptBuffer (unsigned __int8 *buf, GST_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo)
{
	switch (cryptoInfo->mode)
	{
	case XTS:
		{
			unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea);
			unsigned __int8 *ks2 = cryptoInfo->ks2 + EAGetKeyScheduleSize (cryptoInfo->ea);
			UINT64_STRUCT dataUnitNo;
			int cipher;

			// When encrypting/decrypting a buffer (typically a volume header) the sequential number
			// of the first XTS data unit in the buffer is always 0 and the start of the buffer is
			// always assumed to be aligned with the start of the data unit 0.
			dataUnitNo.LowPart = 0;
			dataUnitNo.HighPart = 0;

			for (cipher = EAGetLastCipher (cryptoInfo->ea);
				cipher != 0;
				cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher))
			{
				ks -= CipherGetKeyScheduleSize (cipher);
				ks2 -= CipherGetKeyScheduleSize (cipher);

				DecryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher);
			}
		}
		break;

#ifndef GST_NO_COMPILER_INT64
	case LRW:

		/* Deprecated/legacy */

		switch (CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea)))
		{
		case 8:
			DecryptBufferLRW64 (buf, (unsigned __int64) len, 1, cryptoInfo);
			break;

		case 16:
			DecryptBufferLRW128 (buf, (unsigned __int64) len, 1, cryptoInfo);
			break;

		default:
			GST_THROW_FATAL_EXCEPTION;
		}
		break;

	case CBC:
	case INNER_CBC:
		{
			/* Deprecated/legacy */

			unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea);
			int cipher;
			for (cipher = EAGetLastCipher (cryptoInfo->ea);
				cipher != 0;
				cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher))
			{
				ks -= CipherGetKeyScheduleSize (cipher);

				DecryptBufferCBC ((unsigned __int32 *) buf,
					(unsigned int) len,
					ks,
					(unsigned __int32 *) cryptoInfo->k2,
					(unsigned __int32 *) &cryptoInfo->k2[8],
					0,
					cipher);
			}
		}
		break;

	case OUTER_CBC:

		/* Deprecated/legacy */

		DecryptBufferCBC ((unsigned __int32 *) buf,
			(unsigned int) len,
			cryptoInfo->ks,
			(unsigned __int32 *) cryptoInfo->k2,
			(unsigned __int32 *) &cryptoInfo->k2[8],
			cryptoInfo->ea,
			0);

		break;
#endif	// #ifndef GST_NO_COMPILER_INT64

	default:		
		// Unknown/wrong ID
		GST_THROW_FATAL_EXCEPTION;
	}
}
Esempio n. 10
0
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 );
}
Esempio n. 11
0
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 );
}
Esempio n. 12
0
int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo)
{
	char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
	KEY_INFO keyInfo;
	PCRYPTO_INFO cryptoInfo;
	char dk[MASTER_KEYDATA_SIZE];
	int enqPkcs5Prf, pkcs5_prf;
	uint16 headerVersion;
	int status = ERR_PARAMETER_INCORRECT;
	int primaryKeyOffset;

	TC_EVENT keyDerivationCompletedEvent;
	TC_EVENT noOutstandingWorkItemEvent;
	KeyDerivationWorkItem *keyDerivationWorkItems;
	KeyDerivationWorkItem *item;
	int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1;
	size_t encryptionThreadCount = GetEncryptionThreadCount();
	size_t queuedWorkItems = 0;
	LONG outstandingWorkItemCount = 0;
	int i;

	if (retHeaderCryptoInfo != NULL)
	{
		cryptoInfo = retHeaderCryptoInfo;
	}
	else
	{
		cryptoInfo = *retInfo = crypto_open ();
		if (cryptoInfo == NULL)
			return ERR_OUTOFMEMORY;
	}

	if (encryptionThreadCount > 1)
	{
		keyDerivationWorkItems = TCalloc (sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
		if (!keyDerivationWorkItems)
			return ERR_OUTOFMEMORY;

		for (i = 0; i < pkcs5PrfCount; ++i)
			keyDerivationWorkItems[i].Free = TRUE;

#ifdef DEVICE_DRIVER
		KeInitializeEvent (&keyDerivationCompletedEvent, SynchronizationEvent, FALSE);
		KeInitializeEvent (&noOutstandingWorkItemEvent, SynchronizationEvent, TRUE);
#else
		keyDerivationCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
		if (!keyDerivationCompletedEvent)
		{
			TCfree (keyDerivationWorkItems);
			return ERR_OUTOFMEMORY;
		}

		noOutstandingWorkItemEvent = CreateEvent (NULL, FALSE, TRUE, NULL);
		if (!noOutstandingWorkItemEvent)
		{
			CloseHandle (keyDerivationCompletedEvent);
			TCfree (keyDerivationWorkItems);
			return ERR_OUTOFMEMORY;
		}
#endif
	}
		
#ifndef DEVICE_DRIVER
	VirtualLock (&keyInfo, sizeof (keyInfo));
	VirtualLock (&dk, sizeof (dk));
#endif

	crypto_loadkey (&keyInfo, password->Text, (int) password->Length);

	// PKCS5 is used to derive the primary header key(s) and secondary header key(s) (XTS mode) from the password
	memcpy (keyInfo.salt, encryptedHeader + HEADER_SALT_OFFSET, PKCS5_SALT_SIZE);

	// Test all available PKCS5 PRFs
	for (enqPkcs5Prf = FIRST_PRF_ID; enqPkcs5Prf <= LAST_PRF_ID || queuedWorkItems > 0; ++enqPkcs5Prf)
	{
		BOOL lrw64InitDone = FALSE;		// Deprecated/legacy
		BOOL lrw128InitDone = FALSE;	// Deprecated/legacy

		if (encryptionThreadCount > 1)
		{
			// Enqueue key derivation on thread pool
			if (queuedWorkItems < encryptionThreadCount && enqPkcs5Prf <= LAST_PRF_ID)
			{
				for (i = 0; i < pkcs5PrfCount; ++i)
				{
					item = &keyDerivationWorkItems[i];
					if (item->Free)
					{
						item->Free = FALSE;
						item->KeyReady = FALSE;
						item->Pkcs5Prf = enqPkcs5Prf;

						EncryptionThreadPoolBeginKeyDerivation (&keyDerivationCompletedEvent, &noOutstandingWorkItemEvent,
							&item->KeyReady, &outstandingWorkItemCount, enqPkcs5Prf, keyInfo.userKey,
							keyInfo.keyLength, keyInfo.salt, get_pkcs5_iteration_count (enqPkcs5Prf, bBoot), item->DerivedKey);
						
						++queuedWorkItems;
						break;
					}
				}

				if (enqPkcs5Prf < LAST_PRF_ID)
					continue;
			}
			else
				--enqPkcs5Prf;

			// Wait for completion of a key derivation
			while (queuedWorkItems > 0)
			{
				for (i = 0; i < pkcs5PrfCount; ++i)
				{
					item = &keyDerivationWorkItems[i];
					if (!item->Free && InterlockedExchangeAdd (&item->KeyReady, 0) == TRUE)
					{
						pkcs5_prf = item->Pkcs5Prf;
						keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, bBoot);
						memcpy (dk, item->DerivedKey, sizeof (dk));

						item->Free = TRUE;
						--queuedWorkItems;
						goto KeyReady;
					}
				}

				if (queuedWorkItems > 0)
					TC_WAIT_EVENT (keyDerivationCompletedEvent);
			}
			continue;
KeyReady:	;
		}
		else
		{
			pkcs5_prf = enqPkcs5Prf;
			keyInfo.noIterations = get_pkcs5_iteration_count (enqPkcs5Prf, bBoot);

			switch (pkcs5_prf)
			{
			case RIPEMD160:
				derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
					PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
				break;

			case SHA512:
				derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
					PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
				break;

			case SHA1:
				// Deprecated/legacy
				derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
					PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
				break;

			case WHIRLPOOL:
				derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
					PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
				break;

			default:		
				// Unknown/wrong ID
				TC_THROW_FATAL_EXCEPTION;
			} 
		}

		// Test all available modes of operation
		for (cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID;
			cryptoInfo->mode <= LAST_MODE_OF_OPERATION;
			cryptoInfo->mode++)
		{
			switch (cryptoInfo->mode)
			{
			case LRW:
			case CBC:
			case INNER_CBC:
			case OUTER_CBC:

				// For LRW (deprecated/legacy), copy the tweak key 
				// For CBC (deprecated/legacy), copy the IV/whitening seed 
				memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE);
				primaryKeyOffset = LEGACY_VOL_IV_SIZE;
				break;

			default:
				primaryKeyOffset = 0;
			}

			// Test all available encryption algorithms
			for (cryptoInfo->ea = EAGetFirst ();
				cryptoInfo->ea != 0;
				cryptoInfo->ea = EAGetNext (cryptoInfo->ea))
			{
				int blockSize;

				if (!EAIsModeSupported (cryptoInfo->ea, cryptoInfo->mode))
					continue;	// This encryption algorithm has never been available with this mode of operation

				blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea));

				status = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks);
				if (status == ERR_CIPHER_INIT_FAILURE)
					goto err;

				// Init objects related to the mode of operation

				if (cryptoInfo->mode == XTS)
				{
					// Copy the secondary key (if cascade, multiple concatenated)
					memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));

					// Secondary key schedule
					if (!EAInitMode (cryptoInfo))
					{
						status = ERR_MODE_INIT_FAILED;
						goto err;
					}
				}
				else if (cryptoInfo->mode == LRW
					&& (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone))
				{
					// Deprecated/legacy

					if (!EAInitMode (cryptoInfo))
					{
						status = ERR_MODE_INIT_FAILED;
						goto err;
					}

					if (blockSize == 8)
						lrw64InitDone = TRUE;
					else if (blockSize == 16)
						lrw128InitDone = TRUE;
				}

				// Copy the header for decryption
				memcpy (header, encryptedHeader, sizeof (header));

				// Try to decrypt header 

				DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);

				// Magic 'TRUE'
				if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545)
					continue;

				// Header version
				headerVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION);
				
				if (headerVersion > VOLUME_HEADER_VERSION)
				{
					status = ERR_NEW_VERSION_REQUIRED;
					goto err;
				}

				// Check CRC of the header fields
				if (!ReadVolumeHeaderRecoveryMode
					&& headerVersion >= 4
					&& GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC))
					continue;

				// Required program version
				cryptoInfo->RequiredProgramVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_REQUIRED_VERSION);
				cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x600;

				// Check CRC of the key set
				if (!ReadVolumeHeaderRecoveryMode
					&& GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE))
					continue;

				// Now we have the correct password, cipher, hash algorithm, and volume type

				// Check the version required to handle this volume
				if (cryptoInfo->RequiredProgramVersion > VERSION_NUM)
				{
					status = ERR_NEW_VERSION_REQUIRED;
					goto err;
				}

				// Header version
				cryptoInfo->HeaderVersion = headerVersion;

				// Volume creation time (legacy)
				cryptoInfo->volume_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_CREATION_TIME).Value;

				// Header creation time (legacy)
				cryptoInfo->header_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_MODIFICATION_TIME).Value;

				// Hidden volume size (if any)
				cryptoInfo->hiddenVolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE).Value;

				// Hidden volume status
				cryptoInfo->hiddenVolume = (cryptoInfo->hiddenVolumeSize != 0);

				// Volume size
				cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE);
				
				// Encrypted area size and length
				cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START);
				cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH);

				// Flags
				cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS);

				// Sector size
				if (headerVersion >= 5)
					cryptoInfo->SectorSize = GetHeaderField32 (header, TC_HEADER_OFFSET_SECTOR_SIZE);
				else
					cryptoInfo->SectorSize = TC_SECTOR_SIZE_LEGACY;

				if (cryptoInfo->SectorSize < TC_MIN_VOLUME_SECTOR_SIZE
					|| cryptoInfo->SectorSize > TC_MAX_VOLUME_SECTOR_SIZE
					|| cryptoInfo->SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0)
				{
					status = ERR_PARAMETER_INCORRECT;
					goto err;
				}

				// Preserve scheduled header keys if requested			
				if (retHeaderCryptoInfo)
				{
					if (retInfo == NULL)
					{
						cryptoInfo->pkcs5 = pkcs5_prf;
						cryptoInfo->noIterations = keyInfo.noIterations;
						goto ret;
					}

					cryptoInfo = *retInfo = crypto_open ();
					if (cryptoInfo == NULL)
					{
						status = ERR_OUTOFMEMORY;
						goto err;
					}

					memcpy (cryptoInfo, retHeaderCryptoInfo, sizeof (*cryptoInfo));
				}

				// Master key data
				memcpy (keyInfo.master_keydata, header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE);
				memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE);

				// PKCS #5
				memcpy (cryptoInfo->salt, keyInfo.salt, PKCS5_SALT_SIZE);
				cryptoInfo->pkcs5 = pkcs5_prf;
				cryptoInfo->noIterations = keyInfo.noIterations;

				// Init the cipher with the decrypted master key
				status = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks);
				if (status == ERR_CIPHER_INIT_FAILURE)
					goto err;

				switch (cryptoInfo->mode)
				{
				case LRW:
				case CBC:
				case INNER_CBC:
				case OUTER_CBC:

					// For LRW (deprecated/legacy), the tweak key
					// For CBC (deprecated/legacy), the IV/whitening seed
					memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE);
					break;

				default:
					// The secondary master key (if cascade, multiple concatenated)
					memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));

				}

				if (!EAInitMode (cryptoInfo))
				{
					status = ERR_MODE_INIT_FAILED;
					goto err;
				}

				status = ERR_SUCCESS;
				goto ret;
			}
		}
	}
	status = ERR_PASSWORD_WRONG;

err:
	if (cryptoInfo != retHeaderCryptoInfo)
	{
		crypto_close(cryptoInfo);
		*retInfo = NULL; 
	}

ret:
	burn (&keyInfo, sizeof (keyInfo));
	burn (dk, sizeof(dk));

#ifndef DEVICE_DRIVER
	VirtualUnlock (&keyInfo, sizeof (keyInfo));
	VirtualUnlock (&dk, sizeof (dk));
#endif

	if (encryptionThreadCount > 1)
	{
		TC_WAIT_EVENT (noOutstandingWorkItemEvent);

		burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
		TCfree (keyDerivationWorkItems);

#ifndef DEVICE_DRIVER
		CloseHandle (keyDerivationCompletedEvent);
		CloseHandle (noOutstandingWorkItemEvent);
#endif
	}

	return status;
}
Esempio n. 13
0
///
///	Note: if there are Keyfiles, these must be applied already to the password!
/// int __declspec(dllexport)  __stdcall  CheckVolumeHeaderPassword (BOOL bBoot, char *encryptedHeader, Password *password) 
int __declspec(dllexport)  __cdecl  CheckVolumeHeaderPassword (BOOL bBoot, char *encryptedHeader, Password *password)
{
	char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
	KEY_INFO keyInfo;
	PCRYPTO_INFO cryptoInfo;
	char dk[MASTER_KEYDATA_SIZE];
	int enqPkcs5Prf, pkcs5_prf;
	uint16 headerVersion;
	int status = ERR_PARAMETER_INCORRECT;
	int primaryKeyOffset;

	TC_EVENT keyDerivationCompletedEvent;
	TC_EVENT noOutstandingWorkItemEvent;
	KeyDerivationWorkItem *keyDerivationWorkItems;
	KeyDerivationWorkItem *item;
	int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1;
	size_t encryptionThreadCount = GetEncryptionThreadCount();
	size_t queuedWorkItems = 0;
	LONG outstandingWorkItemCount = 0;
	int i;

	cryptoInfo = crypto_open();
	if (cryptoInfo == NULL)
		return ERR_OUTOFMEMORY;


	if (encryptionThreadCount > 1)
	{
		keyDerivationWorkItems = TCalloc (sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
		if (!keyDerivationWorkItems)
			return ERR_OUTOFMEMORY;

		for (i = 0; i < pkcs5PrfCount; ++i)
			keyDerivationWorkItems[i].Free = TRUE;


		keyDerivationCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
		if (!keyDerivationCompletedEvent)
		{
			TCfree (keyDerivationWorkItems);
			return ERR_OUTOFMEMORY;
		}

		noOutstandingWorkItemEvent = CreateEvent (NULL, FALSE, TRUE, NULL);
		if (!noOutstandingWorkItemEvent)
		{
			CloseHandle (keyDerivationCompletedEvent);
			TCfree (keyDerivationWorkItems);
			return ERR_OUTOFMEMORY;
		}
	}
		

	VirtualLock (&keyInfo, sizeof (keyInfo));
	VirtualLock (&dk, sizeof (dk));

	crypto_loadkey (&keyInfo, password->Text, (int) password->Length);

	// PKCS5 is used to derive the primary header key(s) and secondary header key(s) (XTS mode) from the password
	memcpy (keyInfo.salt, encryptedHeader + HEADER_SALT_OFFSET, PKCS5_SALT_SIZE);

	// Test all available PKCS5 PRFs
	for (enqPkcs5Prf = FIRST_PRF_ID; enqPkcs5Prf <= LAST_PRF_ID || queuedWorkItems > 0; ++enqPkcs5Prf)
	{
		BOOL lrw64InitDone = FALSE;		// Deprecated/legacy
		BOOL lrw128InitDone = FALSE;	// Deprecated/legacy

		if (encryptionThreadCount > 1)
		{
			// Enqueue key derivation on thread pool
			if (queuedWorkItems < encryptionThreadCount && enqPkcs5Prf <= LAST_PRF_ID)
			{
				for (i = 0; i < pkcs5PrfCount; ++i)
				{
					item = &keyDerivationWorkItems[i];
					if (item->Free)
					{
						item->Free = FALSE;
						item->KeyReady = FALSE;
						item->Pkcs5Prf = enqPkcs5Prf;

						EncryptionThreadPoolBeginKeyDerivation (&keyDerivationCompletedEvent, &noOutstandingWorkItemEvent,
							&item->KeyReady, &outstandingWorkItemCount, enqPkcs5Prf, keyInfo.userKey,
							keyInfo.keyLength, keyInfo.salt, get_pkcs5_iteration_count (enqPkcs5Prf, bBoot), item->DerivedKey);
						
						++queuedWorkItems;
						break;
					}
				}

				if (enqPkcs5Prf < LAST_PRF_ID)
					continue;
			}
			else
				--enqPkcs5Prf;

			// Wait for completion of a key derivation
			while (queuedWorkItems > 0)
			{
				for (i = 0; i < pkcs5PrfCount; ++i)
				{
					item = &keyDerivationWorkItems[i];
					if (!item->Free && InterlockedExchangeAdd (&item->KeyReady, 0) == TRUE)
					{
						pkcs5_prf = item->Pkcs5Prf;
						keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, bBoot);
						memcpy (dk, item->DerivedKey, sizeof (dk));

						item->Free = TRUE;
						--queuedWorkItems;
						goto KeyReady;
					}
				}

				if (queuedWorkItems > 0)
					TC_WAIT_EVENT (keyDerivationCompletedEvent);
			}
			continue;
KeyReady:	;
		}
		else
		{
			pkcs5_prf = enqPkcs5Prf;
			keyInfo.noIterations = get_pkcs5_iteration_count (enqPkcs5Prf, bBoot);

			switch (pkcs5_prf)
			{
			case RIPEMD160:
				derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
					PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
				break;

			case SHA512:
				derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
					PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
				break;

			case SHA1:
				// Deprecated/legacy
				derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
					PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
				break;

			case WHIRLPOOL:
				derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
					PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
				break;

			default:		
				// Unknown/wrong ID
				TC_THROW_FATAL_EXCEPTION;
			} 
		}

		// Test all available modes of operation
		for (cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID;
			cryptoInfo->mode <= LAST_MODE_OF_OPERATION;
			cryptoInfo->mode++)
		{
			switch (cryptoInfo->mode)
			{
			case LRW:
			case CBC:
			case INNER_CBC:
			case OUTER_CBC:

				// For LRW (deprecated/legacy), copy the tweak key 
				// For CBC (deprecated/legacy), copy the IV/whitening seed 
				memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE);
				primaryKeyOffset = LEGACY_VOL_IV_SIZE;
				break;

			default:
				primaryKeyOffset = 0;
			}

			// Test all available encryption algorithms
			for (cryptoInfo->ea = EAGetFirst ();
				cryptoInfo->ea != 0;
				cryptoInfo->ea = EAGetNext (cryptoInfo->ea))
			{
				int blockSize;

				if (!EAIsModeSupported (cryptoInfo->ea, cryptoInfo->mode))
					continue;	// This encryption algorithm has never been available with this mode of operation

				blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea));

				status = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks);
				if (status == ERR_CIPHER_INIT_FAILURE)
					goto err;

				// Init objects related to the mode of operation

				if (cryptoInfo->mode == XTS)
				{
					// Copy the secondary key (if cascade, multiple concatenated)
					memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));

					// Secondary key schedule
					if (!EAInitMode (cryptoInfo))
					{
						status = ERR_MODE_INIT_FAILED;
						goto err;
					}
				}
				else if (cryptoInfo->mode == LRW
					&& (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone))
				{
					// Deprecated/legacy

					if (!EAInitMode (cryptoInfo))
					{
						status = ERR_MODE_INIT_FAILED;
						goto err;
					}

					if (blockSize == 8)
						lrw64InitDone = TRUE;
					else if (blockSize == 16)
						lrw128InitDone = TRUE;
				}

				// Copy the header for decryption
				memcpy (header, encryptedHeader, sizeof (header));

				// Try to decrypt header 

				DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);

				// Magic 'TRUE'
				if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) == 0x54525545){
					status = ERR_SUCCESS;
					goto ret;
				}
			}
		}
	}
	status = ERR_PASSWORD_WRONG;

err:
ret:
	burn (&keyInfo, sizeof (keyInfo));
	burn (dk, sizeof(dk));

	VirtualUnlock (&keyInfo, sizeof (keyInfo));
	VirtualUnlock (&dk, sizeof (dk));

	if (encryptionThreadCount > 1)
	{
	//	TC_WAIT_EVENT (noOutstandingWorkItemEvent);

		burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
		TCfree (keyDerivationWorkItems);

		CloseHandle (keyDerivationCompletedEvent);
		CloseHandle (noOutstandingWorkItemEvent);
	}

	return status;
}
Esempio n. 14
0
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;
                }