1 // ==++== 2 // 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // 5 // ==--== 6 7 using System; 8 using System.Diagnostics; 9 using System.Diagnostics.CodeAnalysis; 10 using System.Runtime.CompilerServices; 11 using System.Runtime.ConstrainedExecution; 12 using System.Runtime.InteropServices; 13 using System.Diagnostics.Contracts; 14 using Microsoft.Win32; 15 using Microsoft.Win32.SafeHandles; 16 using System.Security.Cryptography.X509Certificates; 17 18 namespace System.Security.Cryptography { 19 20 internal enum AsymmetricPaddingMode { 21 /// <summary> 22 /// No padding 23 /// </summary> 24 None = 1, // BCRYPT_PAD_NONE 25 26 /// <summary> 27 /// PKCS #1 padding 28 /// </summary> 29 Pkcs1 = 2, // BCRYPT_PAD_PKCS1 30 31 /// <summary> 32 /// Optimal Asymmetric Encryption Padding 33 /// </summary> 34 Oaep = 4, // BCRYPT_PAD_OAEP 35 36 /// <summary> 37 /// Probabilistic Signature Scheme padding 38 /// </summary> 39 Pss = 8 // BCRYPT_PAD_PSS 40 } 41 #if !MONO 42 [StructLayout(LayoutKind.Sequential)] 43 internal struct BCRYPT_DSA_KEY_BLOB_V2 44 { 45 public BCryptNative.KeyBlobMagicNumber dwMagic; // BCRYPT_DSA_PUBLIC_MAGIC_V2 or BCRYPT_DSA_PRIVATE_MAGIC_V2 46 public int cbKey; // key lengths in BYTES (e.g. for a 3072-bit key, cbKey = 3072/8 = 384) 47 public HASHALGORITHM_ENUM hashAlgorithm; 48 public DSAFIPSVERSION_ENUM standardVersion; 49 public int cbSeedLength; // size (in bytes) of the seed value 50 public int cbGroupSize; // size (in bytes) of the Q value 51 public byte Count3; // # of iterations used to generate Q. In big-endian format. 52 public byte Count2; 53 public byte Count1; 54 public byte Count0; 55 } 56 #endif 57 internal enum HASHALGORITHM_ENUM : int 58 { 59 DSA_HASH_ALGORITHM_SHA1 = 0, 60 DSA_HASH_ALGORITHM_SHA256 = 1, 61 DSA_HASH_ALGORITHM_SHA512 = 2, 62 } 63 64 internal enum DSAFIPSVERSION_ENUM : int 65 { 66 DSA_FIPS186_2 = 0, 67 DSA_FIPS186_3 = 1, 68 } 69 70 /// <summary> 71 /// Native interop with CNG's BCrypt layer. Native definitions can be found in bcrypt.h 72 /// </summary> 73 internal static class BCryptNative { 74 /// <summary> 75 /// Well known algorithm names 76 /// </summary> 77 internal static class AlgorithmName { 78 public const string ECDH = "ECDH"; // BCRYPT_ECDH_ALGORITHM 79 public const string ECDHP256 = "ECDH_P256"; // BCRYPT_ECDH_P256_ALGORITHM 80 public const string ECDHP384 = "ECDH_P384"; // BCRYPT_ECDH_P384_ALGORITHM 81 public const string ECDHP521 = "ECDH_P521"; // BCRYPT_ECDH_P521_ALGORITHM 82 public const string ECDsa = "ECDSA"; // BCRYPT_ECDSA_ALGORITHM 83 public const string ECDsaP256 = "ECDSA_P256"; // BCRYPT_ECDSA_P256_ALGORITHM 84 public const string ECDsaP384 = "ECDSA_P384"; // BCRYPT_ECDSA_P384_ALGORITHM 85 public const string ECDsaP521 = "ECDSA_P521"; // BCRYPT_ECDSA_P521_ALGORITHM 86 public const string MD5 = "MD5"; // BCRYPT_MD5_ALGORITHM 87 public const string Sha1 = "SHA1"; // BCRYPT_SHA1_ALGORITHM 88 public const string Sha256 = "SHA256"; // BCRYPT_SHA256_ALGORITHM 89 public const string Sha384 = "SHA384"; // BCRYPT_SHA384_ALGORITHM 90 public const string Sha512 = "SHA512"; // BCRYPT_SHA512_ALGORITHM 91 internal const string Rsa = "RSA"; // BCRYPT_RSA_ALGORITHM 92 } 93 #if !MONO 94 /// <summary> 95 /// Well known key blob tyes 96 /// </summary> 97 internal static class KeyBlobType { 98 //During Win8 Windows introduced BCRYPT_PUBLIC_KEY_BLOB L"PUBLICBLOB" 99 //and #define BCRYPT_PRIVATE_KEY_BLOB L"PRIVATEBLOB". We should use the 100 //same on ProjectN and ProjectK 101 internal const string RsaFullPrivateBlob = "RSAFULLPRIVATEBLOB"; // BCRYPT_RSAFULLPRIVATE_BLOB 102 internal const string RsaPrivateBlob = "RSAPRIVATEBLOB"; // BCRYPT_RSAPRIVATE_BLOB 103 internal const string RsaPublicBlob = "RSAPUBLICBLOB"; // BCRYPT_PUBLIC_KEY_BLOB 104 } 105 106 [StructLayout(LayoutKind.Sequential)] 107 internal struct BCRYPT_RSAKEY_BLOB { 108 internal KeyBlobMagicNumber Magic; 109 internal int BitLength; 110 internal int cbPublicExp; 111 internal int cbModulus; 112 internal int cbPrime1; 113 internal int cbPrime2; 114 } 115 116 /// <summary> 117 /// Result codes from BCrypt APIs 118 /// </summary> 119 internal enum ErrorCode { 120 Success = 0x00000000, // STATUS_SUCCESS 121 BufferToSmall = unchecked((int)0xC0000023), // STATUS_BUFFER_TOO_SMALL 122 ObjectNameNotFound = unchecked((int)0xC0000034) // SATUS_OBJECT_NAME_NOT_FOUND 123 } 124 125 /// <summary> 126 /// Well known BCrypt hash property names 127 /// </summary> 128 internal static class HashPropertyName { 129 public const string HashLength = "HashDigestLength"; // BCRYPT_HASH_LENGTH 130 } 131 132 /// <summary> 133 /// Magic numbers identifying blob types 134 /// </summary> 135 internal enum KeyBlobMagicNumber { 136 DsaPublic = 0x42505344, // BCRYPT_DSA_PUBLIC_MAGIC for key lengths <= 1024 bits 137 DsaPublicV2 = 0x32425044, // BCRYPT_DSA_PUBLIC_MAGIC_V2 for key lengths > 1024 bits 138 DsaPrivate = 0x56505344, // BCRYPT_DSA_PRIVATE_MAGIC for key lengths <= 1024 bits 139 DsaPrivateV2 = 0x32565044, // BCRYPT_DSA_PRIVATE_MAGIC_V2 for key lengths > 1024 bits 140 ECDHPublicP256 = 0x314B4345, // BCRYPT_ECDH_PUBLIC_P256_MAGIC 141 ECDHPublicP384 = 0x334B4345, // BCRYPT_ECDH_PUBLIC_P384_MAGIC 142 ECDHPublicP521 = 0x354B4345, // BCRYPT_ECDH_PUBLIC_P521_MAGIC 143 ECDsaPublicP256 = 0x31534345, // BCRYPT_ECDSA_PUBLIC_P256_MAGIC 144 ECDsaPublicP384 = 0x33534345, // BCRYPT_ECDSA_PUBLIC_P384_MAGIC 145 ECDsaPublicP521 = 0x35534345, // BCRYPT_ECDSA_PUBLIC_P521_MAGIC 146 RsaPublic = 0x31415352, // BCRYPT_RSAPUBLIC_MAGIC 147 RsaPrivate = 0x32415352, // BCRYPT_RSAPRIVATE_MAGIC 148 RsaFullPrivateMagic = 0x33415352, //BCRYPT_RSAFULLPRIVATE_MAGIC 149 KeyDataBlob = 0x4d42444b // BCRYPT_KEY_DATA_BLOB_MAGIC 150 } 151 152 [StructLayout(LayoutKind.Sequential)] 153 internal struct BCRYPT_OAEP_PADDING_INFO { 154 [MarshalAs(UnmanagedType.LPWStr)] 155 internal string pszAlgId; 156 157 internal IntPtr pbLabel; 158 159 internal int cbLabel; 160 } 161 162 [StructLayout(LayoutKind.Sequential)] 163 internal struct BCRYPT_PKCS1_PADDING_INFO { 164 [MarshalAs(UnmanagedType.LPWStr)] 165 internal string pszAlgId; 166 } 167 168 [StructLayout(LayoutKind.Sequential)] 169 internal struct BCRYPT_PSS_PADDING_INFO { 170 [MarshalAs(UnmanagedType.LPWStr)] 171 internal string pszAlgId; 172 173 internal int cbSalt; 174 } 175 176 [StructLayout(LayoutKind.Sequential)] 177 private struct BCRYPT_KEY_DATA_BLOB_HEADER 178 { 179 public uint dwMagic; 180 public uint dwVersion; 181 public uint cbKeyData; 182 183 public const uint BCRYPT_KEY_DATA_BLOB_MAGIC = 0x4d42444b; 184 public const uint BCRYPT_KEY_DATA_BLOB_VERSION1 = 0x1; 185 } 186 187 /// <summary> 188 /// Well known KDF names 189 /// </summary> 190 internal static class KeyDerivationFunction { 191 public const string Hash = "HASH"; // BCRYPT_KDF_HASH 192 public const string Hmac = "HMAC"; // BCRYPT_KDF_HMAC 193 public const string Tls = "TLS_PRF"; // BCRYPT_KDF_TLS_PRF 194 } 195 196 internal const string BCRYPT_ECCPUBLIC_BLOB = "ECCPUBLICBLOB"; 197 internal const string BCRYPT_ECCPRIVATE_BLOB = "ECCPRIVATEBLOB"; 198 199 internal const string BCRYPT_ECC_CURVE_NISTP256 = "nistP256"; 200 internal const string BCRYPT_ECC_CURVE_NISTP384 = "nistP384"; 201 internal const string BCRYPT_ECC_CURVE_NISTP521 = "nistP521"; 202 203 /// <summary> 204 /// Well known BCrypt provider names 205 /// </summary> 206 internal static class ProviderName { 207 public const string MicrosoftPrimitiveProvider = "Microsoft Primitive Provider"; // MS_PRIMITIVE_PROVIDER 208 } 209 210 /// <summary> 211 /// Well known BCrypt object property names 212 /// </summary> 213 internal static class ObjectPropertyName { 214 public const string ObjectLength = "ObjectLength"; // BCRYPT_OBJECT_LENGTH 215 } 216 217 #pragma warning disable 618 // Have not migrated to v4 transparency yet 218 [SecurityCritical(SecurityCriticalScope.Everything)] 219 #pragma warning restore 618 220 [SuppressUnmanagedCodeSecurity] 221 internal static class UnsafeNativeMethods { 222 /// <summary> 223 /// Create a hash object 224 /// </summary> 225 [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] BCryptCreateHash(SafeBCryptAlgorithmHandle hAlgorithm, [Out] out SafeBCryptHashHandle phHash, IntPtr pbHashObject, int cbHashObject, IntPtr pbSecret, int cbSecret, int dwFlags)226 internal static extern ErrorCode BCryptCreateHash(SafeBCryptAlgorithmHandle hAlgorithm, 227 [Out] out SafeBCryptHashHandle phHash, 228 IntPtr pbHashObject, 229 int cbHashObject, 230 IntPtr pbSecret, 231 int cbSecret, 232 int dwFlags); 233 234 /// <summary> 235 /// Get a property from a BCrypt algorithm object 236 /// </summary> 237 [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] BCryptGetProperty(SafeBCryptAlgorithmHandle hObject, string pszProperty, [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput, int cbOutput, [In, Out] ref int pcbResult, int flags)238 internal static extern ErrorCode BCryptGetProperty(SafeBCryptAlgorithmHandle hObject, 239 string pszProperty, 240 [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput, 241 int cbOutput, 242 [In, Out] ref int pcbResult, 243 int flags); 244 245 /// <summary> 246 /// Get a property from a BCrypt algorithm object 247 /// </summary> 248 [DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty", CharSet = CharSet.Unicode)] BCryptGetAlgorithmProperty(SafeBCryptAlgorithmHandle hObject, string pszProperty, [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput, int cbOutput, [In, Out] ref int pcbResult, int flags)249 internal static extern ErrorCode BCryptGetAlgorithmProperty(SafeBCryptAlgorithmHandle hObject, 250 string pszProperty, 251 [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput, 252 int cbOutput, 253 [In, Out] ref int pcbResult, 254 int flags); 255 256 /// <summary> 257 /// Get a property from a BCrypt hash object 258 /// </summary> 259 [DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty", CharSet = CharSet.Unicode)] BCryptGetHashProperty(SafeBCryptHashHandle hObject, string pszProperty, [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput, int cbOutput, [In, Out] ref int pcbResult, int flags)260 internal static extern ErrorCode BCryptGetHashProperty(SafeBCryptHashHandle hObject, 261 string pszProperty, 262 [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput, 263 int cbOutput, 264 [In, Out] ref int pcbResult, 265 int flags); 266 267 /// <summary> 268 /// Get the hash value of the data 269 /// </summary> 270 [DllImport("bcrypt.dll")] BCryptFinishHash(SafeBCryptHashHandle hHash, [MarshalAs(UnmanagedType.LPArray), Out] byte[] pbInput, int cbInput, int dwFlags)271 internal static extern ErrorCode BCryptFinishHash(SafeBCryptHashHandle hHash, 272 [MarshalAs(UnmanagedType.LPArray), Out] byte[] pbInput, 273 int cbInput, 274 int dwFlags); 275 276 /// <summary> 277 /// Hash a block of data 278 /// </summary> 279 [DllImport("bcrypt.dll")] BCryptHashData(SafeBCryptHashHandle hHash, [MarshalAs(UnmanagedType.LPArray), In] byte[] pbInput, int cbInput, int dwFlags)280 internal static extern ErrorCode BCryptHashData(SafeBCryptHashHandle hHash, 281 [MarshalAs(UnmanagedType.LPArray), In] byte[] pbInput, 282 int cbInput, 283 int dwFlags); 284 285 /// <summary> 286 /// Get a handle to an algorithm provider 287 /// </summary> 288 [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] BCryptOpenAlgorithmProvider([Out] out SafeBCryptAlgorithmHandle phAlgorithm, string pszAlgId, string pszImplementation, int dwFlags)289 internal static extern ErrorCode BCryptOpenAlgorithmProvider([Out] out SafeBCryptAlgorithmHandle phAlgorithm, 290 string pszAlgId, // BCryptAlgorithm 291 string pszImplementation, // ProviderNames 292 int dwFlags); 293 294 [DllImport("bcrypt.dll", SetLastError = true)] BCryptExportKey([In]SafeBCryptKeyHandle hKey, [In]IntPtr hExportKey, [In][MarshalAs(UnmanagedType.LPWStr)] string pszBlobType, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput, [In]int cbOutput, [In]ref int pcbResult, [In] int dwFlags)295 internal static extern ErrorCode BCryptExportKey([In]SafeBCryptKeyHandle hKey, 296 [In]IntPtr hExportKey, 297 [In][MarshalAs(UnmanagedType.LPWStr)] string pszBlobType, 298 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput, 299 [In]int cbOutput, 300 [In]ref int pcbResult, 301 [In] int dwFlags); 302 303 [DllImport("Crypt32.dll", SetLastError = true)] CryptImportPublicKeyInfoEx2([In] uint dwCertEncodingType, [In] ref X509Native.CERT_PUBLIC_KEY_INFO pInfo, [In] int dwFlags, [In] IntPtr pvAuxInfo, [Out] out SafeBCryptKeyHandle phKey)304 internal static extern int CryptImportPublicKeyInfoEx2([In] uint dwCertEncodingType, 305 [In] ref X509Native.CERT_PUBLIC_KEY_INFO pInfo, 306 [In] int dwFlags, 307 [In] IntPtr pvAuxInfo, 308 [Out] out SafeBCryptKeyHandle phKey); 309 310 [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] BCryptImportKey( SafeBCryptAlgorithmHandle hAlgorithm, IntPtr hImportKey, string pszBlobType, out SafeBCryptKeyHandle hKey, IntPtr pbKeyObject, int cbKeyObject, byte[] pbInput, int cbInput, int dwFlags)311 internal static extern ErrorCode BCryptImportKey( 312 SafeBCryptAlgorithmHandle hAlgorithm, 313 IntPtr hImportKey, 314 string pszBlobType, 315 out SafeBCryptKeyHandle hKey, 316 IntPtr pbKeyObject, 317 int cbKeyObject, 318 byte[] pbInput, 319 int cbInput, 320 int dwFlags); 321 322 [DllImport("bcrypt.dll", SetLastError = true)] BCryptEncrypt( SafeBCryptKeyHandle hKey, byte* pbInput, int cbInput, IntPtr paddingInfo, [In, Out] byte[] pbIV, int cbIV, byte* pbOutput, int cbOutput, out int cbResult, int dwFlags)323 public static extern unsafe ErrorCode BCryptEncrypt( 324 SafeBCryptKeyHandle hKey, 325 byte* pbInput, 326 int cbInput, 327 IntPtr paddingInfo, 328 [In, Out] byte[] pbIV, 329 int cbIV, 330 byte* pbOutput, 331 int cbOutput, 332 out int cbResult, 333 int dwFlags); 334 335 [DllImport("bcrypt.dll", SetLastError = true)] BCryptDecrypt( SafeBCryptKeyHandle hKey, byte* pbInput, int cbInput, IntPtr paddingInfo, [In, Out] byte[] pbIV, int cbIV, byte* pbOutput, int cbOutput, out int cbResult, int dwFlags)336 public static extern unsafe ErrorCode BCryptDecrypt( 337 SafeBCryptKeyHandle hKey, 338 byte* pbInput, 339 int cbInput, 340 IntPtr paddingInfo, 341 [In, Out] byte[] pbIV, 342 int cbIV, 343 byte* pbOutput, 344 int cbOutput, 345 out int cbResult, 346 int dwFlags); 347 348 [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] BCryptSetProperty( SafeBCryptAlgorithmHandle hObject, string pszProperty, string pbInput, int cbInput, int dwFlags)349 public static extern ErrorCode BCryptSetProperty( 350 SafeBCryptAlgorithmHandle hObject, 351 string pszProperty, 352 string pbInput, 353 int cbInput, 354 int dwFlags); 355 } 356 357 [SecuritySafeCritical] 358 internal static class AesBCryptModes 359 { 360 [SecurityCritical] 361 private static readonly SafeBCryptAlgorithmHandle s_hAlgCbc = OpenAesAlgorithm(Interop.BCrypt.BCRYPT_CHAIN_MODE_CBC); 362 363 [SecurityCritical] 364 private static readonly SafeBCryptAlgorithmHandle s_hAlgEcb = OpenAesAlgorithm(Interop.BCrypt.BCRYPT_CHAIN_MODE_ECB); 365 GetSharedHandle(CipherMode cipherMode)366 internal static SafeBCryptAlgorithmHandle GetSharedHandle(CipherMode cipherMode) 367 { 368 // Windows 8 added support to set the CipherMode value on a key, 369 // but Windows 7 requires that it be set on the algorithm before key creation. 370 switch (cipherMode) 371 { 372 case CipherMode.CBC: 373 return s_hAlgCbc; 374 case CipherMode.ECB: 375 return s_hAlgEcb; 376 default: 377 throw new NotSupportedException(); 378 } 379 } 380 OpenAesAlgorithm(string cipherMode)381 private static SafeBCryptAlgorithmHandle OpenAesAlgorithm(string cipherMode) 382 { 383 const string BCRYPT_AES_ALGORITHM = "AES"; 384 SafeBCryptAlgorithmHandle hAlg = OpenAlgorithm(BCRYPT_AES_ALGORITHM, null); 385 SetCipherMode(hAlg, cipherMode); 386 387 return hAlg; 388 } 389 } 390 391 [SecuritySafeCritical] 392 internal static class TripleDesBCryptModes 393 { 394 [SecurityCritical] 395 private static readonly SafeBCryptAlgorithmHandle s_hAlgCbc = OpenAesAlgorithm(Interop.BCrypt.BCRYPT_CHAIN_MODE_CBC); 396 397 [SecurityCritical] 398 private static readonly SafeBCryptAlgorithmHandle s_hAlgEcb = OpenAesAlgorithm(Interop.BCrypt.BCRYPT_CHAIN_MODE_ECB); 399 GetSharedHandle(CipherMode cipherMode)400 internal static SafeBCryptAlgorithmHandle GetSharedHandle(CipherMode cipherMode) 401 { 402 // Windows 8 added support to set the CipherMode value on a key, 403 // but Windows 7 requires that it be set on the algorithm before key creation. 404 switch (cipherMode) 405 { 406 case CipherMode.CBC: 407 return s_hAlgCbc; 408 case CipherMode.ECB: 409 return s_hAlgEcb; 410 default: 411 throw new NotSupportedException(); 412 } 413 } 414 OpenAesAlgorithm(string cipherMode)415 private static SafeBCryptAlgorithmHandle OpenAesAlgorithm(string cipherMode) 416 { 417 const string BCRYPT_3DES_ALGORITHM = "3DES"; 418 SafeBCryptAlgorithmHandle hAlg = OpenAlgorithm(BCRYPT_3DES_ALGORITHM, null); 419 SetCipherMode(hAlg, cipherMode); 420 421 return hAlg; 422 } 423 } 424 425 // 426 // Wrapper and utility functions 427 // 428 429 /// <summary> 430 /// Adapter to wrap specific BCryptGetProperty P/Invokes with a generic handle type 431 /// </summary> 432 #pragma warning disable 618 // System.Core.dll still uses SecurityRuleSet.Level1 433 [SecurityCritical(SecurityCriticalScope.Everything)] 434 #pragma warning restore 618 435 private delegate ErrorCode BCryptPropertyGetter<T>(T hObject, 436 string pszProperty, 437 byte[] pbOutput, 438 int cbOutput, 439 ref int pcbResult, 440 int dwFlags) where T : SafeHandle; 441 442 private static volatile bool s_haveBcryptSupported; 443 private static volatile bool s_bcryptSupported; 444 445 /// <summary> 446 /// Determine if BCrypt is supported on the current machine 447 /// </summary> 448 internal static bool BCryptSupported { 449 [SecuritySafeCritical] 450 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] 451 get { 452 if (!s_haveBcryptSupported) 453 { 454 // Attempt to load bcrypt.dll to see if the BCrypt CNG APIs are available on the machine 455 using (SafeLibraryHandle bcrypt = Microsoft.Win32.UnsafeNativeMethods.LoadLibraryEx("bcrypt", IntPtr.Zero, 0)) { 456 s_bcryptSupported = !bcrypt.IsInvalid; 457 s_haveBcryptSupported = true; 458 } 459 } 460 461 return s_bcryptSupported; 462 } 463 } 464 465 /// <summary> 466 /// Get the value of a DWORD property of a BCrypt object 467 /// </summary> 468 [System.Security.SecurityCritical] 469 internal static int GetInt32Property<T>(T algorithm, string property) where T : SafeHandle { 470 Contract.Requires(algorithm != null); 471 Contract.Requires(property == HashPropertyName.HashLength || 472 property == ObjectPropertyName.ObjectLength); 473 474 return BitConverter.ToInt32(GetProperty(algorithm, property), 0); 475 } 476 477 /// <summary> 478 /// Get the value of a property of a BCrypt object 479 /// </summary> 480 [System.Security.SecurityCritical] 481 internal static byte[] GetProperty<T>(T algorithm, string property) where T : SafeHandle { 482 Contract.Requires(algorithm != null); 483 Contract.Requires(!String.IsNullOrEmpty(property)); 484 Contract.Ensures(Contract.Result<byte[]>() != null); 485 486 BCryptPropertyGetter<T> getter = null; 487 if (typeof(T) == typeof(SafeBCryptAlgorithmHandle)) { 488 getter = new BCryptPropertyGetter<SafeBCryptAlgorithmHandle>(UnsafeNativeMethods.BCryptGetAlgorithmProperty) 489 as BCryptPropertyGetter<T>; 490 } 491 else if (typeof(T) == typeof(SafeBCryptHashHandle)) { 492 getter = new BCryptPropertyGetter<SafeBCryptHashHandle>(UnsafeNativeMethods.BCryptGetHashProperty) 493 as BCryptPropertyGetter<T>; 494 } 495 496 Debug.Assert(getter != null, "Unknown handle type"); 497 498 // Figure out how big the property is 499 int bufferSize = 0; 500 ErrorCode error = getter(algorithm, property, null, 0, ref bufferSize, 0); 501 502 if (error != ErrorCode.BufferToSmall && error != ErrorCode.Success) { 503 throw new CryptographicException((int)error); 504 } 505 506 // Allocate the buffer, and return the property 507 Debug.Assert(bufferSize > 0, "bufferSize > 0"); 508 byte[] buffer = new byte[bufferSize]; 509 error = getter(algorithm, property, buffer, buffer.Length, ref bufferSize, 0); 510 511 if (error != ErrorCode.Success) { 512 throw new CryptographicException((int)error); 513 } 514 515 return buffer; 516 } 517 518 519 /// <summary> 520 /// Map an algorithm identifier to a key size and magic number 521 /// </summary> MapAlgorithmIdToMagic(string algorithm, out KeyBlobMagicNumber algorithmMagic, out int keySize)522 internal static void MapAlgorithmIdToMagic(string algorithm, 523 out KeyBlobMagicNumber algorithmMagic, 524 out int keySize) { 525 Contract.Requires(!String.IsNullOrEmpty(algorithm)); 526 527 switch (algorithm) { 528 case AlgorithmName.ECDHP256: 529 algorithmMagic = KeyBlobMagicNumber.ECDHPublicP256; 530 keySize = 256; 531 break; 532 533 case AlgorithmName.ECDHP384: 534 algorithmMagic = KeyBlobMagicNumber.ECDHPublicP384; 535 keySize = 384; 536 break; 537 538 case AlgorithmName.ECDHP521: 539 algorithmMagic = KeyBlobMagicNumber.ECDHPublicP521; 540 keySize = 521; 541 break; 542 543 case AlgorithmName.ECDsaP256: 544 algorithmMagic = KeyBlobMagicNumber.ECDsaPublicP256; 545 keySize = 256; 546 break; 547 548 case AlgorithmName.ECDsaP384: 549 algorithmMagic = KeyBlobMagicNumber.ECDsaPublicP384; 550 keySize = 384; 551 break; 552 553 case AlgorithmName.ECDsaP521: 554 algorithmMagic = KeyBlobMagicNumber.ECDsaPublicP521; 555 keySize = 521; 556 break; 557 558 default: 559 throw new ArgumentException(SR.GetString(SR.Cryptography_UnknownEllipticCurveAlgorithm)); 560 } 561 } 562 563 /// <summary> 564 /// Open a handle to an algorithm provider 565 /// </summary> 566 [System.Security.SecurityCritical] OpenAlgorithm(string algorithm, string implementation)567 internal static SafeBCryptAlgorithmHandle OpenAlgorithm(string algorithm, string implementation) { 568 Contract.Requires(!String.IsNullOrEmpty(algorithm)); 569 Contract.Requires(!String.IsNullOrEmpty(implementation)); 570 Contract.Ensures(Contract.Result<SafeBCryptAlgorithmHandle>() != null && 571 !Contract.Result<SafeBCryptAlgorithmHandle>().IsInvalid && 572 !Contract.Result<SafeBCryptAlgorithmHandle>().IsClosed); 573 574 SafeBCryptAlgorithmHandle algorithmHandle = null; 575 ErrorCode error = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algorithmHandle, 576 algorithm, 577 implementation, 578 0); 579 580 if (error != ErrorCode.Success) { 581 throw new CryptographicException((int)error); 582 } 583 584 return algorithmHandle; 585 } 586 587 [SecuritySafeCritical] ImportAsymmetricPublicKey(X509Native.CERT_PUBLIC_KEY_INFO certPublicKeyInfo, int dwFlag)588 internal static SafeBCryptKeyHandle ImportAsymmetricPublicKey(X509Native.CERT_PUBLIC_KEY_INFO certPublicKeyInfo, int dwFlag) { 589 SafeBCryptKeyHandle keyHandle = null; 590 int error = UnsafeNativeMethods.CryptImportPublicKeyInfoEx2( 591 X509Native.X509_ASN_ENCODING, 592 ref certPublicKeyInfo, 593 dwFlag, 594 IntPtr.Zero, 595 out keyHandle); 596 if (error == 0) { 597 throw new CryptographicException(Marshal.GetLastWin32Error()); 598 } 599 return keyHandle; 600 } 601 602 [SecuritySafeCritical] ExportBCryptKey(SafeBCryptKeyHandle hKey, string blobType)603 internal static byte[] ExportBCryptKey(SafeBCryptKeyHandle hKey, string blobType) { 604 byte[] keyBlob = null; 605 int length = 0; 606 607 ErrorCode error = UnsafeNativeMethods.BCryptExportKey(hKey, IntPtr.Zero, blobType, null, 0, ref length, 0); 608 609 if (error != ErrorCode.BufferToSmall && error != ErrorCode.Success) 610 { 611 throw new CryptographicException(Marshal.GetLastWin32Error()); 612 } 613 614 keyBlob = new byte[length]; 615 error = UnsafeNativeMethods.BCryptExportKey(hKey, IntPtr.Zero, blobType, keyBlob, length, ref length, 0); 616 if (error != ErrorCode.Success) { 617 throw new CryptographicException(Marshal.GetLastWin32Error()); 618 } 619 return keyBlob; 620 } 621 622 623 [SecuritySafeCritical] BCryptImportKey(SafeBCryptAlgorithmHandle hAlg, byte[] key)624 internal static SafeBCryptKeyHandle BCryptImportKey(SafeBCryptAlgorithmHandle hAlg, byte[] key) 625 { 626 unsafe 627 { 628 const String BCRYPT_KEY_DATA_BLOB = "KeyDataBlob"; 629 int keySize = key.Length; 630 int blobSize = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) keySize; 631 byte[] blob = new byte[blobSize]; 632 fixed (byte* pbBlob = blob) 633 { 634 BCRYPT_KEY_DATA_BLOB_HEADER* pBlob = (BCRYPT_KEY_DATA_BLOB_HEADER*)pbBlob; 635 pBlob->dwMagic = BCRYPT_KEY_DATA_BLOB_HEADER.BCRYPT_KEY_DATA_BLOB_MAGIC; 636 pBlob->dwVersion = BCRYPT_KEY_DATA_BLOB_HEADER.BCRYPT_KEY_DATA_BLOB_VERSION1; 637 pBlob->cbKeyData = (uint)keySize; 638 } 639 Buffer.BlockCopy(key, 0, blob, sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), keySize); 640 SafeBCryptKeyHandle hKey; 641 642 ErrorCode error = UnsafeNativeMethods.BCryptImportKey( 643 hAlg, 644 IntPtr.Zero, 645 BCRYPT_KEY_DATA_BLOB, 646 out hKey, 647 IntPtr.Zero, 648 0, 649 blob, 650 blobSize, 651 0); 652 653 if (error != ErrorCode.Success) 654 throw new CryptographicException((int)error); 655 656 return hKey; 657 } 658 } 659 660 // Note: input and output are allowed to be the same buffer. 661 // BCryptEncrypt will correctly do the encryption in place according to CNG documentation. 662 [SecuritySafeCritical] BCryptEncrypt( SafeBCryptKeyHandle hKey, byte[] input, int inputOffset, int inputCount, byte[] iv, byte[] output, int outputOffset, int outputCount)663 public static int BCryptEncrypt( 664 SafeBCryptKeyHandle hKey, 665 byte[] input, 666 int inputOffset, 667 int inputCount, 668 byte[] iv, 669 byte[] output, 670 int outputOffset, 671 int outputCount) 672 { 673 Debug.Assert(input != null); 674 Debug.Assert(inputOffset >= 0); 675 Debug.Assert(inputCount >= 0); 676 Debug.Assert(inputCount <= input.Length - inputOffset); 677 Debug.Assert(output != null); 678 Debug.Assert(outputOffset >= 0); 679 Debug.Assert(outputCount >= 0); 680 Debug.Assert(outputCount <= output.Length - outputOffset); 681 682 unsafe 683 { 684 fixed (byte* pbInput = input) 685 { 686 fixed (byte* pbOutput = output) 687 { 688 int cbResult; 689 ErrorCode error = UnsafeNativeMethods.BCryptEncrypt( 690 hKey, 691 pbInput inputOffset, 692 inputCount, 693 IntPtr.Zero, 694 iv, 695 iv == null ? 0 : iv.Length, 696 pbOutput outputOffset, 697 outputCount, 698 out cbResult, 699 0); 700 701 if (error != ErrorCode.Success) 702 throw new CryptographicException((int)error); 703 704 return cbResult; 705 } 706 } 707 } 708 } 709 710 // Note: input and output are allowed to be the same buffer. 711 // BCryptDecrypt will correctly do the decryption in place according to CNG documentation. 712 [SecuritySafeCritical] BCryptDecrypt( SafeBCryptKeyHandle hKey, byte[] input, int inputOffset, int inputCount, byte[] iv, byte[] output, int outputOffset, int outputCount)713 public static int BCryptDecrypt( 714 SafeBCryptKeyHandle hKey, 715 byte[] input, 716 int inputOffset, 717 int inputCount, 718 byte[] iv, 719 byte[] output, 720 int outputOffset, 721 int outputCount) 722 { 723 Debug.Assert(input != null); 724 Debug.Assert(inputOffset >= 0); 725 Debug.Assert(inputCount >= 0); 726 Debug.Assert(inputCount <= input.Length - inputOffset); 727 Debug.Assert(output != null); 728 Debug.Assert(outputOffset >= 0); 729 Debug.Assert(outputCount >= 0); 730 Debug.Assert(outputCount <= output.Length - outputOffset); 731 732 unsafe 733 { 734 fixed (byte* pbInput = input) 735 { 736 fixed (byte* pbOutput = output) 737 { 738 int cbResult; 739 ErrorCode error = UnsafeNativeMethods.BCryptDecrypt( 740 hKey, 741 pbInput inputOffset, 742 inputCount, 743 IntPtr.Zero, 744 iv, 745 iv == null ? 0 : iv.Length, 746 pbOutput outputOffset, 747 outputCount, 748 out cbResult, 749 0); 750 751 if (error != ErrorCode.Success) 752 throw new CryptographicException((int)error); 753 754 return cbResult; 755 } 756 } 757 } 758 } 759 760 [SecurityCritical] SetCipherMode(SafeBCryptAlgorithmHandle hAlg, string cipherMode)761 public static void SetCipherMode(SafeBCryptAlgorithmHandle hAlg, string cipherMode) 762 { 763 const string BCRYPT_CHAINING_MODE = "ChainingMode"; 764 765 ErrorCode error = UnsafeNativeMethods.BCryptSetProperty( 766 hAlg, 767 BCRYPT_CHAINING_MODE, 768 cipherMode, 769 // Explicit \0 terminator, UCS-2 770 (cipherMode.Length 1) * 2, 771 0); 772 773 if (error != ErrorCode.Success) 774 { 775 throw new CryptographicException((int)error); 776 } 777 } 778 #endif 779 } 780 } 781