2013-08-31 120 views
2

我已经将Christophe Devine的FIPS-197 compliant AES implementation包装在托管的C++/CLI类中。在加密/解密每个4096字节的20到52个块之后,我遇到了麻烦。我已经能够缩小问题到这一点:内存和结构互操作性的C++/CLI编组/混叠

如果我宣布一个本地指针aes_context结构,只是新一轮上涨在构造函数中aes_context,像这样

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

然后代码会运行良好。

但是,当我试图宣布aes_contextarray<System::Byte>^,然后在构造函数中执行此

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

虽然它编译并在理论上应该工作,这个现在不

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

有效和有限的经验,这应该工作得很好。唯一的区别是内存是由GC分配的,我必须在将内存传递给AES库之前对其进行固定。我还应该澄清这是一个在运行时发生的错误,而不是编译器错误。

我无法以任何其他方式重现此问题,并且我针对其他参考实施运行的所有测试均未发现实施方面的任何问题。我甚至设置了两个完全相同的测试用例,一个用C语言编写,一个用C++/CLI(使用托管包装调用AES库);当托管的字节数组支持托管包装器不起作用!

由于问题没有通过公平的数据处理后显示出来,我一直认为这是一个截断或对齐问题,但无论我多少分配过多,我都会得到相同的结果。

我正在使用Visual Studio 2012 C++编译器。

有没有人知道任何可能暗示为什么会出现这种情况?

+0

是'数组<系统::字节> ^'正确/有意? –

+0

@JonathanLeffler是的,它告诉C++/CLI编译器它是一个托管类型。由'gcnew'返回的任何值都有'^'的类型来指示它的生命周期由GC管理。它反过来限制你如何使用这种类型来确保正确的行为。 –

+0

好的 - 我对是否删除它有所怀疑,并决定检查。这是微软对C++ 11标准(和/或任何早期的C++标准)的扩展,不是吗? –

回答

3

不确定是只有问题,但aes_context被声明为包含指针rk;

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

...由(例如)aes_setkey_enc指向一个地址insinde buf相同的上下文内设定;

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

如果 - 这个指针,而且你的钉住指针之间 - 的情况下内存块是在内存中移动,则将ctx-> RK将指向未分配的内存。

我怀疑制作m_Context固定指针,以保持它永久固定,而不是暂时固定它为每个调用将使程序运行成功。

+1

当然,就是这样!我改变了它,所以我存储了'rk',相对'buf'和瞧。谢谢,我一直坚持这一段时间! –