2 // CryptoConfig.cs: Handles cryptographic implementations and OIDs.
5 // Sebastien Pouliot (spouliot@motus.com)
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
11 using System.Collections;
13 using System.Reflection;
14 using System.Runtime.CompilerServices;
17 namespace System.Security.Cryptography {
19 internal class CorlibReader : MiniParser.IReader {
23 public CorlibReader (string filename)
26 StreamReader sr = new StreamReader (filename);
27 xml = sr.ReadToEnd ();
37 return (int) xml [pos++];
45 internal class CorlibHandler : MiniParser.IHandler {
47 private bool mscorlib;
48 private bool cryptographySettings;
49 private bool cryptoNameMapping;
50 private bool cryptoClasses;
52 private Hashtable algo;
53 private Hashtable cryptoClass;
54 private Hashtable nameEntry;
55 private Hashtable oid;
57 public CorlibHandler (Hashtable algo, Hashtable oid)
61 cryptoClass = new Hashtable ();
62 nameEntry = new Hashtable ();
65 public void OnStartParsing (MiniParser parser) {}
67 public void OnStartElement (string name, MiniParser.IAttrList attrs)
73 case "cryptographySettings":
75 cryptographySettings = true;
77 case "cryptoNameMapping":
78 if (cryptographySettings)
79 cryptoNameMapping = true;
82 if (cryptoNameMapping) {
83 string ename = attrs.Values [0];
84 string eclas = attrs.Values [1];
85 nameEntry.Add (ename, eclas);
89 if (cryptoNameMapping)
94 cryptoClass.Add (attrs.Names [0], attrs.Values [0]);
97 // unknown tag in parameters
102 public void OnEndElement (string name)
108 case "cryptographySettings":
109 cryptographySettings = false;
111 case "cryptoNameMapping":
112 cryptoNameMapping = false;
114 case "cryptoClasses":
115 cryptoClasses = false;
118 // unknown tag in parameters
123 public void OnChars (string ch) {}
125 public void OnEndParsing (MiniParser parser)
127 foreach (string key in nameEntry.Keys) {
128 string eclass = (string) nameEntry [key];
130 // is it a class or a friendly name ?
131 object o = cryptoClass [eclass];
133 // friendly name, so get it's class
137 if (algo.ContainsKey (key))
139 algo.Add (key, eclass);
145 public class CryptoConfig {
147 static private Hashtable algorithms;
148 static private Hashtable oid;
150 private const string defaultNamespace = "System.Security.Cryptography.";
151 private const string defaultSHA1 = defaultNamespace + "SHA1CryptoServiceProvider";
152 private const string defaultMD5 = defaultNamespace + "MD5CryptoServiceProvider";
153 private const string defaultSHA256 = defaultNamespace + "SHA256Managed";
154 private const string defaultSHA384 = defaultNamespace + "SHA384Managed";
155 private const string defaultSHA512 = defaultNamespace + "SHA512Managed";
156 private const string defaultRSA = defaultNamespace + "RSACryptoServiceProvider";
157 private const string defaultDSA = defaultNamespace + "DSACryptoServiceProvider";
158 private const string defaultDES = defaultNamespace + "DESCryptoServiceProvider";
159 private const string default3DES = defaultNamespace + "TripleDESCryptoServiceProvider";
160 private const string defaultRC2 = defaultNamespace + "RC2CryptoServiceProvider";
161 private const string defaultAES = defaultNamespace + "RijndaelManaged";
162 // LAMESPEC: undocumented names in CryptoConfig
163 private const string defaultRNG = defaultNamespace + "RNGCryptoServiceProvider";
164 private const string defaultHMAC = defaultNamespace + "HMACSHA1";
165 private const string defaultMAC3DES = defaultNamespace + "MACTripleDES";
166 // LAMESPEC: undocumented classes (also undocumented in CryptoConfig ;-)
167 private const string defaultDSASigDesc = defaultNamespace + "DSASignatureDescription";
168 private const string defaultRSASigDesc = defaultNamespace + "RSAPKCS1SHA1SignatureDescription";
169 // LAMESPEC: undocumented names in CryptoConfig
170 private const string xmlAssembly = ", System.Security, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
171 private const string defaultC14N = defaultNamespace + "Xml.XmlDsigC14NTransform" + xmlAssembly;
172 private const string defaultC14NWithComments = defaultNamespace + "Xml.XmlDsigC14NWithCommentsTransform" + xmlAssembly;
173 private const string defaultBase64 = defaultNamespace + "Xml.XmlDsigBase64Transform" + xmlAssembly;
174 private const string defaultXPath = defaultNamespace + "Xml.XmlDsigXPathTransform" + xmlAssembly;
175 private const string defaultXslt = defaultNamespace + "Xml.XmlDsigXsltTransform" + xmlAssembly;
176 private const string defaultEnveloped = defaultNamespace + "Xml.XmlDsigEnvelopedSignatureTransform" + xmlAssembly;
177 // LAMESPEC: only documentated in ".NET Framework Security" book
178 private const string defaultX509Data = defaultNamespace + "Xml.KeyInfoX509Data" + xmlAssembly;
179 private const string defaultKeyName = defaultNamespace + "Xml.KeyInfoName" + xmlAssembly;
180 private const string defaultKeyValueDSA = defaultNamespace + "Xml.DSAKeyValue" + xmlAssembly;
181 private const string defaultKeyValueRSA = defaultNamespace + "Xml.RSAKeyValue" + xmlAssembly;
182 private const string defaultRetrievalMethod = defaultNamespace + "Xml.KeyInfoRetrievalMethod" + xmlAssembly;
184 private const string managedSHA1 = defaultNamespace + "SHA1Managed";
186 // Oddly OID seems only available for hash algorithms
187 private const string oidSHA1 = "1.3.14.3.2.26";
188 private const string oidMD5 = "1.2.840.113549.2.5";
189 private const string oidSHA256 = "2.16.840.1.101.3.4.1";
190 private const string oidSHA384 = "2.16.840.1.101.3.4.2";
191 private const string oidSHA512 = "2.16.840.1.101.3.4.3";
192 // LAMESPEC: only documentated in ".NET Framework Security" book
193 private const string oid3DESKeyWrap = "1.2.840.113549.1.9.16.3.6";
195 private const string nameSHA1a = "SHA";
196 private const string nameSHA1b = "SHA1";
197 private const string nameSHA1c = "System.Security.Cryptography.SHA1";
198 private const string nameSHA1d = "System.Security.Cryptography.HashAlgorithm";
199 private const string nameMD5a = "MD5";
200 private const string nameMD5b = "System.Security.Cryptography.MD5";
201 private const string nameSHA256a = "SHA256";
202 private const string nameSHA256b = "SHA-256";
203 private const string nameSHA256c = "System.Security.Cryptography.SHA256";
204 private const string nameSHA384a = "SHA384";
205 private const string nameSHA384b = "SHA-384";
206 private const string nameSHA384c = "System.Security.Cryptography.SHA384";
207 private const string nameSHA512a = "SHA512";
208 private const string nameSHA512b = "SHA-512";
209 private const string nameSHA512c = "System.Security.Cryptography.SHA512";
210 private const string nameRSAa = "RSA";
211 private const string nameRSAb = "System.Security.Cryptography.RSA";
212 private const string nameRSAc = "System.Security.Cryptography.AsymmetricAlgorithm";
213 private const string nameDSAa = "DSA";
214 private const string nameDSAb = "System.Security.Cryptography.DSA";
215 private const string nameDESa = "DES";
216 private const string nameDESb = "System.Security.Cryptography.DES";
217 private const string name3DESa = "3DES";
218 private const string name3DESb = "TripleDES";
219 private const string name3DESc = "Triple DES";
220 private const string name3DESd = "System.Security.Cryptography.TripleDES";
221 private const string nameRC2a = "RC2";
222 private const string nameRC2b = "System.Security.Cryptography.RC2";
223 private const string nameAESa = "Rijndael";
224 private const string nameAESb = "System.Security.Cryptography.Rijndael";
225 private const string nameAESc = "System.Security.Cryptography.SymmetricAlgorithm";
226 // LAMESPEC: undocumented names in CryptoConfig
227 private const string nameRNGa = "RandomNumberGenerator";
228 private const string nameRNGb = "System.Security.Cryptography.RandomNumberGenerator";
229 private const string nameKeyHasha = "System.Security.Cryptography.KeyedHashAlgorithm";
230 private const string nameHMACa = "HMACSHA1";
231 private const string nameHMACb = "System.Security.Cryptography.HMACSHA1";
232 private const string nameMAC3DESa = "MACTripleDES";
233 private const string nameMAC3DESb = "System.Security.Cryptography.MACTripleDES";
234 // LAMESPEC: only documentated in ".NET Framework Security" book
235 private const string name3DESKeyWrap = "TripleDESKeyWrap";
237 private const string urlXmlDsig = "http://www.w3.org/2000/09/xmldsig#";
238 // LAMESPEC: undocumented URLs in CryptoConfig
239 private const string urlDSASHA1 = urlXmlDsig + "dsa-sha1"; // no space
240 private const string urlRSASHA1 = urlXmlDsig + "rsa-sha1"; // no space
241 private const string urlSHA1 = urlXmlDsig + "sha1"; // no space
242 private const string urlC14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
243 private const string urlC14NWithComments = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments";
244 private const string urlBase64 = "http://www.w3.org/2000/09/xmldsig#base64";
245 private const string urlXPath = "http://www.w3.org/TR/1999/REC-xpath-19991116";
246 private const string urlXslt = "http://www.w3.org/TR/1999/REC-xslt-19991116";
247 private const string urlEnveloped = urlXmlDsig + "enveloped-signature"; // no space
248 // LAMESPEC: only documentated in ".NET Framework Security" book
249 private const string urlX509Data = urlXmlDsig + " X509Data"; // space is required
250 private const string urlKeyName = urlXmlDsig + " KeyName"; // space is required
251 private const string urlKeyValueDSA = urlXmlDsig + " KeyValue/DSAKeyValue"; // space is required
252 private const string urlKeyValueRSA = urlXmlDsig + " KeyValue/RSAKeyValue"; // space is required
253 private const string urlRetrievalMethod = urlXmlDsig + " RetrievalMethod"; // space is required
255 // ??? must we read from the machine.config each time or just at startup ???
256 [MonoTODO ("support OID in machine.config")]
257 static CryptoConfig ()
259 algorithms = new Hashtable ();
260 // see list @ http://msdn.microsoft.com/library/en-us/cpref/html/
261 // frlrfSystemSecurityCryptographyCryptoConfigClassTopic.asp
262 algorithms.Add (nameSHA1a, defaultSHA1);
263 algorithms.Add (nameSHA1b, defaultSHA1);
264 algorithms.Add (nameSHA1c, defaultSHA1);
265 algorithms.Add (nameSHA1d, defaultSHA1);
267 algorithms.Add (nameMD5a, defaultMD5);
268 algorithms.Add (nameMD5b, defaultMD5);
270 algorithms.Add (nameSHA256a, defaultSHA256);
271 algorithms.Add (nameSHA256b, defaultSHA256);
272 algorithms.Add (nameSHA256c, defaultSHA256);
274 algorithms.Add (nameSHA384a, defaultSHA384);
275 algorithms.Add (nameSHA384b, defaultSHA384);
276 algorithms.Add (nameSHA384c, defaultSHA384);
278 algorithms.Add (nameSHA512a, defaultSHA512);
279 algorithms.Add (nameSHA512b, defaultSHA512);
280 algorithms.Add (nameSHA512c, defaultSHA512);
282 algorithms.Add (nameRSAa, defaultRSA);
283 algorithms.Add (nameRSAb, defaultRSA);
284 algorithms.Add (nameRSAc, defaultRSA);
286 algorithms.Add (nameDSAa, defaultDSA);
287 algorithms.Add (nameDSAb, defaultDSA);
289 algorithms.Add (nameDESa, defaultDES);
290 algorithms.Add (nameDESb, defaultDES);
292 algorithms.Add (name3DESa, default3DES);
293 algorithms.Add (name3DESb, default3DES);
294 algorithms.Add (name3DESc, default3DES);
295 algorithms.Add (name3DESd, default3DES);
297 algorithms.Add (nameRC2a, defaultRC2);
298 algorithms.Add (nameRC2b, defaultRC2);
300 algorithms.Add (nameAESa, defaultAES);
301 algorithms.Add (nameAESb, defaultAES);
302 // LAMESPEC SymmetricAlgorithm documented as TripleDESCryptoServiceProvider
303 algorithms.Add (nameAESc, defaultAES);
305 // LAMESPEC These names aren't documented but (hint) the classes also have
306 // static Create methods. So logically they should (and are) here.
307 algorithms.Add (nameRNGa, defaultRNG);
308 algorithms.Add (nameRNGb, defaultRNG);
309 algorithms.Add (nameKeyHasha, defaultHMAC);
310 algorithms.Add (nameHMACa, defaultHMAC);
311 algorithms.Add (nameHMACb, defaultHMAC);
312 algorithms.Add (nameMAC3DESa, defaultMAC3DES);
313 algorithms.Add (nameMAC3DESb, defaultMAC3DES);
315 // LAMESPEC These URLs aren't documented but (hint) installing the WSDK
316 // add some of the XMLDSIG urls into machine.config (and they make a LOT
317 // of sense for implementing XMLDSIG in System.Security.Cryptography.Xml)
318 algorithms.Add (urlDSASHA1, defaultDSASigDesc);
319 algorithms.Add (urlRSASHA1, defaultRSASigDesc);
320 algorithms.Add (urlSHA1, defaultSHA1);
321 algorithms.Add (urlC14N, defaultC14N);
322 algorithms.Add (urlC14NWithComments, defaultC14NWithComments);
323 algorithms.Add (urlBase64, defaultBase64);
324 algorithms.Add (urlXPath, defaultXPath);
325 algorithms.Add (urlXslt, defaultXslt);
326 algorithms.Add (urlEnveloped, defaultEnveloped);
327 // LAMESPEC: only documentated in ".NET Framework Security" book
328 algorithms.Add (urlX509Data, defaultX509Data);
329 algorithms.Add (urlKeyName, defaultKeyName);
330 algorithms.Add (urlKeyValueDSA, defaultKeyValueDSA);
331 algorithms.Add (urlKeyValueRSA, defaultKeyValueRSA);
332 algorithms.Add (urlRetrievalMethod, defaultRetrievalMethod);
334 oid = new Hashtable ();
335 // comments here are to match with MS implementation (but not with doc)
336 // LAMESPEC: only HashAlgorithm seems to have their OID included
337 oid.Add (defaultSHA1, oidSHA1);
338 oid.Add (managedSHA1, oidSHA1);
339 oid.Add (nameSHA1b, oidSHA1);
340 oid.Add (nameSHA1c, oidSHA1);
342 oid.Add (defaultMD5, oidMD5);
343 oid.Add (nameMD5a, oidMD5);
344 oid.Add (nameMD5b, oidMD5);
346 oid.Add (defaultSHA256, oidSHA256);
347 oid.Add (nameSHA256a, oidSHA256);
348 oid.Add (nameSHA256c, oidSHA256);
350 oid.Add (defaultSHA384, oidSHA384);
351 oid.Add (nameSHA384a, oidSHA384);
352 oid.Add (nameSHA384c, oidSHA384);
354 oid.Add (defaultSHA512, oidSHA512);
355 oid.Add (nameSHA512a, oidSHA512);
356 oid.Add (nameSHA512c, oidSHA512);
358 // surprise! documented in ".NET Framework Security" book
359 oid.Add (name3DESKeyWrap, oid3DESKeyWrap);
361 // Add/modify the config as specified by machine.config
362 string config = GetMachineConfigPath ();
363 // debug @"C:\mono-0.17\install\etc\mono\machine.config";
364 if (config != null) {
365 MiniParser parser = new MiniParser ();
366 CorlibReader reader = new CorlibReader (config);
367 CorlibHandler handler = new CorlibHandler (algorithms, oid);
368 parser.Parse (reader, handler);
372 // managed version of "get_machine_config_path"
373 private static string GetMachineConfigPath ()
375 string env = Environment.GetEnvironmentVariable ("MONO_CONFIG");
378 env = Environment.GetEnvironmentVariable ("MONO_BASEPATH");
382 StringBuilder sb = new StringBuilder ();
384 sb.Append (Path.DirectorySeparatorChar);
386 sb.Append (Path.DirectorySeparatorChar);
388 sb.Append (Path.DirectorySeparatorChar);
389 sb.Append ("machine.config");
390 return sb.ToString ();
393 public static object CreateFromName (string name)
395 return CreateFromName (name, null);
398 public static object CreateFromName (string name, object[] args)
401 throw new ArgumentNullException ();
404 Type algoClass = null;
405 string algo = (string) algorithms [name];
406 // do we have an entry
409 algoClass = Type.GetType (algo);
410 // call the constructor for the type
411 return Activator.CreateInstance (algoClass, args);
414 // method deosn't throw any exception
419 // encode (7bits array) number greater than 127
420 private static byte[] EncodeLongNumber (long x)
422 // for MS BCL compatibility
423 // comment next two lines to remove restriction
424 if ((x > Int32.MaxValue) || (x < Int32.MinValue))
425 throw new OverflowException("part of OID doesn't fit in Int32");
428 // number of bytes required to encode this number
434 byte[] num = new byte [n];
436 for (int i = 0; i < n; i++) {
441 num[n-i-1] = Convert.ToByte (y);
446 public static byte[] EncodeOID (string str)
448 char[] delim = { '.' };
449 string[] parts = str.Split (delim);
450 // according to X.208 n is always at least 2
451 if (parts.Length < 2)
452 throw new CryptographicUnexpectedOperationException ();
453 // we're sure that the encoded OID is shorter than its string representation
454 byte[] oid = new byte [str.Length];
455 // now encoding value
457 byte part0 = Convert.ToByte (parts [0]);
458 // OID[0] > 2 is invalid but "supported" in MS BCL
459 // uncomment next line to trap this error
460 // if (part0 > 2) throw new CryptographicUnexpectedOperationException ();
461 byte part1 = Convert.ToByte (parts [1]);
462 // OID[1] >= 40 is illegal for OID[0] < 2 because of the % 40
463 // however the syntax is "supported" in MS BCL
464 // uncomment next 2 lines to trap this error
465 //if ((part0 < 2) && (part1 >= 40))
466 // throw new CryptographicUnexpectedOperationException ();
467 oid[2] = Convert.ToByte (part0 * 40 + part1);
470 throw new CryptographicUnexpectedOperationException ();
473 for (int i = 2; i < parts.Length; i++) {
474 long x = Convert.ToInt64( parts [i]);
476 byte[] num = EncodeLongNumber (x);
477 Array.Copy(num, 0, oid, j, num.Length);
481 oid[j++] = Convert.ToByte (x);
485 // copy the exact number of byte required
486 byte[] oid2 = new byte [j];
487 oid2[0] = 0x06; // always - this tag means OID
490 // for compatibility with MS BCL
491 throw new CryptographicUnexpectedOperationException ("OID > 127 bytes");
492 // comment exception and uncomment next 3 lines to remove restriction
493 //byte[] num = EncodeLongNumber (j);
494 //Array.Copy (num, 0, oid, j, num.Length);
495 //k = num.Length + 1;
498 oid2 [1] = Convert.ToByte (j - 2);
500 System.Array.Copy (oid, k, oid2, k, j - k);
504 public static string MapNameToOID (string name)
507 throw new ArgumentNullException ("name");
509 return (string)oid [name];