【问题标题】:Passing a structure appears to corrupt data传递结构似乎会损坏数据
【发布时间】:2012-02-02 16:28:39
【问题描述】:

我有一个程序需要将数据从 C++ 传递到 C# 并返回进行处理。为此,我检索了一个结构,将其转换为字节数组,然后在另一端将其转换回。但是,在转换回来时,数据不正确,即使内存转储显示内存中每个变量的值都是相同的。

这是检索值的代码:

array<Byte> ^ GetPublicKeyBlob(String ^ ContainerName) {
    const TCHAR * tContainer = context->marshal_as<const TCHAR*>(ContainerName);
    HCRYPTPROV hProv = NULL;
    CryptAcquireContext(&hProv, tContainer, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET);
    DWORD dwKeySize = 0;
    CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL, &dwKeySize);
    PCERT_PUBLIC_KEY_INFO pbKey = (PCERT_PUBLIC_KEY_INFO)calloc(dwKeySize, sizeof(BYTE));
    CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, (PCERT_PUBLIC_KEY_INFO)pbKey, &dwKeySize);
    array<Byte> ^ retVal = gcnew array<Byte>(dwKeySize);
        for(int i = 0; i < dwKeySize; i++)
            retVal[i] = ((BYTE*)pbKey)[i];

    free(pbKey);
return retVal;
}

然后在另一端,我将其改回 PCERT_PUBLIC_KEY_INFO 结构,代码如下:

BYTE * cpiBuffer = (BYTE*)calloc(_PublicKey->Length, sizeof(BYTE));
for(int i = 0; i < _PublicKey->Length; i++)
    cpiBuffer[i] = _PublicKey[i];
PCERT_PUBLIC_KEY_INFO cpi = (PCERT_PUBLIC_KEY_INFO)cpiBuffer;

在内存转储中查看它们时,pbKey、retVal、_PublicKey、cpiBuffer 和 cpi 都具有完全相同的值。但是当将 cpi 视为一个结构时,Algorithm.pszObjId 指向一些错误的内存位置,当我尝试在函数中使用它时,它会失败。我在这里做错了什么?

【问题讨论】:

  • “Algorithm.pszObjId 指向某个错误的内存位置”是什么意思?是指针吗?
  • 这是一个 LPSTR。当我在手表中展开结构时,它指向一个不在结构内的内存位置,而当我得到原始值时,它指向的是结构内的一个位置。

标签: c# c++ interop c++-cli cryptoapi


【解决方案1】:
typedef struct _CRYPT_ALGORITHM_IDENTIFIER {
  LPSTR            pszObjId;
  CRYPT_OBJID_BLOB Parameters;
} CRYPT_ALGORITHM_IDENTIFIER, *PCRYPT_ALGORITHM_IDENTIFIER;

如您所见,pszObjId 是一个指针,它的内容位于内存中的某个位置。通过将 PCERT_PUBLIC_KEY_INFO 结构转换为字节数组,您只能获取指针的值,而不是它所指向的值。

顺便说一句,我不确定你为什么要编组为 TCHAR*,如果你想要字节,那么你应该使用 char* 或 unsigned char*。如果定义了 UNICODE,TCHAR 将是 wchar_t,这可能会带来一些困难。

【讨论】:

  • TCHAR* 只是习惯的力量。这是拼凑在一起的代码,而不是生产。如果不是通过铸造,我将如何恢复原始结构?
  • 我没有给你一个明确的答案,因为我不知道这些结构是如何创建的,谁分配字符串以及谁负责释放它。但我猜你可以创建一个知道如何序列化结构的函数,逐个成员,将字符串序列化为空终止字符数组或大小前缀。
  • 第一次调用 CryptExportPublicKeyInfo 返回 CERT_PUBLIC_KEY_INFO 结构所需的缓冲区长度。然后我分配该内存量并再次调用该函数并将数据传递到缓冲区中。
  • 该函数返回结构的大小,但不考虑堆分配的成员。 pszObjId 被计为一个指针。想想你将如何为这个结构和它的成员实现一个复制构造函数。然后,不要将所有内容复制到新对象,而是复制到内存缓冲区,然后就可以进行序列化了。
猜你喜欢
  • 2016-05-27
  • 2013-07-07
  • 2022-12-14
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
  • 2020-03-18
  • 1970-01-01
  • 2018-08-09
相关资源
最近更新 更多