2005-04-25 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System.Security.Cryptography / CryptoConfig.cs
1 //
2 // CryptoConfig.cs: Handles cryptographic implementations and OIDs mappings.
3 //
4 // Author:
5 //      Sebastien Pouliot (sebastien@ximian.com)
6 //      Tim Coleman (tim@timcoleman.com)
7 //
8 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) Tim Coleman, 2004
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Collections;
33 using System.Globalization;
34 using System.IO;
35 using System.Reflection;
36 using System.Runtime.CompilerServices;
37 using System.Security.Permissions;
38 using System.Text;
39
40 using Mono.Xml;
41
42 namespace System.Security.Cryptography {
43
44 public class CryptoConfig {
45
46         static private object lockObject;
47         static private Hashtable algorithms;
48         static private Hashtable oid;
49
50         private const string defaultNamespace = "System.Security.Cryptography.";
51         private const string defaultSHA1 = defaultNamespace + "SHA1CryptoServiceProvider";
52         private const string defaultMD5 = defaultNamespace + "MD5CryptoServiceProvider";
53         private const string defaultSHA256 = defaultNamespace + "SHA256Managed";
54         private const string defaultSHA384 = defaultNamespace + "SHA384Managed";
55         private const string defaultSHA512 = defaultNamespace + "SHA512Managed";
56         private const string defaultRSA = defaultNamespace + "RSACryptoServiceProvider";
57         private const string defaultDSA = defaultNamespace + "DSACryptoServiceProvider";
58         private const string defaultDES = defaultNamespace + "DESCryptoServiceProvider";
59         private const string default3DES = defaultNamespace + "TripleDESCryptoServiceProvider";
60         private const string defaultRC2 = defaultNamespace + "RC2CryptoServiceProvider";
61         private const string defaultAES = defaultNamespace + "RijndaelManaged";
62         // LAMESPEC: undocumented names in CryptoConfig
63         private const string defaultRNG = defaultNamespace + "RNGCryptoServiceProvider";
64         private const string defaultHMAC = defaultNamespace + "HMACSHA1";
65         private const string defaultMAC3DES = defaultNamespace + "MACTripleDES";
66         // LAMESPEC: undocumented classes (also undocumented in CryptoConfig ;-)
67         private const string defaultDSASigDesc = defaultNamespace + "DSASignatureDescription";
68         private const string defaultRSASigDesc = defaultNamespace + "RSAPKCS1SHA1SignatureDescription";
69 #if NET_2_0
70         private const string defaultRIPEMD160 = defaultNamespace + "RIPEMD160Managed";
71         private const string defaultHMACMD5 = defaultNamespace + "HMACMD5";
72         private const string defaultHMACRIPEMD160 = defaultNamespace + "HMACRIPEMD160";
73         private const string defaultHMACSHA256 = defaultNamespace + "HMACSHA256";
74         private const string defaultHMACSHA384 = defaultNamespace + "HMACSHA384";
75         private const string defaultHMACSHA512 = defaultNamespace + "HMACSHA512";
76 #endif
77
78         // LAMESPEC: undocumented names in CryptoConfig
79 #if (NET_2_0)
80         private const string xmlAssembly = ", System.Security, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
81 #elif (NET_1_1)
82         private const string xmlAssembly = ", System.Security, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
83 #elif (NET_1_0)
84         private const string xmlAssembly = ", System.Security, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
85 #else
86         private const string xmlAssembly = ", System.Security, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
87 #endif
88         private const string defaultC14N = defaultNamespace + "Xml.XmlDsigC14NTransform" + xmlAssembly;
89         private const string defaultC14NWithComments = defaultNamespace + "Xml.XmlDsigC14NWithCommentsTransform" + xmlAssembly;
90         private const string defaultBase64 = defaultNamespace + "Xml.XmlDsigBase64Transform" + xmlAssembly;
91         private const string defaultXPath = defaultNamespace + "Xml.XmlDsigXPathTransform" + xmlAssembly;
92         private const string defaultXslt = defaultNamespace + "Xml.XmlDsigXsltTransform" + xmlAssembly;
93         private const string defaultEnveloped = defaultNamespace + "Xml.XmlDsigEnvelopedSignatureTransform" + xmlAssembly;
94 #if NET_2_0
95         private const string defaultXmlDecryption = defaultNamespace + "Xml.XmlDecryptionTransform" + xmlAssembly;
96         private const string defaultExcC14N = defaultNamespace + "Xml.XmlDsigExcC14NTransform" + xmlAssembly;
97         private const string defaultExcC14NWithComments = defaultNamespace + "Xml.XmlDsigExcC14NWithCommentsTransform" + xmlAssembly;
98 #endif
99
100         // LAMESPEC: only documentated in ".NET Framework Security" book
101         private const string defaultX509Data = defaultNamespace + "Xml.KeyInfoX509Data" + xmlAssembly;
102         private const string defaultKeyName = defaultNamespace + "Xml.KeyInfoName" + xmlAssembly;
103         private const string defaultKeyValueDSA = defaultNamespace + "Xml.DSAKeyValue" + xmlAssembly;
104         private const string defaultKeyValueRSA = defaultNamespace + "Xml.RSAKeyValue" + xmlAssembly;
105         private const string defaultRetrievalMethod = defaultNamespace + "Xml.KeyInfoRetrievalMethod" + xmlAssembly;
106
107         private const string managedSHA1 = defaultNamespace + "SHA1Managed";
108
109         // Oddly OID seems only available for hash algorithms
110         private const string oidSHA1 = "1.3.14.3.2.26";
111         private const string oidMD5 = "1.2.840.113549.2.5";
112 #if NET_2_0
113         // changed in 2.0
114         private const string oidSHA256 = "2.16.840.1.101.3.4.2.1";
115         private const string oidSHA384 = "2.16.840.1.101.3.4.2.2";
116         private const string oidSHA512 = "2.16.840.1.101.3.4.2.3";
117         // new in 2.0
118 //      private const string oidRSA = "1.2.840.113549.1.1.1";
119         private const string oidDSA = "1.2.840.10040.4.1";
120         private const string oidDES = "1.3.14.3.2.7";
121         private const string oid3DES = "1.2.840.113549.3.7";
122         private const string oidRC2 = "1.2.840.113549.3.2";
123 #else
124         private const string oidSHA256 = "2.16.840.1.101.3.4.1";
125         private const string oidSHA384 = "2.16.840.1.101.3.4.2";
126         private const string oidSHA512 = "2.16.840.1.101.3.4.3";
127 #endif
128         // LAMESPEC: only documentated in ".NET Framework Security" book
129         private const string oid3DESKeyWrap = "1.2.840.113549.1.9.16.3.6";
130
131         private const string nameSHA1a = "SHA";
132         private const string nameSHA1b = "SHA1";
133         private const string nameSHA1c = "System.Security.Cryptography.SHA1";
134         private const string nameSHA1d = "System.Security.Cryptography.HashAlgorithm";
135         private const string nameMD5a = "MD5";
136         private const string nameMD5b = "System.Security.Cryptography.MD5";
137         private const string nameSHA256a = "SHA256";
138         private const string nameSHA256b = "SHA-256";
139         private const string nameSHA256c = "System.Security.Cryptography.SHA256";
140         private const string nameSHA384a = "SHA384";
141         private const string nameSHA384b = "SHA-384";
142         private const string nameSHA384c = "System.Security.Cryptography.SHA384";
143         private const string nameSHA512a = "SHA512";
144         private const string nameSHA512b = "SHA-512";
145         private const string nameSHA512c = "System.Security.Cryptography.SHA512";
146         private const string nameRSAa = "RSA";
147         private const string nameRSAb = "System.Security.Cryptography.RSA";
148         private const string nameRSAc = "System.Security.Cryptography.AsymmetricAlgorithm";
149         private const string nameDSAa = "DSA";
150         private const string nameDSAb = "System.Security.Cryptography.DSA";
151         private const string nameDESa = "DES";
152         private const string nameDESb = "System.Security.Cryptography.DES";
153         private const string name3DESa = "3DES";
154         private const string name3DESb = "TripleDES";
155         private const string name3DESc = "Triple DES";
156         private const string name3DESd = "System.Security.Cryptography.TripleDES";
157         private const string nameRC2a = "RC2";
158         private const string nameRC2b = "System.Security.Cryptography.RC2";
159         private const string nameAESa = "Rijndael";
160         private const string nameAESb = "System.Security.Cryptography.Rijndael";
161         private const string nameAESc = "System.Security.Cryptography.SymmetricAlgorithm";
162         // LAMESPEC: undocumented names in CryptoConfig
163         private const string nameRNGa = "RandomNumberGenerator";
164         private const string nameRNGb = "System.Security.Cryptography.RandomNumberGenerator";
165         private const string nameKeyHasha = "System.Security.Cryptography.KeyedHashAlgorithm";
166         private const string nameHMACSHA1a = "HMACSHA1";
167         private const string nameHMACSHA1b = "System.Security.Cryptography.HMACSHA1";
168         private const string nameMAC3DESa = "MACTripleDES";
169         private const string nameMAC3DESb = "System.Security.Cryptography.MACTripleDES";
170         // LAMESPEC: only documentated in ".NET Framework Security" book
171         private const string name3DESKeyWrap = "TripleDESKeyWrap";
172 #if NET_2_0
173         private const string nameRIPEMD160a = "RIPEMD160";
174         private const string nameRIPEMD160b = "RIPEMD-160";
175         private const string nameRIPEMD160c = "System.Security.Cryptography.RIPEMD160";
176         private const string nameHMACa = "HMAC";
177         private const string nameHMACb = "System.Security.Cryptography.HMAC";
178         private const string nameHMACMD5a = "HMACMD5";
179         private const string nameHMACMD5b = "System.Security.Cryptography.HMACMD5";
180         private const string nameHMACRIPEMD160a = "HMACRIPEMD160";
181         private const string nameHMACRIPEMD160b = "System.Security.Cryptography.HMACRIPEMD160";
182         private const string nameHMACSHA256a = "HMACSHA256";
183         private const string nameHMACSHA256b = "System.Security.Cryptography.HMACSHA256";
184         private const string nameHMACSHA384a = "HMACSHA384";
185         private const string nameHMACSHA384b = "System.Security.Cryptography.HMACSHA384";
186         private const string nameHMACSHA512a = "HMACSHA512";
187         private const string nameHMACSHA512b = "System.Security.Cryptography.HMACSHA512";
188 #endif
189
190         private const string urlXmlDsig = "http://www.w3.org/2000/09/xmldsig#";
191         // LAMESPEC: undocumented URLs in CryptoConfig
192         private const string urlDSASHA1 = urlXmlDsig + "dsa-sha1";                      // no space
193         private const string urlRSASHA1 = urlXmlDsig + "rsa-sha1";                      // no space
194         private const string urlSHA1 = urlXmlDsig + "sha1";                             // no space
195         private const string urlC14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; 
196         private const string urlC14NWithComments = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments";
197         private const string urlBase64 = "http://www.w3.org/2000/09/xmldsig#base64";
198         private const string urlXPath = "http://www.w3.org/TR/1999/REC-xpath-19991116";
199         private const string urlXslt = "http://www.w3.org/TR/1999/REC-xslt-19991116";
200         private const string urlEnveloped = urlXmlDsig + "enveloped-signature";         // no space
201 #if NET_2_0
202         private const string urlXmlDecryption = "http://www.w3.org/2002/07/decrypt#XML";
203         private const string urlExcC14N = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments";
204         private const string urlExcC14NWithComments = "http://www.w3.org/2001/10/xml-exc-c14n#";
205 #endif
206
207         // LAMESPEC: only documentated in ".NET Framework Security" book
208         private const string urlX509Data = urlXmlDsig + " X509Data";                    // space is required
209         private const string urlKeyName = urlXmlDsig + " KeyName";                      // space is required
210         private const string urlKeyValueDSA = urlXmlDsig + " KeyValue/DSAKeyValue";     // space is required
211         private const string urlKeyValueRSA = urlXmlDsig + " KeyValue/RSAKeyValue";     // space is required
212         private const string urlRetrievalMethod = urlXmlDsig + " RetrievalMethod";      // space is required
213
214         static CryptoConfig () 
215         {
216                 // lock(this) is bad
217                 // http://msdn.microsoft.com/library/en-us/dnaskdr/html/askgui06032003.asp?frame=true
218                 lockObject = new object ();
219         }
220
221         private static void Initialize () 
222         {
223                 algorithms = new Hashtable ();
224                 // see list @ http://msdn.microsoft.com/library/en-us/cpref/html/
225                 // frlrfSystemSecurityCryptographyCryptoConfigClassTopic.asp
226                 algorithms.Add (nameSHA1a, defaultSHA1);
227                 algorithms.Add (nameSHA1b, defaultSHA1);
228                 algorithms.Add (nameSHA1c, defaultSHA1);
229                 algorithms.Add (nameSHA1d, defaultSHA1);
230
231                 algorithms.Add (nameMD5a, defaultMD5);
232                 algorithms.Add (nameMD5b, defaultMD5);
233
234                 algorithms.Add (nameSHA256a, defaultSHA256);
235                 algorithms.Add (nameSHA256b, defaultSHA256);
236                 algorithms.Add (nameSHA256c, defaultSHA256);
237
238                 algorithms.Add (nameSHA384a, defaultSHA384);
239                 algorithms.Add (nameSHA384b, defaultSHA384);
240                 algorithms.Add (nameSHA384c, defaultSHA384);
241
242                 algorithms.Add (nameSHA512a, defaultSHA512);
243                 algorithms.Add (nameSHA512b, defaultSHA512);
244                 algorithms.Add (nameSHA512c, defaultSHA512);
245
246                 algorithms.Add (nameRSAa, defaultRSA);
247                 algorithms.Add (nameRSAb, defaultRSA); 
248                 algorithms.Add (nameRSAc, defaultRSA);
249
250                 algorithms.Add (nameDSAa, defaultDSA);  
251                 algorithms.Add (nameDSAb, defaultDSA);  
252
253                 algorithms.Add (nameDESa, defaultDES);
254                 algorithms.Add (nameDESb, defaultDES);
255
256                 algorithms.Add (name3DESa, default3DES);
257                 algorithms.Add (name3DESb, default3DES);
258                 algorithms.Add (name3DESc, default3DES);
259                 algorithms.Add (name3DESd, default3DES);
260
261                 algorithms.Add (nameRC2a, defaultRC2);
262                 algorithms.Add (nameRC2b, defaultRC2);
263
264                 algorithms.Add (nameAESa, defaultAES);  
265                 algorithms.Add (nameAESb, defaultAES);
266                 // LAMESPEC SymmetricAlgorithm documented as TripleDESCryptoServiceProvider
267                 algorithms.Add (nameAESc, defaultAES);
268
269                 // LAMESPEC These names aren't documented but (hint) the classes also have
270                 // static Create methods. So logically they should (and are) here.
271                 algorithms.Add (nameRNGa, defaultRNG);
272                 algorithms.Add (nameRNGb, defaultRNG);
273                 algorithms.Add (nameKeyHasha, defaultHMAC);
274                 algorithms.Add (nameHMACSHA1a, defaultHMAC);
275                 algorithms.Add (nameHMACSHA1b, defaultHMAC);
276                 algorithms.Add (nameMAC3DESa, defaultMAC3DES);
277                 algorithms.Add (nameMAC3DESb, defaultMAC3DES);
278 #if NET_2_0
279                 algorithms.Add (nameRIPEMD160a, defaultRIPEMD160);
280                 algorithms.Add (nameRIPEMD160b, defaultRIPEMD160);
281                 algorithms.Add (nameRIPEMD160c, defaultRIPEMD160);
282                 algorithms.Add (nameHMACb, defaultHMAC);
283                 algorithms.Add (nameHMACMD5a, defaultHMACMD5);
284                 algorithms.Add (nameHMACMD5b, defaultHMACMD5);
285                 algorithms.Add (nameHMACRIPEMD160a, defaultHMACRIPEMD160);
286                 algorithms.Add (nameHMACRIPEMD160b, defaultHMACRIPEMD160);
287                 algorithms.Add (nameHMACSHA256a, defaultHMACSHA256);
288                 algorithms.Add (nameHMACSHA256b, defaultHMACSHA256);
289                 algorithms.Add (nameHMACSHA384a, defaultHMACSHA384);
290                 algorithms.Add (nameHMACSHA384b, defaultHMACSHA384);
291                 algorithms.Add (nameHMACSHA512a, defaultHMACSHA512);
292                 algorithms.Add (nameHMACSHA512b, defaultHMACSHA512);
293 #endif
294
295                 // LAMESPEC These URLs aren't documented but (hint) installing the WSDK
296                 // add some of the XMLDSIG urls into machine.config (and they make a LOT
297                 // of sense for implementing XMLDSIG in System.Security.Cryptography.Xml)
298                 algorithms.Add (urlDSASHA1, defaultDSASigDesc); 
299                 algorithms.Add (urlRSASHA1, defaultRSASigDesc);
300                 algorithms.Add (urlSHA1, defaultSHA1);
301                 algorithms.Add (urlC14N, defaultC14N);
302                 algorithms.Add (urlC14NWithComments, defaultC14NWithComments);
303                 algorithms.Add (urlBase64, defaultBase64);
304                 algorithms.Add (urlXPath, defaultXPath);
305                 algorithms.Add (urlXslt, defaultXslt);
306                 algorithms.Add (urlEnveloped, defaultEnveloped);
307 #if NET_2_0
308                 algorithms.Add (urlExcC14N, defaultExcC14N);
309                 algorithms.Add (urlExcC14NWithComments, defaultExcC14NWithComments);
310                 algorithms.Add (urlXmlDecryption, defaultXmlDecryption);
311 #endif
312                 // LAMESPEC: only documentated in ".NET Framework Security" book
313                 algorithms.Add (urlX509Data, defaultX509Data);
314                 algorithms.Add (urlKeyName, defaultKeyName);
315                 algorithms.Add (urlKeyValueDSA, defaultKeyValueDSA);
316                 algorithms.Add (urlKeyValueRSA, defaultKeyValueRSA);
317                 algorithms.Add (urlRetrievalMethod, defaultRetrievalMethod);
318
319                 oid = new Hashtable ();
320                 // comments here are to match with MS implementation (but not with doc)
321                 // LAMESPEC: only HashAlgorithm seems to have their OID included
322                 oid.Add (defaultSHA1, oidSHA1);
323                 oid.Add (managedSHA1, oidSHA1);
324                 oid.Add (nameSHA1b, oidSHA1);
325                 oid.Add (nameSHA1c, oidSHA1);
326
327                 oid.Add (defaultMD5, oidMD5);
328                 oid.Add (nameMD5a, oidMD5);
329                 oid.Add (nameMD5b, oidMD5);
330
331                 oid.Add (defaultSHA256, oidSHA256);
332                 oid.Add (nameSHA256a, oidSHA256);
333                 oid.Add (nameSHA256c, oidSHA256);
334
335                 oid.Add (defaultSHA384, oidSHA384);
336                 oid.Add (nameSHA384a, oidSHA384);
337                 oid.Add (nameSHA384c, oidSHA384);
338
339                 oid.Add (defaultSHA512, oidSHA512);
340                 oid.Add (nameSHA512a, oidSHA512);
341                 oid.Add (nameSHA512c, oidSHA512);
342
343                 // surprise! documented in ".NET Framework Security" book
344                 oid.Add (name3DESKeyWrap, oid3DESKeyWrap);
345
346 #if NET_2_0
347 //              oid.Add (nameRSAa, oidRSA);
348                 oid.Add (nameDSAa, oidDSA);
349                 oid.Add (nameDESa, oidDES);
350                 oid.Add (name3DESa, oid3DES);
351                 oid.Add (name3DESb, oid3DES);
352                 oid.Add (nameRC2a, oidRC2);
353 #endif
354
355                 // Add/modify the config as specified by machine.config
356                 string config = Environment.GetMachineConfigPath ();
357                 LoadConfig (config);
358         }
359
360         [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
361         private static void LoadConfig (string filename) 
362         {
363                 if (!File.Exists (filename))
364                         return;
365
366                 SecurityParser sp = new SecurityParser ();
367                 StreamReader sr = new StreamReader (filename);
368                 try {
369                         sp.LoadXml (sr.ReadToEnd ());
370                 }
371                 finally {
372                         sr.Close ();
373                 }
374
375                 try {
376                         SecurityElement root = sp.ToXml ();
377                         SecurityElement mscorlib = root.SearchForChildByTag ("mscorlib");
378                         if (mscorlib == null)
379                                 return;
380                         SecurityElement cryptographySettings = mscorlib.SearchForChildByTag ("cryptographySettings");
381                         if (cryptographySettings == null)
382                                 return;
383
384                         // algorithms
385                         SecurityElement cryptoNameMapping = cryptographySettings.SearchForChildByTag ("cryptoNameMapping");
386                         if (cryptoNameMapping != null) {
387                                 SecurityElement cryptoClasses = cryptoNameMapping.SearchForChildByTag ("cryptoClasses");
388                                 if (cryptoClasses != null) {
389                                         foreach (SecurityElement nameEntry in cryptoNameMapping.Children) {
390                                                 if (nameEntry.Tag == "nameEntry") {
391                                                         string name = (string) nameEntry.Attributes ["name"];
392                                                         string clas = (string) nameEntry.Attributes ["class"];
393                                                         foreach (SecurityElement cryptoClass in cryptoClasses.Children) {
394                                                                 string fullname = (string) cryptoClass.Attributes [clas];
395                                                                 if (fullname != null) {
396                                                                         if (algorithms.ContainsKey (name)) 
397                                                                                 algorithms.Remove (name);
398                                                                         algorithms.Add (name, fullname);
399                                                                         break;
400                                                                 }
401                                                         }
402                                                 }
403                                         }
404                                 }
405                         }
406
407                         // oid
408                         SecurityElement oidMap = cryptographySettings.SearchForChildByTag ("oidMap");
409                         if (oidMap == null)
410                                 return;
411                         foreach (SecurityElement oidEntry in oidMap.Children) {
412                                 if (oidEntry.Tag == "oidEntry") {
413                                         string oids = (string) oidEntry.Attributes ["OID"];
414                                         if (oid.ContainsKey (oids)) 
415                                                 oid.Remove (oids);
416                                         oid.Add (oids, oidEntry.Attributes ["name"]);
417                                 }
418                         }
419                 }
420                 catch {
421                         // there's no error/warning in case the machine.config contains bad entries
422                 }
423         }
424
425         public static object CreateFromName (string name)
426         {
427                 return CreateFromName (name, null);
428         }
429
430         [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
431         public static object CreateFromName (string name, object[] args)
432         {
433                 if (name == null)
434                         throw new ArgumentNullException ("name");
435
436                 if (algorithms == null) {
437                         lock (lockObject) {
438                                 Initialize ();
439                         }
440                 }
441         
442                 try {
443                         Type algoClass = null;
444                         string algo = (string) algorithms [name];
445                         // do we have an entry
446                         if (algo == null)
447                                 algo = name;
448                         algoClass = Type.GetType (algo);
449                         // call the constructor for the type
450                         return Activator.CreateInstance (algoClass, args);
451                 }
452                 catch {
453                         // method doesn't throw any exception
454                         return null;
455                 }
456         }
457
458         // encode (7bits array) number greater than 127
459         private static byte[] EncodeLongNumber (long x)
460         {
461                 // for MS BCL compatibility
462                 // comment next two lines to remove restriction
463                 if ((x > Int32.MaxValue) || (x < Int32.MinValue))
464                         throw new OverflowException (Locale.GetText ("Part of OID doesn't fit in Int32"));
465
466                 long y = x;
467                 // number of bytes required to encode this number
468                 int n = 1;
469                 while (y > 0x7F) {
470                         y = y >> 7;
471                         n++;
472                 }
473                 byte[] num = new byte [n];
474                 // encode all bytes 
475                 for (int i = 0; i < n; i++) {
476                         y = x >> (7 * i);
477                         y = y & 0x7F;
478                         if (i != 0)
479                                 y += 0x80;
480                         num[n-i-1] = Convert.ToByte (y);
481                 }
482                 return num;
483         }
484
485         public static byte[] EncodeOID (string str)
486         {
487 #if NET_2_0
488                 if (str == null)
489                         throw new ArgumentNullException ("str");
490 #endif
491                 char[] delim = { '.' };
492                 string[] parts = str.Split (delim);
493                 // according to X.208 n is always at least 2
494                 if (parts.Length < 2) {
495                         throw new CryptographicUnexpectedOperationException (
496                                 Locale.GetText ("OID must have at least two parts"));
497                 }
498
499                 // we're sure that the encoded OID is shorter than its string representation
500                 byte[] oid = new byte [str.Length];
501                 // now encoding value
502                 try {
503                         byte part0 = Convert.ToByte (parts [0]);
504                         // OID[0] > 2 is invalid but "supported" in MS BCL
505                         // uncomment next line to trap this error
506                         // if (part0 > 2) throw new CryptographicUnexpectedOperationException ();
507                         byte part1 = Convert.ToByte (parts [1]);
508                         // OID[1] >= 40 is illegal for OID[0] < 2 because of the % 40
509                         // however the syntax is "supported" in MS BCL
510                         // uncomment next 2 lines to trap this error
511                         //if ((part0 < 2) && (part1 >= 40))
512                         //      throw new CryptographicUnexpectedOperationException ();
513                         oid[2] = Convert.ToByte (part0 * 40 + part1);
514                 }
515                 catch {
516                         throw new CryptographicUnexpectedOperationException (
517                                 Locale.GetText ("Invalid OID"));
518                 }
519                 int j = 3;
520                 for (int i = 2; i < parts.Length; i++) {
521                         long x = Convert.ToInt64 (parts [i]);
522                         if (x > 0x7F) {
523                                 byte[] num = EncodeLongNumber (x);
524                                 Buffer.BlockCopy (num, 0, oid, j, num.Length);
525                                 j += num.Length;
526                         }
527                         else
528                                 oid[j++] = Convert.ToByte (x);
529                 }
530
531                 int k = 2;
532                 // copy the exact number of byte required
533                 byte[] oid2 = new byte [j];
534                 oid2[0] = 0x06; // always - this tag means OID
535                 // Length (of value)
536                 if (j > 0x7F) {
537                         // for compatibility with MS BCL
538                         throw new CryptographicUnexpectedOperationException (
539                                 Locale.GetText ("OID > 127 bytes"));
540                         // comment exception and uncomment next 3 lines to remove restriction
541                         //byte[] num = EncodeLongNumber (j);
542                         //Buffer.BlockCopy (num, 0, oid, j, num.Length);
543                         //k = num.Length + 1;
544                 }
545                 else
546                         oid2 [1] = Convert.ToByte (j - 2); 
547
548                 Buffer.BlockCopy (oid, k, oid2, k, j - k);
549                 return oid2;
550         }
551
552         public static string MapNameToOID (string name)
553         {
554                 if (name == null)
555                         throw new ArgumentNullException ("name");
556
557                 if (oid == null) {
558                         lock (lockObject) {
559                                 Initialize ();
560                         }
561                 }
562
563                 return (string)oid [name];
564         }
565 }
566
567 }