Ejemplo n.º 1
0
	void EncryptionModeXTS::EncryptBufferXTS (const Cipher &cipher, const Cipher &secondaryCipher, byte *buffer, uint64 length, uint64 startDataUnitNo, unsigned int startCipherBlockNo) const
	{
		byte finalCarry;
		byte whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
		byte whiteningValue [BYTES_PER_XTS_BLOCK];
		byte byteBufUnitNo [BYTES_PER_XTS_BLOCK];
		uint64 *whiteningValuesPtr64 = (uint64 *) whiteningValues;
		uint64 *whiteningValuePtr64 = (uint64 *) whiteningValue;
		uint64 *bufPtr = (uint64 *) buffer;
		uint64 *dataUnitBufPtr;
		unsigned int startBlock = startCipherBlockNo, endBlock, block;
		uint64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1;
		uint64 blockCount, dataUnitNo;

		startDataUnitNo += SectorOffset;

		/* The encrypted data unit number (i.e. the resultant ciphertext block) is to be multiplied in the
		finite field GF(2^128) by j-th power of n, where j is the sequential plaintext/ciphertext block
		number and n is 2, a primitive element of GF(2^128). This can be (and is) simplified and implemented
		as a left shift of the preceding whitening value by one bit (with carry propagating). In addition, if
		the shift of the highest byte results in a carry, 135 is XORed into the lowest byte. The value 135 is
		derived from the modulus of the Galois Field (x^128+x^7+x^2+x+1). */

		// Convert the 64-bit data unit number into a little-endian 16-byte array. 
		// Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes.
		dataUnitNo = startDataUnitNo;
		*((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo);
		*((uint64 *) byteBufUnitNo + 1) = 0;

		if (length % BYTES_PER_XTS_BLOCK)
			TC_THROW_FATAL_EXCEPTION;

		blockCount = length / BYTES_PER_XTS_BLOCK;

		// Process all blocks in the buffer
		while (blockCount > 0)
		{
			if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
				endBlock = startBlock + (unsigned int) blockCount;
			else
				endBlock = BLOCKS_PER_XTS_DATA_UNIT;

			whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
			whiteningValuePtr64 = (uint64 *) whiteningValue;

			// Encrypt the data unit number using the secondary key (in order to generate the first 
			// whitening value for this data unit)
			*whiteningValuePtr64 = *((uint64 *) byteBufUnitNo);
			*(whiteningValuePtr64 + 1) = 0;
			secondaryCipher.EncryptBlock (whiteningValue);

			// Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit
			// whitening values are stored in memory as a sequence of 64-bit integers in reverse order.
			for (block = 0; block < endBlock; block++)
			{
				if (block >= startBlock)
				{
					*whiteningValuesPtr64-- = *whiteningValuePtr64++;
					*whiteningValuesPtr64-- = *whiteningValuePtr64;
				}
				else
					whiteningValuePtr64++;

				// Derive the next whitening value

#if BYTE_ORDER == LITTLE_ENDIAN

				// Little-endian platforms

				finalCarry = 
					(*whiteningValuePtr64 & 0x8000000000000000ULL) ?
					135 : 0;

				*whiteningValuePtr64-- <<= 1;

				if (*whiteningValuePtr64 & 0x8000000000000000ULL)
					*(whiteningValuePtr64 + 1) |= 1;	

				*whiteningValuePtr64 <<= 1;
#else

				// Big-endian platforms

				finalCarry = 
					(*whiteningValuePtr64 & 0x80) ?
					135 : 0;

				*whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1);

				whiteningValuePtr64--;

				if (*whiteningValuePtr64 & 0x80)
					*(whiteningValuePtr64 + 1) |= 0x0100000000000000ULL;	

				*whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1);
#endif

				whiteningValue[0] ^= finalCarry;
			}

			dataUnitBufPtr = bufPtr;
			whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;

			// Encrypt all blocks in this data unit

			for (block = startBlock; block < endBlock; block++)
			{
				// Pre-whitening
				*bufPtr++ ^= *whiteningValuesPtr64--;
				*bufPtr++ ^= *whiteningValuesPtr64--;
			}

			// Actual encryption
			cipher.EncryptBlocks ((byte *) dataUnitBufPtr, endBlock - startBlock);

			bufPtr = dataUnitBufPtr;
			whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;

			for (block = startBlock; block < endBlock; block++)
			{
				// Post-whitening
				*bufPtr++ ^= *whiteningValuesPtr64--;
				*bufPtr++ ^= *whiteningValuesPtr64--;
			}

			blockCount -= endBlock - startBlock;
			startBlock = 0;
			dataUnitNo++;
			*((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo);
		}

		FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
		FAST_ERASE64 (whiteningValues, sizeof (whiteningValues));
	}
Ejemplo n.º 2
0
	void EncryptionModeXTS::DecryptBufferXTS (const Cipher &cipher, const Cipher &secondaryCipher, byte *buffer, uint64 length, uint64 startDataUnitNo, unsigned int startCipherBlockNo) const
	{
		byte finalCarry;
		byte whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
		byte whiteningValue [BYTES_PER_XTS_BLOCK];
		byte byteBufUnitNo [BYTES_PER_XTS_BLOCK];
		uint64 *whiteningValuesPtr64 = (uint64 *) whiteningValues;
		uint64 *whiteningValuePtr64 = (uint64 *) whiteningValue;
		uint64 *bufPtr = (uint64 *) buffer;
		uint64 *dataUnitBufPtr;
		unsigned int startBlock = startCipherBlockNo, endBlock, block;
		uint64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1;
		uint64 blockCount, dataUnitNo;

		startDataUnitNo += SectorOffset;

		// Convert the 64-bit data unit number into a little-endian 16-byte array. 
		// Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes.
		dataUnitNo = startDataUnitNo;
		*((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo);
		*((uint64 *) byteBufUnitNo + 1) = 0;

		if (length % BYTES_PER_XTS_BLOCK)
			TC_THROW_FATAL_EXCEPTION;

		blockCount = length / BYTES_PER_XTS_BLOCK;

		// Process all blocks in the buffer
		while (blockCount > 0)
		{
			if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
				endBlock = startBlock + (unsigned int) blockCount;
			else
				endBlock = BLOCKS_PER_XTS_DATA_UNIT;

			whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
			whiteningValuePtr64 = (uint64 *) whiteningValue;

			// Encrypt the data unit number using the secondary key (in order to generate the first 
			// whitening value for this data unit)
			*whiteningValuePtr64 = *((uint64 *) byteBufUnitNo);
			*(whiteningValuePtr64 + 1) = 0;
			secondaryCipher.EncryptBlock (whiteningValue);

			// Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit
			// whitening values are stored in memory as a sequence of 64-bit integers in reverse order.
			for (block = 0; block < endBlock; block++)
			{
				if (block >= startBlock)
				{
					*whiteningValuesPtr64-- = *whiteningValuePtr64++;
					*whiteningValuesPtr64-- = *whiteningValuePtr64;
				}
				else
					whiteningValuePtr64++;

				// Derive the next whitening value

#if BYTE_ORDER == LITTLE_ENDIAN

				// Little-endian platforms

				finalCarry = 
					(*whiteningValuePtr64 & 0x8000000000000000ULL) ?
					135 : 0;

				*whiteningValuePtr64-- <<= 1;

				if (*whiteningValuePtr64 & 0x8000000000000000ULL)
					*(whiteningValuePtr64 + 1) |= 1;	

				*whiteningValuePtr64 <<= 1;

#else
				// Big-endian platforms

				finalCarry = 
					(*whiteningValuePtr64 & 0x80) ?
					135 : 0;

				*whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1);

				whiteningValuePtr64--;

				if (*whiteningValuePtr64 & 0x80)
					*(whiteningValuePtr64 + 1) |= 0x0100000000000000ULL;	

				*whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1);
#endif

				whiteningValue[0] ^= finalCarry;
			}

			dataUnitBufPtr = bufPtr;
			whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;

			// Decrypt blocks in this data unit

			for (block = startBlock; block < endBlock; block++)
			{
				*bufPtr++ ^= *whiteningValuesPtr64--;
				*bufPtr++ ^= *whiteningValuesPtr64--;
			}

			cipher.DecryptBlocks ((byte *) dataUnitBufPtr, endBlock - startBlock);

			bufPtr = dataUnitBufPtr;
			whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;

			for (block = startBlock; block < endBlock; block++)
			{
				*bufPtr++ ^= *whiteningValuesPtr64--;
				*bufPtr++ ^= *whiteningValuesPtr64--;
			}

			blockCount -= endBlock - startBlock;
			startBlock = 0;
			dataUnitNo++;

			*((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo);
		}

		FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
		FAST_ERASE64 (whiteningValues, sizeof (whiteningValues));
	}