A little more work of CorCompare work:
[mono.git] / mcs / class / corlib / System.Security.Cryptography / RNGCryptoServiceProvider.cs
index b6849e276b27953f0a8fbf364bd3742981afa8a4..71fcdc062f1e0aaaa88826b4c5238ff32b04da39 100644 (file)
@@ -6,7 +6,26 @@
 //     Sebastien Pouliot (sebastien@ximian.com)
 //
 // (C) 2002
-// (C) 2004 Novell (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
+// "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.
 //
 
 // "In the beginning there was Chaos,
@@ -14,8 +33,9 @@
 // Great Power without form."
 // -- The Verrah Rubicon of Verena, Book One
 
-using System;
+using System.Globalization;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Text;
 
 namespace System.Security.Cryptography {
@@ -23,40 +43,83 @@ namespace System.Security.Cryptography {
 #if NET_1_0
        public class RNGCryptoServiceProvider : RandomNumberGenerator {
 #else
+       #if NET_2_0
+       [ComVisible (true)]
+       #endif
        public sealed class RNGCryptoServiceProvider : RandomNumberGenerator {
 #endif
+               private static object _lock;
+               private IntPtr _handle;
+
+               static RNGCryptoServiceProvider ()
+               {
+                       if (RngOpen ())
+                               _lock = new object ();
+               }
+
                public RNGCryptoServiceProvider ()
                {
+                       _handle = RngInitialize (null);
+                       Check ();
                }
                
-               public RNGCryptoServiceProvider (byte[] rgb) 
+               public RNGCryptoServiceProvider (byte[] rgb)
                {
-                       Seed (rgb);
+                       _handle = RngInitialize (rgb);
+                       Check ();
                }
                
                public RNGCryptoServiceProvider (CspParameters cspParams)
                {
-                       // CSP selection isn't supported
-                       // but we still return random (no exception) for compatibility
+                       // CSP selection isn't supported but we still return 
+                       // random data (no exception) for compatibility
+                       _handle = RngInitialize (null);
+                       Check ();
                }
                
                public RNGCryptoServiceProvider (string str) 
                {
-                       Seed (Encoding.UTF8.GetBytes (str));
+                       if (str == null)
+                               _handle = RngInitialize (null);
+                       else
+                               _handle = RngInitialize (Encoding.UTF8.GetBytes (str));
+                       Check ();
                }
+
+               private void Check () 
+               {
+                       if (_handle == IntPtr.Zero) {
+                               throw new CryptographicException (
+                                       Locale.GetText ("Couldn't access random source."));
+                       }
+               }
+
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private static extern bool RngOpen ();
                
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private static extern void Seed (byte[] data);
+               private static extern IntPtr RngInitialize (byte[] seed);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern void InternalGetBytes (byte[] data);
+               private static extern IntPtr RngGetBytes (IntPtr handle, byte[] data);
+
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private static extern void RngClose (IntPtr handle);
                
                public override void GetBytes (byte[] data) 
                {
                        if (data == null)
                                throw new ArgumentNullException ("data");
 
-                       InternalGetBytes (data);
+                       if (_lock == null) {
+                               _handle = RngGetBytes (_handle, data);
+                       } else {
+                               // using a global handle for randomness
+                               lock (_lock) {
+                                       _handle = RngGetBytes (_handle, data);
+                               }
+                       }
+                       Check ();
                }
                
                public override void GetNonZeroBytes (byte[] data) 
@@ -68,7 +131,8 @@ namespace System.Security.Cryptography {
                        int i = 0;
                        // one pass should be enough but hey this is random ;-)
                        while (i < data.Length) {
-                               GetBytes (random);
+                               _handle = RngGetBytes (_handle, random);
+                               Check ();
                                for (int j=0; j < random.Length; j++) {
                                        if (i == data.Length)
                                                break;
@@ -78,10 +142,12 @@ namespace System.Security.Cryptography {
                        }
                }
                
-               /* Commented as we don't require this right now (and it will perform better that way)
                ~RNGCryptoServiceProvider () 
                {
-                       // in our case we have nothing unmanaged to dispose
-               }*/
+                       if (_handle != IntPtr.Zero) {
+                               RngClose (_handle);
+                               _handle = IntPtr.Zero;
+                       }
+               }
        }
 }