Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastien Pouliot <sebastien@ximian.com>2005-10-27 17:44:19 +0400
committerSebastien Pouliot <sebastien@ximian.com>2005-10-27 17:44:19 +0400
commit7c505165df7bc99f130d2f60d43a086adac6443c (patch)
treea0210ba27ae65a0ec2fe49b9cbf283e931a6e34a /mcs/class/System.Security/Mono.Security.Cryptography
parentc6d976c7224b00fc43b1ce9a85ffd7aaae2446fd (diff)
2005-10-27 Sebastien Pouliot <sebastien@ximian.com>
* NativeDapiProtection.cs: New. Native access to DPAPI (Data Protection API) to implement ProtectedData on Windows (requires Windows 2000 or later). svn path=/trunk/mcs/; revision=52281
Diffstat (limited to 'mcs/class/System.Security/Mono.Security.Cryptography')
-rw-r--r--mcs/class/System.Security/Mono.Security.Cryptography/ChangeLog6
-rw-r--r--mcs/class/System.Security/Mono.Security.Cryptography/NativeDapiProtection.cs227
2 files changed, 233 insertions, 0 deletions
diff --git a/mcs/class/System.Security/Mono.Security.Cryptography/ChangeLog b/mcs/class/System.Security/Mono.Security.Cryptography/ChangeLog
index 38832930ba0..d3ee03838b1 100644
--- a/mcs/class/System.Security/Mono.Security.Cryptography/ChangeLog
+++ b/mcs/class/System.Security/Mono.Security.Cryptography/ChangeLog
@@ -1,3 +1,9 @@
+2005-10-27 Sebastien Pouliot <sebastien@ximian.com>
+
+ * NativeDapiProtection.cs: New. Native access to DPAPI (Data
+ Protection API) to implement ProtectedData on Windows (requires
+ Windows 2000 or later).
+
2005-10-20 Sebastien Pouliot <sebastien@ximian.com>
* ManagedProtection.cs: New. A managed class similar to ProtectedData.
diff --git a/mcs/class/System.Security/Mono.Security.Cryptography/NativeDapiProtection.cs b/mcs/class/System.Security/Mono.Security.Cryptography/NativeDapiProtection.cs
new file mode 100644
index 00000000000..1724c5d6551
--- /dev/null
+++ b/mcs/class/System.Security/Mono.Security.Cryptography/NativeDapiProtection.cs
@@ -0,0 +1,227 @@
+//
+// NativeDapiProtection.cs -
+// Protect (encrypt) data without (user involved) key management
+//
+// Author:
+// Sebastien Pouliot <sebastien@ximian.com>
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if NET_2_0
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Security.Cryptography;
+using System.Security.Permissions;
+
+namespace Mono.Security.Cryptography {
+
+ // DAPI is only available in Windows 2000 and later operating systems
+ // see ManagedProtection for other platforms
+
+ // notes:
+ // * no need to assert KeyContainerPermission here as unmanaged code can
+ // do what it wants;
+ // * which is why we also need the [SuppressUnmanagedCodeSecurity]
+ // attribute on each native function (so we don't require UnmanagedCode)
+
+ internal class NativeDapiProtection {
+
+ private const uint CRYPTPROTECT_UI_FORBIDDEN = 0x1;
+ private const uint CRYPTPROTECT_LOCAL_MACHINE = 0x4;
+
+ [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ private struct DATA_BLOB {
+
+ private int cbData;
+ private IntPtr pbData;
+
+ public void Alloc (int size)
+ {
+ if (size > 0) {
+ pbData = Marshal.AllocHGlobal (size);
+ cbData = size;
+ }
+ }
+
+ public void Alloc (byte[] managedMemory)
+ {
+ if (managedMemory != null) {
+ int size = managedMemory.Length;
+ pbData = Marshal.AllocHGlobal (size);
+ cbData = size;
+ Marshal.Copy (managedMemory, 0, pbData, cbData);
+ }
+ }
+
+ public void Free ()
+ {
+ if (pbData != IntPtr.Zero) {
+ // clear copied memory!
+ ZeroMemory (pbData, cbData);
+ Marshal.FreeHGlobal (pbData);
+ pbData = IntPtr.Zero;
+ cbData = 0;
+ }
+ }
+
+ public byte[] ToBytes ()
+ {
+ if (cbData <= 0)
+ return new byte [0];
+
+ byte[] managedMemory = new byte[cbData];
+ Marshal.Copy (pbData, managedMemory, 0, cbData);
+ return managedMemory;
+ }
+ }
+
+ [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ private struct CRYPTPROTECT_PROMPTSTRUCT {
+
+ private int cbSize;
+ private uint dwPromptFlags;
+ private IntPtr hwndApp;
+ private string szPrompt;
+
+ public CRYPTPROTECT_PROMPTSTRUCT (uint flags)
+ {
+ cbSize = Marshal.SizeOf (typeof (CRYPTPROTECT_PROMPTSTRUCT));
+ dwPromptFlags = flags;
+ hwndApp = IntPtr.Zero;
+ szPrompt = null;
+ }
+ }
+
+ // http://msdn.microsoft.com/library/en-us/seccrypto/security/cryptprotectdata.asp
+ [SuppressUnmanagedCodeSecurity]
+ [DllImport ("crypt32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
+ private static extern bool CryptProtectData (ref DATA_BLOB pDataIn, string szDataDescr, ref DATA_BLOB pOptionalEntropy,
+ IntPtr pvReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, uint dwFlags, ref DATA_BLOB pDataOut);
+
+ // http://msdn.microsoft.com/library/en-us/seccrypto/security/cryptunprotectdata.asp
+ [SuppressUnmanagedCodeSecurity]
+ [DllImport ("crypt32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
+ private static extern bool CryptUnprotectData (ref DATA_BLOB pDataIn, string szDataDescr, ref DATA_BLOB pOptionalEntropy,
+ IntPtr pvReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, uint dwFlags, ref DATA_BLOB pDataOut);
+
+ // http://msdn.microsoft.com/library/en-us/memory/base/zeromemory.asp
+ // note: SecureZeroMemory is an inline function (and can't be used here)
+ // anyway I don't think the CLR will optimize this call away (like a C/C++ compiler could do)
+ [SuppressUnmanagedCodeSecurity]
+ [DllImport ("kernel32.dll", EntryPoint = "RtlZeroMemory", SetLastError = false, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
+ private static extern void ZeroMemory (IntPtr dest, int size);
+
+
+ // managed helpers
+
+ public static byte[] Protect (byte[] userData, byte[] optionalEntropy, DataProtectionScope scope)
+ {
+ byte[] encdata = null;
+ int hr = 0;
+
+ DATA_BLOB data = new DATA_BLOB ();
+ DATA_BLOB entropy = new DATA_BLOB ();
+ DATA_BLOB cipher = new DATA_BLOB ();
+ try {
+ CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT (0);
+ data.Alloc (userData);
+ entropy.Alloc (optionalEntropy);
+
+ // note: the scope/flags has already been check by the public caller
+ uint flags = CRYPTPROTECT_UI_FORBIDDEN;
+ if (scope == DataProtectionScope.LocalMachine)
+ flags |= CRYPTPROTECT_LOCAL_MACHINE;
+
+ // note: on Windows 2000 the string parameter *cannot* be null
+ if (CryptProtectData (ref data, String.Empty, ref entropy, IntPtr.Zero,
+ ref prompt, flags, ref cipher)) {
+ // copy encrypted data back to managed codde
+ encdata = cipher.ToBytes ();
+ } else {
+ hr = Marshal.GetLastWin32Error ();
+ }
+ }
+ catch (Exception ex) {
+ string msg = Locale.GetText ("Error protecting data.");
+ throw new CryptographicException (msg, ex);
+ }
+ finally {
+ cipher.Free ();
+ data.Free ();
+ entropy.Free ();
+ }
+
+ if ((encdata == null) || (hr != 0)) {
+ throw new CryptographicException (Marshal.GetLastWin32Error ());
+ }
+ return encdata;
+ }
+
+ public static byte[] Unprotect (byte[] encryptedData, byte[] optionalEntropy, DataProtectionScope scope)
+ {
+ byte[] decdata = null;
+ int hr = 0;
+
+ DATA_BLOB cipher = new DATA_BLOB ();
+ DATA_BLOB entropy = new DATA_BLOB ();
+ DATA_BLOB data = new DATA_BLOB ();
+ try {
+ CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT (0);
+ cipher.Alloc (encryptedData);
+ entropy.Alloc (optionalEntropy);
+
+ // note: the scope/flags has already been check by the public caller
+ uint flags = CRYPTPROTECT_UI_FORBIDDEN;
+ if (scope == DataProtectionScope.LocalMachine)
+ flags |= CRYPTPROTECT_LOCAL_MACHINE;
+
+ if (CryptUnprotectData (ref cipher, null, ref entropy, IntPtr.Zero,
+ ref prompt, flags, ref data)) {
+ // copy decrypted data back to managed codde
+ decdata = data.ToBytes ();
+ } else {
+ hr = Marshal.GetLastWin32Error ();
+ }
+ }
+ catch (Exception ex) {
+ string msg = Locale.GetText ("Error protecting data.");
+ throw new CryptographicException (msg, ex);
+ }
+ finally {
+ cipher.Free ();
+ data.Free ();
+ entropy.Free ();
+ }
+
+ if ((decdata == null) || (hr != 0)) {
+ throw new CryptographicException (hr);
+ }
+ return decdata;
+ }
+ }
+}
+
+#endif