AltiVec, Power8 and Asserts

4 views
Skip to first unread message

Jeffrey Walton

unread,
Sep 3, 2017, 8:28:43 PM9/3/17
to Crypto++ Users
Hi Everyone,

We've been working on AltiVec and Power8. We mostly have AES done except for some memory errors. AltiVec and Power8 solve the unaligned buffer problem by masking the low-order address bits so everything is aligned. They turn an address like 0xAAAAAAA8 into 0xAAAAAAA0, so we've got some wild writes.

The processor has revealed some issues in our code. One of the controls I want to put in place is debug assert the buffer alignments. I think the first defense is to make the code debug itself, so this will relieve us of doing it:

   void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t length)
   {
      // If this fires you should align your buffers. There's a non-trival penalty for some processors
      CRYPTOPP_ASSERT(IsAlignedOn(inString, m_cipher->OptimalDataAlignment()));
      CRYPTOPP_ASSERT(IsAlignedOn(outString, m_cipher->OptimalDataAlignment()));
      CRYPTOPP_ASSERT(length%BlockSize()==0);
      ...
   }

Because users expect things to "just work", we need to fixup the buffers on the fly:

   bool align = !IsAlignedOn(m_register, alignment) || !IsAlignedOn(inString, alignment) || !IsAlignedOn(outString, alignment);

   if (align)
   {
      AlignedSecByteBlock i(length), o(length), x;
      std::memcpy(i, inString, blockSize);
      std::memcpy(o, outString, blockSize);
      if (!m_register.empty()) {x = m_register;}

      m_cipher->AdvancedProcessBlocks(i, x, o, blockSize, BlockTransformation::BT_XorInput);
      if (length > blockSize)
         m_cipher->AdvancedProcessBlocks(i+blockSize, o, o+blockSize, length-blockSize, BlockTransformation::BT_XorInput);
      std::memcpy(m_register, o + length - blockSize, blockSize);
      std::memcpy(outString, o, length);
   }

In the future you may see some asserts firing in debug builds. For the Crypto++ project, this is our big offender: https://github.com/weidai11/cryptopp/blob/master/validat1.cpp#L2078. All the byte buffers are misaligned and suffer the masking. We will be switching to an AlignedSecByteBlock or CRYPTOPP_ALIGN_DATA(16).

If the assert fires for your project, then you should align your buffers. If you find std:;string's are causing your problems, then you can use the library's aligned allocator:

  typedef std::basic_string<char, std::char_traits<char>, AllocatorWithCleanup<char, true> > aligned_string;

Jeff
Reply all
Reply to author
Forward
0 new messages