Example #1
0
void CFB_CipherTemplate<BASE>::ProcessData(byte *outString, const byte *inString, unsigned int length)
{
	assert(length % this->MandatoryBlockSize() == 0);

	PolicyInterface &policy = this->AccessPolicy();
	unsigned int bytesPerIteration = policy.GetBytesPerIteration();
	unsigned int alignment = policy.GetAlignment();
	byte *reg = policy.GetRegisterBegin();

	if (m_leftOver)
	{
		unsigned int len = STDMIN(m_leftOver, length);
		CombineMessageAndShiftRegister(outString, reg + bytesPerIteration - m_leftOver, inString, len);
		m_leftOver -= len;
		length -= len;
		inString += len;
		outString += len;
	}

	if (!length)
		return;

	assert(m_leftOver == 0);

	if (policy.CanIterate() && length >= bytesPerIteration && IsAlignedOn(outString, alignment))
	{
		if (IsAlignedOn(inString, alignment))
			policy.Iterate(outString, inString, GetCipherDir(*this), length / bytesPerIteration);
		else
		{
			memcpy(outString, inString, length);
			policy.Iterate(outString, outString, GetCipherDir(*this), length / bytesPerIteration);
		}
		inString += length - length % bytesPerIteration;
		outString += length - length % bytesPerIteration;
		length %= bytesPerIteration;
	}

	while (length >= bytesPerIteration)
	{
		policy.TransformRegister();
		CombineMessageAndShiftRegister(outString, reg, inString, bytesPerIteration);
		length -= bytesPerIteration;
		inString += bytesPerIteration;
		outString += bytesPerIteration;
	}

	if (length > 0)
	{
		policy.TransformRegister();
		CombineMessageAndShiftRegister(outString, reg, inString, length);
		m_leftOver = bytesPerIteration - length;
	}
}
Example #2
0
void CFB_CipherTemplate<BASE>::ProcessData(byte *outString, const byte *inString, size_t length)
{
	CRYPTOPP_ASSERT(outString); CRYPTOPP_ASSERT(inString);
	CRYPTOPP_ASSERT(length % this->MandatoryBlockSize() == 0);

	PolicyInterface &policy = this->AccessPolicy();
	word32 bytesPerIteration = policy.GetBytesPerIteration();
	byte *reg = policy.GetRegisterBegin();

	if (m_leftOver)
	{
		const size_t len = STDMIN(m_leftOver, length);
		CombineMessageAndShiftRegister(outString, PtrAdd(reg, bytesPerIteration - m_leftOver), inString, len);

		m_leftOver -= len; length -= len;
		inString = PtrAdd(inString, len);
		outString = PtrAdd(outString, len);
	}

	// TODO: Figure out what is happening on ARM A-32. x86, Aarch64 and PowerPC are OK.
	//       The issue surfaced for CFB mode when we cut-in Cryptogams AES ARMv7 asm.
	//       Using 'outString' for both input and output leads to incorrect results.
	//
	//       Benchmarking on Cortex-A7 and Cortex-A9 indicates removing the block
	//       below costs about 9 cpb for CFB mode on ARM.
	//
	//       Also see https://github.com/weidai11/cryptopp/issues/683.
	//
	// UPDATE: It appears the issue is related to alignment checks. When we made
	//       the alignment check result volatile GCC and Clang stopped short-
	//       circuiting the transform, which is what we wanted. I suspect
	//       there's a little more to the issue, but we can enable the block again.

	const unsigned int alignment = policy.GetAlignment();
	volatile bool isAligned = IsAlignedOn(outString, alignment);
	if (policy.CanIterate() && length >= bytesPerIteration && isAligned)
	{
		isAligned &= IsAlignedOn(inString, alignment);
		const CipherDir cipherDir = GetCipherDir(*this);
		if (isAligned)
			policy.Iterate(outString, inString, cipherDir, length / bytesPerIteration);
		else
		{
			// GCC and Clang does not like this on ARM. The incorrect result is a string
			// of 0's instead of ciphertext (or plaintext if decrypting). The 0's trace
			// back to the allocation for the std::string in datatest.cpp. Elements in the
			// string are initialized to their default value, which is 0.
			//
			// It almost feels as if the compiler does not see the string is transformed
			// in-place so it short-circuits the transform. However, if we use a stand-alone
			// reproducer with the same data then the issue is _not_ present.
			//
			// When working on this issue we introduced PtrAdd and PtrSub to ensure we were
			// not running afoul of pointer arithmetic rules of the language. Namely we need
			// to use ptrdiff_t when subtracting pointers. We believe the relevant code paths
			// are clean.
			//
			// One workaround is a distinct and aligned temporary buffer. It [mostly] works
			// as expected but requires an extra allocation (casts not shown):
			//
			//   std::string temp(inString, length);
			//   policy.Iterate(outString, &temp[0], cipherDir, length / bytesPerIteration);
			//
			memcpy(outString, inString, length);
			policy.Iterate(outString, outString, cipherDir, length / bytesPerIteration);
		}
		const size_t remainder = length % bytesPerIteration;
		inString = PtrAdd(inString, length - remainder);
		outString = PtrAdd(outString, length - remainder);
		length = remainder;
	}

	while (length >= bytesPerIteration)
	{
		policy.TransformRegister();
		CombineMessageAndShiftRegister(outString, reg, inString, bytesPerIteration);
		length -= bytesPerIteration;
		inString = PtrAdd(inString, bytesPerIteration);
		outString = PtrAdd(outString, bytesPerIteration);
	}

	if (length > 0)
	{
		policy.TransformRegister();
		CombineMessageAndShiftRegister(outString, reg, inString, length);
		m_leftOver = bytesPerIteration - length;
	}
}