我正在做一个使用证书做一些工作的项目,我需要将 CTL_USAGE 结构转换为 C#。原结构如下:
typedef struct _CTL_USAGE {
DWORD cUsageIdentifier;
LPSTR *rgpszUsageIdentifier;
} CTL_USAGE, *PCTL_USAGE, CERT_ENHKEY_USAGE, *PCERT_ENHKEY_USAGE;
根据 P/Invoke 网站,C# 结构应该是这样的:
[StructLayout(LayoutKind.Sequential)]
public struct CTL_USAGE
{
public int cUsageIdentifier;
public IntPtr rgpszUsageIdentifier;
}
要使用此代码,我使用 Encoding.ASCII.GetBytes() 将要添加到结构中的每个字符串转换为字节数组。然后我使用 GCHandle.Alloc(byteArray, GCHandleType.Pinned) 将该字节数组转换为 GCHandle。我将该值添加到 IntPtrs 数组中,然后为 IntPtr 数组创建一个 GCHandle 并将其分配给 rgpszUsageIdentifier。对 CryptEncodeObjectEx 的调用不会引发错误,但生成的数据是垃圾,无法使用 CryptDecodeObject 解密。我的编码如下:
//EnhancedUsage is a List<String> containing the Enhanced Usage OIDs
CTL_USAGE usage = new CTL_USAGE()
{
cUsageIdentifier = EnhancedUsage.Count,
};
List<IntPtr> usageList = new List<IntPtr>();
foreach (string s in EnhancedUsage)
usageList.Add(new PinnedHandle(Encoding.ASCII.GetBytes(s)));
usage.rgpszUsageIdentifier = new PinnedHandle(usageList.ToArray());
IntPtr data = Marshal.AllocHGlobal(Marshal.SizeOf(usage));
Marshal.StructureToPtr(usage, data, false);
int encodedSize = 0;
if (!Crypt32.CryptEncodeObjectEx((int)CertEncoding.X509Asn, CertOid.szOID_ENHANCED_KEY_USAGE, data, 0, IntPtr.Zero, null, ref encodedSize))
throw new Win32Exception();
byte[] buffer = new byte[encodedSize];
if (!Crypt32.CryptEncodeObjectEx((int)CertEncoding.X509Asn, CertOid.szOID_ENHANCED_KEY_USAGE, data, 0, IntPtr.Zero, buffer, ref encodedSize))
throw new Win32Exception();
PinnedHandle 类是 GCHandle 的包装器。它看起来像这样:
public class PinnedHandle : IDisposable
{
private GCHandle handle;
public PinnedHandle(object value)
{
handle = GCHandle.Alloc(value, GCHandleType.Pinned);
}
public static implicit operator IntPtr(PinnedHandle value)
{
return value.handle.AddrOfPinnedObject();
}
public void Dispose()
{
try
{
handle.Free();
}
catch
{
}
}
}
我不认为它在这里造成任何问题,因为我在其他类似情况下使用过它并且它们工作正常。知道如何使它正常工作吗?