A little more work of CorCompare work:
[mono.git] / mcs / class / corlib / System.Security.Cryptography / RNGCryptoServiceProvider.cs
index 1e3ac201400c5b00f098460aeeeece48d5c2f92a..71fcdc062f1e0aaaa88826b4c5238ff32b04da39 100644 (file)
@@ -3,9 +3,29 @@
 //
 // Authors:
 //     Mark Crichton (crichton@gimp.org)
-//     Sebastien Pouliot (spouliot@motus.com)
+//     Sebastien Pouliot (sebastien@ximian.com)
 //
 // (C) 2002
+// 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,
 // 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 {
        
-#if USE_VERSION_1_0
+#if NET_1_0
        public class RNGCryptoServiceProvider : RandomNumberGenerator {
 #else
+       #if NET_2_0
+       [ComVisible (true)]
+       #endif
        public sealed class RNGCryptoServiceProvider : RandomNumberGenerator {
 #endif
-               
-               [MonoTODO]
-               public RNGCryptoServiceProvider () 
+               private static object _lock;
+               private IntPtr _handle;
+
+               static RNGCryptoServiceProvider ()
                {
-                       // This will get some meaning when I figure out what the other
-                       // three constructors do.
+                       if (RngOpen ())
+                               _lock = new object ();
+               }
+
+               public RNGCryptoServiceProvider ()
+               {
+                       _handle = RngInitialize (null);
+                       Check ();
                }
                
-               [MonoTODO]
-               public RNGCryptoServiceProvider (byte[] rgb) 
+               public RNGCryptoServiceProvider (byte[] rgb)
                {
-                       // Ok, not called by app code... someone must call it, though.
+                       _handle = RngInitialize (rgb);
+                       Check ();
                }
                
-               [MonoTODO]
-               public RNGCryptoServiceProvider (CspParameters cspParams) 
+               public RNGCryptoServiceProvider (CspParameters cspParams)
                {
-                       // Why do I have this feeling this is the MS CryptoAPI...
+                       // CSP selection isn't supported but we still return 
+                       // random data (no exception) for compatibility
+                       _handle = RngInitialize (null);
+                       Check ();
                }
                
-               [MonoTODO]
                public RNGCryptoServiceProvider (string str) 
                {
-                       // More !application code.  Interesting...
+                       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 extern void InternalGetBytes (byte[] data);
+               private static extern bool RngOpen ();
                
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern void InternalGetNonZeroBytes (byte[] data);
+               private static extern IntPtr RngInitialize (byte[] seed);
+
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               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) 
                {
-                       InternalGetBytes (data);
+                       if (data == null)
+                               throw new ArgumentNullException ("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) 
                {
-                       InternalGetNonZeroBytes (data);
+                       if (data == null)
+                               throw new ArgumentNullException ("data");
+
+                       byte[] random = new byte [data.Length * 2];
+                       int i = 0;
+                       // one pass should be enough but hey this is random ;-)
+                       while (i < data.Length) {
+                               _handle = RngGetBytes (_handle, random);
+                               Check ();
+                               for (int j=0; j < random.Length; j++) {
+                                       if (i == data.Length)
+                                               break;
+                                       if (random [j] != 0)
+                                               data [i++] = random [j];
+                               }
+                       }
                }
                
                ~RNGCryptoServiceProvider () 
                {
-                       // in our case we have nothing unmamanged to dispose
+                       if (_handle != IntPtr.Zero) {
+                               RngClose (_handle);
+                               _handle = IntPtr.Zero;
+                       }
                }
        }
 }