3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>[....]</OWNER>
13 namespace System.Security.Cryptography {
15 using System.Runtime.Serialization;
16 using System.Security.Util;
17 using System.Globalization;
19 using System.Diagnostics.Contracts;
21 // DSAParameters is serializable so that one could pass the public parameters
22 // across a remote call, but we explicitly make the private key X non-serializable
23 // so you cannot accidently send it along with the public parameters.
25 [System.Runtime.InteropServices.ComVisible(true)]
26 public struct DSAParameters {
32 [NonSerialized] public byte[] X;
37 [System.Runtime.InteropServices.ComVisible(true)]
38 public abstract class DSA : AsymmetricAlgorithm
41 // Extending this class allows us to know that you are really implementing
42 // an DSA key. This is required for anybody providing a new DSA key value
45 // The class provides no methods, fields or anything else. Its only purpose is
46 // as a heirarchy member for identification of the algorithm.
55 new static public DSA Create() {
57 return new System.Security.Cryptography.DSACryptoServiceProvider ();
59 return Create("System.Security.Cryptography.DSA");
63 new static public DSA Create(String algName) {
64 return (DSA) CryptoConfig.CreateFromName(algName);
67 // DSA does not encode the algorithm identifier into the signature blob, therefore CreateSignature and
68 // VerifySignature do not need the HashAlgorithmName value, only SignData and VerifyData do.
69 abstract public byte[] CreateSignature(byte[] rgbHash);
71 abstract public bool VerifySignature(byte[] rgbHash, byte[] rgbSignature);
73 protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
75 throw DerivedClassMustOverride();
78 protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
80 throw DerivedClassMustOverride();
83 public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm)
85 if (data == null) { throw new ArgumentNullException("data"); }
87 return SignData(data, 0, data.Length, hashAlgorithm);
90 public virtual byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
92 if (data == null) { throw new ArgumentNullException("data"); }
93 if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException("offset"); }
94 if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException("count"); }
95 if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
97 byte[] hash = HashData(data, offset, count, hashAlgorithm);
98 return CreateSignature(hash);
101 public virtual byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm)
103 if (data == null) { throw new ArgumentNullException("data"); }
104 if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
106 byte[] hash = HashData(data, hashAlgorithm);
107 return CreateSignature(hash);
110 public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm)
112 if (data == null) { throw new ArgumentNullException("data"); }
114 return VerifyData(data, 0, data.Length, signature, hashAlgorithm);
117 public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm)
119 if (data == null) { throw new ArgumentNullException("data"); }
120 if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException("offset"); }
121 if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException("count"); }
122 if (signature == null) { throw new ArgumentNullException("signature"); }
123 if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
125 byte[] hash = HashData(data, offset, count, hashAlgorithm);
126 return VerifySignature(hash, signature);
129 public virtual bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm)
131 if (data == null) { throw new ArgumentNullException("data"); }
132 if (signature == null) { throw new ArgumentNullException("signature"); }
133 if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
135 byte[] hash = HashData(data, hashAlgorithm);
136 return VerifySignature(hash, signature);
139 // We can provide a default implementation of FromXmlString because we require
140 // every DSA implementation to implement ImportParameters
141 // All we have to do here is parse the XML.
143 public override void FromXmlString(String xmlString) {
144 if (xmlString == null) throw new ArgumentNullException("xmlString");
145 Contract.EndContractBlock();
146 DSAParameters dsaParams = new DSAParameters();
147 Parser p = new Parser(xmlString);
148 SecurityElement topElement = p.GetTopElement();
150 // P is always present
151 String pString = topElement.SearchForTextOfLocalName("P");
152 if (pString == null) {
153 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","P"));
155 dsaParams.P = Convert.FromBase64String(Utils.DiscardWhiteSpaces(pString));
157 // Q is always present
158 String qString = topElement.SearchForTextOfLocalName("Q");
159 if (qString == null) {
160 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","Q"));
162 dsaParams.Q = Convert.FromBase64String(Utils.DiscardWhiteSpaces(qString));
164 // G is always present
165 String gString = topElement.SearchForTextOfLocalName("G");
166 if (gString == null) {
167 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","G"));
169 dsaParams.G = Convert.FromBase64String(Utils.DiscardWhiteSpaces(gString));
171 // Y is always present
172 String yString = topElement.SearchForTextOfLocalName("Y");
173 if (yString == null) {
174 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","Y"));
176 dsaParams.Y = Convert.FromBase64String(Utils.DiscardWhiteSpaces(yString));
179 String jString = topElement.SearchForTextOfLocalName("J");
180 if (jString != null) dsaParams.J = Convert.FromBase64String(Utils.DiscardWhiteSpaces(jString));
182 // X is optional -- private key if present
183 String xString = topElement.SearchForTextOfLocalName("X");
184 if (xString != null) dsaParams.X = Convert.FromBase64String(Utils.DiscardWhiteSpaces(xString));
186 // Seed and PgenCounter are optional as a unit -- both present or both absent
187 String seedString = topElement.SearchForTextOfLocalName("Seed");
188 String pgenCounterString = topElement.SearchForTextOfLocalName("PgenCounter");
189 if ((seedString != null) && (pgenCounterString != null)) {
190 dsaParams.Seed = Convert.FromBase64String(Utils.DiscardWhiteSpaces(seedString));
191 dsaParams.Counter = Utils.ConvertByteArrayToInt(Convert.FromBase64String(Utils.DiscardWhiteSpaces(pgenCounterString)));
192 } else if ((seedString != null) || (pgenCounterString != null)) {
193 if (seedString == null) {
194 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","Seed"));
196 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","PgenCounter"));
200 ImportParameters(dsaParams);
203 // We can provide a default implementation of ToXmlString because we require
204 // every DSA implementation to implement ImportParameters
205 // If includePrivateParameters is false, this is just an XMLDSIG DSAKeyValue
206 // clause. If includePrivateParameters is true, then we extend DSAKeyValue with
207 // the other (private) elements.
209 public override String ToXmlString(bool includePrivateParameters) {
210 // From the XMLDSIG spec, RFC 3075, Section 6.4.1, a DSAKeyValue looks like this:
212 <element name="DSAKeyValue">
216 <element name="P" type="ds:CryptoBinary"/>
217 <element name="Q" type="ds:CryptoBinary"/>
218 <element name="G" type="ds:CryptoBinary"/>
219 <element name="Y" type="ds:CryptoBinary"/>
220 <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
222 <sequence minOccurs="0">
223 <element name="Seed" type="ds:CryptoBinary"/>
224 <element name="PgenCounter" type="ds:CryptoBinary"/>
230 // we extend appropriately for private component X
231 DSAParameters dsaParams = this.ExportParameters(includePrivateParameters);
232 StringBuilder sb = new StringBuilder();
233 sb.Append("<DSAKeyValue>");
235 sb.Append("<P>"+Convert.ToBase64String(dsaParams.P)+"</P>");
236 sb.Append("<Q>"+Convert.ToBase64String(dsaParams.Q)+"</Q>");
237 sb.Append("<G>"+Convert.ToBase64String(dsaParams.G)+"</G>");
238 sb.Append("<Y>"+Convert.ToBase64String(dsaParams.Y)+"</Y>");
239 // Add optional components if present
240 if (dsaParams.J != null) {
241 sb.Append("<J>"+Convert.ToBase64String(dsaParams.J)+"</J>");
243 if ((dsaParams.Seed != null)) { // note we assume counter is correct if Seed is present
244 sb.Append("<Seed>"+Convert.ToBase64String(dsaParams.Seed)+"</Seed>");
245 sb.Append("<PgenCounter>"+Convert.ToBase64String(Utils.ConvertIntToByteArray(dsaParams.Counter))+"</PgenCounter>");
248 if (includePrivateParameters) {
249 // Add the private component
250 sb.Append("<X>"+Convert.ToBase64String(dsaParams.X)+"</X>");
252 sb.Append("</DSAKeyValue>");
253 return(sb.ToString());
256 abstract public DSAParameters ExportParameters(bool includePrivateParameters);
258 abstract public void ImportParameters(DSAParameters parameters);
260 private static Exception DerivedClassMustOverride()
262 return new NotImplementedException(Environment.GetResourceString("NotSupported_SubclassOverride"));
265 internal static Exception HashAlgorithmNameNullOrEmpty()
267 return new ArgumentException(Environment.GetResourceString("Cryptography_HashAlgorithmNameNullOrEmpty"), "hashAlgorithm");