The Grayzone

Implementing DPAPI in Compact Framework

I have used the Windows Data Protection API in a number of Windows applications for machine encrypting values. I was trying to implement CryptProtectData and CryptUnprotectData for use on a Windows Mobile device.

I tried using the wrapper class that I use for standard Windows development with the following DllImports:

[DllImport("crypt32.dll", EntryPoint = "CryptProtectData", CharSet = CharSet.Auto)]
public static extern bool Encrypt ( .... )

[DllImport("crypt32.dll", EntryPoint = "CryptUnprotectData", CharSet = CharSet.Auto)]
public static extern bool Decrypt( .... )

However, when I tried to use this I received the error:

Can’t find an Entry Point ‘CryptProtectData’ in a PInvoke DLL ‘crypt32.dll’.

It took me a while to figure out what was happening. The issue was that in Compact Framework the methods are from coredll.dll, not Crypt32.dll as it is in Desktop Windows. So the signature (including parameters) now becomes:

[DllImport("coredll.dll", EntryPoint = "CryptProtectData", CharSet = CharSet.Auto)]
public static extern bool Encrypt(
  ref DataBlob dataIn,
  String description,
  ref DataBlob optionalEntropy,
  IntPtr reserved,
  ref CryptProtectPromptStruct promptStruct,
  int flags,
  out DataBlob dataOut);

[DllImport("coredll.dll", EntryPoint = "CryptUnprotectData", CharSet = CharSet.Auto)]
public static extern bool Decrypt(
  ref DataBlob dataIn,
  String description,
  ref DataBlob optionalEntropy,
  IntPtr reserved,
  ref CryptProtectPromptStruct promptStruct,
  int flags,
  out DataBlob dataOut);

This is obvious when you fully read the MSDN articles I’ve linked too but I was in a hurry and presumed that it would be the same dll!

I also use the following two structures for passing to the above methods:

[StructLayout(LayoutKind.Sequential)]
internal struct CryptProtectPromptStruct
{
	internal Int32 Size;
	internal Int32 Flags;
	internal IntPtr Window;

	[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
	internal String Message;
}

internal struct DataBlob
{
	internal Int32 Size;
	internal IntPtr Data;
}

Without the StructLayoutAttribute and MarshalAsAttribute on the CryptProtectPromptStruct you will receive the following error:

“NotSupportedException” at System.Runtime.InteropServices.Marshal.SizeOfInternal()

This is because (thanks to this article for the info) the struct must be a Blittable type, meaning that the struct must be represented identically in both managed and unmanaged memory.


Share this: