2007-04-24 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / corlib / System.Security.Cryptography / DSACryptoServiceProvider.cs
index fa7719db8e971069eb5fead63ca47060e70bcb02..7e000fbdfcef3041192da69e35298b139885f963 100644 (file)
-//\r
-// System.Security.Cryptography.DSACryptoServiceProvider.cs\r
-//\r
-// Authors:\r
-//   Dan Lewis (dihlewis@yahoo.co.uk)\r
-//\r
-// (C) 2002\r
-//\r
-// Stubbed.\r
-//\r
-\r
-using System;\r
-using System.IO;\r
-\r
-namespace System.Security.Cryptography {\r
-       \r
-       [MonoTODO]\r
-       public class DSACryptoServiceProvider : DSA {\r
-               public DSACryptoServiceProvider () { }\r
-               public DSACryptoServiceProvider (CspParameters parameters) { }\r
-               public DSACryptoServiceProvider (int key_size) { }\r
-               public DSACryptoServiceProvider (int key_size, CspParameters parameters) { }\r
-\r
-               public override string KeyExchangeAlgorithm {\r
-                       get { return null; }\r
-               }\r
-\r
-               public override int KeySize {\r
-                       get { return 0; }\r
-               }\r
-\r
-               public override KeySizes[] LegalKeySizes {\r
-                       get { return null; }\r
-               }\r
-\r
-               public override string SignatureAlgorithm {\r
-                       get { return null; }\r
-               }\r
-\r
-               public bool PersistKeyInCsp {\r
-                       get { return false; }\r
-                       set { }\r
-               }\r
-               \r
-               protected override void Dispose (bool disposing) {}\r
-\r
-               public override byte[] CreateSignature (byte[] rgb) {\r
-                       return null;\r
-               }\r
-               \r
-               public override bool VerifySignature(byte[] hash, byte[] sig) {\r
-                       return false;\r
-               }\r
-\r
-               public byte[] SignData (byte[] data) {\r
-                       return SignData (data, 0, data.Length);\r
-               }\r
-\r
-               public byte[] SignData (byte[] data, int offset, int count) {\r
-                       return null;\r
-               }\r
-\r
-               public byte[] SignData (Stream data) {\r
-                       return null;\r
-               }\r
-\r
-               public byte[] SignHash (byte[] hash, string str) {\r
-                       return null;\r
-               }\r
-\r
-               public bool VerifyData (byte[] data, byte[] sig) {\r
-                       return false;\r
-               }\r
-\r
-               public override DSAParameters ExportParameters (bool include) {\r
-                       return new DSAParameters ();\r
-               }\r
-\r
-               public override void ImportParameters (DSAParameters parameters) {\r
-               }\r
-\r
-               public override void FromXmlString(string xmlString) {\r
-               }\r
-\r
-               public override string ToXmlString(bool includePrivateParameters) {\r
-                       return null;\r
-               }\r
-       }\r
-}\r
+//
+// System.Security.Cryptography.DSACryptoServiceProvider.cs
+//
+// Authors:
+//     Dan Lewis (dihlewis@yahoo.co.uk)
+//     Sebastien Pouliot <sebastien@ximian.com>
+//     Ben Maurer (bmaurer@users.sf.net)
+//
+// (C) 2002
+// Portions (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
+// Portions (C) 2003 Ben Maurer
+// 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.
+//
+
+using System.IO;
+using System.Globalization;
+using System.Runtime.InteropServices;
+
+using Mono.Security.Cryptography;
+
+namespace System.Security.Cryptography {
+
+#if NET_2_0
+       [ComVisible (true)]
+       public sealed class DSACryptoServiceProvider : DSA, ICspAsymmetricAlgorithm {
+#elif NET_1_1
+       public sealed class DSACryptoServiceProvider : DSA {
+#else
+       public class DSACryptoServiceProvider : DSA {
+#endif
+               private const int PROV_DSS_DH = 13;             // from WinCrypt.h
+
+               private KeyPairPersistence store;
+               private bool persistKey;
+               private bool persisted;
+
+               private bool privateKeyExportable = true;
+               private bool m_disposed;
+
+               private DSAManaged dsa;
+
+               // MS implementation generates a keypair everytime a new DSA 
+               // object is created (unless an existing key container is 
+               // specified in the CspParameters).
+               // However we:
+               // (a) often use DSA to import an existing keypair.
+               // (b) take a LOT of time to generate the DSA group
+               // So we'll generate the keypair only when (and if) it's being
+               // used (or exported). This should save us a lot of time (at
+               // least in the unit tests).
+
+               public DSACryptoServiceProvider ()
+                       : this (1024, null)
+               {
+               }
+
+               public DSACryptoServiceProvider (CspParameters parameters)
+                       : this (1024, parameters)
+               {
+               }
+
+               public DSACryptoServiceProvider (int dwKeySize)
+                       : this (dwKeySize, null)
+               {
+               }
+
+               public DSACryptoServiceProvider (int dwKeySize, CspParameters parameters)
+               {
+                       LegalKeySizesValue = new KeySizes [1];
+                       LegalKeySizesValue [0] = new KeySizes (512, 1024, 64);
+
+                       // will throw an exception is key size isn't supported
+                       KeySize = dwKeySize;
+                       dsa = new DSAManaged (dwKeySize);
+                       dsa.KeyGenerated += new DSAManaged.KeyGeneratedEventHandler (OnKeyGenerated);
+
+                       persistKey = (parameters != null);
+                       if (parameters == null) {
+                               parameters = new CspParameters (PROV_DSS_DH);
+#if NET_1_1
+                               if (useMachineKeyStore)
+                                       parameters.Flags |= CspProviderFlags.UseMachineKeyStore;
+#endif
+                               store = new KeyPairPersistence (parameters);
+                               // no need to load - it cannot exists
+                       }
+                       else {
+                               store = new KeyPairPersistence (parameters);
+                               store.Load ();
+                               if (store.KeyValue != null) {
+                                       persisted = true;
+                                       this.FromXmlString (store.KeyValue);
+                               }
+                       }
+               }
+
+               ~DSACryptoServiceProvider ()
+               {
+                       Dispose (false);
+               }
+
+               // DSA isn't used for key exchange
+               public override string KeyExchangeAlgorithm {
+                       get { return null; }
+               }
+
+               public override int KeySize {
+                       get { return dsa.KeySize; }
+               }
+
+#if !NET_2_0
+               public override KeySizes[] LegalKeySizes {
+                       get { return LegalKeySizesValue; }
+               }
+#endif
+
+               public bool PersistKeyInCsp {
+                       get { return persistKey; }
+                       set { persistKey = value; }
+               }
+
+#if NET_2_0
+               [ComVisible (false)]
+               public 
+#else
+               internal
+#endif
+               bool PublicOnly {
+                       get { return dsa.PublicOnly; }
+               }
+
+               public override string SignatureAlgorithm {
+                       get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }
+               }
+
+#if NET_1_1
+               private static bool useMachineKeyStore = false;
+
+               public static bool UseMachineKeyStore {
+                       get { return useMachineKeyStore; }
+                       set { useMachineKeyStore = value; }
+               }
+#endif
+
+               public override DSAParameters ExportParameters (bool includePrivateParameters) 
+               {
+                       if ((includePrivateParameters) && (!privateKeyExportable)) {
+                               throw new CryptographicException (
+                                       Locale.GetText ("Cannot export private key"));
+                       }
+
+                       return dsa.ExportParameters (includePrivateParameters);
+               }
+
+               public override void ImportParameters (DSAParameters parameters) 
+               {
+                       dsa.ImportParameters (parameters);
+               }
+
+               public override byte[] CreateSignature (byte[] rgbHash)
+               {
+                       return dsa.CreateSignature (rgbHash);
+               }
+
+               public byte[] SignData (byte[] data)
+               {
+                       // right now only SHA1 is supported by FIPS186-2
+                       HashAlgorithm hash = SHA1.Create ();
+                       byte[] toBeSigned = hash.ComputeHash (data);
+                       return dsa.CreateSignature (toBeSigned);
+               }
+
+               public byte[] SignData (byte[] data, int offset, int count)
+               {
+                       // right now only SHA1 is supported by FIPS186-2
+                       HashAlgorithm hash = SHA1.Create ();
+                       byte[] toBeSigned = hash.ComputeHash (data, offset, count);
+                       return dsa.CreateSignature (toBeSigned);
+               }
+
+               public byte[] SignData (Stream inputStream)
+               {
+                       // right now only SHA1 is supported by FIPS186-2
+                       HashAlgorithm hash = SHA1.Create ();
+                       byte[] toBeSigned = hash.ComputeHash (inputStream);
+                       return dsa.CreateSignature (toBeSigned);
+               }
+
+               public byte[] SignHash (byte[] rgbHash, string str)
+               {
+                       // right now only SHA1 is supported by FIPS186-2
+                       if (String.Compare (str, "SHA1", true, CultureInfo.InvariantCulture) != 0) {
+                               // not documented
+                               throw new CryptographicException (Locale.GetText ("Only SHA1 is supported."));
+                       }
+
+                       return dsa.CreateSignature (rgbHash);
+               }
+
+               public bool VerifyData (byte[] rgbData, byte[] rgbSignature)
+               {
+                       // right now only SHA1 is supported by FIPS186-2
+                       HashAlgorithm hash = SHA1.Create();
+                       byte[] toBeVerified = hash.ComputeHash (rgbData);
+                       return dsa.VerifySignature (toBeVerified, rgbSignature);
+               }
+
+               // LAMESPEC: MD5 isn't allowed with DSA
+               public bool VerifyHash (byte[] rgbHash, string str, byte[] rgbSignature)
+               {
+                       if (str == null)
+                               str = "SHA1"; // default value
+                       if (String.Compare (str, "SHA1", true, CultureInfo.InvariantCulture) != 0) {
+                               throw new CryptographicException (Locale.GetText ("Only SHA1 is supported."));
+                       }
+
+                       return dsa.VerifySignature (rgbHash, rgbSignature);
+               }
+
+               public override bool VerifySignature (byte[] rgbHash, byte[] rgbSignature)
+               {
+                       return dsa.VerifySignature (rgbHash, rgbSignature);
+               }
+
+               protected override void Dispose (bool disposing) 
+               {
+                       if (!m_disposed) {
+                               // the key is persisted and we do not want it persisted
+                               if ((persisted) && (!persistKey)) {
+                                       store.Remove ();        // delete the container
+                               }
+                               if (dsa != null)
+                                       dsa.Clear ();
+                               // call base class 
+                               // no need as they all are abstract before us
+                               m_disposed = true;
+                       }
+               }
+
+               // private stuff
+
+               private void OnKeyGenerated (object sender, EventArgs e) 
+               {
+                       // the key isn't persisted and we want it persisted
+                       if ((persistKey) && (!persisted)) {
+                               // save the current keypair
+                               store.KeyValue = this.ToXmlString (!dsa.PublicOnly);
+                               store.Save ();
+                               persisted = true;
+                       }
+               }
+#if NET_2_0
+               // ICspAsymmetricAlgorithm
+
+               [MonoTODO ("call into KeyPairPersistence to get details")]
+               [ComVisible (false)]
+               public CspKeyContainerInfo CspKeyContainerInfo {
+                       get { return null; }
+               }
+
+               [MonoTODO ("call into CryptoConvert (doesn't currently support DSA)")]
+               [ComVisible (false)]
+               public byte[] ExportCspBlob (bool includePrivateParameters)
+               {
+                       throw new NotImplementedException ("CryptoConvert doesn't currently support DSA");
+               }
+
+               [MonoTODO ("call into CryptoConvert (doesn't currently support DSA)")]
+               [ComVisible (false)]
+               public void ImportCspBlob (byte[] rawData)
+               {
+                       if (rawData == null)
+                               throw new ArgumentNullException ("rawData");
+                       throw new NotImplementedException ("CryptoConvert doesn't currently support DSA");
+               }
+#endif
+       }
+}