Private/Import-IDBridgeDpapiNGType.ps1
|
<# .SYNOPSIS Compile the DPAPI-NG P/Invoke type used by the DpapiNG secrets provider (internal). .DESCRIPTION Internal helper for the IDBridge secret vault. Adds the [IDBridge.DpapiNG] type, a thin P/Invoke wrapper over ncrypt.dll (NCryptCreateProtectionDescriptor / NCryptProtectSecret / NCryptUnprotectSecret) so secrets can be protected to an AD principal (e.g. a gMSA SID) with no external module. The type is compiled once per session; later calls are no-ops. .EXAMPLE Import-IDBridgeDpapiNGType $blob = [IDBridge.DpapiNG]::Protect('SID=S-1-5-21-...', $bytes) .NOTES Created by: Sam Cattanach Modified: 2026-07-01 #> function Import-IDBridgeDpapiNGType { [CmdletBinding()] param () if ('IDBridge.DpapiNG' -as [type]) { return } Add-Type -TypeDefinition @' using System; using System.Runtime.InteropServices; namespace IDBridge { public static class DpapiNG { [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] private static extern int NCryptCreateProtectionDescriptor(string pwszDescriptorString, uint dwFlags, out IntPtr phDescriptor); [DllImport("ncrypt.dll")] private static extern int NCryptCloseProtectionDescriptor(IntPtr hDescriptor); [DllImport("ncrypt.dll")] private static extern int NCryptProtectSecret(IntPtr hDescriptor, uint dwFlags, byte[] pbData, uint cbData, IntPtr pMemPara, IntPtr hWnd, out IntPtr ppbProtectedBlob, out uint pcbProtectedBlob); [DllImport("ncrypt.dll")] private static extern int NCryptUnprotectSecret(out IntPtr phDescriptor, uint dwFlags, byte[] pbProtectedBlob, uint cbProtectedBlob, IntPtr pMemPara, IntPtr hWnd, out IntPtr ppbData, out uint pcbData); [DllImport("kernel32.dll")] private static extern IntPtr LocalFree(IntPtr hMem); private const uint NCRYPT_SILENT_FLAG = 0x00000040; public static byte[] Protect(string descriptor, byte[] data) { IntPtr hDescriptor; int status = NCryptCreateProtectionDescriptor(descriptor, 0, out hDescriptor); if (status != 0) throw new InvalidOperationException(string.Format("NCryptCreateProtectionDescriptor failed for '{0}' (0x{1:X8})", descriptor, status)); try { IntPtr blobPtr; uint blobLen; status = NCryptProtectSecret(hDescriptor, NCRYPT_SILENT_FLAG, data, (uint)data.Length, IntPtr.Zero, IntPtr.Zero, out blobPtr, out blobLen); if (status != 0) throw new InvalidOperationException(string.Format("NCryptProtectSecret failed (0x{0:X8})", status)); try { byte[] blob = new byte[blobLen]; Marshal.Copy(blobPtr, blob, 0, (int)blobLen); return blob; } finally { LocalFree(blobPtr); } } finally { NCryptCloseProtectionDescriptor(hDescriptor); } } public static byte[] Unprotect(byte[] blob) { IntPtr hDescriptor; IntPtr dataPtr; uint dataLen; int status = NCryptUnprotectSecret(out hDescriptor, NCRYPT_SILENT_FLAG, blob, (uint)blob.Length, IntPtr.Zero, IntPtr.Zero, out dataPtr, out dataLen); if (status != 0) throw new InvalidOperationException(string.Format("NCryptUnprotectSecret failed (0x{0:X8})", status)); try { byte[] data = new byte[dataLen]; Marshal.Copy(dataPtr, data, 0, (int)dataLen); return data; } finally { LocalFree(dataPtr); if (hDescriptor != IntPtr.Zero) { NCryptCloseProtectionDescriptor(hDescriptor); } } } } } '@ } |