2004-03-09 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / corlib / System.Security.Cryptography / DSA.cs
1 //
2 // System.Security.Cryptography.DSA.cs class implementation
3 //
4 // Authors:
5 //   Thomas Neidhart (tome@sbox.tugraz.at)
6 //   Sebastien Pouliot (spouliot@motus.com)
7 //
8 // Portions (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
9 //
10
11 using System;
12 using System.Text;
13
14 using Mono.Xml;
15
16 // References:
17 // a.   FIPS PUB 186-2: Digital Signature Standard (DSS) 
18 //      http://csrc.nist.gov/publications/fips/fips186-2/fips186-2-change1.pdf
19
20 namespace System.Security.Cryptography {
21
22         /// <summary>
23         /// Abstract base class for all implementations of the DSA algorithm
24         /// </summary>
25         public abstract class DSA : AsymmetricAlgorithm {
26
27                 // LAMESPEC: It says to derive new DSA implemenation from DSA class.
28                 // Well it's aint gonna be easy this way.
29                 // RSA constructor is public
30                 internal DSA () {}
31         
32                 public static new DSA Create ()
33                 {
34                         return Create ("System.Security.Cryptography.DSA");
35                 }
36
37                 public static new DSA Create (string algName) 
38                 {
39                         return (DSA) CryptoConfig.CreateFromName (algName);
40                 }
41                 
42                 public abstract byte[] CreateSignature (byte[] rgbHash);
43                 
44                 public abstract DSAParameters ExportParameters (bool includePrivateParameters);
45
46                 internal void ZeroizePrivateKey (DSAParameters parameters)
47                 {
48                         if (parameters.X != null)
49                                 Array.Clear (parameters.X, 0, parameters.X.Length);
50                 }
51
52                 private byte[] GetNamedParam (SecurityElement se, string param) 
53                 {
54                         SecurityElement sep = se.SearchForChildByTag (param);
55                         if (sep == null)
56                                 return null;
57                         return Convert.FromBase64String (sep.Text);
58                 }
59
60                 public override void FromXmlString (string xmlString) 
61                 {
62                         if (xmlString == null)
63                                 throw new ArgumentNullException ("xmlString");
64                         
65                         DSAParameters dsaParams = new DSAParameters ();
66                         try {
67                                 SecurityParser sp = new SecurityParser ();
68                                 sp.LoadXml (xmlString);
69                                 SecurityElement se = sp.ToXml ();
70                                 if (se.Tag != "DSAKeyValue")
71                                         throw new Exception ();
72                                 dsaParams.P = GetNamedParam (se, "P");
73                                 dsaParams.Q = GetNamedParam (se, "Q");
74                                 dsaParams.G = GetNamedParam (se, "G");
75                                 dsaParams.J = GetNamedParam (se, "J");
76                                 dsaParams.Y = GetNamedParam (se, "Y");
77                                 dsaParams.X = GetNamedParam (se, "X");
78                                 dsaParams.Seed = GetNamedParam (se, "Seed");
79                                 byte[] counter = GetNamedParam (se, "PgenCounter");
80                                 if (counter != null) {
81                                         byte[] counter4b = new byte [4]; // always 4 bytes
82                                         Array.Copy (counter, 0, counter4b, 0, counter.Length);
83                                         dsaParams.Counter = BitConverter.ToInt32 (counter4b, 0);
84                                 }
85                                 ImportParameters (dsaParams);
86                         }
87                         catch {
88                                 ZeroizePrivateKey (dsaParams);
89                                 throw;
90                         }
91                         finally {
92                                 ZeroizePrivateKey (dsaParams);
93                         }
94                 }
95                 
96                 public abstract void ImportParameters (DSAParameters parameters);
97
98                 // note: using SecurityElement.ToXml wouldn't generate the same string as the MS implementation
99                 public override string ToXmlString (bool includePrivateParameters)
100                 {
101                         StringBuilder sb = new StringBuilder ();
102                         DSAParameters dsaParams = ExportParameters (includePrivateParameters);
103                         try {
104                                 sb.Append ("<DSAKeyValue>");
105                                 
106                                 sb.Append ("<P>");
107                                 sb.Append (Convert.ToBase64String (dsaParams.P));
108                                 sb.Append ("</P>");
109                                 
110                                 sb.Append ("<Q>");
111                                 sb.Append (Convert.ToBase64String (dsaParams.Q));
112                                 sb.Append ("</Q>");
113
114                                 sb.Append ("<G>");
115                                 sb.Append (Convert.ToBase64String (dsaParams.G));
116                                 sb.Append ("</G>");
117
118                                 sb.Append ("<Y>");
119                                 sb.Append (Convert.ToBase64String (dsaParams.Y));
120                                 sb.Append( "</Y>");
121
122                                 sb.Append ("<J>");
123                                 sb.Append (Convert.ToBase64String (dsaParams.J));
124                                 sb.Append ("</J>");
125
126                                 if (dsaParams.Seed != null) {
127                                         sb.Append ("<Seed>");
128                                         sb.Append (Convert.ToBase64String (dsaParams.Seed));
129                                         sb.Append ("</Seed>");
130
131                                         sb.Append ("<PgenCounter>");
132                                         // the number of bytes is important (no matter == 0x00)
133                                         byte[] inArr = BitConverter.GetBytes (dsaParams.Counter);
134                                         int l = inArr.Length;
135                                         while (inArr[l-1] == 0x00)
136                                                 l--;
137                                         byte[] c = new byte[l];
138                                         Array.Copy (inArr, 0, c, 0, l);
139                                         sb.Append (Convert.ToBase64String (c));
140                                         sb.Append ("</PgenCounter>");
141                                 }
142
143                                 if (dsaParams.X != null) {
144                                         sb.Append ("<X>");
145                                         sb.Append (Convert.ToBase64String (dsaParams.X));
146                                         sb.Append ("</X>");
147                                 }
148                                 else if (includePrivateParameters)
149                                         throw new CryptographicException();
150
151                                 sb.Append ("</DSAKeyValue>");
152                         }
153                         catch (NotImplementedException ex) {
154                                 ZeroizePrivateKey (dsaParams);
155                                 throw;
156                         }
157                                                 
158                         return sb.ToString ();
159                 }
160                 
161                 public abstract bool VerifySignature (byte[] rgbHash, byte[] rgbSignature);
162                 
163         } // DSA
164         
165 } // System.Security.Cryptography