[coop] Temporarily restore MonoThreadInfo when TLS destructor runs. Fixes #43099
[mono.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / dsa.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>[....]</OWNER>
7 // 
8
9 //
10 // DSA.cs
11 //
12
13 namespace System.Security.Cryptography {
14     using System.Text;
15     using System.Runtime.Serialization;
16     using System.Security.Util;
17     using System.Globalization;
18     using System.Diagnostics.Contracts;
19
20     // DSAParameters is serializable so that one could pass the public parameters
21     // across a remote call, but we explicitly make the private key X non-serializable
22     // so you cannot accidently send it along with the public parameters.
23     [Serializable]
24 [System.Runtime.InteropServices.ComVisible(true)]
25     public struct DSAParameters {
26         public byte[]      P;
27         public byte[]      Q;
28         public byte[]      G;
29         public byte[]      Y;
30         public byte[]      J;
31         [NonSerialized] public byte[]      X;
32         public byte[]      Seed;
33         public int         Counter;
34     }
35
36 [System.Runtime.InteropServices.ComVisible(true)]
37     public abstract class DSA : AsymmetricAlgorithm
38     {
39         //
40         //  Extending this class allows us to know that you are really implementing
41         //  an DSA key.  This is required for anybody providing a new DSA key value
42         //  implemention.
43         //
44         //  The class provides no methods, fields or anything else.  Its only purpose is
45         //  as a heirarchy member for identification of the algorithm.
46         //
47
48         protected DSA() { }
49
50         //
51         // public methods
52         //
53
54         new static public DSA Create() {
55 #if FULL_AOT_RUNTIME
56             return new System.Security.Cryptography.DSACryptoServiceProvider ();
57 #else
58             return Create("System.Security.Cryptography.DSA");
59 #endif
60         }
61
62         new static public DSA Create(String algName) {
63             return (DSA) CryptoConfig.CreateFromName(algName);
64         }
65
66         abstract public byte[] CreateSignature(byte[] rgbHash);
67
68         abstract public bool VerifySignature(byte[] rgbHash, byte[] rgbSignature); 
69
70         // We can provide a default implementation of FromXmlString because we require 
71         // every DSA implementation to implement ImportParameters
72         // All we have to do here is parse the XML.
73
74         public override void FromXmlString(String xmlString) {
75             if (xmlString == null) throw new ArgumentNullException("xmlString");
76             Contract.EndContractBlock();
77             DSAParameters dsaParams = new DSAParameters();
78             Parser p = new Parser(xmlString);
79             SecurityElement topElement = p.GetTopElement();
80
81             // P is always present
82             String pString = topElement.SearchForTextOfLocalName("P");
83             if (pString == null) {
84                 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","P"));
85             }
86             dsaParams.P = Convert.FromBase64String(Utils.DiscardWhiteSpaces(pString));
87
88             // Q is always present
89             String qString = topElement.SearchForTextOfLocalName("Q");
90             if (qString == null) {
91                 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","Q"));
92             }
93             dsaParams.Q = Convert.FromBase64String(Utils.DiscardWhiteSpaces(qString));
94
95             // G is always present
96             String gString = topElement.SearchForTextOfLocalName("G");
97             if (gString == null) {
98                 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","G"));
99             }
100             dsaParams.G = Convert.FromBase64String(Utils.DiscardWhiteSpaces(gString));
101
102             // Y is always present
103             String yString = topElement.SearchForTextOfLocalName("Y");
104             if (yString == null) {
105                 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","Y"));
106             }
107             dsaParams.Y = Convert.FromBase64String(Utils.DiscardWhiteSpaces(yString));
108
109             // J is optional
110             String jString = topElement.SearchForTextOfLocalName("J");
111             if (jString != null) dsaParams.J = Convert.FromBase64String(Utils.DiscardWhiteSpaces(jString));
112
113             // X is optional -- private key if present
114             String xString = topElement.SearchForTextOfLocalName("X");
115             if (xString != null) dsaParams.X = Convert.FromBase64String(Utils.DiscardWhiteSpaces(xString));
116
117             // Seed and PgenCounter are optional as a unit -- both present or both absent
118             String seedString = topElement.SearchForTextOfLocalName("Seed");
119             String pgenCounterString = topElement.SearchForTextOfLocalName("PgenCounter");
120             if ((seedString != null) && (pgenCounterString != null)) {
121                 dsaParams.Seed = Convert.FromBase64String(Utils.DiscardWhiteSpaces(seedString));
122                 dsaParams.Counter = Utils.ConvertByteArrayToInt(Convert.FromBase64String(Utils.DiscardWhiteSpaces(pgenCounterString)));
123             } else if ((seedString != null) || (pgenCounterString != null)) {
124                 if (seedString == null) {
125                     throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","Seed"));
126                 } else {
127                     throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidFromXmlString","DSA","PgenCounter"));
128                 }
129             }
130
131             ImportParameters(dsaParams);
132         }
133
134         // We can provide a default implementation of ToXmlString because we require 
135         // every DSA implementation to implement ImportParameters
136         // If includePrivateParameters is false, this is just an XMLDSIG DSAKeyValue
137         // clause.  If includePrivateParameters is true, then we extend DSAKeyValue with 
138         // the other (private) elements.
139
140         public override String ToXmlString(bool includePrivateParameters) {
141             // From the XMLDSIG spec, RFC 3075, Section 6.4.1, a DSAKeyValue looks like this:
142             /* 
143                <element name="DSAKeyValue"> 
144                  <complexType> 
145                    <sequence>
146                      <sequence>
147                        <element name="P" type="ds:CryptoBinary"/> 
148                        <element name="Q" type="ds:CryptoBinary"/> 
149                        <element name="G" type="ds:CryptoBinary"/> 
150                        <element name="Y" type="ds:CryptoBinary"/> 
151                        <element name="J" type="ds:CryptoBinary" minOccurs="0"/> 
152                      </sequence>
153                      <sequence minOccurs="0">
154                        <element name="Seed" type="ds:CryptoBinary"/> 
155                        <element name="PgenCounter" type="ds:CryptoBinary"/> 
156                      </sequence>
157                    </sequence>
158                  </complexType>
159                </element>
160             */
161             // we extend appropriately for private component X
162             DSAParameters dsaParams = this.ExportParameters(includePrivateParameters);
163             StringBuilder sb = new StringBuilder();
164             sb.Append("<DSAKeyValue>");
165             // Add P, Q, G and Y
166             sb.Append("<P>"+Convert.ToBase64String(dsaParams.P)+"</P>");
167             sb.Append("<Q>"+Convert.ToBase64String(dsaParams.Q)+"</Q>");
168             sb.Append("<G>"+Convert.ToBase64String(dsaParams.G)+"</G>");
169             sb.Append("<Y>"+Convert.ToBase64String(dsaParams.Y)+"</Y>");
170             // Add optional components if present
171             if (dsaParams.J != null) {
172                 sb.Append("<J>"+Convert.ToBase64String(dsaParams.J)+"</J>");
173             }
174             if ((dsaParams.Seed != null)) {  // note we assume counter is correct if Seed is present
175                 sb.Append("<Seed>"+Convert.ToBase64String(dsaParams.Seed)+"</Seed>");
176                 sb.Append("<PgenCounter>"+Convert.ToBase64String(Utils.ConvertIntToByteArray(dsaParams.Counter))+"</PgenCounter>");
177             }
178
179             if (includePrivateParameters) {
180                 // Add the private component
181                 sb.Append("<X>"+Convert.ToBase64String(dsaParams.X)+"</X>");
182             } 
183             sb.Append("</DSAKeyValue>");
184             return(sb.ToString());
185         }
186
187         abstract public DSAParameters ExportParameters(bool includePrivateParameters);
188
189         abstract public void ImportParameters(DSAParameters parameters);
190     }
191 }