CryptoHelper.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Security
  5. {
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.ServiceModel.Channels;
  9. using System.ServiceModel;
  10. using System.Reflection;
  11. using System.Threading;
  12. using System.IO;
  13. using System.Runtime.InteropServices;
  14. using System.IdentityModel.Tokens;
  15. using System.Text;
  16. using System.Xml;
  17. using System.Diagnostics;
  18. using System.Security.Cryptography;
  19. using Psha1DerivedKeyGenerator = System.IdentityModel.Psha1DerivedKeyGenerator;
  20. using CryptoAlgorithms = System.IdentityModel.CryptoHelper;
  21. static class CryptoHelper
  22. {
  23. static byte[] emptyBuffer;
  24. static readonly RandomNumberGenerator random = new RNGCryptoServiceProvider();
  25. enum CryptoAlgorithmType
  26. {
  27. Unknown,
  28. Symmetric,
  29. Asymmetric
  30. }
  31. internal static byte[] EmptyBuffer
  32. {
  33. get
  34. {
  35. if (emptyBuffer == null)
  36. {
  37. byte[] tmp = new byte[0];
  38. emptyBuffer = tmp;
  39. }
  40. return emptyBuffer;
  41. }
  42. }
  43. internal static HashAlgorithm NewSha1HashAlgorithm()
  44. {
  45. return CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha1Digest);
  46. }
  47. internal static HashAlgorithm NewSha256HashAlgorithm()
  48. {
  49. return CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha256Digest);
  50. }
  51. internal static HashAlgorithm CreateHashAlgorithm(string digestMethod)
  52. {
  53. object algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(digestMethod);
  54. if (algorithmObject != null)
  55. {
  56. HashAlgorithm hashAlgorithm = algorithmObject as HashAlgorithm;
  57. if (hashAlgorithm != null)
  58. return hashAlgorithm;
  59. throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidHashAlgorithm, digestMethod)));
  60. }
  61. switch (digestMethod)
  62. {
  63. case SecurityAlgorithms.Sha1Digest:
  64. if (SecurityUtilsEx.RequiresFipsCompliance)
  65. return new SHA1CryptoServiceProvider();
  66. else
  67. return new SHA1Managed();
  68. case SecurityAlgorithms.Sha256Digest:
  69. if (SecurityUtilsEx.RequiresFipsCompliance)
  70. return new SHA256CryptoServiceProvider();
  71. else
  72. return new SHA256Managed();
  73. default:
  74. throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.UnsupportedCryptoAlgorithm, digestMethod)));
  75. }
  76. }
  77. internal static HashAlgorithm CreateHashForAsymmetricSignature(string signatureMethod)
  78. {
  79. object algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(signatureMethod);
  80. if (algorithmObject != null)
  81. {
  82. HashAlgorithm hashAlgorithm;
  83. SignatureDescription signatureDescription = algorithmObject as SignatureDescription;
  84. if (signatureDescription != null)
  85. {
  86. hashAlgorithm = signatureDescription.CreateDigest();
  87. if (hashAlgorithm != null)
  88. return hashAlgorithm;
  89. }
  90. hashAlgorithm = algorithmObject as HashAlgorithm;
  91. if (hashAlgorithm != null)
  92. return hashAlgorithm;
  93. throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidAsymmetricSignature, signatureMethod)));
  94. }
  95. switch (signatureMethod)
  96. {
  97. case SecurityAlgorithms.RsaSha1Signature:
  98. case SecurityAlgorithms.DsaSha1Signature:
  99. if (SecurityUtilsEx.RequiresFipsCompliance)
  100. return new SHA1CryptoServiceProvider();
  101. else
  102. return new SHA1Managed();
  103. case SecurityAlgorithms.RsaSha256Signature:
  104. if (SecurityUtilsEx.RequiresFipsCompliance)
  105. return new SHA256CryptoServiceProvider();
  106. else
  107. return new SHA256Managed();
  108. default:
  109. throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.UnsupportedCryptoAlgorithm, signatureMethod)));
  110. }
  111. }
  112. internal static byte[] ExtractIVAndDecrypt(SymmetricAlgorithm algorithm, byte[] cipherText, int offset, int count)
  113. {
  114. if (cipherText == null)
  115. {
  116. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("cipherText");
  117. }
  118. if (count < 0 || count > cipherText.Length)
  119. {
  120. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeInRange, 0, cipherText.Length)));
  121. }
  122. if (offset < 0 || offset > cipherText.Length - count)
  123. {
  124. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeInRange, 0, cipherText.Length - count)));
  125. }
  126. int ivSize = algorithm.BlockSize / 8;
  127. byte[] iv = new byte[ivSize];
  128. Buffer.BlockCopy(cipherText, offset, iv, 0, iv.Length);
  129. algorithm.Padding = PaddingMode.ISO10126;
  130. algorithm.Mode = CipherMode.CBC;
  131. try
  132. {
  133. using (ICryptoTransform decrTransform = algorithm.CreateDecryptor(algorithm.Key, iv))
  134. {
  135. return decrTransform.TransformFinalBlock(cipherText, offset + iv.Length, count - iv.Length);
  136. }
  137. }
  138. catch (CryptographicException ex)
  139. {
  140. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.DecryptionFailed), ex));
  141. }
  142. }
  143. internal static void FillRandomBytes(byte[] buffer)
  144. {
  145. random.GetBytes(buffer);
  146. }
  147. static CryptoAlgorithmType GetAlgorithmType(string algorithm)
  148. {
  149. object algorithmObject = null;
  150. try
  151. {
  152. algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(algorithm);
  153. }
  154. catch (InvalidOperationException)
  155. {
  156. algorithmObject = null;
  157. // We ---- the exception and continue.
  158. }
  159. if (algorithmObject != null)
  160. {
  161. SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
  162. KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm;
  163. if (symmetricAlgorithm != null || keyedHashAlgorithm != null)
  164. return CryptoAlgorithmType.Symmetric;
  165. // NOTE: A KeyedHashAlgorithm is symmetric in nature.
  166. AsymmetricAlgorithm asymmetricAlgorithm = algorithmObject as AsymmetricAlgorithm;
  167. SignatureDescription signatureDescription = algorithmObject as SignatureDescription;
  168. if (asymmetricAlgorithm != null || signatureDescription != null)
  169. return CryptoAlgorithmType.Asymmetric;
  170. return CryptoAlgorithmType.Unknown;
  171. }
  172. switch (algorithm)
  173. {
  174. case SecurityAlgorithms.DsaSha1Signature:
  175. case SecurityAlgorithms.RsaSha1Signature:
  176. case SecurityAlgorithms.RsaSha256Signature:
  177. case SecurityAlgorithms.RsaOaepKeyWrap:
  178. case SecurityAlgorithms.RsaV15KeyWrap:
  179. return CryptoAlgorithmType.Asymmetric;
  180. case SecurityAlgorithms.HmacSha1Signature:
  181. case SecurityAlgorithms.HmacSha256Signature:
  182. case SecurityAlgorithms.Aes128Encryption:
  183. case SecurityAlgorithms.Aes192Encryption:
  184. case SecurityAlgorithms.Aes256Encryption:
  185. case SecurityAlgorithms.TripleDesEncryption:
  186. case SecurityAlgorithms.Aes128KeyWrap:
  187. case SecurityAlgorithms.Aes192KeyWrap:
  188. case SecurityAlgorithms.Aes256KeyWrap:
  189. case SecurityAlgorithms.TripleDesKeyWrap:
  190. case SecurityAlgorithms.Psha1KeyDerivation:
  191. case SecurityAlgorithms.Psha1KeyDerivationDec2005:
  192. return CryptoAlgorithmType.Symmetric;
  193. default:
  194. return CryptoAlgorithmType.Unknown;
  195. }
  196. }
  197. internal static byte[] GenerateIVAndEncrypt(SymmetricAlgorithm algorithm, byte[] plainText, int offset, int count)
  198. {
  199. byte[] iv;
  200. byte[] cipherText;
  201. GenerateIVAndEncrypt(algorithm, new ArraySegment<byte>(plainText, offset, count), out iv, out cipherText);
  202. byte[] output = DiagnosticUtility.Utility.AllocateByteArray(checked(iv.Length + cipherText.Length));
  203. Buffer.BlockCopy(iv, 0, output, 0, iv.Length);
  204. Buffer.BlockCopy(cipherText, 0, output, iv.Length, cipherText.Length);
  205. return output;
  206. }
  207. internal static void GenerateIVAndEncrypt(SymmetricAlgorithm algorithm, ArraySegment<byte> plainText, out byte[] iv, out byte[] cipherText)
  208. {
  209. int ivSize = algorithm.BlockSize / 8;
  210. iv = new byte[ivSize];
  211. FillRandomBytes(iv);
  212. algorithm.Padding = PaddingMode.PKCS7;
  213. algorithm.Mode = CipherMode.CBC;
  214. using (ICryptoTransform encrTransform = algorithm.CreateEncryptor(algorithm.Key, iv))
  215. {
  216. cipherText = encrTransform.TransformFinalBlock(plainText.Array, plainText.Offset, plainText.Count);
  217. }
  218. }
  219. internal static bool IsEqual(byte[] a, byte[] b)
  220. {
  221. if (a == null || b == null || a.Length != b.Length)
  222. {
  223. return false;
  224. }
  225. for (int i = 0; i < a.Length; i++)
  226. {
  227. if (a[i] != b[i])
  228. {
  229. return false;
  230. }
  231. }
  232. return true;
  233. }
  234. internal static bool IsSymmetricAlgorithm(string algorithm)
  235. {
  236. return GetAlgorithmType(algorithm) == CryptoAlgorithmType.Symmetric;
  237. }
  238. internal static bool IsSymmetricSupportedAlgorithm(string algorithm, int keySize)
  239. {
  240. bool found = false;
  241. object algorithmObject = null;
  242. try
  243. {
  244. algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(algorithm);
  245. }
  246. catch (InvalidOperationException)
  247. {
  248. algorithmObject = null;
  249. // We ---- the exception and continue.
  250. }
  251. if (algorithmObject != null)
  252. {
  253. SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
  254. KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm;
  255. if (symmetricAlgorithm != null || keyedHashAlgorithm != null)
  256. found = true;
  257. }
  258. switch (algorithm)
  259. {
  260. case SecurityAlgorithms.DsaSha1Signature:
  261. case SecurityAlgorithms.RsaSha1Signature:
  262. case SecurityAlgorithms.RsaSha256Signature:
  263. case SecurityAlgorithms.RsaOaepKeyWrap:
  264. case SecurityAlgorithms.RsaV15KeyWrap:
  265. return false;
  266. case SecurityAlgorithms.HmacSha1Signature:
  267. case SecurityAlgorithms.HmacSha256Signature:
  268. case SecurityAlgorithms.Psha1KeyDerivation:
  269. case SecurityAlgorithms.Psha1KeyDerivationDec2005:
  270. return true;
  271. case SecurityAlgorithms.Aes128Encryption:
  272. case SecurityAlgorithms.Aes128KeyWrap:
  273. return keySize == 128;
  274. case SecurityAlgorithms.Aes192Encryption:
  275. case SecurityAlgorithms.Aes192KeyWrap:
  276. return keySize == 192;
  277. case SecurityAlgorithms.Aes256Encryption:
  278. case SecurityAlgorithms.Aes256KeyWrap:
  279. return keySize == 256;
  280. case SecurityAlgorithms.TripleDesEncryption:
  281. case SecurityAlgorithms.TripleDesKeyWrap:
  282. return keySize == 128 || keySize == 192;
  283. default:
  284. if (found)
  285. return true;
  286. return false;
  287. }
  288. }
  289. internal static void ValidateBufferBounds(Array buffer, int offset, int count)
  290. {
  291. if (buffer == null)
  292. {
  293. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("buffer"));
  294. }
  295. if (count < 0 || count > buffer.Length)
  296. {
  297. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeInRange, 0, buffer.Length)));
  298. }
  299. if (offset < 0 || offset > buffer.Length - count)
  300. {
  301. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeInRange, 0, buffer.Length - count)));
  302. }
  303. }
  304. internal static void ValidateSymmetricKeyLength(int keyLength, SecurityAlgorithmSuite algorithmSuite)
  305. {
  306. if (!algorithmSuite.IsSymmetricKeyLengthSupported(keyLength))
  307. {
  308. throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new ArgumentOutOfRangeException("algorithmSuite",
  309. SR.GetString(SR.UnsupportedKeyLength, keyLength, algorithmSuite.ToString())));
  310. }
  311. if (keyLength % 8 != 0)
  312. {
  313. throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new ArgumentOutOfRangeException("algorithmSuite",
  314. SR.GetString(SR.KeyLengthMustBeMultipleOfEight, keyLength)));
  315. }
  316. }
  317. }
  318. }