private static byte[] ProtectWithDpapiNGCore(NCryptDescriptorHandle protectionDescriptorHandle, byte* pbData, uint cbData) { Debug.Assert(protectionDescriptorHandle != null); Debug.Assert(pbData != null); // Perform the encryption operation, putting the protected data into LocalAlloc-allocated memory. LocalAllocHandle protectedData; uint cbProtectedData; int ntstatus = UnsafeNativeMethods.NCryptProtectSecret( hDescriptor: protectionDescriptorHandle, dwFlags: NCRYPT_SILENT_FLAG, pbData: pbData, cbData: cbData, pMemPara: IntPtr.Zero, hWnd: IntPtr.Zero, ppbProtectedBlob: out protectedData, pcbProtectedBlob: out cbProtectedData); UnsafeNativeMethods.ThrowExceptionForNCryptStatus(ntstatus); CryptoUtil.AssertSafeHandleIsValid(protectedData); // Copy the data from LocalAlloc-allocated memory into a managed memory buffer. using (protectedData) { byte[] retVal = new byte[cbProtectedData]; if (cbProtectedData > 0) { fixed (byte* pbRetVal = retVal) { bool handleAcquired = false; #if !DOTNET5_4 RuntimeHelpers.PrepareConstrainedRegions(); #endif try { protectedData.DangerousAddRef(ref handleAcquired); UnsafeBufferUtil.BlockCopy(from: (void*)protectedData.DangerousGetHandle(), to: pbRetVal, byteCount: cbProtectedData); } finally { if (handleAcquired) { protectedData.DangerousRelease(); } } } } return retVal; } }
public static byte[] ProtectWithDpapiNG(ISecret secret, NCryptDescriptorHandle protectionDescriptorHandle) { Debug.Assert(secret != null); Debug.Assert(protectionDescriptorHandle != null); byte[] plaintextSecret = new byte[secret.Length]; fixed (byte* pbPlaintextSecret = plaintextSecret) { try { secret.WriteSecretIntoBuffer(new ArraySegment<byte>(plaintextSecret)); byte dummy; // used to provide a valid memory address if secret is zero-length return ProtectWithDpapiNGCore( protectionDescriptorHandle: protectionDescriptorHandle, pbData: (pbPlaintextSecret != null) ? pbPlaintextSecret : &dummy, cbData: (uint)plaintextSecret.Length); } finally { // Limits secret exposure to garbage collector. Array.Clear(plaintextSecret, 0, plaintextSecret.Length); } } }