CryptoConfig.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. //
  2. // CryptoConfig.cs: Handles cryptographic implementations and OIDs.
  3. //
  4. // Author:
  5. // Sebastien Pouliot ([email protected])
  6. //
  7. // (C) 2002 Motus Technologies Inc. (http://www.motus.com)
  8. //
  9. using System;
  10. using System.Collections;
  11. using System.Reflection;
  12. namespace System.Security.Cryptography
  13. {
  14. public class CryptoConfig
  15. {
  16. static private Hashtable algorithms;
  17. static private Hashtable oid;
  18. static Assembly xmldsig;
  19. private const string defaultNamespace = "System.Security.Cryptography.";
  20. private const string defaultSHA1 = defaultNamespace + "SHA1CryptoServiceProvider";
  21. private const string defaultMD5 = defaultNamespace + "MD5CryptoServiceProvider";
  22. private const string defaultSHA256 = defaultNamespace + "SHA256Managed";
  23. private const string defaultSHA384 = defaultNamespace + "SHA384Managed";
  24. private const string defaultSHA512 = defaultNamespace + "SHA512Managed";
  25. private const string defaultRSA = defaultNamespace + "RSACryptoServiceProvider";
  26. private const string defaultDSA = defaultNamespace + "DSACryptoServiceProvider";
  27. private const string defaultDES = defaultNamespace + "DESCryptoServiceProvider";
  28. private const string default3DES = defaultNamespace + "TripleDESCryptoServiceProvider";
  29. private const string defaultRC2 = defaultNamespace + "RC2CryptoServiceProvider";
  30. private const string defaultAES = defaultNamespace + "RijndaelManaged";
  31. // LAMESPEC: undocumented names in CryptoConfig
  32. private const string defaultRNG = defaultNamespace + "RNGCryptoServiceProvider";
  33. private const string defaultHMAC = defaultNamespace + "HMACSHA1";
  34. private const string defaultMAC3DES = defaultNamespace + "MACTripleDES";
  35. // LAMESPEC: undocumented classes (also undocumented in CryptoConfig ;-)
  36. private const string defaultDSASigDesc = defaultNamespace + "DSASignatureDescription";
  37. private const string defaultRSASigDesc = defaultNamespace + "RSAPKCS1SHA1SignatureDescription";
  38. // LAMESPEC: undocumented names in CryptoConfig
  39. private const string defaultC14N = defaultNamespace + "Xml.XmlDsigC14NTransform";
  40. private const string defaultC14NWithComments = defaultNamespace + "Xml.XmlDsigC14NWithCommentsTransform";
  41. private const string defaultBase64 = defaultNamespace + "Xml.XmlDsigBase64Transform";
  42. private const string defaultXPath = defaultNamespace + "Xml.XmlDsigXPathTransform";
  43. private const string defaultXslt = defaultNamespace + "Xml.XmlDsigXsltTransform";
  44. private const string defaultEnveloped = defaultNamespace + "Xml.XmlDsigEnvelopedSignatureTransform";
  45. private const string managedSHA1 = defaultNamespace + "SHA1Managed";
  46. // Oddly OID seems only available for hash algorithms
  47. private const string oidSHA1 = "1.3.14.3.2.26";
  48. private const string oidMD5 = "1.2.840.113549.2.5";
  49. private const string oidSHA256 = "2.16.840.1.101.3.4.1";
  50. private const string oidSHA384 = "2.16.840.1.101.3.4.2";
  51. private const string oidSHA512 = "2.16.840.1.101.3.4.3";
  52. private const string nameSHA1a = "SHA";
  53. private const string nameSHA1b = "SHA1";
  54. private const string nameSHA1c = "System.Security.Cryptography.SHA1";
  55. private const string nameSHA1d = "System.Security.Cryptography.HashAlgorithm";
  56. private const string nameMD5a = "MD5";
  57. private const string nameMD5b = "System.Security.Cryptography.MD5";
  58. private const string nameSHA256a = "SHA256";
  59. private const string nameSHA256b = "SHA-256";
  60. private const string nameSHA256c = "System.Security.Cryptography.SHA256";
  61. private const string nameSHA384a = "SHA384";
  62. private const string nameSHA384b = "SHA-384";
  63. private const string nameSHA384c = "System.Security.Cryptography.SHA384";
  64. private const string nameSHA512a = "SHA512";
  65. private const string nameSHA512b = "SHA-512";
  66. private const string nameSHA512c = "System.Security.Cryptography.SHA512";
  67. private const string nameRSAa = "RSA";
  68. private const string nameRSAb = "System.Security.Cryptography.RSA";
  69. private const string nameRSAc = "System.Security.Cryptography.AsymmetricAlgorithm";
  70. private const string nameDSAa = "DSA";
  71. private const string nameDSAb = "System.Security.Cryptography.DSA";
  72. private const string nameDESa = "DES";
  73. private const string nameDESb = "System.Security.Cryptography.DES";
  74. private const string name3DESa = "3DES";
  75. private const string name3DESb = "TripleDES";
  76. private const string name3DESc = "Triple DES";
  77. private const string name3DESd = "System.Security.Cryptography.TripleDES";
  78. private const string nameRC2a = "RC2";
  79. private const string nameRC2b = "System.Security.Cryptography.RC2";
  80. private const string nameAESa = "Rijndael";
  81. private const string nameAESb = "System.Security.Cryptography.Rijndael";
  82. private const string nameAESc = "System.Security.Cryptography.SymmetricAlgorithm";
  83. // LAMESPEC: undocumented names in CryptoConfig
  84. private const string nameRNGa = "RandomNumberGenerator";
  85. private const string nameRNGb = "System.Security.Cryptography.RandomNumberGenerator";
  86. private const string nameKeyHasha = "System.Security.Cryptography.KeyedHashAlgorithm";
  87. private const string nameHMACa = "HMACSHA1";
  88. private const string nameHMACb = "System.Security.Cryptography.HMACSHA1";
  89. private const string nameMAC3DESa = "MACTripleDES";
  90. private const string nameMAC3DESb = "System.Security.Cryptography.MACTripleDES";
  91. // LAMESPEC: undocumented URLs in CryptoConfig
  92. private const string urlDSASHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
  93. private const string urlRSASHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
  94. private const string urlSHA1 = "http://www.w3.org/2000/09/xmldsig#sha1";
  95. private const string urlC14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
  96. private const string urlC14NWithComments = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments";
  97. private const string urlBase64 = "http://www.w3.org/2000/09/xmldsig#base64";
  98. private const string urlXPath = "http://www.w3.org/TR/1999/REC-xpath-19991116";
  99. private const string urlXslt = "http://www.w3.org/TR/1999/REC-xslt-19991116";
  100. private const string urlEnveloped = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
  101. // ??? must we read from the machine.config each time or just at startup ???
  102. [MonoTODO ("support machine.config")]
  103. static CryptoConfig()
  104. {
  105. algorithms = new Hashtable ();
  106. // see list @ http://msdn.microsoft.com/library/en-us/cpref/html/
  107. // frlrfSystemSecurityCryptographyCryptoConfigClassTopic.asp
  108. algorithms.Add (nameSHA1a, defaultSHA1);
  109. algorithms.Add (nameSHA1b, defaultSHA1);
  110. algorithms.Add (nameSHA1c, defaultSHA1);
  111. algorithms.Add (nameSHA1d, defaultSHA1);
  112. algorithms.Add (nameMD5a, defaultMD5);
  113. algorithms.Add (nameMD5b, defaultMD5);
  114. algorithms.Add (nameSHA256a, defaultSHA256);
  115. algorithms.Add (nameSHA256b, defaultSHA256);
  116. algorithms.Add (nameSHA256c, defaultSHA256);
  117. algorithms.Add (nameSHA384a, defaultSHA384);
  118. algorithms.Add (nameSHA384b, defaultSHA384);
  119. algorithms.Add (nameSHA384c, defaultSHA384);
  120. algorithms.Add (nameSHA512a, defaultSHA512);
  121. algorithms.Add (nameSHA512b, defaultSHA512);
  122. algorithms.Add (nameSHA512c, defaultSHA512);
  123. algorithms.Add (nameRSAa, defaultRSA);
  124. algorithms.Add (nameRSAb, defaultRSA);
  125. algorithms.Add (nameRSAc, defaultRSA);
  126. algorithms.Add (nameDSAa, defaultDSA);
  127. algorithms.Add (nameDSAb, defaultDSA);
  128. algorithms.Add (nameDESa, defaultDES);
  129. algorithms.Add (nameDESb, defaultDES);
  130. algorithms.Add (name3DESa, default3DES);
  131. algorithms.Add (name3DESb, default3DES);
  132. algorithms.Add (name3DESc, default3DES);
  133. algorithms.Add (name3DESd, default3DES);
  134. algorithms.Add (nameRC2a, defaultRC2);
  135. algorithms.Add (nameRC2b, defaultRC2);
  136. algorithms.Add (nameAESa, defaultAES);
  137. algorithms.Add (nameAESb, defaultAES);
  138. // LAMESPEC SymmetricAlgorithm documented as TripleDESCryptoServiceProvider
  139. algorithms.Add (nameAESc, defaultAES);
  140. // LAMESPEC These names aren't documented but (hint) the classes also have
  141. // static Create methods. So logically they should (and are) here.
  142. algorithms.Add (nameRNGa, defaultRNG);
  143. algorithms.Add (nameRNGb, defaultRNG);
  144. algorithms.Add (nameKeyHasha, defaultHMAC);
  145. algorithms.Add (nameHMACa, defaultHMAC);
  146. algorithms.Add (nameHMACb, defaultHMAC);
  147. algorithms.Add (nameMAC3DESa, defaultMAC3DES);
  148. algorithms.Add (nameMAC3DESb, defaultMAC3DES);
  149. // LAMESPEC These URLs aren't documented but (hint) installing the WSDK
  150. // add some of the XMLDSIG urls into machine.config (and they make a LOT
  151. // of sense for implementing XMLDSIG in System.Security.Cryptography.Xml)
  152. algorithms.Add (urlDSASHA1, defaultDSASigDesc);
  153. algorithms.Add (urlRSASHA1, defaultRSASigDesc);
  154. algorithms.Add (urlSHA1, defaultSHA1);
  155. algorithms.Add (urlC14N, defaultC14N);
  156. algorithms.Add (urlC14NWithComments, defaultC14NWithComments);
  157. algorithms.Add (urlBase64, defaultBase64);
  158. algorithms.Add (urlXPath, defaultXPath);
  159. algorithms.Add (urlXslt, defaultXslt);
  160. algorithms.Add (urlEnveloped, defaultEnveloped);
  161. oid = new Hashtable ();
  162. // comments here are to match with MS implementation (but not with doc)
  163. // LAMESPEC: only HashAlgorithm seems to have their OID included
  164. oid.Add (defaultSHA1, oidSHA1);
  165. oid.Add (managedSHA1, oidSHA1);
  166. // oid.Add (nameSHA1a, oidSHA1);
  167. oid.Add (nameSHA1b, oidSHA1);
  168. oid.Add (nameSHA1c, oidSHA1);
  169. // oid.Add (nameSHA1d, oidSHA1);
  170. oid.Add (defaultMD5, oidMD5);
  171. oid.Add (nameMD5a, oidMD5);
  172. oid.Add (nameMD5b, oidMD5);
  173. oid.Add (defaultSHA256, oidSHA256);
  174. oid.Add (nameSHA256a, oidSHA256);
  175. // oid.Add (nameSHA256b, oidSHA256);
  176. oid.Add (nameSHA256c, oidSHA256);
  177. oid.Add (defaultSHA384, oidSHA384);
  178. oid.Add (nameSHA384a, oidSHA384);
  179. // oid.Add (nameSHA384b, oidSHA384);
  180. oid.Add (nameSHA384c, oidSHA384);
  181. oid.Add (defaultSHA512, oidSHA512);
  182. oid.Add (nameSHA512a, oidSHA512);
  183. // oid.Add (nameSHA512b, oidSHA512);
  184. oid.Add (nameSHA512c, oidSHA512);
  185. }
  186. public static object CreateFromName (string name)
  187. {
  188. return CreateFromName (name, null);
  189. }
  190. public static object CreateFromName (string name, object[] args)
  191. {
  192. if (name == null)
  193. throw new ArgumentNullException ();
  194. try {
  195. Type algoClass = null;
  196. string algo = (string)algorithms [name];
  197. // do we have an entry
  198. if (algo != null) {
  199. algoClass = Type.GetType (algo);
  200. // some classes are in assembly System.Security.Cryptography.Xml
  201. if ((algoClass == null) && (algo.StartsWith ("System.Security.Cryptography.Xml."))) {
  202. // second chance !
  203. if (xmldsig == null)
  204. xmldsig = Assembly.LoadWithPartialName ("System.Security");
  205. if (xmldsig != null)
  206. algoClass = xmldsig.GetType (algo);
  207. }
  208. }
  209. else
  210. algoClass = Type.GetType (name);
  211. // call the constructor for the type
  212. return Activator.CreateInstance (algoClass, args);
  213. }
  214. catch {
  215. return null;
  216. }
  217. }
  218. // Note: Couldn't access private in DefaultConfig so I copied the
  219. // two required functions.
  220. /* [MethodImplAttribute(MethodImplOptions.InternalCall)]
  221. extern private static string get_machine_config_path ();
  222. private static string GetMachineConfigPath ()
  223. {
  224. return get_machine_config_path ();
  225. }*/
  226. // encode (7bits array) number greater than 127
  227. private static byte[] EncodeLongNumber (long x)
  228. {
  229. // for MS BCL compatibility
  230. // comment next two lines to remove restriction
  231. if ((x > Int32.MaxValue) || (x < Int32.MinValue))
  232. throw new OverflowException("part of OID doesn't fit in Int32");
  233. long y = x;
  234. // number of bytes required to encode this number
  235. int n = 1;
  236. while (y > 0x7F) {
  237. y = y >> 7;
  238. n++;
  239. }
  240. byte[] num = new byte [n];
  241. // encode all bytes
  242. for (int i = 0; i < n; i++) {
  243. y = x >> (7 * i);
  244. y = y & 0x7F;
  245. if (i != 0)
  246. y += 0x80;
  247. num[n-i-1] = Convert.ToByte (y);
  248. }
  249. return num;
  250. }
  251. public static byte[] EncodeOID (string str)
  252. {
  253. char[] delim = { '.' };
  254. string[] parts = str.Split (delim);
  255. // according to X.208 n is always at least 2
  256. if (parts.Length < 2)
  257. throw new CryptographicUnexpectedOperationException ();
  258. // we're sure that the encoded OID is shorter than its string representation
  259. byte[] oid = new byte [str.Length];
  260. // now encoding value
  261. try {
  262. byte part0 = Convert.ToByte (parts [0]);
  263. // OID[0] > 2 is invalid but "supported" in MS BCL
  264. // uncomment next line to trap this error
  265. // if (part0 > 2) throw new CryptographicUnexpectedOperationException ();
  266. byte part1 = Convert.ToByte (parts [1]);
  267. // OID[1] >= 40 is illegal for OID[0] < 2 because of the % 40
  268. // however the syntax is "supported" in MS BCL
  269. // uncomment next 2 lines to trap this error
  270. //if ((part0 < 2) && (part1 >= 40))
  271. // throw new CryptographicUnexpectedOperationException ();
  272. oid[2] = Convert.ToByte (part0 * 40 + part1);
  273. }
  274. catch {
  275. throw new CryptographicUnexpectedOperationException ();
  276. }
  277. int j = 3;
  278. for (int i = 2; i < parts.Length; i++) {
  279. long x = Convert.ToInt64( parts [i]);
  280. if (x > 0x7F) {
  281. byte[] num = EncodeLongNumber (x);
  282. Array.Copy(num, 0, oid, j, num.Length);
  283. j += num.Length;
  284. }
  285. else
  286. oid[j++] = Convert.ToByte (x);
  287. }
  288. int k = 2;
  289. // copy the exact number of byte required
  290. byte[] oid2 = new byte [j];
  291. oid2[0] = 0x06; // always - this tag means OID
  292. // Length (of value)
  293. if (j > 0x7F) {
  294. // for compatibility with MS BCL
  295. throw new CryptographicUnexpectedOperationException ("OID > 127 bytes");
  296. // comment exception and uncomment next 3 lines to remove restriction
  297. //byte[] num = EncodeLongNumber (j);
  298. //Array.Copy (num, 0, oid, j, num.Length);
  299. //k = num.Length + 1;
  300. }
  301. else
  302. oid2 [1] = Convert.ToByte (j - 2);
  303. System.Array.Copy (oid, k, oid2, k, j - k);
  304. return oid2;
  305. }
  306. public static string MapNameToOID (string name)
  307. {
  308. if (name == null)
  309. throw new ArgumentNullException ();
  310. return (string)oid [name];
  311. }
  312. }
  313. }