// http://msdn.microsoft.com/en-us/library/windows/desktop/aa380882(v=vs.85).aspx internal static extern bool CryptUnprotectData( [In] DATA_BLOB *pDataIn, [In] IntPtr ppszDataDescr, [In] DATA_BLOB *pOptionalEntropy, [In] IntPtr pvReserved, [In] IntPtr pPromptStruct, [In] uint dwFlags, [Out] out DATA_BLOB pDataOut);
internal static byte[] ProtectWithDpapiCore(byte* pbSecret, uint cbSecret, byte* pbOptionalEntropy, uint cbOptionalEntropy, bool fLocalMachine = false) { byte dummy; // provides a valid memory address if the secret or entropy has zero length DATA_BLOB dataIn = new DATA_BLOB() { cbData = cbSecret, pbData = (pbSecret != null) ? pbSecret : &dummy }; DATA_BLOB entropy = new DATA_BLOB() { cbData = cbOptionalEntropy, pbData = (pbOptionalEntropy != null) ? pbOptionalEntropy : &dummy }; DATA_BLOB dataOut = default(DATA_BLOB); #if !DOTNET5_4 RuntimeHelpers.PrepareConstrainedRegions(); #endif try { bool success = UnsafeNativeMethods.CryptProtectData( pDataIn: &dataIn, szDataDescr: IntPtr.Zero, pOptionalEntropy: &entropy, pvReserved: IntPtr.Zero, pPromptStruct: IntPtr.Zero, dwFlags: CRYPTPROTECT_UI_FORBIDDEN | ((fLocalMachine) ? CRYPTPROTECT_LOCAL_MACHINE : 0), pDataOut: out dataOut); if (!success) { int errorCode = Marshal.GetLastWin32Error(); throw new CryptographicException(errorCode); } int dataLength = checked((int)dataOut.cbData); byte[] retVal = new byte[dataLength]; Marshal.Copy((IntPtr)dataOut.pbData, retVal, 0, dataLength); return retVal; } finally { // Free memory so that we don't leak. // FreeHGlobal actually calls LocalFree. if (dataOut.pbData != null) { Marshal.FreeHGlobal((IntPtr)dataOut.pbData); } } }
internal static Secret UnprotectWithDpapiCore(byte* pbProtectedData, uint cbProtectedData, byte* pbOptionalEntropy, uint cbOptionalEntropy) { byte dummy; // provides a valid memory address if the secret or entropy has zero length DATA_BLOB dataIn = new DATA_BLOB() { cbData = cbProtectedData, pbData = (pbProtectedData != null) ? pbProtectedData : &dummy }; DATA_BLOB entropy = new DATA_BLOB() { cbData = cbOptionalEntropy, pbData = (pbOptionalEntropy != null) ? pbOptionalEntropy : &dummy }; DATA_BLOB dataOut = default(DATA_BLOB); #if !DOTNET5_4 RuntimeHelpers.PrepareConstrainedRegions(); #endif try { bool success = UnsafeNativeMethods.CryptUnprotectData( pDataIn: &dataIn, ppszDataDescr: IntPtr.Zero, pOptionalEntropy: &entropy, pvReserved: IntPtr.Zero, pPromptStruct: IntPtr.Zero, dwFlags: CRYPTPROTECT_UI_FORBIDDEN, pDataOut: out dataOut); if (!success) { int errorCode = Marshal.GetLastWin32Error(); throw new CryptographicException(errorCode); } return new Secret(dataOut.pbData, checked((int)dataOut.cbData)); } finally { // Zero and free memory so that we don't leak secrets. // FreeHGlobal actually calls LocalFree. if (dataOut.pbData != null) { UnsafeBufferUtil.SecureZeroMemory(dataOut.pbData, dataOut.cbData); Marshal.FreeHGlobal((IntPtr)dataOut.pbData); } } }