I'd like to read an EFS certificate (say from a pfx file) and use it temporarily to read/write some files. (I'd like it to not persist in any store once the program exits.) It looks like SetUserFileEncryptionKey
might provide this functionality, but I get a bizarre return code (0x80092004
) when I try it. Here's my code:
var x509Cert = new X509Certificate2(@"C:\Users\Public\Downloads\key.pfx", "<mypass>");
var certContext = Marshal.PtrToStructure<CertContext>(x509Cert.Handle);
var blob = new EfsCertificateBlob
{
dwCertEncodingType = certContext.dwCertEncodingType,
cbData = certContext.cbCertEncoded,
pbData = certContext.pbCertEncoded,
};
var pCertBlob = Marshal.AllocHGlobal(Marshal.SizeOf(blob));
Marshal.StructureToPtr(blob, pCertBlob, false);
var id = WindowsIdentity.GetCurrent();
var curStringSid = id.User?.Value;
Console.WriteLine(curStringSid);
ConvertStringSidToSid(curStringSid, out var sidPtr);
var certStruct = new EncryptionCertificate
{
cbTotalLength = (uint) Marshal.SizeOf(typeof(EncryptionCertificate)),
pUserSid = sidPtr,
pCertBlob = pCertBlob,
};
var res = SetUserFileEncryptionKey(certStruct);
Console.WriteLine($"Result: 0x{res:X}"); // Result: 0x80092004
Here too is my interop code:
[StructLayout(LayoutKind.Sequential)]
public class CertContext
{
public uint dwCertEncodingType;
public IntPtr pbCertEncoded;
public uint cbCertEncoded;
public IntPtr pCertInfo;
public IntPtr hCertStore;
}
[StructLayout(LayoutKind.Sequential)]
public class EfsCertificateBlob
{
public uint dwCertEncodingType;
public uint cbData;
public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential)]
public class EncryptionCertificate
{
public uint cbTotalLength;
public IntPtr pUserSid;
public IntPtr pCertBlob;
}
[DllImport("Advapi32.dll")]
public static extern uint SetUserFileEncryptionKey(EncryptionCertificate pEncryptionCertificate);
Does SetUserFileEncryptionKey
do what I hope it does? And what am I doing wrong here?
(My use case is in working with sensitive data that I don't want the user to later be able to read or redistribute. So I'd like those files to be inaccessible as soon as the process terminates.)
It appears that 0x80092004
is CRYPT_E_NOT_FOUND
and that SetUserFileEncryptionKey
only works with certificates that are already part of the user's certificate store. When I import the relevant certificate, the above code returns ERROR_SUCCESS
. It seems this function doesn't serve the use case that I hoped it did.
User contributions licensed under CC BY-SA 3.0