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