简体   繁体   中英

C++/CLI marshalling/aliasing of memory and struct interoperability

I've wrapped Christophe Devine's FIPS-197 compliant AES implementation in a managed C++/CLI class. I'm running into trouble after encrypting/decrypting anywhere from 20 to 52 blocks of 4096 bytes each. I've been able to narrow the issue down to this:

If I declare a native pointer to the aes_context struct and just new up the aes_context in the constructor, like so

Aes::Aes()
    : m_Context(new aes_context)
{
}

Then the code will run fine.

But when I attempt to declare the aes_context as array<System::Byte>^ and then in the constructor do this

Aes::Aes()
    : m_Context(gcnew array<System::Byte>(sizeof(aes_context)))
{
}

While it does compile and in theory should work, this now doesn't

pin_ptr<System::Byte> pinned_context = &m_Context[0];
auto context = (aes_context*)pinned_context;
aes_crypt_cbc(context, ...);

Effectively and in my limited experience, this should work just fine. The only difference is that the memory was allocated by the GC and that I have to pin the memory before I pass it to the AES library. I should also clarify that this is an error that happens at run-time not a compiler error.

I was unable to reproduce this issue any other way and all tests that I have run against other reference implementation doesn't reveal any issues with implementation. I've even set up two exactly identical test cases, one in C and one in C++/CLI (that uses the managed wrapper to call into the AES library); the managed wrapper doesn't work when backed by a managed byte array !?

Since the problem doesn't reveal itself after you've run through a fair deal of data, I've been thinking it's a truncation or alignment issue, but regardless of how much I over-allocate I get the same result.

I'm using the Visual Studio 2012 C++ compiler.

Does anyone know anything that might suggest why this is the case?

Not sure it's the only problem, but aes_context is declared to contain a pointer, rk ;

typedef struct
{
    int nr;                     /*!<  number of rounds  */
    unsigned long *rk;          /*!<  AES round keys    */
    unsigned long buf[68];      /*!<  unaligned data    */
}
aes_context;

...that is set by (for example) aes_setkey_enc to point to an address insinde buf inside the same context;

ctx->rk = RK = ctx->buf;

If - between that pointer set and your pinning the pointer - the context memory block is moved in memory, ctx->rk will point to unallocated memory.

I suspect making m_Context a pinned pointer to keep it permanently pinned instead of pinning it temporarily for each call would make the program run successfully.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM