aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/embeddable-dll-service
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-10-03 16:59:50 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-10-06 15:10:50 +0200
commit14c87ed03042d8217eb75fd5326d60d324143696 (patch)
treec3e17f964340604cab9dfd7ddb9689c4ea07d0b3 /embeddable-dll-service
parentui: remove unused struct (diff)
downloadwireguard-windows-14c87ed03042d8217eb75fd5326d60d324143696.tar.xz
wireguard-windows-14c87ed03042d8217eb75fd5326d60d324143696.zip
embeddable-dll-service: add csharp example code
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'embeddable-dll-service')
-rw-r--r--embeddable-dll-service/README.md2
-rw-r--r--embeddable-dll-service/csharp/Keypair.cs65
-rw-r--r--embeddable-dll-service/csharp/Program.cs56
-rw-r--r--embeddable-dll-service/csharp/Ringlogger.cs46
-rw-r--r--embeddable-dll-service/csharp/Service.cs131
-rw-r--r--embeddable-dll-service/csharp/Win32.cs245
6 files changed, 545 insertions, 0 deletions
diff --git a/embeddable-dll-service/README.md b/embeddable-dll-service/README.md
index 6b42787f..3ac0dbae 100644
--- a/embeddable-dll-service/README.md
+++ b/embeddable-dll-service/README.md
@@ -38,3 +38,5 @@ is absolutely essential; do not forget it.
##### 3. Scoop up logs by implementing a ringlogger format reader.
##### 4. Talk to the service over its named pipe.
+
+There is a sample implementation of bits and pieces of this inside of the `csharp\` directory.
diff --git a/embeddable-dll-service/csharp/Keypair.cs b/embeddable-dll-service/csharp/Keypair.cs
new file mode 100644
index 00000000..98a00a30
--- /dev/null
+++ b/embeddable-dll-service/csharp/Keypair.cs
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+using System;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+
+namespace Tunnel
+{
+ public class Keypair
+ {
+ public readonly string Public;
+ public readonly string Private;
+
+ private Keypair(string pub, string priv)
+ {
+ Public = pub;
+ Private = priv;
+ }
+
+ public static Keypair Generate()
+ {
+ var algoHandle = new IntPtr();
+ var statusCode = Win32.BCryptOpenAlgorithmProvider(ref algoHandle, Win32.BCRYPT_ECDH_ALGORITHM, null, 0);
+ if (statusCode > 0)
+ throw new Win32Exception((int)statusCode);
+
+ try
+ {
+ var curveType = Win32.BCRYPT_ECC_CURVE_25519 + Char.MinValue;
+ statusCode = Win32.BCryptSetProperty(algoHandle, Win32.BCRYPT_ECC_CURVE_NAME, curveType, curveType.Length * sizeof(char), 0);
+ if (statusCode > 0)
+ throw new Win32Exception((int)statusCode);
+ var key = new IntPtr();
+ statusCode = Win32.BCryptGenerateKeyPair(algoHandle, ref key, 255, 0);
+ if (statusCode > 0)
+ throw new Win32Exception((int)statusCode);
+ try
+ {
+ statusCode = Win32.BCryptFinalizeKeyPair(key, 0);
+ if (statusCode > 0)
+ throw new Win32Exception((int)statusCode);
+
+ var keyBlob = new Win32.KeyBlob();
+ int exportedKeySize = 0;
+ statusCode = Win32.BCryptExportKey(key, IntPtr.Zero, Win32.BCRYPT_ECCPRIVATE_BLOB, keyBlob, Marshal.SizeOf(typeof(Win32.KeyBlob)), out exportedKeySize);
+ if (statusCode > 0)
+ throw new Win32Exception((int)statusCode);
+
+ return new Keypair(Convert.ToBase64String(keyBlob.Public), Convert.ToBase64String(keyBlob.Private));
+ }
+ finally
+ {
+ Win32.BCryptDestroyKey(key);
+ }
+ }
+ finally
+ {
+ Win32.BCryptCloseAlgorithmProvider(algoHandle, 0);
+ }
+ }
+ }
+}
diff --git a/embeddable-dll-service/csharp/Program.cs b/embeddable-dll-service/csharp/Program.cs
new file mode 100644
index 00000000..27cefdc9
--- /dev/null
+++ b/embeddable-dll-service/csharp/Program.cs
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+using System;
+using System.Net.Sockets;
+using System.IO;
+using System.Text;
+using System.Diagnostics;
+
+namespace Tunnel
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ if (args.Length == 2 && args[0] == "/service")
+ {
+ Service.Run(args[1]);
+ return;
+ }
+ var keys = Keypair.Generate();
+ var client = new TcpClient("demo.wireguard.com", 42912);
+ var stream = client.GetStream();
+ var reader = new StreamReader(stream, Encoding.UTF8);
+ var pubKeyBytes = Encoding.UTF8.GetBytes(keys.Public + "\n");
+ stream.Write(pubKeyBytes, 0, pubKeyBytes.Length);
+ stream.Flush();
+ var ret = reader.ReadLine().Split(':');
+ client.Close();
+ var status = ret.Length >= 1 ? ret[0] : "";
+ var serverPubkey = ret.Length >= 2 ? ret[1] : "";
+ var serverPort = ret.Length >= 3 ? ret[2] : "";
+ var internalIP = ret.Length >= 4 ? ret[3] : "";
+
+ if (status != "OK")
+ throw new InvalidOperationException(String.Format("Server status is {0}", status));
+
+ var configFileContents = String.Format("[Interface]\nPrivateKey = {0}\nAddress = {1}/24\nDNS = 8.8.8.8, 8.8.4.4\n\n[Peer]\nPublicKey = {2}\nEndpoint = demo.wireguard.com:{3}\nAllowedIPs = 0.0.0.0/0\n", keys.Private, internalIP, serverPubkey, serverPort);
+ var configFile = Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "demobox.conf");
+ File.WriteAllText(configFile, configFileContents);
+
+ try
+ {
+ Service.Add(configFile);
+ Console.WriteLine("=== Press enter to exit ===");
+ Console.ReadLine();
+ }
+ finally
+ {
+ Service.Remove(configFile);
+ }
+ }
+ }
+}
diff --git a/embeddable-dll-service/csharp/Ringlogger.cs b/embeddable-dll-service/csharp/Ringlogger.cs
new file mode 100644
index 00000000..711c22e7
--- /dev/null
+++ b/embeddable-dll-service/csharp/Ringlogger.cs
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+using System;
+using System.IO;
+using System.IO.MemoryMappedFiles;
+using System.Text;
+
+namespace Tunnel
+{
+ public class Ringlogger
+ {
+ private readonly MemoryMappedViewAccessor _viewAccessor;
+
+ public Ringlogger(string filename)
+ {
+ var file = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
+ var mmap = MemoryMappedFile.CreateFromFile(file, null, 0, MemoryMappedFileAccess.Read, HandleInheritability.None, false);
+ _viewAccessor = mmap.CreateViewAccessor(0, 8 + 2048 * (512 + 8), MemoryMappedFileAccess.Read);
+ if (_viewAccessor.ReadUInt32(0) != 0xbadbabe)
+ throw new InvalidDataException("The provided file is missing the magic number.");
+ }
+
+ public void WriteTo(TextWriter writer)
+ {
+ var start = _viewAccessor.ReadUInt32(4);
+ for (var i = 0; i < 2048; ++i)
+ {
+ var lineOffset = 8 + (8 + 512) * ((i + start) % 2048);
+ var timeNs = _viewAccessor.ReadInt64(lineOffset);
+ if (timeNs == 0)
+ continue;
+ var textBytes = new byte[512];
+ _viewAccessor.ReadArray<byte>(lineOffset + 8, textBytes, 0, textBytes.Length);
+ var nullByte = Array.IndexOf<byte>(textBytes, 0);
+ if (nullByte <= 0)
+ continue;
+ var text = Encoding.UTF8.GetString(textBytes, 0, nullByte);
+ var time = DateTimeOffset.FromUnixTimeMilliseconds(timeNs / 1000000).ToString("yyyy'-'MM'-'dd HH':'mm':'ss'.'ffffff");
+ writer.WriteLine(String.Format("{0}: {1}", time, text));
+ }
+ }
+ }
+}
diff --git a/embeddable-dll-service/csharp/Service.cs b/embeddable-dll-service/csharp/Service.cs
new file mode 100644
index 00000000..1375a3cb
--- /dev/null
+++ b/embeddable-dll-service/csharp/Service.cs
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+using System;
+using System.IO;
+using System.IO.Pipes;
+using System.Runtime.InteropServices;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Security.Principal;
+using System.Threading;
+
+namespace Tunnel
+{
+ public class Service
+ {
+ private const string LongName = "Example WireGuard Tunnel Client";
+ private const string Description = "A WireGuard tunnel created by example code.";
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct GoString
+ {
+ public string str;
+ public long len;
+ }
+
+ [DllImport("tunnel.dll", EntryPoint = "WireGuardTunnelService", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool WireGuardTunnelService(GoString configFile);
+
+ public static bool Run(string configFile)
+ {
+ return WireGuardTunnelService(new GoString { str = configFile, len = configFile.Length });
+ }
+
+ public static NamedPipeClientStream GetPipe(string configFile)
+ {
+ var pipepath = "ProtectedPrefix\\Administrators\\WireGuard\\" + Path.GetFileNameWithoutExtension(configFile);
+ return new NamedPipeClientStream(pipepath);
+ }
+
+ public static void Add(string configFile)
+ {
+ var tunnelName = Path.GetFileNameWithoutExtension(configFile);
+ var shortName = String.Format("WireGuardTunnel${0}", tunnelName);
+ var longName = String.Format("{0}: {1}", LongName, tunnelName);
+ var exeName = Process.GetCurrentProcess().MainModule.FileName;
+ var pathAndArgs = String.Format("\"{0}\" /service \"{1}\"", exeName, configFile); //TODO: This is not the proper way to escape file args.
+
+ var accessControl = File.GetAccessControl(configFile); //TODO: TOCTOU!
+ accessControl.SetOwner(new NTAccount(Environment.UserDomainName, Environment.UserName));
+ File.SetAccessControl(configFile, accessControl);
+
+ var scm = Win32.OpenSCManager(null, null, Win32.ScmAccessRights.AllAccess);
+ if (scm == IntPtr.Zero)
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ try
+ {
+ var service = Win32.OpenService(scm, shortName, Win32.ServiceAccessRights.AllAccess);
+ if (service != IntPtr.Zero)
+ {
+ Win32.CloseServiceHandle(service);
+ Remove(configFile);
+ }
+ service = Win32.CreateService(scm, shortName, longName, Win32.ServiceAccessRights.AllAccess, Win32.ServiceType.Win32OwnProcess, Win32.ServiceStartType.Auto, Win32.ServiceError.Normal, pathAndArgs, null, IntPtr.Zero, "Nsi", null, null);
+ if (service == IntPtr.Zero)
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ try
+ {
+ var sidType = Win32.ServiceSidType.Unrestricted;
+ if (!Win32.ChangeServiceConfig2(service, Win32.ServiceConfigType.SidInfo, ref sidType))
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+
+ var description = new Win32.ServiceDescription { lpDescription = Description };
+ if (!Win32.ChangeServiceConfig2(service, Win32.ServiceConfigType.Description, ref description))
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+
+ if (!Win32.StartService(service, 0, null))
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ }
+ finally
+ {
+ Win32.CloseServiceHandle(service);
+ }
+ }
+ finally
+ {
+ Win32.CloseServiceHandle(scm);
+ }
+ }
+
+ public static void Remove(string configFile)
+ {
+ var tunnelName = Path.GetFileNameWithoutExtension(configFile);
+ var shortName = String.Format("WireGuardTunnel${0}", tunnelName);
+
+ var scm = Win32.OpenSCManager(null, null, Win32.ScmAccessRights.AllAccess);
+ if (scm == IntPtr.Zero)
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ try
+ {
+ var service = Win32.OpenService(scm, shortName, Win32.ServiceAccessRights.AllAccess);
+ if (service == IntPtr.Zero)
+ {
+ Win32.CloseServiceHandle(service);
+ return;
+ }
+ try
+ {
+ var serviceStatus = new Win32.ServiceStatus();
+ Win32.ControlService(service, Win32.ServiceControl.Stop, serviceStatus);
+
+ for (int i = 0; i < 180 && Win32.QueryServiceStatus(service, serviceStatus) && serviceStatus.dwCurrentState != Win32.ServiceState.Stopped; ++i)
+ Thread.Sleep(1000);
+
+ if (!Win32.DeleteService(service))
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ }
+ finally
+ {
+ Win32.CloseServiceHandle(service);
+ }
+ }
+ finally
+ {
+ Win32.CloseServiceHandle(scm);
+ }
+ }
+ }
+}
diff --git a/embeddable-dll-service/csharp/Win32.cs b/embeddable-dll-service/csharp/Win32.cs
new file mode 100644
index 00000000..3dd9cfca
--- /dev/null
+++ b/embeddable-dll-service/csharp/Win32.cs
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Tunnel
+{
+ static class Win32
+ {
+ [Flags]
+ public enum ScmAccessRights
+ {
+ Connect = 0x0001,
+ CreateService = 0x0002,
+ EnumerateService = 0x0004,
+ Lock = 0x0008,
+ QueryLockStatus = 0x0010,
+ ModifyBootConfig = 0x0020,
+ StandardRightsRequired = 0xF0000,
+ AllAccess = (StandardRightsRequired | Connect | CreateService | EnumerateService | Lock | QueryLockStatus | ModifyBootConfig)
+ }
+
+ [Flags]
+ public enum ServiceAccessRights
+ {
+ QueryConfig = 0x1,
+ ChangeConfig = 0x2,
+ QueryStatus = 0x4,
+ EnumerateDependants = 0x8,
+ Start = 0x10,
+ Stop = 0x20,
+ PauseContinue = 0x40,
+ Interrogate = 0x80,
+ UserDefinedControl = 0x100,
+ Delete = 0x00010000,
+ StandardRightsRequired = 0xF0000,
+ AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig | QueryStatus | EnumerateDependants | Start | Stop | PauseContinue | Interrogate | UserDefinedControl)
+ }
+
+ [Flags]
+ public enum ServiceStartType
+ {
+ Boot = 0x00000000,
+ System = 0x00000001,
+ Auto = 0x00000002,
+ Demand = 0x00000003,
+ Disabled = 0x00000004
+ }
+
+ [Flags]
+ public enum ServiceControl
+ {
+ Stop = 0x00000001,
+ Pause = 0x00000002,
+ Continue = 0x00000003,
+ Interrogate = 0x00000004,
+ Shutdown = 0x00000005,
+ ParamChange = 0x00000006,
+ NetBindAdd = 0x00000007,
+ NetBindRemove = 0x00000008,
+ NetBindEnable = 0x00000009,
+ NetBindDisable = 0x0000000A
+ }
+
+ [Flags]
+ public enum ServiceError
+ {
+ Ignore = 0x00000000,
+ Normal = 0x00000001,
+ Severe = 0x00000002,
+ Critical = 0x00000003
+ }
+
+ [Flags]
+ public enum ServiceSidType
+ {
+ None = 0x00000000,
+ Unrestricted = 0x00000001,
+ Restricted = 0x00000003
+ }
+
+ [Flags]
+ public enum ServiceType
+ {
+ KernelDriver = 0x00000001,
+ FileSystemDriver = 0x00000002,
+ Win32OwnProcess = 0x00000010,
+ Win32ShareProcess = 0x00000020,
+ InteractiveProcess = 0x00000100
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size = 8192), ComVisible(false)]
+ public struct ServiceSidInfo
+ {
+ public ServiceSidType serviceSidType;
+ };
+
+ public enum ServiceState
+ {
+ Unknown = -1,
+ NotFound = 0,
+ Stopped = 1,
+ StartPending = 2,
+ StopPending = 3,
+ Running = 4,
+ ContinuePending = 5,
+ PausePending = 6,
+ Paused = 7
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class ServiceStatus
+ {
+ public int dwServiceType = 0;
+ public ServiceState dwCurrentState = 0;
+ public int dwControlsAccepted = 0;
+ public int dwWin32ExitCode = 0;
+ public int dwServiceSpecificExitCode = 0;
+ public int dwCheckPoint = 0;
+ public int dwWaitHint = 0;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size = 8192), ComVisible(false)]
+ public struct ServiceDescription
+ {
+ public String lpDescription;
+ };
+
+ public enum ServiceConfigType
+ {
+ Description = 1,
+ SidInfo = 5
+ }
+
+ [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
+ public static extern IntPtr OpenSCManager(string machineName, string databaseName, ScmAccessRights dwDesiredAccess);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceAccessRights dwDesiredAccess);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CloseServiceHandle(IntPtr hSCObject);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType, ServiceStartType dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DeleteService(IntPtr hService);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool ControlService(IntPtr hService, ServiceControl dwControl, ServiceStatus lpServiceStatus);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool QueryServiceStatus(IntPtr hService, ServiceStatus lpServiceStatus);
+
+ [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool ChangeServiceConfig2(IntPtr hService, ServiceConfigType dwInfoLevel, ref ServiceSidType lpInfo);
+
+ [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool ChangeServiceConfig2(IntPtr hService, ServiceConfigType dwInfoLevel, ref ServiceDescription lpInfo);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public class KeyBlob
+ {
+ BCRYPT_ECCKEY_BLOB Header;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] Public;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] Unused;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] Private;
+ }
+
+ public const string BCRYPT_ECC_CURVE_NAME = "ECCCurveName";
+ public const string BCRYPT_ECDH_ALGORITHM = "ECDH";
+ public const string BCRYPT_ECC_CURVE_25519 = "curve25519";
+ public const string BCRYPT_ECCPRIVATE_BLOB = "ECCPRIVATEBLOB";
+
+ [DllImport("bcrypt.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
+ public static extern uint BCryptSetProperty(IntPtr hObject, string property, string input, int inputSize, uint Flags = 0);
+
+ [DllImport("bcrypt.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern uint BCryptOpenAlgorithmProvider(ref IntPtr hAlgorithm, string AlgId, string Implementation, uint Flags);
+
+ [DllImport("bcrypt.dll", SetLastError = true)]
+ public static extern uint BCryptGenerateKeyPair(IntPtr hObject, ref IntPtr hKey, uint length, uint Flags);
+
+ [DllImport("bcrypt.dll", SetLastError = true)]
+ public static extern uint BCryptFinalizeKeyPair(IntPtr hKey, uint Flags);
+
+ [DllImport("bcrypt.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
+ public static extern uint BCryptExportKey(IntPtr hKey, IntPtr hExportKey, [MarshalAs(UnmanagedType.LPWStr)] string pszBlobType, [Out] KeyBlob pbOutput, int cbOutput, out int pcbResult, uint Flags = 0);
+
+ [DllImport("bcrypt.dll", SetLastError = true)]
+ public static extern uint BCryptDestroyKey(IntPtr hKey);
+
+ [DllImport("bcrypt.dll", SetLastError = true)]
+ public static extern uint BCryptCloseAlgorithmProvider(IntPtr hAlgorithm, uint Flags);
+
+ [DllImport("bcrypt.dll", SetLastError = true)]
+ public static extern uint BCryptDestroySecret(IntPtr hSecretAgreement);
+
+ [DllImport("bcrypt.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern uint BCryptImportKeyPair(IntPtr hAlgorithm, IntPtr hImportKey, string BlobType, ref IntPtr hPublicKey, byte[] Input, uint InputByteLength, uint Flags);
+
+ [DllImport("bcrypt.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern uint BCryptSecretAgreement(IntPtr hPrivKey, IntPtr hPublicKey, ref IntPtr phSecret, uint Flags);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public class BCryptBufferDesc
+ {
+ public uint ulVersion;
+ public uint cBuffers;
+ public IntPtr pBuffers;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public class BCryptBuffer
+ {
+ public uint cbBuffer;
+ public uint bufferType;
+ public IntPtr pvBuffer;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class BCRYPT_ECCKEY_BLOB
+ {
+ uint magic;
+ uint cbKey;
+ }
+ }
+}