2005-10-20 Sebastien Pouliot <sebastien@ximian.com>
authorSebastien Pouliot <sebastien@ximian.com>
Thu, 20 Oct 2005 19:14:00 +0000 (19:14 -0000)
committerSebastien Pouliot <sebastien@ximian.com>
Thu, 20 Oct 2005 19:14:00 +0000 (19:14 -0000)
* CryptographicAttributeCollection.cs: Fixed Add and Remove methods.
* ProtectedMemory.cs: Implemented (unmanaged) for Windows only.
* ProtectedData.cs: Implemented for everything except Windows ;-) by
using the new ManagedProtection class.

svn path=/trunk/mcs/; revision=52000

mcs/class/System.Security/System.Security.Cryptography/ChangeLog
mcs/class/System.Security/System.Security.Cryptography/CryptographicAttributeCollection.cs
mcs/class/System.Security/System.Security.Cryptography/ProtectedData.cs
mcs/class/System.Security/System.Security.Cryptography/ProtectedMemory.cs

index bbf7fc1941cd594ed12b7b065f1130ed2e44fcd9..acabeab439660342b5e0e2b3bc64ce77cfb66c8c 100644 (file)
@@ -1,3 +1,10 @@
+2005-10-20  Sebastien Pouliot  <sebastien@ximian.com>
+
+       * CryptographicAttributeCollection.cs: Fixed Add and Remove methods.
+       * ProtectedMemory.cs: Implemented (unmanaged) for Windows only.
+       * ProtectedData.cs: Implemented for everything except Windows ;-) by
+       using the new ManagedProtection class.
+
 2005-09-26  Sebastien Pouliot  <sebastien@ximian.com>
 
        * Asn*.cs, Oid*.cs: Moved to System.dll
index 1ebe0597ec079d35efc5a4de23576a37cdb203d4..d3a08efa6d8816129365635ae837c19198279f4b 100644 (file)
@@ -38,13 +38,13 @@ namespace System.Security.Cryptography {
                private ArrayList _list;
 
                public CryptographicAttributeObjectCollection () 
-               {
+               {\r
                        _list = new ArrayList ();
                }
 
                public CryptographicAttributeObjectCollection (CryptographicAttributeObject attribute)
                        : this ()
-               {
+               {\r
                        _list.Add (attribute);
                }
 
@@ -63,7 +63,7 @@ namespace System.Security.Cryptography {
                }
 
                public object SyncRoot {
-                       get { return _list.SyncRoot; }
+                       get { return this; }
                }
 
                // methods
@@ -71,17 +71,34 @@ namespace System.Security.Cryptography {
                public int Add (AsnEncodedData asnEncodedData)
                {
                        if (asnEncodedData == null)
-                               throw new ArgumentNullException ("asnEncodedData");
-
-                       return _list.Add (asnEncodedData);
+                               throw new ArgumentNullException ("asnEncodedData");\r
+\r
+                       AsnEncodedDataCollection coll = new AsnEncodedDataCollection (asnEncodedData);\r
+                       return Add (new CryptographicAttributeObject (asnEncodedData.Oid, coll));
                }
 
                public int Add (CryptographicAttributeObject attribute)
                {
                        if (attribute == null)
-                               throw new ArgumentNullException ("attribute");
-
-                       return _list.Add (attribute);
+                               throw new ArgumentNullException ("attribute");\r
+\r
+                       int existing = -1;\r
+                       string oid = attribute.Oid.Value;\r
+                       for (int i=0; i < _list.Count; i++) {\r
+                               if ((_list[i] as CryptographicAttributeObject).Oid.Value == oid) {\r
+                                       existing = i;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       if (existing >= 0) {\r
+                               CryptographicAttributeObject cao = this[existing];\r
+                               foreach (AsnEncodedData value in attribute.Values) {\r
+                                       cao.Values.Add (value);\r
+                               }\r
+                               return existing;\r
+                       } else {\r
+                               return _list.Add (attribute);\r
+                       }
                }
 
                public void CopyTo (CryptographicAttributeObject[] array, int index)
@@ -105,7 +122,10 @@ namespace System.Security.Cryptography {
                }
 
                public void Remove (CryptographicAttributeObject attribute) 
-               {
+               {\r
+                       if (attribute == null)\r
+                               throw new ArgumentNullException ("attribute");\r
+\r
                        _list.Remove (attribute);
                }
        }
index fcc07f0b4206e32f2e703b9ebad7af86b259e38a..1e86ee11b733cfc4097ce9d2682219291de22d98 100644 (file)
@@ -1,11 +1,11 @@
 //
 // ProtectedData.cs: Protect (encrypt) data without (user involved) key management
 //
-// Author:
-//     Sebastien Pouliot (spouliot@motus.com)
+// Author:\r
+//     Sebastien Pouliot  <sebastien@ximian.com>\r
 //
-// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)\r
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)\r
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_2_0
+#if NET_2_0\r
+\r
+using System.Runtime.InteropServices;\r
+using System.Security.Permissions;
 
-using System;
+using Mono.Security.Cryptography;
 
 namespace System.Security.Cryptography {
 
@@ -43,29 +46,106 @@ namespace System.Security.Cryptography {
                {
                }
 
-               // FIXME: interop could be important under windows - if one application protect some data using
-               // mono and another one unprotects it using ms.net
-
-               [MonoTODO ("interop with MS implementation ?")]
+               [MonoTODO ("not (yet) supported on Windows")]\r
+// FIXME       [DataProtectionPermission (SecurityAction.Demand, ProtectData = true)]\r
                public static byte[] Protect (byte[] userData, byte[] optionalEntropy, DataProtectionScope scope) 
                {
                        if (userData == null)
                                throw new ArgumentNullException ("userData");
 
-                       // on Windows this is supported only under 2000 and later OS
-                       throw new PlatformNotSupportedException ();
-               }
-
-               [MonoTODO ("interop with MS implementation ?")]
+                       // on Windows this is supported only under 2000 and later OS\r
+                       Check (scope);\r
+\r
+                       switch (impl) {\r
+                       case DataProtectionImplementation.ManagedProtection:\r
+                               try {\r
+                                       return ManagedProtection.Protect (userData, optionalEntropy, scope);\r
+                               }\r
+                               catch (Exception e) {\r
+                                       string msg = Locale.GetText ("Data protection failed.");\r
+                                       throw new CryptographicException (msg, e);\r
+                               }\r
+                       case DataProtectionImplementation.Win32CryptoProtect:\r
+                       default:\r
+                               throw new PlatformNotSupportedException ();\r
+                       }\r
+               }\r
+\r
+               [MonoTODO ("not (yet) supported on Windows")]\r
+// FIXME       [DataProtectionPermission (SecurityAction.Demand, UnprotectData = true)]\r
                public static byte[] Unprotect (byte[] encryptedData, byte[] optionalEntropy, DataProtectionScope scope) 
                {
                        if (encryptedData == null)
                                throw new ArgumentNullException ("encryptedData");
 
-                       // on Windows this is supported only under 2000 and later OS
-                       throw new PlatformNotSupportedException ();
+                       // on Windows this is supported only under 2000 and later OS\r
+                       Check (scope);\r
+\r
+                       switch (impl) {\r
+                       case DataProtectionImplementation.ManagedProtection:\r
+                               try {\r
+                                       return ManagedProtection.Unprotect (encryptedData, optionalEntropy, scope);\r
+                               }\r
+                               catch (Exception e) {\r
+                                       string msg = Locale.GetText ("Data unprotection failed.");\r
+                                       throw new CryptographicException (msg, e);\r
+                               }\r
+                       case DataProtectionImplementation.Win32CryptoProtect:\r
+                       default:\r
+                               throw new PlatformNotSupportedException ();\r
+                       }\r
                }
-       } 
+
+               // private stuff\r
+\r
+               enum DataProtectionImplementation {\r
+                       Unknown,\r
+                       Win32CryptoProtect,\r
+                       ManagedProtection,\r
+                       Unsupported = Int32.MinValue\r
+               }\r
+\r
+               private static DataProtectionImplementation impl;\r
+\r
+               private static void Detect ()\r
+               {\r
+                       OperatingSystem os = Environment.OSVersion;\r
+                       switch (os.Platform) {\r
+                       case PlatformID.Win32NT:\r
+                               Version v = os.Version;\r
+                               if (v.Major < 5) {\r
+                                       impl = DataProtectionImplementation.Unsupported;\r
+                               } else {\r
+                                       // Windows 2000 (5.0) and later\r
+                                       impl = DataProtectionImplementation.Win32CryptoProtect;\r
+                               }\r
+                               break;\r
+                       case PlatformID.Unix:\r
+                               impl = DataProtectionImplementation.ManagedProtection;\r
+                               break;\r
+                       default:\r
+                               impl = DataProtectionImplementation.Unsupported;\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               private static void Check (DataProtectionScope scope)\r
+               {\r
+                       if ((scope < DataProtectionScope.CurrentUser) || (scope > DataProtectionScope.LocalMachine)) {\r
+                               string msg = Locale.GetText ("Invalid enum value '{0}' for '{1}'.", \r
+                                       scope, "DataProtectionScope");\r
+                               throw new ArgumentException (msg, "scope");\r
+                       }\r
+\r
+                       switch (impl) {\r
+                       case DataProtectionImplementation.Unknown:\r
+                               Detect ();\r
+                               break;\r
+                       case DataProtectionImplementation.Unsupported:\r
+                               throw new PlatformNotSupportedException ();\r
+                       }\r
+               }\r
+       }
 }
 
 #endif
index 2b1dfab08ec349a2e4633dd6d9fb2c5f8239511a..d550ca67abde68d5ae689107e9a812ec515afa80 100644 (file)
@@ -2,10 +2,10 @@
 // ProtectedMemory.cs: Protect (encrypt) memory without (user involved) key management
 //
 // Author:
-//     Sebastien Pouliot (spouliot@motus.com)
+//     Sebastien Pouliot  <sebastien@ximian.com>
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-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
@@ -29,7 +29,9 @@
 
 #if NET_2_0
 
-using System;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Security.Permissions;
 
 namespace System.Security.Cryptography {
 
@@ -43,29 +45,159 @@ namespace System.Security.Cryptography {
                {
                }
 
-               [MonoTODO]
+               [MonoTODO ("only supported on Windows 2000 SP3 and later")]\r
+// FIXME       [DataProtectionPermission (SecurityAction.Demand, ProtectMemory = true)]\r
                public static void Protect (byte[] userData, MemoryProtectionScope scope) 
                {
                        if (userData == null)
-                               throw new ArgumentNullException ("userData");
-                       if (userData.Length % 16 != 0)
-                               throw new CryptographicException ("not a multiple of 16 bytes");
-
-                       // on Windows this is supported only under XP and later OS
-                       throw new PlatformNotSupportedException ();
-               }
-
-               [MonoTODO]
+                               throw new ArgumentNullException ("userData");\r
+\r
+                       Check (userData.Length, scope);\r
+                       try {\r
+                               uint flags = (uint) scope;\r
+                               uint length = (uint) userData.Length;\r
+\r
+                               switch (impl) {\r
+                               case MemoryProtectionImplementation.Win32RtlEncryptMemory:\r
+                                       int err = RtlEncryptMemory (userData, length, flags);\r
+                                       if (err < 0) {\r
+                                               string msg = Locale.GetText ("Error. NTSTATUS = {0}.", err);\r
+                                               throw new CryptographicException (msg);\r
+                                       }\r
+                                       break;\r
+                               case MemoryProtectionImplementation.Win32CryptoProtect:\r
+                                       bool result = CryptProtectMemory (userData, length, flags);\r
+                                       if (!result)\r
+                                               throw new CryptographicException (Marshal.GetLastWin32Error ());\r
+                                       break;\r
+                               default:\r
+                                       throw new PlatformNotSupportedException ();\r
+                               }\r
+                       }\r
+                       catch {\r
+                               // Windows 2000 before SP3 will throw\r
+                               impl = MemoryProtectionImplementation.Unsupported;\r
+                               throw new PlatformNotSupportedException ();\r
+                       }\r
+               }\r
+\r
+               [MonoTODO ("only supported on Windows 2000 SP3 and later")]\r
+// FIXME       [DataProtectionPermission (SecurityAction.Demand, UnprotectMemory = true)]\r
                public static void Unprotect (byte[] encryptedData, MemoryProtectionScope scope) 
                {
                        if (encryptedData == null)
-                               throw new ArgumentNullException ("encryptedData");
-                       if (encryptedData.Length % 16 != 0)
-                               throw new CryptographicException ("not a multiple of 16 bytes");
-
-                       // on Windows this is supported only under XP and later OS
-                       throw new PlatformNotSupportedException ();
+                               throw new ArgumentNullException ("encryptedData");\r
+\r
+                       Check (encryptedData.Length, scope);\r
+                       try {\r
+                               uint flags = (uint) scope;\r
+                               uint length = (uint) encryptedData.Length;\r
+\r
+                               switch (impl) {\r
+                               case MemoryProtectionImplementation.Win32RtlEncryptMemory:\r
+                                       int err = RtlDecryptMemory (encryptedData, length, flags);\r
+                                       if (err < 0) {\r
+                                               string msg = Locale.GetText ("Error. NTSTATUS = {0}.", err);\r
+                                               throw new CryptographicException (msg);\r
+                                       }\r
+                                       break;\r
+                               case MemoryProtectionImplementation.Win32CryptoProtect:\r
+                                       bool result = CryptUnprotectMemory (encryptedData, length, flags);\r
+                                       if (!result)\r
+                                               throw new CryptographicException (Marshal.GetLastWin32Error ());\r
+                                       break;\r
+                               default:\r
+                                       throw new PlatformNotSupportedException ();\r
+                               }\r
+                       }\r
+                       catch {\r
+                               // Windows 2000 before SP3 will throw\r
+                               impl = MemoryProtectionImplementation.Unsupported;\r
+                               throw new PlatformNotSupportedException ();\r
+                       }\r
                }
+
+               // private stuff\r
+\r
+               private const int BlockSize = 16;\r
+\r
+               enum MemoryProtectionImplementation {\r
+                       Unknown,\r
+                       Win32RtlEncryptMemory,\r
+                       Win32CryptoProtect,\r
+                       Unsupported = Int32.MinValue\r
+               }\r
+\r
+               private static MemoryProtectionImplementation impl;\r
+\r
+               private static void Detect ()\r
+               {\r
+                       OperatingSystem os = Environment.OSVersion;\r
+                       switch (os.Platform) {\r
+                       case PlatformID.Win32NT:\r
+                               Version v = os.Version;\r
+                               if (v.Major < 5) {\r
+                                       impl = MemoryProtectionImplementation.Unsupported;\r
+                               } else if (v.Major == 5) {\r
+                                       if (v.Minor < 2) {\r
+                                               // 2000 (5.0) Service Pack 3 and XP (5.1)\r
+                                               impl = MemoryProtectionImplementation.Win32RtlEncryptMemory;\r
+                                       } else {\r
+                                               impl = MemoryProtectionImplementation.Win32CryptoProtect;\r
+                                       }\r
+                               } else {\r
+                                       // vista (6.0) and later\r
+                                       impl = MemoryProtectionImplementation.Win32CryptoProtect;\r
+                               }\r
+                               break;\r
+                       default:\r
+                               impl = MemoryProtectionImplementation.Unsupported;\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               private static void Check (int size, MemoryProtectionScope scope)
+               {\r
+                       if (size % BlockSize != 0) {\r
+                               string msg = Locale.GetText ("Not a multiple of {0} bytes.", BlockSize);\r
+                               throw new CryptographicException (msg);\r
+                       }
+
+                       if ((scope < MemoryProtectionScope.SameProcess) || (scope > MemoryProtectionScope.SameLogon)) {
+                               string msg = Locale.GetText ("Invalid enum value for '{0}'.", "MemoryProtectionScope");
+                               throw new ArgumentException (msg, "scope");
+                       }\r
+\r
+                       switch (impl) {\r
+                       case MemoryProtectionImplementation.Unknown:\r
+                               Detect ();\r
+                               break;\r
+                       case MemoryProtectionImplementation.Unsupported:\r
+                               throw new PlatformNotSupportedException ();\r
+                       }
+               }\r
+\r
+               // http://msdn.microsoft.com/library/en-us/dncode/html/secure06122003.asp\r
+               // Summary: CryptProtectMemory and CryptUnprotectMemory exists only in Windows 2003 +\r
+               // but they are available in advapi32.dll as RtlEncryptMemory (SystemFunction040) and\r
+               // RtlDecryptMemory (SystemFunction041) since Windows 2000 SP 3. Sadly both can disappear\r
+               // anytime with newer OS so we include support for Crypt[Unp|P]rotectMemory too.
+
+               [SuppressUnmanagedCodeSecurity]
+               [DllImport ("advapi32.dll", EntryPoint="SystemFunction040", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]\r
+               private static extern int RtlEncryptMemory (byte[] pData, uint cbData, uint dwFlags);\r
+\r
+               [SuppressUnmanagedCodeSecurity]\r
+               [DllImport ("advapi32.dll", EntryPoint = "SystemFunction041", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]\r
+               private static extern int RtlDecryptMemory (byte[] pData, uint cbData, uint dwFlags);\r
+\r
+               [SuppressUnmanagedCodeSecurity]\r
+               [DllImport ("crypt32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]\r
+               private static extern bool CryptProtectMemory (byte[] pData, uint cbData, uint dwFlags);\r
+\r
+               [SuppressUnmanagedCodeSecurity]\r
+               [DllImport ("crypt32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]\r
+               private static extern bool CryptUnprotectMemory (byte[] pData, uint cbData, uint dwFlags);\r
        } 
 }