Jelajahi Sumber

Merge branch 'feature/encryption'

Conflicts:
	Proftaak Remote Healthcare/Server/Client.cs
Bart Reedijk 10 tahun lalu
induk
melakukan
58c6b4d4d7

+ 84 - 29
Proftaak Remote Healthcare/FietsClientV2/TCPConnection.cs

@@ -3,10 +3,13 @@ using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net.Security;
 using System.Net.Sockets;
 using System.Text;
 using System.Threading;
 using System.Windows.Forms;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Authentication;
 
 namespace FietsClient
 {
@@ -14,9 +17,10 @@ namespace FietsClient
     {
         public TcpClient client;
         public bool isConnectedFlag { private set; get; }
-        private NetworkStream serverStream;
+        private SslStream sslStream;
         public CurrentData currentData { private set; get; }
         public string userID { private set; get; }
+
         private Thread receiveThread;
 
         public delegate void ChatmassegeDelegate(string[] data);
@@ -28,7 +32,7 @@ namespace FietsClient
             connect();
         }
 
-	    private void onIncomingChatMessage(string[] data)
+        private void onIncomingChatMessage(string[] data)
         {
             ChatmassegeDelegate cMD = IncomingChatmessageEvent;
             if (cMD != null)
@@ -44,28 +48,77 @@ namespace FietsClient
 
         public void connect()
         {
+            try
+            {
+                client.Connect("127.0.0.1", 1288);
+
+
+                // create streams
+                sslStream = new SslStream(client.GetStream(), false,
+                    new RemoteCertificateValidationCallback(CertificateValidationCallback),
+                    new LocalCertificateSelectionCallback(CertificateSelectionCallback));
+
+                bool authenticationPassed = true;
                 try
                 {
-                    client.Connect("127.0.0.1", 1288);
+                    string serverName = System.Environment.MachineName;
+
+                    X509Certificate cert = GetServerCert();
+                    X509CertificateCollection certs = new X509CertificateCollection();
+                    certs.Add(cert);
 
-                    // create streams
-                    serverStream = client.GetStream();
+                    sslStream.AuthenticateAsClient(
+                        serverName,
+                        certs,
+                        SslProtocols.Default,
+                        false); // check cert revokation
+                }
+                catch (AuthenticationException)
+                {
+                    authenticationPassed = false;
+                }
+                if (authenticationPassed)
+                {
                     receiveThread = new Thread(receive);
                     receiveThread.Start();
                     isConnectedFlag = true;
                 }
-                catch (Exception ex)
-                {
-                    Console.WriteLine(ex);
-                    Thread.Sleep(1000);
-                    isConnectedFlag = false;
-                }
+
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex);
+                Thread.Sleep(1000);
+                isConnectedFlag = false;
+            }
+        }
+
+        static X509Certificate CertificateSelectionCallback(object sender,
+            string targetHost,
+            X509CertificateCollection localCertificates,
+            X509Certificate remoteCertificate,
+            string[] acceptableIssuers)
+        {
+            return localCertificates[0];
+        }
+
+        private X509Certificate GetServerCert()
+        {
+            X509Certificate cert = new X509Certificate2(
+                            @"testcert.pfx",
+                            "jancoow");
+            return cert;
+        }
+
+        private bool CertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
+        {
+            return true;
         }
 
         public void disconnect()
         {
             receiveThread.Abort();
-            serverStream.Close();
+            sslStream.Close();
             client.Close();
             isConnectedFlag = false;
         }
@@ -75,7 +128,7 @@ namespace FietsClient
             while (true)
             {
                 byte[] bytesFrom = new byte[(int)client.ReceiveBufferSize];
-                serverStream.Read(bytesFrom, 0, client.ReceiveBufferSize);
+                sslStream.Read(bytesFrom, 0, client.ReceiveBufferSize);
                 string response = Encoding.ASCII.GetString(bytesFrom);
                 string[] response_parts = response.Split('|');
 
@@ -104,6 +157,7 @@ namespace FietsClient
                             }
                             break;
                         case "1":
+                            response_parts[1] = response_parts[1].TrimEnd('\0');
                             currentData.setSessionList(JsonConvert.DeserializeObject<List<Session>>(response_parts[1]));
 
                             if (currentData.isDoctor == true)
@@ -136,17 +190,18 @@ namespace FietsClient
                             break;
                         case "7":
                             //                                        sender              receiver          message
-                            onIncomingChatMessage(new string[] { response_parts[1], response_parts[2], response_parts[3].TrimEnd('\0') } );
+                            onIncomingChatMessage(new string[] { response_parts[1], response_parts[2], response_parts[3].TrimEnd('\0') });
                             break;
                         case "8":
                             if (response_parts[1].TrimEnd('\0') != "-1")
                             {
                                 DoctorModel.doctorModel.onlinePatients = response_parts[1].TrimEnd('\0').Split('\t').ToList();
-                            } else if (response_parts[1].TrimEnd('\0') == "-1")
+                            }
+                            else if (response_parts[1].TrimEnd('\0') == "-1")
                             {
                                 DoctorModel.doctorModel.onlinePatients = new List<String>();
                             }
-                            
+
                             break;
                     }
                 }
@@ -177,18 +232,18 @@ namespace FietsClient
             // send command ( cmdID | username )
             SendString("5|" + userID + lib.JsonConverter.SerializeLastMeasurement(currentData.GetSessions().Last().GetLastMeasurement()) + "|");
         }
-	
-	    public void SendChatMessage(string[] data)
+
+        public void SendChatMessage(string[] data)
         {
             String receiverID = data[1];
 
             if (currentData != null)
             {
-                    String message = data[0];
+                String message = data[0];
 
-                    // send command ( cmdID | username sender | username receiverID | message )
-                    string protocol = "6|" + this.userID + "|" + receiverID + "|" + message;
-                    SendString(protocol);
+                // send command ( cmdID | username sender | username receiverID | message )
+                string protocol = "6|" + this.userID + "|" + receiverID + "|" + message;
+                SendString(protocol);
             }
         }
         public void SendGetActivePatients()
@@ -200,8 +255,8 @@ namespace FietsClient
         {
             SendString("10|" + userID + "|" + distance + "|");
         }
-	
-	    public void SendTime(int Minutes, int seconds)
+
+        public void SendTime(int Minutes, int seconds)
         {
             SendString("11|" + userID + "|" + Minutes + ":" + seconds + "|");
         }
@@ -211,14 +266,14 @@ namespace FietsClient
             SendString("12|" + userID + "|" + power + "|");
         }
 
-        
-	
-	    public void SendString(string s)
+
+
+        public void SendString(string s)
         {
 
             byte[] b = Encoding.ASCII.GetBytes(s);
-            serverStream.Write(b, 0, b.Length);
-            serverStream.Flush();
+            sslStream.Write(b, 0, b.Length);
+            sslStream.Flush();
         }
     }
 }

+ 2 - 2
Proftaak Remote Healthcare/Server/AppGlobal.cs

@@ -36,12 +36,12 @@ namespace Server
 
             Random r = new Random();
             Session session = new Session(1, "100");
-            for (int i = 0; i < 100; i++)
+            for (int i = 0; i < 20; i++)
                 session.AddMeasurement(new Measurement(r.Next(100, 200), r.Next(60, 100), r.Next(100, 150), r.Next(0, 100), i, r.Next(100), r.Next(100), r.Next(100), i, r.Next(100)));
             users.ElementAt(1).tests.Add(session);
 
             Session session2 = new Session(2, "100");
-            for (int i = 0; i < 200; i++)
+            for (int i = 0; i < 50; i++)
                 session2.AddMeasurement(new Measurement(r.Next(100, 200), r.Next(60, 100), r.Next(100, 150), r.Next(0, 100), i, r.Next(100), r.Next(100), r.Next(100), i, r.Next(100)));
             users.ElementAt(1).tests.Add(session2);
         }

+ 14 - 9
Proftaak Remote Healthcare/Server/Client.cs

@@ -8,13 +8,16 @@ using Newtonsoft.Json.Converters;
 using Server.JSONObjecten;
 using JsonConverter = Server.FileIO.JsonConverter;
 using System.Collections.Generic;
+using System.Net.Security;
+using System.Security.Authentication;
+using Server.lib;
 
 namespace Server
 {
     public class Client
     {
         TcpClient client;
-        NetworkStream networkStream;
+        SslStream sslStream;
         private readonly AppGlobal _global;
         public int iduser { get; private set; }
         public string username { get; private set; }
@@ -23,7 +26,9 @@ namespace Server
         public Client(TcpClient socket)
         {
             client = socket;
-            networkStream = client.GetStream();
+            
+            sslStream = new SslStream(client.GetStream());
+            sslStream.AuthenticateAsServer(lib.SSLCrypto.LoadCert(), false, SslProtocols.Default, false);
             _global = AppGlobal.Instance;
             iduser = -1;
             Console.WriteLine("New client connected");
@@ -36,14 +41,14 @@ namespace Server
             while (!(client.Client.Poll(0, SelectMode.SelectRead) && client.Client.Available == 0))
             {
                 byte[] bytesFrom = new byte[(int)client.ReceiveBufferSize];
-                try
-                {
-                    networkStream.Read(bytesFrom, 0, (int)client.ReceiveBufferSize);
-                } catch (Exception)
+		try
+		{
+		    sslStream.Read(bytesFrom, 0, (int)client.ReceiveBufferSize);
+                } 
+		catch (Exception)
                 {
                     Stop();
                 }
-                
                 String response = Encoding.ASCII.GetString(bytesFrom);
                 String[] response_parts = response.Split('|');
                 if (response_parts.Length > 0)
@@ -163,8 +168,8 @@ namespace Server
         public void sendString(string s)
         {
             byte[] b = Encoding.ASCII.GetBytes(s);
-            networkStream.Write(b, 0, b.Length);
-            networkStream.Flush();
+            sslStream.Write(b, 0, b.Length);
+            sslStream.Flush();
         }
     }
 }

+ 18 - 12
Proftaak Remote Healthcare/Server/Client.cs.orig

@@ -8,13 +8,16 @@ using Newtonsoft.Json.Converters;
 using Server.JSONObjecten;
 using JsonConverter = Server.FileIO.JsonConverter;
 using System.Collections.Generic;
+using System.Net.Security;
+using System.Security.Authentication;
+using Server.lib;
 
 namespace Server
 {
     public class Client
     {
         TcpClient client;
-        NetworkStream networkStream;
+        SslStream sslStream;
         private readonly AppGlobal _global;
         public int iduser { get; private set; }
         public string username { get; private set; }
@@ -23,7 +26,9 @@ namespace Server
         public Client(TcpClient socket)
         {
             client = socket;
-            networkStream = client.GetStream();
+            
+            sslStream = new SslStream(client.GetStream());
+            sslStream.AuthenticateAsServer(lib.SSLCrypto.LoadCert(), false, SslProtocols.Default, false);
             _global = AppGlobal.Instance;
             iduser = -1;
             Console.WriteLine("New client connected");
@@ -36,6 +41,7 @@ namespace Server
             while (!(client.Client.Poll(0, SelectMode.SelectRead) && client.Client.Available == 0))
             {
                 byte[] bytesFrom = new byte[(int)client.ReceiveBufferSize];
+<<<<<<< HEAD
                 try
                 {
                     networkStream.Read(bytesFrom, 0, (int)client.ReceiveBufferSize);
@@ -44,6 +50,10 @@ namespace Server
                     Stop();
                 }
                 
+=======
+                sslStream.Read(bytesFrom, 0, (int)client.ReceiveBufferSize);
+
+>>>>>>> feature/encryption
                 String response = Encoding.ASCII.GetString(bytesFrom);
                 String[] response_parts = response.Split('|');
                 if (response_parts.Length > 0)
@@ -113,19 +123,15 @@ namespace Server
                                 String receiver = response_parts[2];
                                 String sender = response_parts[1];
 
-<<<<<<< HEAD
-                                sendString("7|" + sender + "|" + receiver + "|" + message);
+                                string case6str = "7|" + sender + "|" + receiver + "|" + message;
+                                Console.WriteLine(case6str);
+                                sendString(case6str);
+
                                 foreach (var client in Program.Clients)
                                 {
                                     if (client.username == receiver)
                                         client.sendString("7|" + sender + "|" + receiver + "|" + message);
                                 }
-=======
-                                //bericht doorsturen naar alle actieve gebruikers (de Fietsclient zorgt ervoor dat alleen de geadresseerde het bericht kan zien)
-                                string case6str = "7|" + sender + "|" + receiver + "|" + message;
-                                Console.WriteLine(case6str);
-                                sendString(case6str);
->>>>>>> feature/Server_brdk.nl
                             }
                             break;
                         case "8": //alle online Patients sturen naar Doctorclient
@@ -167,8 +173,8 @@ namespace Server
         public void sendString(string s)
         {
             byte[] b = Encoding.ASCII.GetBytes(s);
-            networkStream.Write(b, 0, b.Length);
-            networkStream.Flush();
+            sslStream.Write(b, 0, b.Length);
+            sslStream.Flush();
         }
     }
 }

+ 1 - 1
Proftaak Remote Healthcare/Server/FileIO/JsonConverter.cs

@@ -13,7 +13,7 @@ namespace Server.FileIO
     {
         public static void SaveUser(User u)
         {
-            File.WriteAllText(@"../../JSONObjecten/JSON Files/" + u.id + ".json", GetUser(u));
+            File.WriteAllText(@"JSON Files\" + u.id + ".json", GetUser(u));
         }
 
         public static string GetUser(User u)

+ 5 - 1
Proftaak Remote Healthcare/Server/JSONObjecten/Session.cs

@@ -23,7 +23,11 @@ namespace Server.JSONObjecten
 
         public Session(int bikeMode, string modevalue)
         {
-            string[] fileEntries = Directory.GetFiles(@"../../JSONObjecten/JSON Files/");
+            if (!(Directory.Exists(@"JSON Files"))) 
+            {
+                Directory.CreateDirectory(@"JSON Files");
+            }
+            string[] fileEntries = Directory.GetFiles(@"JSON Files\");
 
             if (fileEntries.Length > 0)
                 this.id = int.Parse(fileEntries[fileEntries.Length]);

+ 4 - 1
Proftaak Remote Healthcare/Server/Program.cs

@@ -17,8 +17,11 @@ namespace Server
         {
             Console.WriteLine("Server gestart");
 
-            //zorg dat AppGlobal bestaat...
+            // zorg dat AppGlobal bestaat...
             AppGlobal.Instance.ToString();
+            // zorg dat de certificaat bestaat
+            lib.SSLCrypto.CreateSelfSignedCert();
+
             TcpListener serverSocket = new TcpListener(1288);
             serverSocket.Start();
 

+ 2 - 0
Proftaak Remote Healthcare/Server/Server.csproj

@@ -52,6 +52,8 @@
     <Compile Include="JSONObjecten\Measurement.cs" />
     <Compile Include="JSONObjecten\Session.cs" />
     <Compile Include="JSONObjecten\User.cs" />
+    <Compile Include="lib\SelfSignedCertificate.cs" />
+    <Compile Include="lib\SSLCrypto.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>

+ 40 - 0
Proftaak Remote Healthcare/Server/lib/SSLCrypto.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Server.lib
+{
+    class SSLCrypto
+    {
+        public static void CreateSelfSignedCert()
+        {
+            if (!File.Exists("testcert.pfx"))
+            {
+                byte[] c = SelfSignedCertificate.CreateSelfSignCertificatePfx(
+            "CN=brdk.nl", //host name
+            DateTime.Parse("2015-01-01"), //not valid before
+            DateTime.Parse("2025-01-01"), //not valid after
+            "jancoow"); //password to encrypt key file
+
+                using (BinaryWriter binWriter = new BinaryWriter(
+                    File.Open(@"testcert.pfx", FileMode.Create)))
+                {
+                    binWriter.Write(c);
+                }
+            }
+        }
+
+        public static X509Certificate LoadCert()
+        {
+            X509Certificate cert = new X509Certificate2(
+                            @"testcert.pfx",
+                            "jancoow");
+            return cert;
+        }
+
+    }
+}

+ 416 - 0
Proftaak Remote Healthcare/Server/lib/SelfSignedCertificate.cs

@@ -0,0 +1,416 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+using SecureString = System.Security.SecureString;
+using RuntimeHelpers = System.Runtime.CompilerServices.RuntimeHelpers;
+
+namespace Server.lib
+{
+    internal class SelfSignedCertificate
+    {
+        public static byte[] CreateSelfSignCertificatePfx(
+            string x500,
+            DateTime startTime,
+            DateTime endTime)
+        {
+            byte[] pfxData = CreateSelfSignCertificatePfx(
+                x500,
+                startTime,
+                endTime,
+                (SecureString)null);
+            return pfxData;
+        }
+
+        public static byte[] CreateSelfSignCertificatePfx(
+            string x500,
+            DateTime startTime,
+            DateTime endTime,
+            string insecurePassword)
+        {
+            byte[] pfxData;
+            SecureString password = null;
+
+            try
+            {
+                if (!string.IsNullOrEmpty(insecurePassword))
+                {
+                    password = new SecureString();
+                    foreach (char ch in insecurePassword)
+                    {
+                        password.AppendChar(ch);
+                    }
+
+                    password.MakeReadOnly();
+                }
+
+                pfxData = CreateSelfSignCertificatePfx(
+                    x500,
+                    startTime,
+                    endTime,
+                    password);
+            }
+            finally
+            {
+                if (password != null)
+                {
+                    password.Dispose();
+                }
+            }
+
+            return pfxData;
+        }
+
+        public static byte[] CreateSelfSignCertificatePfx(
+            string x500,
+            DateTime startTime,
+            DateTime endTime,
+            SecureString password)
+        {
+            byte[] pfxData;
+
+            if (x500 == null)
+            {
+                x500 = "";
+            }
+
+            SystemTime startSystemTime = ToSystemTime(startTime);
+            SystemTime endSystemTime = ToSystemTime(endTime);
+            string containerName = Guid.NewGuid().ToString();
+
+            GCHandle dataHandle = new GCHandle();
+            IntPtr providerContext = IntPtr.Zero;
+            IntPtr cryptKey = IntPtr.Zero;
+            IntPtr certContext = IntPtr.Zero;
+            IntPtr certStore = IntPtr.Zero;
+            IntPtr storeCertContext = IntPtr.Zero;
+            IntPtr passwordPtr = IntPtr.Zero;
+            RuntimeHelpers.PrepareConstrainedRegions();
+            try
+            {
+                Check(NativeMethods.CryptAcquireContextW(
+                    out providerContext,
+                    containerName,
+                    null,
+                    1, // PROV_RSA_FULL
+                    8)); // CRYPT_NEWKEYSET
+
+                Check(NativeMethods.CryptGenKey(
+                    providerContext,
+                    1, // AT_KEYEXCHANGE
+                    1, // CRYPT_EXPORTABLE
+                    out cryptKey));
+
+                IntPtr errorStringPtr;
+                int nameDataLength = 0;
+                byte[] nameData;
+
+                // errorStringPtr gets a pointer into the middle of the x500 string,
+                // so x500 needs to be pinned until after we've copied the value
+                // of errorStringPtr.
+                dataHandle = GCHandle.Alloc(x500, GCHandleType.Pinned);
+
+                if (!NativeMethods.CertStrToNameW(
+                    0x00010001, // X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
+                    dataHandle.AddrOfPinnedObject(),
+                    3, // CERT_X500_NAME_STR = 3
+                    IntPtr.Zero,
+                    null,
+                    ref nameDataLength,
+                    out errorStringPtr))
+                {
+                    string error = Marshal.PtrToStringUni(errorStringPtr);
+                    throw new ArgumentException(error);
+                }
+
+                nameData = new byte[nameDataLength];
+
+                if (!NativeMethods.CertStrToNameW(
+                    0x00010001, // X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
+                    dataHandle.AddrOfPinnedObject(),
+                    3, // CERT_X500_NAME_STR = 3
+                    IntPtr.Zero,
+                    nameData,
+                    ref nameDataLength,
+                    out errorStringPtr))
+                {
+                    string error = Marshal.PtrToStringUni(errorStringPtr);
+                    throw new ArgumentException(error);
+                }
+
+                dataHandle.Free();
+
+                dataHandle = GCHandle.Alloc(nameData, GCHandleType.Pinned);
+                CryptoApiBlob nameBlob = new CryptoApiBlob(
+                    nameData.Length,
+                    dataHandle.AddrOfPinnedObject());
+
+                CryptKeyProviderInformation kpi = new CryptKeyProviderInformation();
+                kpi.ContainerName = containerName;
+                kpi.ProviderType = 1; // PROV_RSA_FULL
+                kpi.KeySpec = 1; // AT_KEYEXCHANGE
+
+                certContext = NativeMethods.CertCreateSelfSignCertificate(
+                    providerContext,
+                    ref nameBlob,
+                    0,
+                    ref kpi,
+                    IntPtr.Zero, // default = SHA1RSA
+                    ref startSystemTime,
+                    ref endSystemTime,
+                    IntPtr.Zero);
+                Check(certContext != IntPtr.Zero);
+                dataHandle.Free();
+
+                certStore = NativeMethods.CertOpenStore(
+                    "Memory", // sz_CERT_STORE_PROV_MEMORY
+                    0,
+                    IntPtr.Zero,
+                    0x2000, // CERT_STORE_CREATE_NEW_FLAG
+                    IntPtr.Zero);
+                Check(certStore != IntPtr.Zero);
+
+                Check(NativeMethods.CertAddCertificateContextToStore(
+                    certStore,
+                    certContext,
+                    1, // CERT_STORE_ADD_NEW
+                    out storeCertContext));
+
+                NativeMethods.CertSetCertificateContextProperty(
+                    storeCertContext,
+                    2, // CERT_KEY_PROV_INFO_PROP_ID
+                    0,
+                    ref kpi);
+
+                if (password != null)
+                {
+                    passwordPtr = Marshal.SecureStringToCoTaskMemUnicode(password);
+                }
+
+                CryptoApiBlob pfxBlob = new CryptoApiBlob();
+                Check(NativeMethods.PFXExportCertStoreEx(
+                    certStore,
+                    ref pfxBlob,
+                    passwordPtr,
+                    IntPtr.Zero,
+                    7)); // EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
+
+                pfxData = new byte[pfxBlob.DataLength];
+                dataHandle = GCHandle.Alloc(pfxData, GCHandleType.Pinned);
+                pfxBlob.Data = dataHandle.AddrOfPinnedObject();
+                Check(NativeMethods.PFXExportCertStoreEx(
+                    certStore,
+                    ref pfxBlob,
+                    passwordPtr,
+                    IntPtr.Zero,
+                    7)); // EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
+                dataHandle.Free();
+            }
+            finally
+            {
+                if (passwordPtr != IntPtr.Zero)
+                {
+                    Marshal.ZeroFreeCoTaskMemUnicode(passwordPtr);
+                }
+
+                if (dataHandle.IsAllocated)
+                {
+                    dataHandle.Free();
+                }
+
+                if (certContext != IntPtr.Zero)
+                {
+                    NativeMethods.CertFreeCertificateContext(certContext);
+                }
+
+                if (storeCertContext != IntPtr.Zero)
+                {
+                    NativeMethods.CertFreeCertificateContext(storeCertContext);
+                }
+
+                if (certStore != IntPtr.Zero)
+                {
+                    NativeMethods.CertCloseStore(certStore, 0);
+                }
+
+                if (cryptKey != IntPtr.Zero)
+                {
+                    NativeMethods.CryptDestroyKey(cryptKey);
+                }
+
+                if (providerContext != IntPtr.Zero)
+                {
+                    NativeMethods.CryptReleaseContext(providerContext, 0);
+                    NativeMethods.CryptAcquireContextW(
+                        out providerContext,
+                        containerName,
+                        null,
+                        1, // PROV_RSA_FULL
+                        0x10); // CRYPT_DELETEKEYSET
+                }
+            }
+
+            return pfxData;
+        }
+
+        private static SystemTime ToSystemTime(DateTime dateTime)
+        {
+            long fileTime = dateTime.ToFileTime();
+            SystemTime systemTime;
+            Check(NativeMethods.FileTimeToSystemTime(ref fileTime, out systemTime));
+            return systemTime;
+        }
+
+        private static void Check(bool nativeCallSucceeded)
+        {
+            if (!nativeCallSucceeded)
+            {
+                int error = Marshal.GetHRForLastWin32Error();
+                Marshal.ThrowExceptionForHR(error);
+            }
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        private struct SystemTime
+        {
+            public short Year;
+            public short Month;
+            public short DayOfWeek;
+            public short Day;
+            public short Hour;
+            public short Minute;
+            public short Second;
+            public short Milliseconds;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        private struct CryptoApiBlob
+        {
+            public int DataLength;
+            public IntPtr Data;
+
+            public CryptoApiBlob(int dataLength, IntPtr data)
+            {
+                this.DataLength = dataLength;
+                this.Data = data;
+            }
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        private struct CryptKeyProviderInformation
+        {
+            [MarshalAs(UnmanagedType.LPWStr)]
+            public string ContainerName;
+            [MarshalAs(UnmanagedType.LPWStr)]
+            public string ProviderName;
+            public int ProviderType;
+            public int Flags;
+            public int ProviderParameterCount;
+            public IntPtr ProviderParameters; // PCRYPT_KEY_PROV_PARAM
+            public int KeySpec;
+        }
+
+        private static class NativeMethods
+        {
+            [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool FileTimeToSystemTime(
+                [In] ref long fileTime,
+                out SystemTime systemTime);
+
+            [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CryptAcquireContextW(
+                out IntPtr providerContext,
+                [MarshalAs(UnmanagedType.LPWStr)] string container,
+                [MarshalAs(UnmanagedType.LPWStr)] string provider,
+                int providerType,
+                int flags);
+
+            [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CryptReleaseContext(
+                IntPtr providerContext,
+                int flags);
+
+            [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CryptGenKey(
+                IntPtr providerContext,
+                int algorithmId,
+                int flags,
+                out IntPtr cryptKeyHandle);
+
+            [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CryptDestroyKey(
+                IntPtr cryptKeyHandle);
+
+            [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CertStrToNameW(
+                int certificateEncodingType,
+                IntPtr x500,
+                int strType,
+                IntPtr reserved,
+                [MarshalAs(UnmanagedType.LPArray)] [Out] byte[] encoded,
+                ref int encodedLength,
+                out IntPtr errorString);
+
+            [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+            public static extern IntPtr CertCreateSelfSignCertificate(
+                IntPtr providerHandle,
+                [In] ref CryptoApiBlob subjectIssuerBlob,
+                int flags,
+                [In] ref CryptKeyProviderInformation keyProviderInformation,
+                IntPtr signatureAlgorithm,
+                [In] ref SystemTime startTime,
+                [In] ref SystemTime endTime,
+                IntPtr extensions);
+
+            [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CertFreeCertificateContext(
+                IntPtr certificateContext);
+
+            [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+            public static extern IntPtr CertOpenStore(
+                [MarshalAs(UnmanagedType.LPStr)] string storeProvider,
+                int messageAndCertificateEncodingType,
+                IntPtr cryptProvHandle,
+                int flags,
+                IntPtr parameters);
+
+            [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CertCloseStore(
+                IntPtr certificateStoreHandle,
+                int flags);
+
+            [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CertAddCertificateContextToStore(
+                IntPtr certificateStoreHandle,
+                IntPtr certificateContext,
+                int addDisposition,
+                out IntPtr storeContextPtr);
+
+            [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool CertSetCertificateContextProperty(
+                IntPtr certificateContext,
+                int propertyId,
+                int flags,
+                [In] ref CryptKeyProviderInformation data);
+
+            [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+            [return: MarshalAs(UnmanagedType.Bool)]
+            public static extern bool PFXExportCertStoreEx(
+                IntPtr certificateStoreHandle,
+                ref CryptoApiBlob pfxBlob,
+                IntPtr password,
+                IntPtr reserved,
+                int flags);
+        }
+    }
+
+}