2 // CryptoConfig.cs: Handles cryptographic implementations and OIDs mappings.
5 // Sebastien Pouliot (sebastien@ximian.com)
6 // Tim Coleman (tim@timcoleman.com)
8 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) Tim Coleman, 2004
10 // (C) 2004 Novell (http://www.novell.com)
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System
.Collections
;
38 using System
.Globalization
;
40 using System
.Reflection
;
41 using System
.Runtime
.CompilerServices
;
46 namespace System
.Security
.Cryptography
{
48 public class CryptoConfig
{
50 static private object lockObject
;
51 static private Hashtable algorithms
;
52 static private Hashtable oid
;
54 private const string defaultNamespace
= "System.Security.Cryptography.";
55 private const string defaultSHA1
= defaultNamespace
+ "SHA1CryptoServiceProvider";
56 private const string defaultMD5
= defaultNamespace
+ "MD5CryptoServiceProvider";
57 private const string defaultSHA256
= defaultNamespace
+ "SHA256Managed";
58 private const string defaultSHA384
= defaultNamespace
+ "SHA384Managed";
59 private const string defaultSHA512
= defaultNamespace
+ "SHA512Managed";
60 private const string defaultRSA
= defaultNamespace
+ "RSACryptoServiceProvider";
61 private const string defaultDSA
= defaultNamespace
+ "DSACryptoServiceProvider";
62 private const string defaultDES
= defaultNamespace
+ "DESCryptoServiceProvider";
63 private const string default3DES
= defaultNamespace
+ "TripleDESCryptoServiceProvider";
64 private const string defaultRC2
= defaultNamespace
+ "RC2CryptoServiceProvider";
65 private const string defaultAES
= defaultNamespace
+ "RijndaelManaged";
66 // LAMESPEC: undocumented names in CryptoConfig
67 private const string defaultRNG
= defaultNamespace
+ "RNGCryptoServiceProvider";
68 private const string defaultHMAC
= defaultNamespace
+ "HMACSHA1";
69 private const string defaultMAC3DES
= defaultNamespace
+ "MACTripleDES";
70 // LAMESPEC: undocumented classes (also undocumented in CryptoConfig ;-)
71 private const string defaultDSASigDesc
= defaultNamespace
+ "DSASignatureDescription";
72 private const string defaultRSASigDesc
= defaultNamespace
+ "RSAPKCS1SHA1SignatureDescription";
74 private const string defaultRIPEMD160
= defaultNamespace
+ "RIPEMD160Managed";
77 // LAMESPEC: undocumented names in CryptoConfig
79 private const string xmlAssembly
= ", System.Security, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
81 private const string xmlAssembly
= ", System.Security, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
83 private const string xmlAssembly
= ", System.Security, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
85 private const string xmlAssembly
= ", System.Security, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
87 private const string defaultC14N
= defaultNamespace
+ "Xml.XmlDsigC14NTransform" + xmlAssembly
;
88 private const string defaultC14NWithComments
= defaultNamespace
+ "Xml.XmlDsigC14NWithCommentsTransform" + xmlAssembly
;
89 private const string defaultBase64
= defaultNamespace
+ "Xml.XmlDsigBase64Transform" + xmlAssembly
;
90 private const string defaultXPath
= defaultNamespace
+ "Xml.XmlDsigXPathTransform" + xmlAssembly
;
91 private const string defaultXslt
= defaultNamespace
+ "Xml.XmlDsigXsltTransform" + xmlAssembly
;
92 private const string defaultEnveloped
= defaultNamespace
+ "Xml.XmlDsigEnvelopedSignatureTransform" + xmlAssembly
;
94 private const string defaultXmlDecryption
= defaultNamespace
+ "Xml.XmlDecryptionTransform" + xmlAssembly
;
95 private const string defaultExcC14N
= defaultNamespace
+ "Xml.XmlDsigExcC14NTransform" + xmlAssembly
;
96 private const string defaultExcC14NWithComments
= defaultNamespace
+ "Xml.XmlDsigExcC14NWithCommentsTransform" + xmlAssembly
;
99 // LAMESPEC: only documentated in ".NET Framework Security" book
100 private const string defaultX509Data
= defaultNamespace
+ "Xml.KeyInfoX509Data" + xmlAssembly
;
101 private const string defaultKeyName
= defaultNamespace
+ "Xml.KeyInfoName" + xmlAssembly
;
102 private const string defaultKeyValueDSA
= defaultNamespace
+ "Xml.DSAKeyValue" + xmlAssembly
;
103 private const string defaultKeyValueRSA
= defaultNamespace
+ "Xml.RSAKeyValue" + xmlAssembly
;
104 private const string defaultRetrievalMethod
= defaultNamespace
+ "Xml.KeyInfoRetrievalMethod" + xmlAssembly
;
106 private const string managedSHA1
= defaultNamespace
+ "SHA1Managed";
108 // Oddly OID seems only available for hash algorithms
109 private const string oidSHA1
= "1.3.14.3.2.26";
110 private const string oidMD5
= "1.2.840.113549.2.5";
111 private const string oidSHA256
= "2.16.840.1.101.3.4.1";
112 private const string oidSHA384
= "2.16.840.1.101.3.4.2";
113 private const string oidSHA512
= "2.16.840.1.101.3.4.3";
114 // LAMESPEC: only documentated in ".NET Framework Security" book
115 private const string oid3DESKeyWrap
= "1.2.840.113549.1.9.16.3.6";
117 private const string nameSHA1a
= "SHA";
118 private const string nameSHA1b
= "SHA1";
119 private const string nameSHA1c
= "System.Security.Cryptography.SHA1";
120 private const string nameSHA1d
= "System.Security.Cryptography.HashAlgorithm";
121 private const string nameMD5a
= "MD5";
122 private const string nameMD5b
= "System.Security.Cryptography.MD5";
123 private const string nameSHA256a
= "SHA256";
124 private const string nameSHA256b
= "SHA-256";
125 private const string nameSHA256c
= "System.Security.Cryptography.SHA256";
126 private const string nameSHA384a
= "SHA384";
127 private const string nameSHA384b
= "SHA-384";
128 private const string nameSHA384c
= "System.Security.Cryptography.SHA384";
129 private const string nameSHA512a
= "SHA512";
130 private const string nameSHA512b
= "SHA-512";
131 private const string nameSHA512c
= "System.Security.Cryptography.SHA512";
132 private const string nameRSAa
= "RSA";
133 private const string nameRSAb
= "System.Security.Cryptography.RSA";
134 private const string nameRSAc
= "System.Security.Cryptography.AsymmetricAlgorithm";
135 private const string nameDSAa
= "DSA";
136 private const string nameDSAb
= "System.Security.Cryptography.DSA";
137 private const string nameDESa
= "DES";
138 private const string nameDESb
= "System.Security.Cryptography.DES";
139 private const string name3DESa
= "3DES";
140 private const string name3DESb
= "TripleDES";
141 private const string name3DESc
= "Triple DES";
142 private const string name3DESd
= "System.Security.Cryptography.TripleDES";
143 private const string nameRC2a
= "RC2";
144 private const string nameRC2b
= "System.Security.Cryptography.RC2";
145 private const string nameAESa
= "Rijndael";
146 private const string nameAESb
= "System.Security.Cryptography.Rijndael";
147 private const string nameAESc
= "System.Security.Cryptography.SymmetricAlgorithm";
148 // LAMESPEC: undocumented names in CryptoConfig
149 private const string nameRNGa
= "RandomNumberGenerator";
150 private const string nameRNGb
= "System.Security.Cryptography.RandomNumberGenerator";
151 private const string nameKeyHasha
= "System.Security.Cryptography.KeyedHashAlgorithm";
152 private const string nameHMACa
= "HMACSHA1";
153 private const string nameHMACb
= "System.Security.Cryptography.HMACSHA1";
154 private const string nameMAC3DESa
= "MACTripleDES";
155 private const string nameMAC3DESb
= "System.Security.Cryptography.MACTripleDES";
156 // LAMESPEC: only documentated in ".NET Framework Security" book
157 private const string name3DESKeyWrap
= "TripleDESKeyWrap";
159 private const string nameRIPEMD160a
= "RIPEMD160";
160 private const string nameRIPEMD160b
= "RIPEMD-160";
161 private const string nameRIPEMD160c
= "System.Security.Cryptography.RIPEMD160";
164 private const string urlXmlDsig
= "http://www.w3.org/2000/09/xmldsig#";
165 // LAMESPEC: undocumented URLs in CryptoConfig
166 private const string urlDSASHA1
= urlXmlDsig
+ "dsa-sha1"; // no space
167 private const string urlRSASHA1
= urlXmlDsig
+ "rsa-sha1"; // no space
168 private const string urlSHA1
= urlXmlDsig
+ "sha1"; // no space
169 private const string urlC14N
= "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
170 private const string urlC14NWithComments
= "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments";
171 private const string urlBase64
= "http://www.w3.org/2000/09/xmldsig#base64";
172 private const string urlXPath
= "http://www.w3.org/TR/1999/REC-xpath-19991116";
173 private const string urlXslt
= "http://www.w3.org/TR/1999/REC-xslt-19991116";
174 private const string urlEnveloped
= urlXmlDsig
+ "enveloped-signature"; // no space
176 private const string urlXmlDecryption
= "http://www.w3.org/2002/07/decrypt#XML";
177 private const string urlExcC14N
= "http://www.w3.org/2001/10/xml-exc-c14n#WithComments";
178 private const string urlExcC14NWithComments
= "http://www.w3.org/2001/10/xml-exc-c14n#";
181 // LAMESPEC: only documentated in ".NET Framework Security" book
182 private const string urlX509Data
= urlXmlDsig
+ " X509Data"; // space is required
183 private const string urlKeyName
= urlXmlDsig
+ " KeyName"; // space is required
184 private const string urlKeyValueDSA
= urlXmlDsig
+ " KeyValue/DSAKeyValue"; // space is required
185 private const string urlKeyValueRSA
= urlXmlDsig
+ " KeyValue/RSAKeyValue"; // space is required
186 private const string urlRetrievalMethod
= urlXmlDsig
+ " RetrievalMethod"; // space is required
188 static CryptoConfig ()
191 // http://msdn.microsoft.com/library/en-us/dnaskdr/html/askgui06032003.asp?frame=true
192 lockObject
= new object ();
195 private static void Initialize ()
197 algorithms
= new Hashtable ();
198 // see list @ http://msdn.microsoft.com/library/en-us/cpref/html/
199 // frlrfSystemSecurityCryptographyCryptoConfigClassTopic.asp
200 algorithms
.Add (nameSHA1a
, defaultSHA1
);
201 algorithms
.Add (nameSHA1b
, defaultSHA1
);
202 algorithms
.Add (nameSHA1c
, defaultSHA1
);
203 algorithms
.Add (nameSHA1d
, defaultSHA1
);
205 algorithms
.Add (nameMD5a
, defaultMD5
);
206 algorithms
.Add (nameMD5b
, defaultMD5
);
208 algorithms
.Add (nameSHA256a
, defaultSHA256
);
209 algorithms
.Add (nameSHA256b
, defaultSHA256
);
210 algorithms
.Add (nameSHA256c
, defaultSHA256
);
212 algorithms
.Add (nameSHA384a
, defaultSHA384
);
213 algorithms
.Add (nameSHA384b
, defaultSHA384
);
214 algorithms
.Add (nameSHA384c
, defaultSHA384
);
216 algorithms
.Add (nameSHA512a
, defaultSHA512
);
217 algorithms
.Add (nameSHA512b
, defaultSHA512
);
218 algorithms
.Add (nameSHA512c
, defaultSHA512
);
220 algorithms
.Add (nameRSAa
, defaultRSA
);
221 algorithms
.Add (nameRSAb
, defaultRSA
);
222 algorithms
.Add (nameRSAc
, defaultRSA
);
224 algorithms
.Add (nameDSAa
, defaultDSA
);
225 algorithms
.Add (nameDSAb
, defaultDSA
);
227 algorithms
.Add (nameDESa
, defaultDES
);
228 algorithms
.Add (nameDESb
, defaultDES
);
230 algorithms
.Add (name3DESa
, default3DES
);
231 algorithms
.Add (name3DESb
, default3DES
);
232 algorithms
.Add (name3DESc
, default3DES
);
233 algorithms
.Add (name3DESd
, default3DES
);
235 algorithms
.Add (nameRC2a
, defaultRC2
);
236 algorithms
.Add (nameRC2b
, defaultRC2
);
238 algorithms
.Add (nameAESa
, defaultAES
);
239 algorithms
.Add (nameAESb
, defaultAES
);
240 // LAMESPEC SymmetricAlgorithm documented as TripleDESCryptoServiceProvider
241 algorithms
.Add (nameAESc
, defaultAES
);
243 // LAMESPEC These names aren't documented but (hint) the classes also have
244 // static Create methods. So logically they should (and are) here.
245 algorithms
.Add (nameRNGa
, defaultRNG
);
246 algorithms
.Add (nameRNGb
, defaultRNG
);
247 algorithms
.Add (nameKeyHasha
, defaultHMAC
);
248 algorithms
.Add (nameHMACa
, defaultHMAC
);
249 algorithms
.Add (nameHMACb
, defaultHMAC
);
250 algorithms
.Add (nameMAC3DESa
, defaultMAC3DES
);
251 algorithms
.Add (nameMAC3DESb
, defaultMAC3DES
);
253 algorithms
.Add (nameRIPEMD160a
, defaultRIPEMD160
);
254 algorithms
.Add (nameRIPEMD160b
, defaultRIPEMD160
);
255 algorithms
.Add (nameRIPEMD160c
, defaultRIPEMD160
);
258 // LAMESPEC These URLs aren't documented but (hint) installing the WSDK
259 // add some of the XMLDSIG urls into machine.config (and they make a LOT
260 // of sense for implementing XMLDSIG in System.Security.Cryptography.Xml)
261 algorithms
.Add (urlDSASHA1
, defaultDSASigDesc
);
262 algorithms
.Add (urlRSASHA1
, defaultRSASigDesc
);
263 algorithms
.Add (urlSHA1
, defaultSHA1
);
264 algorithms
.Add (urlC14N
, defaultC14N
);
265 algorithms
.Add (urlC14NWithComments
, defaultC14NWithComments
);
266 algorithms
.Add (urlBase64
, defaultBase64
);
267 algorithms
.Add (urlXPath
, defaultXPath
);
268 algorithms
.Add (urlXslt
, defaultXslt
);
269 algorithms
.Add (urlEnveloped
, defaultEnveloped
);
271 algorithms
.Add (urlExcC14N
, defaultExcC14N
);
272 algorithms
.Add (urlExcC14NWithComments
, defaultExcC14NWithComments
);
273 algorithms
.Add (urlXmlDecryption
, defaultXmlDecryption
);
275 // LAMESPEC: only documentated in ".NET Framework Security" book
276 algorithms
.Add (urlX509Data
, defaultX509Data
);
277 algorithms
.Add (urlKeyName
, defaultKeyName
);
278 algorithms
.Add (urlKeyValueDSA
, defaultKeyValueDSA
);
279 algorithms
.Add (urlKeyValueRSA
, defaultKeyValueRSA
);
280 algorithms
.Add (urlRetrievalMethod
, defaultRetrievalMethod
);
282 oid
= new Hashtable ();
283 // comments here are to match with MS implementation (but not with doc)
284 // LAMESPEC: only HashAlgorithm seems to have their OID included
285 oid
.Add (defaultSHA1
, oidSHA1
);
286 oid
.Add (managedSHA1
, oidSHA1
);
287 oid
.Add (nameSHA1b
, oidSHA1
);
288 oid
.Add (nameSHA1c
, oidSHA1
);
290 oid
.Add (defaultMD5
, oidMD5
);
291 oid
.Add (nameMD5a
, oidMD5
);
292 oid
.Add (nameMD5b
, oidMD5
);
294 oid
.Add (defaultSHA256
, oidSHA256
);
295 oid
.Add (nameSHA256a
, oidSHA256
);
296 oid
.Add (nameSHA256c
, oidSHA256
);
298 oid
.Add (defaultSHA384
, oidSHA384
);
299 oid
.Add (nameSHA384a
, oidSHA384
);
300 oid
.Add (nameSHA384c
, oidSHA384
);
302 oid
.Add (defaultSHA512
, oidSHA512
);
303 oid
.Add (nameSHA512a
, oidSHA512
);
304 oid
.Add (nameSHA512c
, oidSHA512
);
306 // surprise! documented in ".NET Framework Security" book
307 oid
.Add (name3DESKeyWrap
, oid3DESKeyWrap
);
309 // Add/modify the config as specified by machine.config
310 string config
= Environment
.GetMachineConfigPath ();
314 private static void LoadConfig (string filename
)
316 if (!File
.Exists (filename
))
319 SecurityParser sp
= new SecurityParser ();
320 StreamReader sr
= new StreamReader (filename
);
322 sp
.LoadXml (sr
.ReadToEnd ());
329 SecurityElement root
= sp
.ToXml ();
330 SecurityElement mscorlib
= root
.SearchForChildByTag ("mscorlib");
331 if (mscorlib
== null)
333 SecurityElement cryptographySettings
= mscorlib
.SearchForChildByTag ("cryptographySettings");
334 if (cryptographySettings
== null)
338 SecurityElement cryptoNameMapping
= cryptographySettings
.SearchForChildByTag ("cryptoNameMapping");
339 if (cryptoNameMapping
!= null) {
340 SecurityElement cryptoClasses
= cryptoNameMapping
.SearchForChildByTag ("cryptoClasses");
341 if (cryptoClasses
!= null) {
342 foreach (SecurityElement nameEntry
in cryptoNameMapping
.Children
) {
343 if (nameEntry
.Tag
== "nameEntry") {
344 string name
= (string) nameEntry
.Attributes
["name"];
345 string clas
= (string) nameEntry
.Attributes
["class"];
346 foreach (SecurityElement cryptoClass
in cryptoClasses
.Children
) {
347 string fullname
= (string) cryptoClass
.Attributes
[clas
];
348 if (fullname
!= null) {
349 if (algorithms
.ContainsKey (name
))
350 algorithms
.Remove (name
);
351 algorithms
.Add (name
, fullname
);
361 SecurityElement oidMap
= cryptographySettings
.SearchForChildByTag ("oidMap");
364 foreach (SecurityElement oidEntry
in oidMap
.Children
) {
365 if (oidEntry
.Tag
== "oidEntry") {
366 string oids
= (string) oidEntry
.Attributes
["OID"];
367 if (oid
.ContainsKey (oids
))
369 oid
.Add (oids
, oidEntry
.Attributes
["name"]);
374 // there's no error/warning in case the machine.config contains bad entries
378 public static object CreateFromName (string name
)
380 return CreateFromName (name
, null);
383 public static object CreateFromName (string name
, object[] args
)
386 throw new ArgumentNullException ("name");
388 if (algorithms
== null) {
395 Type algoClass
= null;
396 string algo
= (string) algorithms
[name
];
397 // do we have an entry
400 algoClass
= Type
.GetType (algo
);
401 // call the constructor for the type
402 return Activator
.CreateInstance (algoClass
, args
);
405 // method doesn't throw any exception
410 // encode (7bits array) number greater than 127
411 private static byte[] EncodeLongNumber (long x
)
413 // for MS BCL compatibility
414 // comment next two lines to remove restriction
415 if ((x
> Int32
.MaxValue
) || (x
< Int32
.MinValue
))
416 throw new OverflowException (Locale
.GetText ("Part of OID doesn't fit in Int32"));
419 // number of bytes required to encode this number
425 byte[] num
= new byte [n
];
427 for (int i
= 0; i
< n
; i
++) {
432 num
[n
-i
-1] = Convert
.ToByte (y
);
437 public static byte[] EncodeOID (string str
)
439 char[] delim
= { '.' }
;
440 string[] parts
= str
.Split (delim
);
441 // according to X.208 n is always at least 2
442 if (parts
.Length
< 2) {
443 throw new CryptographicUnexpectedOperationException (
444 Locale
.GetText ("OID must have at least two parts"));
447 // we're sure that the encoded OID is shorter than its string representation
448 byte[] oid
= new byte [str
.Length
];
449 // now encoding value
451 byte part0
= Convert
.ToByte (parts
[0]);
452 // OID[0] > 2 is invalid but "supported" in MS BCL
453 // uncomment next line to trap this error
454 // if (part0 > 2) throw new CryptographicUnexpectedOperationException ();
455 byte part1
= Convert
.ToByte (parts
[1]);
456 // OID[1] >= 40 is illegal for OID[0] < 2 because of the % 40
457 // however the syntax is "supported" in MS BCL
458 // uncomment next 2 lines to trap this error
459 //if ((part0 < 2) && (part1 >= 40))
460 // throw new CryptographicUnexpectedOperationException ();
461 oid
[2] = Convert
.ToByte (part0
* 40 + part1
);
464 throw new CryptographicUnexpectedOperationException (
465 Locale
.GetText ("Invalid OID"));
468 for (int i
= 2; i
< parts
.Length
; i
++) {
469 long x
= Convert
.ToInt64 (parts
[i
]);
471 byte[] num
= EncodeLongNumber (x
);
472 Buffer
.BlockCopy (num
, 0, oid
, j
, num
.Length
);
476 oid
[j
++] = Convert
.ToByte (x
);
480 // copy the exact number of byte required
481 byte[] oid2
= new byte [j
];
482 oid2
[0] = 0x06; // always - this tag means OID
485 // for compatibility with MS BCL
486 throw new CryptographicUnexpectedOperationException (
487 Locale
.GetText ("OID > 127 bytes"));
488 // comment exception and uncomment next 3 lines to remove restriction
489 //byte[] num = EncodeLongNumber (j);
490 //Buffer.BlockCopy (num, 0, oid, j, num.Length);
491 //k = num.Length + 1;
494 oid2
[1] = Convert
.ToByte (j
- 2);
496 Buffer
.BlockCopy (oid
, k
, oid2
, k
, j
- k
);
500 public static string MapNameToOID (string name
)
503 throw new ArgumentNullException ("name");
511 return (string)oid
[name
];