1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using Internal.Cryptography; 6 using Microsoft.Win32.SafeHandles; 7 using System; 8 using System.Diagnostics; 9 using System.IO; 10 using System.Reflection; 11 using System.Runtime.InteropServices; 12 using System.Security.Cryptography; 13 using System.Text; 14 using static Interop.Crypt32; 15 using Libraries = Interop.Libraries; 16 using CryptProvParam = global::Interop.Advapi32.CryptProvParam; 17 18 namespace Internal.NativeCrypto 19 { 20 /// <summary> 21 /// Following part of CAPIHelper keeps the wrappers for all the PInvoke calls 22 /// </summary> 23 internal static partial class CapiHelper 24 { 25 private static readonly byte[] s_RgbPubKey = 26 { 27 0x06, 0x02, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 28 0x52, 0x53, 0x41, 0x31, 0x00, 0x02, 0x00, 0x00, 29 0x01, 0x00, 0x00, 0x00, 0xab, 0xef, 0xfa, 0xc6, 30 0x7d, 0xe8, 0xde, 0xfb, 0x68, 0x38, 0x09, 0x92, 31 0xd9, 0x42, 0x7e, 0x6b, 0x89, 0x9e, 0x21, 0xd7, 32 0x52, 0x1c, 0x99, 0x3c, 0x17, 0x48, 0x4e, 0x3a, 33 0x44, 0x02, 0xf2, 0xfa, 0x74, 0x57, 0xda, 0xe4, 34 0xd3, 0xc0, 0x35, 0x67, 0xfa, 0x6e, 0xdf, 0x78, 35 0x4c, 0x75, 0x35, 0x1c, 0xa0, 0x74, 0x49, 0xe3, 36 0x20, 0x13, 0x71, 0x35, 0x65, 0xdf, 0x12, 0x20, 37 0xf5, 0xf5, 0xf5, 0xc1 38 }; 39 40 /// <summary> 41 /// Check to see if a better CSP than the one requested is available 42 /// RSA providers are supersets of each other in the following order: 43 /// 1. MS_ENH_RSA_AES_PROV 44 /// 2. MS_ENHANCED_PROV 45 /// 3. MS_DEF_PROV 46 /// 47 /// This will return the best provider which is a superset of wszProvider, 48 /// or NULL if there is no upgrade available on the machine. 49 /// </summary> 50 /// <param name="dwProvType">Provider type</param> 51 /// <param name="wszProvider">Provider name</param> 52 /// <returns>Returns upgrade CSP name</returns> UpgradeRSA(int dwProvType, string wszProvider)53 public static string UpgradeRSA(int dwProvType, string wszProvider) 54 { 55 bool requestedEnhanced = string.Equals(wszProvider, MS_ENHANCED_PROV, StringComparison.Ordinal); 56 bool requestedBase = string.Equals(wszProvider, MS_DEF_PROV, StringComparison.Ordinal); 57 string wszUpgrade = null; 58 if (requestedBase || requestedEnhanced) 59 { 60 SafeProvHandle safeProvHandle; 61 62 // attempt to use the AES provider 63 if (S_OK == AcquireCryptContext(out safeProvHandle, null, MS_ENH_RSA_AES_PROV, 64 dwProvType, (uint)CryptAcquireContextFlags.CRYPT_VERIFYCONTEXT)) 65 { 66 wszUpgrade = MS_ENH_RSA_AES_PROV; 67 } 68 69 safeProvHandle.Dispose(); 70 } 71 72 return wszUpgrade; 73 } 74 75 /// <summary> 76 /// Find the default provider name to be used in the case that we 77 /// were not actually passed in a provider name. The main purpose 78 /// of this code is really to deal with the enhanced/default provider 79 /// problems given to us by CAPI. 80 /// </summary> 81 /// <param name="dwType">Type of the provider</param> 82 /// <returns>Name of the provider to be used</returns> GetDefaultProvider(int dwType)83 internal static string GetDefaultProvider(int dwType) 84 { 85 int sizeofProviderName = 0; 86 //Get the size of the provider name 87 if (!Interop.CryptGetDefaultProvider(dwType, IntPtr.Zero, 88 (int)GetDefaultProviderFlags.CRYPT_MACHINE_DEFAULT, 89 null, ref sizeofProviderName)) 90 { 91 throw GetErrorCode().ToCryptographicException(); 92 } 93 //allocate memory for the provider name 94 StringBuilder providerName = new StringBuilder((int)sizeofProviderName); 95 96 //Now call the function CryptGetDefaultProvider again to get the name of the provider 97 if (!Interop.CryptGetDefaultProvider(dwType, IntPtr.Zero, 98 (int)GetDefaultProviderFlags.CRYPT_MACHINE_DEFAULT, 99 providerName, ref sizeofProviderName)) 100 { 101 throw GetErrorCode().ToCryptographicException(); 102 } 103 // check to see if there are upgrades available for the requested CSP 104 string wszUpgrade = null; 105 if (dwType == (int)ProviderType.PROV_RSA_FULL) 106 { 107 wszUpgrade = UpgradeRSA(dwType, providerName.ToString()); 108 } 109 else if (dwType == (int)ProviderType.PROV_DSS_DH) 110 { 111 wszUpgrade = UpgradeDSS(dwType, providerName.ToString()); 112 } 113 if (null != wszUpgrade) 114 { 115 //Overwrite the provider name with the upgraded provider name 116 providerName = new StringBuilder(wszUpgrade); 117 } 118 return providerName.ToString(); 119 } 120 121 /// <summary> 122 /// Creates a new key container 123 /// </summary> CreateCSP(CspParameters parameters, bool randomKeyContainer, out SafeProvHandle safeProvHandle)124 private static void CreateCSP(CspParameters parameters, bool randomKeyContainer, out SafeProvHandle safeProvHandle) 125 { 126 uint dwFlags = (uint)CryptAcquireContextFlags.CRYPT_NEWKEYSET; 127 if (randomKeyContainer) 128 { 129 dwFlags |= (uint)CryptAcquireContextFlags.CRYPT_VERIFYCONTEXT; 130 } 131 132 SafeProvHandle hProv; 133 int ret = OpenCSP(parameters, dwFlags, out hProv); 134 if (S_OK != ret) 135 { 136 hProv.Dispose(); 137 throw ret.ToCryptographicException(); 138 } 139 safeProvHandle = hProv; 140 } 141 142 /// <summary> 143 /// Acquire a handle to a crypto service provider and optionally a key container 144 /// This function implements the WszCryptAcquireContext_SO_TOLERANT 145 /// </summary> AcquireCryptContext(out SafeProvHandle safeProvHandle, string keyContainer, string providerName, int providerType, uint flags)146 private static int AcquireCryptContext(out SafeProvHandle safeProvHandle, string keyContainer, 147 string providerName, int providerType, uint flags) 148 { 149 const uint VerifyContextFlag = (uint)CryptAcquireContextFlags.CRYPT_VERIFYCONTEXT; 150 const uint MachineContextFlag = (uint)CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET; 151 152 int ret = S_OK; 153 // Specifying both verify context (for an ephemeral key) and machine keyset (for a persisted machine key) 154 // does not make sense. Additionally, Windows is beginning to lock down against uses of MACHINE_KEYSET 155 // (for instance in the app container), even if verify context is present. Therefore, if we're using 156 // an ephemeral key, strip out MACHINE_KEYSET from the flags. 157 if (((flags & VerifyContextFlag) == VerifyContextFlag) && 158 ((flags & MachineContextFlag) == MachineContextFlag)) 159 { 160 flags &= ~MachineContextFlag; 161 } 162 //Do not throw in this function. Just return the error code 163 if (!Interop.CryptAcquireContext(out safeProvHandle, keyContainer, providerName, providerType, flags)) 164 { 165 ret = GetErrorCode(); 166 } 167 168 return ret; 169 } 170 171 /// <summary> 172 /// Acquire a handle to a crypto service provider and optionally a key container 173 /// </summary> CryptAcquireContext(out SafeProvHandle psafeProvHandle, string pszContainer, string pszProvider, int dwProvType, uint dwFlags)174 public static bool CryptAcquireContext(out SafeProvHandle psafeProvHandle, string pszContainer, string pszProvider, int dwProvType, uint dwFlags) 175 { 176 return Interop.CryptAcquireContext(out psafeProvHandle, pszContainer, pszProvider, dwProvType, dwFlags); 177 } 178 179 /// <summary> 180 /// This method opens the CSP using CRYPT_VERIFYCONTEXT 181 /// KeyContainer must be null for the flag CRYPT_VERIFYCONTEXT 182 /// This method asserts if keyContainer is not null 183 /// </summary> 184 /// <param name="cspParameters">CSPParameter to use</param> 185 /// <param name="safeProvHandle">Safe provider handle</param> AcquireCsp(CspParameters cspParameters, out SafeProvHandle safeProvHandle)186 internal static void AcquireCsp(CspParameters cspParameters, out SafeProvHandle safeProvHandle) 187 { 188 Debug.Assert(cspParameters != null); 189 Debug.Assert(cspParameters.KeyContainerName == null); 190 191 SafeProvHandle hProv; 192 // 193 // We want to just open this CSP. Passing in verify context will 194 // open it and, if a container is given, map to open the container. 195 // 196 int ret = OpenCSP(cspParameters, (uint)CryptAcquireContextFlags.CRYPT_VERIFYCONTEXT, out hProv); 197 if (S_OK != ret) 198 { 199 hProv.Dispose(); 200 throw ret.ToCryptographicException(); 201 } 202 203 safeProvHandle = hProv; 204 } 205 206 /// <summary> 207 /// OpenCSP performs the core work of opening and creating CSPs and containers in CSPs 208 /// </summary> OpenCSP(CspParameters cspParameters, uint flags, out SafeProvHandle safeProvHandle)209 public static int OpenCSP(CspParameters cspParameters, uint flags, out SafeProvHandle safeProvHandle) 210 { 211 string providerName = null; 212 string containerName = null; 213 if (null == cspParameters) 214 { 215 throw new ArgumentException(SR.Format(SR.CspParameter_invalid, nameof(cspParameters))); 216 } 217 218 //look for provider type in the cspParameters 219 int providerType = cspParameters.ProviderType; 220 221 //look for provider name in the cspParamters 222 //if CSP provider is not null then use the provider name from cspParameters 223 if (null != cspParameters.ProviderName) 224 { 225 providerName = cspParameters.ProviderName; 226 } 227 else //Get the default provider name 228 { 229 providerName = GetDefaultProvider(providerType); 230 cspParameters.ProviderName = providerName; 231 } 232 // look to see if the user specified that we should pass 233 // CRYPT_MACHINE_KEYSET to CAPI to use machine key storage instead 234 // of user key storage 235 int cspProviderFlags = (int)cspParameters.Flags; 236 237 // If the user specified CSP_PROVIDER_FLAGS_USE_DEFAULT_KEY_CONTAINER, 238 // then ignore the key container name and hand back the default container 239 if (!IsFlagBitSet((uint)cspProviderFlags, (uint)CspProviderFlags.UseDefaultKeyContainer)) 240 { 241 //look for key container name in the cspParameters 242 if (null != cspParameters.KeyContainerName) 243 { 244 containerName = cspParameters.KeyContainerName; 245 } 246 } 247 248 SafeProvHandle hProv; 249 250 // Go ahead and try to open the CSP. If we fail, make sure the CSP 251 // returned is 0 as that is going to be the error check in the caller. 252 flags |= MapCspProviderFlags((int)cspParameters.Flags); 253 int hr = AcquireCryptContext(out hProv, containerName, providerName, providerType, flags); 254 if (hr != S_OK) 255 { 256 hProv.Dispose(); 257 safeProvHandle = SafeProvHandle.InvalidHandle; 258 return hr; 259 } 260 261 hProv.ContainerName = containerName; 262 hProv.ProviderName = providerName; 263 hProv.Types = providerType; 264 hProv.Flags = flags; 265 266 // We never want to delete a key container if it's already there. 267 if (IsFlagBitSet(flags, (uint)CryptAcquireContextFlags.CRYPT_VERIFYCONTEXT)) 268 { 269 hProv.PersistKeyInCsp = false; 270 } 271 272 safeProvHandle = hProv; 273 return S_OK; 274 } 275 276 /// <summary> 277 /// This method acquires CSP and returns the handle of CSP 278 /// </summary> 279 /// <param name="parameters">Accepts the CSP Parameters</param> 280 /// <param name="randomKeyContainer">Bool to indicate if key needs to be persisted</param> 281 /// <returns>Returns the safehandle of CSP </returns> CreateProvHandle(CspParameters parameters, bool randomKeyContainer)282 internal static SafeProvHandle CreateProvHandle(CspParameters parameters, bool randomKeyContainer) 283 { 284 SafeProvHandle safeProvHandle; 285 uint flag = 0; 286 uint hr = unchecked((uint)OpenCSP(parameters, flag, out safeProvHandle)); 287 //Open container failed 288 if (hr != S_OK) 289 { 290 safeProvHandle.Dispose(); 291 // If UseExistingKey flag is used and the key container does not exist 292 // throw an exception without attempting to create the container. 293 if (IsFlagBitSet((uint)parameters.Flags, (uint)CspProviderFlags.UseExistingKey) || 294 ((hr != (uint)CryptKeyError.NTE_KEYSET_NOT_DEF && hr != 295 (uint)CryptKeyError.NTE_BAD_KEYSET && hr != 296 (uint)CryptKeyError.NTE_FILENOTFOUND))) 297 { 298 throw ((int)hr).ToCryptographicException(); 299 } 300 301 //Create a new CSP. This method throws exception on failure 302 CreateCSP(parameters, randomKeyContainer, out safeProvHandle); 303 } 304 305 if (parameters.ParentWindowHandle != IntPtr.Zero) 306 { 307 IntPtr parentWindowHandle = parameters.ParentWindowHandle; 308 309 if (!Interop.CryptSetProvParamIndirectPtr(safeProvHandle, CryptProvParam.PP_CLIENT_HWND, ref parentWindowHandle, 0)) 310 { 311 throw GetErrorCode().ToCryptographicException(); 312 } 313 } 314 315 if (parameters.KeyPassword != null) 316 { 317 IntPtr password = Marshal.SecureStringToCoTaskMemAnsi(parameters.KeyPassword); 318 try 319 { 320 CryptProvParam param = 321 (parameters.KeyNumber == (int)KeySpec.AT_SIGNATURE) ? 322 CryptProvParam.PP_SIGNATURE_PIN : 323 CryptProvParam.PP_KEYEXCHANGE_PIN; 324 if (!Interop.CryptSetProvParam(safeProvHandle, param, password, 0)) 325 { 326 throw GetErrorCode().ToCryptographicException(); 327 } 328 } 329 finally 330 { 331 if (password != IntPtr.Zero) 332 { 333 Marshal.ZeroFreeCoTaskMemAnsi(password); 334 } 335 } 336 } 337 338 return safeProvHandle; 339 } 340 341 /// <summary> 342 /// This method validates the flag bits set or not. Only works for flags with just one bit set 343 /// </summary> 344 /// <param name="dwImp">int where you want to check the flag bits</param> 345 /// <param name="flag">Actual flag</param> 346 /// <returns>true if bits are set or false</returns> IsFlagBitSet(uint dwImp, uint flag)347 internal static bool IsFlagBitSet(uint dwImp, uint flag) 348 { 349 return (dwImp & flag) == flag; 350 } 351 352 /// <summary> 353 /// This method helps reduce the duplicate code in the GetProviderParameter method 354 /// </summary> GetProviderParameterWorker(SafeProvHandle safeProvHandle, byte[] impType, ref int cb, CryptProvParam flags)355 internal static int GetProviderParameterWorker(SafeProvHandle safeProvHandle, byte[] impType, ref int cb, CryptProvParam flags) 356 { 357 int impTypeReturn = 0; 358 if (!Interop.CryptGetProvParam(safeProvHandle, flags, impType, ref cb, 0)) 359 { 360 throw GetErrorCode().ToCryptographicException(); 361 } 362 if (null != impType && cb == Constants.SIZE_OF_DWORD) 363 { 364 impTypeReturn = BitConverter.ToInt32(impType, 0); 365 } 366 return impTypeReturn; 367 } 368 369 /// <summary> 370 /// This method queries the key container and get some of it's properties. 371 /// Those properties should never cause UI to display. 372 /// </summary> GetProviderParameter(SafeProvHandle safeProvHandle, int keyNumber, int keyParam)373 public static object GetProviderParameter(SafeProvHandle safeProvHandle, int keyNumber, int keyParam) 374 { 375 VerifyValidHandle(safeProvHandle); 376 byte[] impType = new byte[Constants.SIZE_OF_DWORD]; 377 int cb = sizeof(byte) * Constants.SIZE_OF_DWORD; 378 SafeKeyHandle safeKeyHandle = SafeKeyHandle.InvalidHandle; 379 int impTypeReturn = 0; 380 int returnType = 0; //using 0 for bool and 1 for string return types 381 bool retVal = false; 382 string retStr = null; 383 384 try 385 { 386 switch (keyParam) 387 { 388 case Constants.CLR_EXPORTABLE: 389 { 390 impTypeReturn = GetProviderParameterWorker(safeProvHandle, impType, ref cb, CryptProvParam.PP_IMPTYPE); 391 //If implementation type is not HW 392 if (!IsFlagBitSet((uint)impTypeReturn, (uint)CryptGetProvParamPPImpTypeFlags.CRYPT_IMPL_HARDWARE)) 393 { 394 if (!Interop.CryptGetUserKey(safeProvHandle, keyNumber, out safeKeyHandle)) 395 { 396 throw GetErrorCode().ToCryptographicException(); 397 } 398 byte[] permissions = null; 399 int permissionsReturn = 0; 400 permissions = new byte[Constants.SIZE_OF_DWORD]; 401 cb = sizeof(byte) * Constants.SIZE_OF_DWORD; 402 if (!Interop.CryptGetKeyParam(safeKeyHandle, (int)CryptGetKeyParamFlags.KP_PERMISSIONS, permissions, ref cb, 0)) 403 { 404 throw GetErrorCode().ToCryptographicException(); 405 } 406 permissionsReturn = BitConverter.ToInt32(permissions, 0); 407 retVal = IsFlagBitSet((uint)permissionsReturn, (uint)CryptGetKeyParamFlags.CRYPT_EXPORT); 408 } 409 else 410 { 411 //Assumption HW keys are not exportable. 412 retVal = false; 413 } 414 415 break; 416 } 417 case Constants.CLR_REMOVABLE: 418 { 419 impTypeReturn = GetProviderParameterWorker(safeProvHandle, impType, ref cb, CryptProvParam.PP_IMPTYPE); 420 retVal = IsFlagBitSet((uint)impTypeReturn, (uint)CryptGetProvParamPPImpTypeFlags.CRYPT_IMPL_REMOVABLE); 421 break; 422 } 423 case Constants.CLR_HARDWARE: 424 case Constants.CLR_PROTECTED: 425 { 426 impTypeReturn = GetProviderParameterWorker(safeProvHandle, impType, ref cb, CryptProvParam.PP_IMPTYPE); 427 retVal = IsFlagBitSet((uint)impTypeReturn, (uint)CryptGetProvParamPPImpTypeFlags.CRYPT_IMPL_HARDWARE); 428 break; 429 } 430 case Constants.CLR_ACCESSIBLE: 431 { 432 retVal = Interop.CryptGetUserKey(safeProvHandle, keyNumber, out safeKeyHandle) ? true : false; 433 break; 434 } 435 case Constants.CLR_UNIQUE_CONTAINER: 436 { 437 returnType = 1; 438 byte[] pb = null; 439 impTypeReturn = GetProviderParameterWorker(safeProvHandle, pb, ref cb, CryptProvParam.PP_UNIQUE_CONTAINER); 440 pb = new byte[cb]; 441 impTypeReturn = GetProviderParameterWorker(safeProvHandle, pb, ref cb, CryptProvParam.PP_UNIQUE_CONTAINER); 442 // GetProviderParameterWorker allocated the null character, we want to not interpret that. 443 Debug.Assert(cb > 0); 444 Debug.Assert(pb[cb - 1] == 0); 445 retStr = Encoding.ASCII.GetString(pb, 0, cb - 1); 446 break; 447 } 448 default: 449 { 450 Debug.Assert(false); 451 break; 452 } 453 } 454 } 455 finally 456 { 457 safeKeyHandle.Dispose(); 458 } 459 460 Debug.Assert(returnType == 0 || returnType == 1); 461 return returnType == 0 ? (object)retVal : retStr; 462 } 463 464 /// <summary> 465 /// Retrieves the handle for user public / private key pair. 466 /// </summary> GetUserKey(SafeProvHandle safeProvHandle, int keySpec, out SafeKeyHandle safeKeyHandle)467 internal static int GetUserKey(SafeProvHandle safeProvHandle, int keySpec, out SafeKeyHandle safeKeyHandle) 468 { 469 int hr = S_OK; 470 VerifyValidHandle(safeProvHandle); 471 if (!Interop.CryptGetUserKey(safeProvHandle, keySpec, out safeKeyHandle)) 472 { 473 hr = GetErrorCode(); 474 } 475 if (hr == S_OK) 476 { 477 safeKeyHandle.KeySpec = keySpec; 478 } 479 return hr; 480 } 481 482 /// <summary> 483 /// Generates the key if provided CSP handle is valid 484 /// </summary> GenerateKey(SafeProvHandle safeProvHandle, int algID, int flags, uint keySize, out SafeKeyHandle safeKeyHandle)485 internal static int GenerateKey(SafeProvHandle safeProvHandle, int algID, int flags, uint keySize, out SafeKeyHandle safeKeyHandle) 486 { 487 int hr = S_OK; 488 VerifyValidHandle(safeProvHandle); 489 int capiFlags = (int)((uint)MapCspKeyFlags(flags) | ((uint)keySize << 16)); 490 if (!Interop.CryptGenKey(safeProvHandle, algID, capiFlags, out safeKeyHandle)) 491 { 492 hr = GetErrorCode(); 493 } 494 if (hr != S_OK) 495 { 496 throw GetErrorCode().ToCryptographicException(); 497 } 498 499 safeKeyHandle.KeySpec = algID; 500 return hr; 501 } 502 503 /// <summary> 504 /// Maps CspProviderFlags enumeration into CAPI flags. 505 /// </summary> MapCspKeyFlags(int flags)506 internal static int MapCspKeyFlags(int flags) 507 { 508 int capiFlags = 0; 509 if (!IsFlagBitSet((uint)flags, (uint)CspProviderFlags.UseNonExportableKey)) 510 { 511 capiFlags |= (int)CryptGenKeyFlags.CRYPT_EXPORTABLE; 512 } 513 if (IsFlagBitSet((uint)flags, (uint)CspProviderFlags.UseArchivableKey)) 514 { 515 capiFlags |= (int)CryptGenKeyFlags.CRYPT_ARCHIVABLE; 516 } 517 if (IsFlagBitSet((uint)flags, (uint)CspProviderFlags.UseUserProtectedKey)) 518 { 519 capiFlags |= (int)CryptGenKeyFlags.CRYPT_USER_PROTECTED; 520 } 521 return capiFlags; 522 } 523 524 /// <summary> 525 ///Maps CspProviderFlags enumeration into CAPI flags 526 /// </summary> MapCspProviderFlags(int flags)527 internal static uint MapCspProviderFlags(int flags) 528 { 529 uint cspFlags = 0; 530 531 if (IsFlagBitSet((uint)flags, (uint)CspProviderFlags.UseMachineKeyStore)) 532 { 533 cspFlags |= (uint)CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET; 534 } 535 if (IsFlagBitSet((uint)flags, (uint)CspProviderFlags.NoPrompt)) 536 { 537 cspFlags |= (uint)CryptAcquireContextFlags.CRYPT_SILENT; 538 } 539 if (IsFlagBitSet((uint)flags, (uint)CspProviderFlags.CreateEphemeralKey)) 540 { 541 cspFlags |= (uint)CryptAcquireContextFlags.CRYPT_VERIFYCONTEXT; 542 } 543 return cspFlags; 544 } 545 546 /// <summary> 547 /// This method checks if the handle is invalid then it throws error 548 /// </summary> 549 /// <param name="handle">Accepts handle</param> VerifyValidHandle(SafeHandleZeroOrMinusOneIsInvalid handle)550 internal static void VerifyValidHandle(SafeHandleZeroOrMinusOneIsInvalid handle) 551 { 552 if (handle.IsInvalid) 553 { 554 throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); 555 } 556 } 557 558 /// <summary> 559 ///Method helps get the different key properties 560 /// </summary> 561 /// <param name="safeKeyHandle">Key handle</param> 562 /// <param name="keyParam"> Key property you want to get</param> 563 /// <returns>Returns the key property</returns> GetKeyParameter(SafeKeyHandle safeKeyHandle, int keyParam)564 internal static byte[] GetKeyParameter(SafeKeyHandle safeKeyHandle, int keyParam) 565 { 566 byte[] pb = null; 567 int cb = 0; 568 VerifyValidHandle(safeKeyHandle); //This will throw if handle is invalid 569 570 switch (keyParam) 571 { 572 case Constants.CLR_KEYLEN: 573 { 574 if (!Interop.CryptGetKeyParam(safeKeyHandle, (int)CryptGetKeyParamQueryType.KP_KEYLEN, null, ref cb, 0)) 575 { 576 throw GetErrorCode().ToCryptographicException(); 577 } 578 pb = new byte[cb]; 579 if (!Interop.CryptGetKeyParam(safeKeyHandle, (int)CryptGetKeyParamQueryType.KP_KEYLEN, pb, ref cb, 0)) 580 { 581 throw GetErrorCode().ToCryptographicException(); 582 } 583 break; 584 } 585 case Constants.CLR_PUBLICKEYONLY: 586 { 587 pb = new byte[1]; 588 pb[0] = safeKeyHandle.PublicOnly ? (byte)1 : (byte)0; 589 break; 590 } 591 case Constants.CLR_ALGID: 592 { 593 // returns the algorithm ID for the key 594 if (!Interop.CryptGetKeyParam(safeKeyHandle, (int)CryptGetKeyParamQueryType.KP_ALGID, null, ref cb, 0)) 595 { 596 throw GetErrorCode().ToCryptographicException(); 597 } 598 pb = new byte[cb]; 599 if (!Interop.CryptGetKeyParam(safeKeyHandle, (int)CryptGetKeyParamQueryType.KP_ALGID, pb, ref cb, 0)) 600 { 601 throw GetErrorCode().ToCryptographicException(); 602 } 603 break; 604 } 605 default: 606 { 607 Debug.Assert(false); 608 break; 609 } 610 } 611 return pb; 612 } 613 614 /// <summary> 615 /// Set a key property which is based on byte[] 616 /// </summary> 617 /// <param name="safeKeyHandle">Key handle</param> 618 /// <param name="keyParam"> Key property you want to set</param> 619 /// <param name="value"> Key property value you want to set</param> SetKeyParameter(SafeKeyHandle safeKeyHandle, CryptGetKeyParamQueryType keyParam, byte[] value)620 internal static void SetKeyParameter(SafeKeyHandle safeKeyHandle, CryptGetKeyParamQueryType keyParam, byte[] value) 621 { 622 VerifyValidHandle(safeKeyHandle); //This will throw if handle is invalid 623 624 switch (keyParam) 625 { 626 case CryptGetKeyParamQueryType.KP_IV: 627 if (!Interop.CryptSetKeyParam(safeKeyHandle, (int)keyParam, value, 0)) 628 throw new CryptographicException(SR.CryptSetKeyParam_Failed, Convert.ToString(GetErrorCode())); 629 630 break; 631 default: 632 Debug.Fail("Unknown param in SetKeyParameter"); 633 break; 634 } 635 } 636 637 /// <summary> 638 /// Set a key property which is based on int 639 /// </summary> 640 /// <param name="safeKeyHandle">Key handle</param> 641 /// <param name="keyParam"> Key property you want to set</param> 642 /// <param name="value"> Key property value you want to set</param> SetKeyParameter(SafeKeyHandle safeKeyHandle, CryptGetKeyParamQueryType keyParam, int value)643 internal static void SetKeyParameter(SafeKeyHandle safeKeyHandle, CryptGetKeyParamQueryType keyParam, int value) 644 { 645 VerifyValidHandle(safeKeyHandle); //This will throw if handle is invalid 646 647 switch (keyParam) 648 { 649 case CryptGetKeyParamQueryType.KP_MODE: 650 case CryptGetKeyParamQueryType.KP_MODE_BITS: 651 case CryptGetKeyParamQueryType.KP_EFFECTIVE_KEYLEN: 652 if (! Interop.CryptSetKeyParamInt(safeKeyHandle, (int)keyParam, ref value, 0)) 653 throw new CryptographicException(SR.CryptSetKeyParam_Failed, Convert.ToString(GetErrorCode())); 654 655 break; 656 default: 657 Debug.Fail("Unknown param in SetKeyParameter"); 658 break; 659 } 660 } 661 662 /// <summary> 663 /// Helper method to save the CSP parameters. 664 /// </summary> 665 /// <param name="keyType">CSP algorithm type</param> 666 /// <param name="userParameters">CSP Parameters passed by user</param> 667 /// <param name="defaultFlags">flags </param> 668 /// <param name="randomKeyContainer">identifies if it is random key container</param> 669 /// <returns></returns> SaveCspParameters( CspAlgorithmType keyType, CspParameters userParameters, CspProviderFlags defaultFlags, out bool randomKeyContainer)670 internal static CspParameters SaveCspParameters( 671 CspAlgorithmType keyType, 672 CspParameters userParameters, 673 CspProviderFlags defaultFlags, 674 out bool randomKeyContainer) 675 { 676 CspParameters parameters; 677 if (userParameters == null) 678 { 679 parameters = new CspParameters(keyType == CspAlgorithmType.Dss ? 680 DefaultDssProviderType : DefaultRsaProviderType, 681 null, null, defaultFlags); 682 } 683 else 684 { 685 ValidateCspFlags(userParameters.Flags); 686 parameters = new CspParameters(userParameters); 687 } 688 689 if (parameters.KeyNumber == -1) 690 { 691 parameters.KeyNumber = keyType == CapiHelper.CspAlgorithmType.Dss ? (int)KeyNumber.Signature : (int)KeyNumber.Exchange; 692 } 693 else if (parameters.KeyNumber == CALG_DSS_SIGN || parameters.KeyNumber == CALG_RSA_SIGN) 694 { 695 parameters.KeyNumber = (int)KeyNumber.Signature; 696 } 697 else if (parameters.KeyNumber == CALG_RSA_KEYX) 698 { 699 parameters.KeyNumber = (int)KeyNumber.Exchange; 700 } 701 // If no key container was specified and UseDefaultKeyContainer is not used, then use CRYPT_VERIFYCONTEXT 702 // to generate an ephemeral key 703 randomKeyContainer = IsFlagBitSet((uint)parameters.Flags, (uint)CspProviderFlags.CreateEphemeralKey); 704 705 if (parameters.KeyContainerName == null && !IsFlagBitSet((uint)parameters.Flags, 706 (uint)CspProviderFlags.UseDefaultKeyContainer)) 707 { 708 parameters.Flags |= CspProviderFlags.CreateEphemeralKey; 709 randomKeyContainer = true; 710 } 711 712 return parameters; 713 } 714 715 /// <summary> 716 /// Validates the CSP flags are expected 717 /// </summary> 718 /// <param name="flags">CSP provider flags</param> ValidateCspFlags(CspProviderFlags flags)719 private static void ValidateCspFlags(CspProviderFlags flags) 720 { 721 // check that the flags are consistent. 722 if (IsFlagBitSet((uint)flags, (uint)CspProviderFlags.UseExistingKey)) 723 { 724 CspProviderFlags keyFlags = (CspProviderFlags.UseNonExportableKey | 725 CspProviderFlags.UseArchivableKey | 726 CspProviderFlags.UseUserProtectedKey); 727 if ((flags & keyFlags) != CspProviderFlags.NoFlags) 728 { 729 throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, Convert.ToString(flags)), nameof(flags)); 730 } 731 } 732 } 733 734 /// <summary> 735 /// Helper function to get the key pair 736 /// </summary> GetKeyPairHelper( CspAlgorithmType keyType, CspParameters parameters, int keySize, SafeProvHandle safeProvHandle)737 internal static SafeKeyHandle GetKeyPairHelper( 738 CspAlgorithmType keyType, 739 CspParameters parameters, 740 int keySize, 741 SafeProvHandle safeProvHandle) 742 { 743 // If the key already exists, use it, else generate a new one 744 SafeKeyHandle hKey; 745 int hr = CapiHelper.GetUserKey(safeProvHandle, parameters.KeyNumber, out hKey); 746 if (hr != S_OK) 747 { 748 hKey.Dispose(); 749 if (unchecked(IsFlagBitSet((uint)parameters.Flags, (uint)CspProviderFlags.UseExistingKey) || 750 (uint)hr != (uint)CryptKeyError.NTE_NO_KEY)) 751 { 752 throw hr.ToCryptographicException(); 753 } 754 755 // GenerateKey will check for failures and throw an exception 756 CapiHelper.GenerateKey(safeProvHandle, parameters.KeyNumber, (int)parameters.Flags, 757 (uint)keySize, out hKey); 758 } 759 760 // check that this is indeed an RSA/DSS key. 761 byte[] algid = CapiHelper.GetKeyParameter(hKey, Constants.CLR_ALGID); 762 763 int dwAlgId = (algid[0] | (algid[1] << 8) | (algid[2] << 16) | (algid[3] << 24)); 764 765 if ((keyType == CspAlgorithmType.Rsa && dwAlgId != CALG_RSA_KEYX && dwAlgId != CALG_RSA_SIGN) || 766 (keyType == CspAlgorithmType.Dss && dwAlgId != CALG_DSS_SIGN)) 767 { 768 hKey.Dispose(); 769 throw new CryptographicException(SR.Format(SR.Cryptography_CSP_WrongKeySpec, Convert.ToString(keyType))); 770 } 771 772 return hKey; 773 } 774 775 /// <summary> 776 /// Wrapper for get last error function 777 /// </summary> 778 /// <returns>returns the error code</returns> GetErrorCode()779 internal static int GetErrorCode() 780 { 781 return Marshal.GetLastWin32Error(); 782 } 783 784 /// <summary> 785 /// Returns PersistKeyInCsp value 786 /// </summary> 787 /// <param name="safeProvHandle">Safe Prov Handle. Expects a valid handle</param> 788 /// <returns>true if key is persisted otherwise false</returns> GetPersistKeyInCsp(SafeProvHandle safeProvHandle)789 internal static bool GetPersistKeyInCsp(SafeProvHandle safeProvHandle) 790 { 791 VerifyValidHandle(safeProvHandle); 792 return safeProvHandle.PersistKeyInCsp; 793 } 794 795 /// <summary> 796 /// Sets the PersistKeyInCsp 797 /// </summary> 798 /// <param name="safeProvHandle">Safe Prov Handle. Expects a valid handle</param> 799 /// <param name="fPersistKeyInCsp">Sets the PersistKeyInCsp value</param> SetPersistKeyInCsp(SafeProvHandle safeProvHandle, bool fPersistKeyInCsp)800 internal static void SetPersistKeyInCsp(SafeProvHandle safeProvHandle, bool fPersistKeyInCsp) 801 { 802 VerifyValidHandle(safeProvHandle); 803 safeProvHandle.PersistKeyInCsp = fPersistKeyInCsp; 804 } 805 806 //--------------------------------------------------------------------------------------- 807 // 808 // Decrypt a symmetric key using the private key in pKeyContext 809 // 810 // Arguments: 811 // pKeyContext - private key used for decrypting pbEncryptedKey 812 // pbEncryptedKey - [in] encrypted symmetric key 813 // cbEncryptedKey - size, in bytes, of pbEncryptedKey 814 // fOAEP - TRUE to use OAEP padding, FALSE to use PKCS #1 type 2 padding 815 // ohRetDecryptedKey - [out] decrypted key 816 // 817 // Notes: 818 // pbEncryptedKey is byte-reversed from the format that CAPI expects. This is for compatibility with 819 // previous CLR versions and other RSA implementations. 820 // 821 // This method is the target of the System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey QCall 822 // 823 824 // static DecryptKey(SafeKeyHandle safeKeyHandle, byte[] encryptedData, int encryptedDataLength, bool fOAEP, out byte[] decryptedData)825 internal static void DecryptKey(SafeKeyHandle safeKeyHandle, byte[] encryptedData, int encryptedDataLength, bool fOAEP, out byte[] decryptedData) 826 { 827 VerifyValidHandle(safeKeyHandle); 828 Debug.Assert(encryptedData != null, "Encrypted Data is null"); 829 Debug.Assert(encryptedDataLength >= 0, "Encrypted data length is less than 0"); 830 831 byte[] dataTobeDecrypted = new byte[encryptedDataLength]; 832 Buffer.BlockCopy(encryptedData, 0, dataTobeDecrypted, 0, encryptedDataLength); 833 Array.Reverse(dataTobeDecrypted); 834 835 int dwFlags = fOAEP ? (int)CryptDecryptFlags.CRYPT_OAEP : 0; 836 int decryptedDataLength = encryptedDataLength; 837 if (!Interop.CryptDecrypt(safeKeyHandle, SafeHashHandle.InvalidHandle, true, dwFlags, dataTobeDecrypted, ref decryptedDataLength)) 838 { 839 int ErrCode = GetErrorCode(); 840 // If we're using OAEP mode and we received an NTE_BAD_FLAGS error, then OAEP is not supported on 841 // this platform (XP+ only). Throw a generic cryptographic exception if we failed to decrypt OAEP 842 // padded data in order to prevent a chosen ciphertext attack. We will allow NTE_BAD_KEY out, since 843 // that error does not relate to the padding. Otherwise just throw a cryptographic exception based on 844 // the error code. 845 if ((uint)((uint)dwFlags & (uint)CryptDecryptFlags.CRYPT_OAEP) == (uint)CryptDecryptFlags.CRYPT_OAEP && 846 unchecked((uint)ErrCode) != (uint)CryptKeyError.NTE_BAD_KEY) 847 { 848 if (unchecked((uint)ErrCode) == (uint)CryptKeyError.NTE_BAD_FLAGS) 849 { 850 throw new CryptographicException("Cryptography_OAEP_XPPlus_Only"); 851 } 852 else 853 { 854 throw new CryptographicException("Cryptography_OAEPDecoding"); 855 } 856 } 857 else 858 { 859 throw ErrCode.ToCryptographicException(); 860 } 861 } 862 863 864 decryptedData = new byte[decryptedDataLength]; 865 Buffer.BlockCopy(dataTobeDecrypted, 0, decryptedData, 0, decryptedDataLength); 866 return; 867 } 868 869 870 //--------------------------------------------------------------------------------------- 871 // 872 // Encrypt a symmetric key using the public key in pKeyContext 873 // 874 // Arguments: 875 // safeKeyHandle [in] Key handle 876 // pbKey - [in] symmetric key to encrypt 877 // cbKey - size, in bytes, of pbKey 878 // fOAEP - TRUE to use OAEP padding, FALSE to use PKCS #1 type 2 padding 879 // ohRetEncryptedKey - [out] byte array holding the encrypted key 880 // 881 // Notes: 882 // The returned value in ohRetEncryptedKey is byte-reversed from the version CAPI gives us. This is for 883 // compatibility with previous releases of the CLR and other RSA implementations. 884 // EncryptKey(SafeKeyHandle safeKeyHandle, byte[] pbKey, int cbKey, bool foep, ref byte[] pbEncryptedKey)885 internal static void EncryptKey(SafeKeyHandle safeKeyHandle, byte[] pbKey, int cbKey, bool foep, ref byte[] pbEncryptedKey) 886 { 887 VerifyValidHandle(safeKeyHandle); 888 Debug.Assert(pbKey != null, "pbKey is null"); 889 Debug.Assert(cbKey >= 0, $"cbKey is less than 0 ({cbKey})"); 890 891 int dwEncryptFlags = foep ? (int)CryptDecryptFlags.CRYPT_OAEP : 0; 892 // Figure out how big the encrypted key will be 893 int cbEncryptedKey = cbKey; 894 if (!Interop.CryptEncrypt(safeKeyHandle, SafeHashHandle.InvalidHandle, true, dwEncryptFlags, null, ref cbEncryptedKey, cbEncryptedKey)) 895 { 896 throw GetErrorCode().ToCryptographicException(); 897 } 898 // pbData is an in/out buffer for CryptEncrypt. allocate space for the encrypted key, and copy the 899 // plaintext key into that space. Since encrypted keys will have padding applied, the size of the encrypted 900 // key should always be larger than the plaintext key, so use that to determine the buffer size. 901 Debug.Assert(cbEncryptedKey >= cbKey); 902 pbEncryptedKey = new byte[cbEncryptedKey]; 903 Buffer.BlockCopy(pbKey, 0, pbEncryptedKey, 0, cbKey); 904 905 // Encrypt for real - the last parameter is the total size of the in/out buffer, while the second to last 906 // parameter specifies the size of the plaintext to encrypt. 907 if (!Interop.CryptEncrypt(safeKeyHandle, SafeHashHandle.InvalidHandle, true, dwEncryptFlags, pbEncryptedKey, ref cbKey, cbEncryptedKey)) 908 { 909 } 910 Debug.Assert(cbKey == cbEncryptedKey); 911 Array.Reverse(pbEncryptedKey); 912 } 913 EncryptData( SafeKeyHandle hKey, byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset, int outputCount, bool isFinal)914 internal static int EncryptData( 915 SafeKeyHandle hKey, 916 byte[] input, 917 int inputOffset, 918 int inputCount, 919 byte[] output, 920 int outputOffset, 921 int outputCount, 922 bool isFinal) 923 { 924 VerifyValidHandle(hKey); 925 Debug.Assert(input != null); 926 Debug.Assert(inputOffset >= 0); 927 Debug.Assert(inputCount >= 0); 928 Debug.Assert(inputCount <= input.Length - inputOffset); 929 Debug.Assert(output != null); 930 Debug.Assert(outputOffset >= 0); 931 Debug.Assert(outputCount >= 0); 932 Debug.Assert(outputCount <= output.Length - outputOffset); 933 Debug.Assert((inputCount % 8) == 0); 934 935 // Figure out how big the encrypted data will be 936 int cbEncryptedData = inputCount; 937 if (!Interop.CryptEncrypt(hKey, SafeHashHandle.InvalidHandle, isFinal, 0, null, ref cbEncryptedData, cbEncryptedData)) 938 { 939 throw GetErrorCode().ToCryptographicException(); 940 } 941 942 // encryptedData is an in/out buffer for CryptEncrypt. Allocate space for the encrypted data, and copy the 943 // plaintext data into that space. Since encrypted data will have padding applied, the size of the encrypted 944 // data should always be larger than the plaintext key, so use that to determine the buffer size. 945 Debug.Assert(cbEncryptedData >= inputCount); 946 var encryptedData = new byte[cbEncryptedData]; 947 Buffer.BlockCopy(input, inputOffset, encryptedData, 0, inputCount); 948 949 // Encrypt for real - the last parameter is the total size of the in/out buffer, while the second to last 950 // parameter specifies the size of the plaintext to encrypt. 951 int encryptedDataLength = inputCount; 952 if (!Interop.CryptEncrypt(hKey, SafeHashHandle.InvalidHandle, isFinal, 0, encryptedData, ref encryptedDataLength, cbEncryptedData)) 953 { 954 throw GetErrorCode().ToCryptographicException(); 955 } 956 Debug.Assert(encryptedDataLength == cbEncryptedData); 957 958 if (isFinal) 959 { 960 Debug.Assert(outputCount == inputCount); 961 } 962 else 963 { 964 Debug.Assert(outputCount >= encryptedDataLength); 965 outputCount = encryptedDataLength; 966 } 967 968 // If isFinal, padding was added so ignore it by using outputCount as size 969 Buffer.BlockCopy(encryptedData, 0, output, outputOffset, outputCount); 970 971 return outputCount; 972 } 973 DecryptData( SafeKeyHandle hKey, byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset, int outputCount)974 internal static int DecryptData( 975 SafeKeyHandle hKey, 976 byte[] input, 977 int inputOffset, 978 int inputCount, 979 byte[] output, 980 int outputOffset, 981 int outputCount) 982 { 983 VerifyValidHandle(hKey); 984 Debug.Assert(input != null); 985 Debug.Assert(inputOffset >= 0); 986 Debug.Assert(inputCount >= 0); 987 Debug.Assert(inputCount <= input.Length - inputOffset); 988 Debug.Assert(output != null); 989 Debug.Assert(outputOffset >= 0); 990 Debug.Assert(outputCount >= 0); 991 Debug.Assert(outputCount <= output.Length - outputOffset); 992 Debug.Assert((inputCount % 8) == 0); 993 994 byte[] dataTobeDecrypted = new byte[inputCount]; 995 Buffer.BlockCopy(input, inputOffset, dataTobeDecrypted, 0, inputCount); 996 997 int decryptedDataLength = inputCount; 998 // Always call decryption with false (not final); deal with padding manually 999 if (!Interop.CryptDecrypt(hKey, SafeHashHandle.InvalidHandle, false, 0, dataTobeDecrypted, ref decryptedDataLength)) 1000 { 1001 throw GetErrorCode().ToCryptographicException(); 1002 } 1003 1004 Buffer.BlockCopy(dataTobeDecrypted, 0, output, outputOffset, decryptedDataLength); 1005 1006 return decryptedDataLength; 1007 } 1008 1009 /// <summary> 1010 /// Helper for Import CSP 1011 /// </summary> ImportKeyBlob(SafeProvHandle saveProvHandle, CspProviderFlags flags, bool addNoSaltFlag, byte[] keyBlob, out SafeKeyHandle safeKeyHandle)1012 internal static void ImportKeyBlob(SafeProvHandle saveProvHandle, CspProviderFlags flags, bool addNoSaltFlag, byte[] keyBlob, out SafeKeyHandle safeKeyHandle) 1013 { 1014 // Compat note: This isn't the same check as the one done by the CLR _ImportCspBlob QCall, 1015 // but this does match the desktop CLR behavior and the only scenarios it 1016 // affects are cases where a corrupt blob is passed in. 1017 bool isPublic = keyBlob.Length > 0 && keyBlob[0] == CapiHelper.PUBLICKEYBLOB; 1018 1019 int dwCapiFlags = MapCspKeyFlags((int)flags); 1020 if (isPublic) 1021 { 1022 dwCapiFlags &= ~(int)(CryptGenKeyFlags.CRYPT_EXPORTABLE); 1023 } 1024 1025 if (addNoSaltFlag) 1026 { 1027 // For RC2 running in rsabase.dll compatibility mode, make sure 11 bytes of 1028 // zero salt are generated when using a 40 bit RC2 key. 1029 dwCapiFlags |= (int)CryptGenKeyFlags.CRYPT_NO_SALT; 1030 } 1031 1032 SafeKeyHandle hKey; 1033 if (!Interop.CryptImportKey(saveProvHandle, keyBlob, keyBlob.Length, SafeKeyHandle.InvalidHandle, dwCapiFlags, out hKey)) 1034 { 1035 int hr = Marshal.GetHRForLastWin32Error(); 1036 1037 hKey.Dispose(); 1038 1039 throw hr.ToCryptographicException(); 1040 } 1041 1042 hKey.PublicOnly = isPublic; 1043 safeKeyHandle = hKey; 1044 1045 return; 1046 } 1047 1048 /// <summary> 1049 /// Helper for Export CSP 1050 /// </summary> ExportKeyBlob(bool includePrivateParameters, SafeKeyHandle safeKeyHandle)1051 internal static byte[] ExportKeyBlob(bool includePrivateParameters, SafeKeyHandle safeKeyHandle) 1052 { 1053 VerifyValidHandle(safeKeyHandle); 1054 1055 byte[] pbRawData = null; 1056 int cbRawData = 0; 1057 int dwBlobType = includePrivateParameters ? PRIVATEKEYBLOB : PUBLICKEYBLOB; 1058 1059 if (!Interop.CryptExportKey(safeKeyHandle, SafeKeyHandle.InvalidHandle, dwBlobType, 0, null, ref cbRawData)) 1060 { 1061 throw GetErrorCode().ToCryptographicException(); 1062 } 1063 pbRawData = new byte[cbRawData]; 1064 1065 if (!Interop.CryptExportKey(safeKeyHandle, SafeKeyHandle.InvalidHandle, dwBlobType, 0, pbRawData, ref cbRawData)) 1066 { 1067 throw GetErrorCode().ToCryptographicException(); 1068 } 1069 return pbRawData; 1070 } 1071 1072 /// <summary> 1073 /// Helper for signing and verifications that accept a string to specify a hashing algorithm. 1074 /// </summary> NameOrOidToHashAlgId(string nameOrOid, OidGroup oidGroup)1075 public static int NameOrOidToHashAlgId(string nameOrOid, OidGroup oidGroup) 1076 { 1077 // Default Algorithm Id is CALG_SHA1 1078 if (nameOrOid == null) 1079 return CapiHelper.CALG_SHA1; 1080 1081 string oidValue = CryptoConfig.MapNameToOID(nameOrOid); 1082 if (oidValue == null) 1083 oidValue = nameOrOid; // we were probably passed an OID value directly 1084 1085 int algId = GetAlgIdFromOid(oidValue, oidGroup); 1086 if (algId == 0 || algId == -1) 1087 throw new CryptographicException(SR.Cryptography_InvalidOID); 1088 1089 return algId; 1090 } 1091 1092 /// <summary> 1093 /// Helper for signing and verifications that accept a string/Type/HashAlgorithm to specify a hashing algorithm. 1094 /// </summary> ObjToHashAlgId(Object hashAlg)1095 public static int ObjToHashAlgId(Object hashAlg) 1096 { 1097 if (hashAlg == null) 1098 throw new ArgumentNullException(nameof(hashAlg)); 1099 1100 String hashAlgString = hashAlg as String; 1101 if (hashAlgString != null) 1102 { 1103 int algId = NameOrOidToHashAlgId(hashAlgString, OidGroup.HashAlgorithm); 1104 return algId; 1105 } 1106 else if (hashAlg is HashAlgorithm) 1107 { 1108 if (hashAlg is MD5) 1109 return CapiHelper.CALG_MD5; 1110 1111 if (hashAlg is SHA1) 1112 return CapiHelper.CALG_SHA1; 1113 1114 if (hashAlg is SHA256) 1115 return CapiHelper.CALG_SHA_256; 1116 1117 if (hashAlg is SHA384) 1118 return CapiHelper.CALG_SHA_384; 1119 1120 if (hashAlg is SHA512) 1121 return CapiHelper.CALG_SHA_512; 1122 } 1123 else 1124 { 1125 Type hashAlgType = hashAlg as Type; 1126 if ((object)hashAlgType != null) 1127 { 1128 if (typeof(MD5).IsAssignableFrom(hashAlgType)) 1129 return CapiHelper.CALG_MD5; 1130 1131 if (typeof(SHA1).IsAssignableFrom(hashAlgType)) 1132 return CapiHelper.CALG_SHA1; 1133 1134 if (typeof(SHA256).IsAssignableFrom(hashAlgType)) 1135 return CapiHelper.CALG_SHA_256; 1136 1137 if (typeof(SHA384).IsAssignableFrom(hashAlgType)) 1138 return CapiHelper.CALG_SHA_384; 1139 1140 if (typeof(SHA512).IsAssignableFrom(hashAlgType)) 1141 return CapiHelper.CALG_SHA_512; 1142 } 1143 } 1144 1145 throw new ArgumentException(SR.Argument_InvalidValue, nameof(hashAlg)); 1146 } 1147 1148 /// <summary> 1149 /// Helper for signing and verifications that accept a string/Type/HashAlgorithm to specify a hashing algorithm. 1150 /// </summary> 1151 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "MD5 is used when the user asks for it.")] 1152 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is used when the user asks for it.")] ObjToHashAlgorithm(Object hashAlg)1153 internal static HashAlgorithm ObjToHashAlgorithm(Object hashAlg) 1154 { 1155 int algId = ObjToHashAlgId(hashAlg); 1156 switch (algId) 1157 { 1158 case CapiHelper.CALG_MD5: 1159 return MD5.Create(); 1160 1161 case CapiHelper.CALG_SHA1: 1162 return SHA1.Create(); 1163 1164 case CapiHelper.CALG_SHA_256: 1165 return SHA256.Create(); 1166 1167 case CapiHelper.CALG_SHA_384: 1168 return SHA384.Create(); 1169 1170 case CapiHelper.CALG_SHA_512: 1171 return SHA512.Create(); 1172 1173 default: 1174 throw new ArgumentException(SR.Argument_InvalidValue, nameof(hashAlg)); 1175 } 1176 } 1177 1178 /// <summary> 1179 /// Convert an OID into a CAPI-1 CALG ID. 1180 /// </summary> GetAlgIdFromOid(string oid, OidGroup oidGroup)1181 private static int GetAlgIdFromOid(string oid, OidGroup oidGroup) 1182 { 1183 Debug.Assert(oid != null); 1184 1185 // CAPI does not have ALGID mappings for all of the hash algorithms - see if we know the mapping 1186 // first to avoid doing an AD lookup on these values 1187 if (String.Equals(oid, CapiHelper.OID_OIWSEC_SHA256, StringComparison.Ordinal)) 1188 { 1189 return CapiHelper.CALG_SHA_256; 1190 } 1191 else if (String.Equals(oid, CapiHelper.OID_OIWSEC_SHA384, StringComparison.Ordinal)) 1192 { 1193 return CapiHelper.CALG_SHA_384; 1194 } 1195 else if (String.Equals(oid, CapiHelper.OID_OIWSEC_SHA512, StringComparison.Ordinal)) 1196 { 1197 return CapiHelper.CALG_SHA_512; 1198 } 1199 else 1200 { 1201 return global::Interop.Crypt32.FindOidInfo(CryptOidInfoKeyType.CRYPT_OID_INFO_OID_KEY, oid, oidGroup, fallBackToAllGroups: false).AlgId; 1202 } 1203 } 1204 1205 /// <summary> 1206 /// Helper for RSACryptoServiceProvider.SignData/SignHash apis. 1207 /// </summary> SignValue(SafeProvHandle hProv, SafeKeyHandle hKey, int keyNumber, int calgKey, int calgHash, byte[] hash)1208 public static byte[] SignValue(SafeProvHandle hProv, SafeKeyHandle hKey, int keyNumber, int calgKey, int calgHash, byte[] hash) 1209 { 1210 using (SafeHashHandle hHash = hProv.CreateHashHandle(hash, calgHash)) 1211 { 1212 int cbSignature = 0; 1213 if (!Interop.CryptSignHash(hHash, (KeySpec)keyNumber, null, CryptSignAndVerifyHashFlags.None, null, ref cbSignature)) 1214 { 1215 int hr = Marshal.GetHRForLastWin32Error(); 1216 throw hr.ToCryptographicException(); 1217 } 1218 1219 byte[] signature = new byte[cbSignature]; 1220 if (!Interop.CryptSignHash(hHash, (KeySpec)keyNumber, null, CryptSignAndVerifyHashFlags.None, signature, ref cbSignature)) 1221 { 1222 int hr = Marshal.GetHRForLastWin32Error(); 1223 throw hr.ToCryptographicException(); 1224 } 1225 1226 switch (calgKey) 1227 { 1228 case CALG_RSA_SIGN: 1229 Array.Reverse(signature); 1230 break; 1231 1232 case CALG_DSS_SIGN: 1233 ReverseDsaSignature(signature, cbSignature); 1234 break; 1235 default: 1236 throw new InvalidOperationException(); 1237 } 1238 return signature; 1239 } 1240 } 1241 1242 /// <summary> 1243 /// Helper for RSACryptoServiceProvider.VerifyData/VerifyHash apis. 1244 /// </summary> VerifySign(SafeProvHandle hProv, SafeKeyHandle hKey, int calgKey, int calgHash, byte[] hash, byte[] signature)1245 public static bool VerifySign(SafeProvHandle hProv, SafeKeyHandle hKey, int calgKey, int calgHash, byte[] hash, byte[] signature) 1246 { 1247 switch (calgKey) 1248 { 1249 case CALG_RSA_SIGN: 1250 signature = signature.CloneByteArray(); 1251 Array.Reverse(signature); 1252 break; 1253 1254 case CALG_DSS_SIGN: 1255 signature = signature.CloneByteArray(); 1256 ReverseDsaSignature(signature, signature.Length); 1257 break; 1258 1259 default: 1260 throw new InvalidOperationException(); 1261 } 1262 1263 using (SafeHashHandle hHash = hProv.CreateHashHandle(hash, calgHash)) 1264 { 1265 bool verified = Interop.CryptVerifySignature(hHash, signature, signature.Length, hKey, null, CryptSignAndVerifyHashFlags.None); 1266 return verified; 1267 } 1268 } 1269 1270 /// Helper method used by PasswordDeriveBytes.CryptDeriveKey to invoke CAPI CryptDeriveKey. DeriveKey( SafeProvHandle hProv, int algid, int algidHash, byte[] password, int cbPassword, int dwFlags, byte[] IV_Out, int cbIV_In, ref byte[] pbKey)1271 public static void DeriveKey( 1272 SafeProvHandle hProv, 1273 int algid, 1274 int algidHash, 1275 byte[] password, 1276 int cbPassword, 1277 int dwFlags, 1278 byte[] IV_Out, 1279 int cbIV_In, 1280 ref byte[] pbKey) 1281 { 1282 VerifyValidHandle(hProv); 1283 1284 SafeHashHandle hHash = null; 1285 SafeKeyHandle hKey = null; 1286 try 1287 { 1288 if (!Interop.CryptCreateHash(hProv, algidHash, SafeKeyHandle.InvalidHandle, CryptCreateHashFlags.None, out hHash)) 1289 { 1290 int hr = Marshal.GetHRForLastWin32Error(); 1291 throw hr.ToCryptographicException(); 1292 } 1293 1294 // Hash the password string 1295 if (!Interop.CryptHashData(hHash, password, cbPassword, 0)) 1296 { 1297 int hr = Marshal.GetHRForLastWin32Error(); 1298 throw hr.ToCryptographicException(); 1299 } 1300 1301 // Create a block cipher session key based on the hash of the password 1302 if (!Interop.CryptDeriveKey(hProv, algid, hHash, dwFlags | (int)CryptGenKeyFlags.CRYPT_EXPORTABLE, out hKey)) 1303 { 1304 int hr = Marshal.GetHRForLastWin32Error(); 1305 throw hr.ToCryptographicException(); 1306 } 1307 1308 // Get the key contents 1309 byte[] rgbKey = null; 1310 int cbKey = 0; 1311 UnloadKey(hProv, hKey, ref rgbKey, ref cbKey); 1312 1313 // Get the length of the IV 1314 int cbIV = 0; 1315 if (!Interop.CryptGetKeyParam(hKey, (int)CryptGetKeyParamFlags.KP_IV, null, ref cbIV, 0)) 1316 { 1317 int hr = Marshal.GetHRForLastWin32Error(); 1318 throw hr.ToCryptographicException(); 1319 } 1320 1321 // Now allocate space for the IV 1322 byte[] pbIV = new byte[cbIV]; 1323 if (!Interop.CryptGetKeyParam(hKey, (int)CryptGetKeyParamFlags.KP_IV, pbIV, ref cbIV, 0)) 1324 { 1325 int hr = Marshal.GetHRForLastWin32Error(); 1326 throw hr.ToCryptographicException(); 1327 } 1328 1329 if (cbIV != cbIV_In) 1330 { 1331 throw new CryptographicException(SR.Cryptography_PasswordDerivedBytes_InvalidIV); 1332 } 1333 1334 // Copy the IV 1335 Buffer.BlockCopy(pbIV, 0, IV_Out, 0, cbIV); 1336 1337 pbKey = new byte[cbKey]; 1338 Buffer.BlockCopy(rgbKey, 0, pbKey, 0, cbKey); 1339 } 1340 finally 1341 { 1342 hKey?.Dispose(); 1343 hHash?.Dispose(); 1344 } 1345 } 1346 1347 // Helper method used by DeriveKey (above) to return the key contents. 1348 // WARNING: This function side-effects its first argument (hProv) UnloadKey(SafeProvHandle hProv, SafeKeyHandle hKey, ref byte[] key_out, ref int cb_out)1349 private static void UnloadKey(SafeProvHandle hProv, SafeKeyHandle hKey, ref byte[] key_out, ref int cb_out) 1350 { 1351 SafeKeyHandle hPubKey = null; 1352 try 1353 { 1354 // Import the public key 1355 if (!Interop.CryptImportKey(hProv, s_RgbPubKey, s_RgbPubKey.Length, SafeKeyHandle.InvalidHandle, 0, out hPubKey)) 1356 { 1357 int hr = Marshal.GetHRForLastWin32Error(); 1358 throw hr.ToCryptographicException(); 1359 } 1360 1361 // Determine length of hKey 1362 int cbOut = 0; 1363 if (!Interop.CryptExportKey(hKey, hPubKey, SIMPLEBLOB, 0, null, ref cbOut)) 1364 { 1365 int hr = Marshal.GetHRForLastWin32Error(); 1366 throw hr.ToCryptographicException(); 1367 } 1368 1369 // Export hKey 1370 byte[] key_full = new byte[cbOut]; 1371 if (!Interop.CryptExportKey(hKey, hPubKey, SIMPLEBLOB, 0, key_full, ref cbOut)) 1372 { 1373 int hr = Marshal.GetHRForLastWin32Error(); 1374 throw hr.ToCryptographicException(); 1375 } 1376 1377 // Get size of the key without the header parts 1378 int sizeOfBlobHeader = sizeof(byte) + sizeof(byte) + sizeof(ushort) + sizeof(int); 1379 // The format of BLOBHEADER: 1380 // BYTE bType 1381 // BYTE bVersion 1382 // WORD reserved 1383 // ALG_ID aiKeyAlg 1384 int offsetPastHeader = sizeOfBlobHeader + sizeof(int); 1385 int i; 1386 checked 1387 { 1388 i = cbOut - sizeOfBlobHeader - sizeof(int) - 2; 1389 } 1390 while (i > 0) 1391 { 1392 if (key_full[i + offsetPastHeader] == 0) 1393 { 1394 break; 1395 } 1396 1397 i--; 1398 } 1399 1400 // Allocate and initialize the return buffer 1401 key_out = new byte[i]; 1402 Buffer.BlockCopy(key_full, offsetPastHeader, key_out, 0, i); 1403 Array.Reverse(key_out); 1404 cb_out = i; 1405 } 1406 finally 1407 { 1408 hPubKey?.Dispose(); 1409 } 1410 } 1411 1412 /// <summary> 1413 /// Create a CAPI-1 hash handle that contains the specified bits as its hash value. 1414 /// </summary> CreateHashHandle(this SafeProvHandle hProv, byte[] hash, int calgHash)1415 private static SafeHashHandle CreateHashHandle(this SafeProvHandle hProv, byte[] hash, int calgHash) 1416 { 1417 SafeHashHandle hHash; 1418 if (!Interop.CryptCreateHash(hProv, calgHash, SafeKeyHandle.InvalidHandle, CryptCreateHashFlags.None, out hHash)) 1419 { 1420 int hr = Marshal.GetHRForLastWin32Error(); 1421 1422 hHash.Dispose(); 1423 1424 throw hr.ToCryptographicException(); 1425 } 1426 1427 try 1428 { 1429 int dwHashSize = 0; 1430 int cbHashSize = sizeof(int); 1431 if (!Interop.CryptGetHashParam(hHash, CryptHashProperty.HP_HASHSIZE, out dwHashSize, ref cbHashSize, 0)) 1432 { 1433 int hr = Marshal.GetHRForLastWin32Error(); 1434 throw hr.ToCryptographicException(); 1435 } 1436 if (dwHashSize != hash.Length) 1437 throw unchecked((int)CryptKeyError.NTE_BAD_HASH).ToCryptographicException(); 1438 1439 if (!Interop.CryptSetHashParam(hHash, CryptHashProperty.HP_HASHVAL, hash, 0)) 1440 { 1441 int hr = Marshal.GetHRForLastWin32Error(); 1442 throw hr.ToCryptographicException(); 1443 } 1444 1445 SafeHashHandle hHashPermanent = hHash; 1446 hHash = null; 1447 return hHashPermanent; 1448 } 1449 finally 1450 { 1451 if (hHash != null) 1452 { 1453 hHash.Dispose(); 1454 } 1455 } 1456 } 1457 1458 /// <summary> 1459 /// Destroy a crypto provider. 1460 /// </summary> CryptReleaseContext(IntPtr safeProvHandle, int dwFlags)1461 public static bool CryptReleaseContext(IntPtr safeProvHandle, int dwFlags) 1462 { 1463 return Interop.CryptReleaseContext(safeProvHandle, dwFlags); 1464 } 1465 1466 /// <summary> 1467 /// Destroy a crypto key. 1468 /// </summary> CryptDestroyKey(IntPtr hKey)1469 public static bool CryptDestroyKey(IntPtr hKey) 1470 { 1471 return Interop.CryptDestroyKey(hKey); 1472 } 1473 1474 /// <summary> 1475 /// Destroy a crypto hash. 1476 /// </summary> CryptDestroyHash(IntPtr hHash)1477 public static bool CryptDestroyHash(IntPtr hHash) 1478 { 1479 return Interop.CryptDestroyHash(hHash); 1480 } 1481 GetBadDataException()1482 public static CryptographicException GetBadDataException() 1483 { 1484 const int NTE_BAD_DATA = unchecked((int)CryptKeyError.NTE_BAD_DATA); 1485 return NTE_BAD_DATA.ToCryptographicException(); 1486 } 1487 GetEFailException()1488 public static CryptographicException GetEFailException() 1489 { 1490 return E_FAIL.ToCryptographicException(); 1491 } 1492 }//End of class CapiHelper : Wrappers 1493 1494 // 1495 /// <summary> 1496 /// All the PInvoke are captured in following part of CapiHelper class 1497 /// </summary> 1498 internal static partial class CapiHelper 1499 { 1500 private static class Interop 1501 { 1502 [DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CryptGetDefaultProviderW")] 1503 [return: MarshalAs(UnmanagedType.Bool)] CryptGetDefaultProvider(int dwProvType, IntPtr pdwReserved, int dwFlags, StringBuilder pszProvName, ref int IntPtrProvName)1504 public static extern bool CryptGetDefaultProvider(int dwProvType, IntPtr pdwReserved, int dwFlags, 1505 StringBuilder pszProvName, ref int IntPtrProvName); 1506 1507 [DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CryptAcquireContextW")] 1508 [return: MarshalAs(UnmanagedType.Bool)] CryptAcquireContext(out SafeProvHandle psafeProvHandle, string pszContainer, string pszProvider, int dwProvType, uint dwFlags)1509 public static extern bool CryptAcquireContext(out SafeProvHandle psafeProvHandle, string pszContainer, 1510 string pszProvider, int dwProvType, uint dwFlags); 1511 CryptGetProvParam( SafeProvHandle safeProvHandle, CryptProvParam dwParam, byte[] pbData, ref int dwDataLen, int dwFlags)1512 public static unsafe bool CryptGetProvParam( 1513 SafeProvHandle safeProvHandle, 1514 CryptProvParam dwParam, 1515 byte[] pbData, 1516 ref int dwDataLen, 1517 int dwFlags) 1518 { 1519 if (dwDataLen > pbData?.Length) 1520 { 1521 throw new IndexOutOfRangeException(); 1522 } 1523 1524 fixed (byte* bytePtr = pbData) 1525 { 1526 return global::Interop.Advapi32.CryptGetProvParam( 1527 safeProvHandle, 1528 dwParam, 1529 (IntPtr)bytePtr, 1530 ref dwDataLen, 1531 dwFlags); 1532 } 1533 } 1534 1535 [DllImport(Libraries.Advapi32, SetLastError = true, EntryPoint = "CryptSetProvParam")] 1536 [return: MarshalAs(UnmanagedType.Bool)] CryptSetProvParamIndirectPtr(SafeProvHandle safeProvHandle, CryptProvParam dwParam, ref IntPtr pbData, int dwFlags)1537 public static extern bool CryptSetProvParamIndirectPtr(SafeProvHandle safeProvHandle, CryptProvParam dwParam, ref IntPtr pbData, int dwFlags); 1538 CryptSetProvParam( SafeProvHandle safeProvHandle, CryptProvParam dwParam, IntPtr pbData, int dwFlags)1539 public static bool CryptSetProvParam( 1540 SafeProvHandle safeProvHandle, 1541 CryptProvParam dwParam, 1542 IntPtr pbData, 1543 int dwFlags) 1544 { 1545 return global::Interop.Advapi32.CryptSetProvParam(safeProvHandle, dwParam, pbData, dwFlags); 1546 } 1547 1548 [DllImport(Libraries.Advapi32, SetLastError = true, EntryPoint = "CryptGetUserKey")] 1549 [return: MarshalAs(UnmanagedType.Bool)] _CryptGetUserKey(SafeProvHandle safeProvHandle, int dwKeySpec, out SafeKeyHandle safeKeyHandle)1550 private static extern bool _CryptGetUserKey(SafeProvHandle safeProvHandle, int dwKeySpec, out SafeKeyHandle safeKeyHandle); 1551 1552 [DllImport(Libraries.Advapi32, SetLastError = true)] 1553 [return: MarshalAs(UnmanagedType.Bool)] CryptGetKeyParam(SafeKeyHandle safeKeyHandle, int dwParam, byte[] pbData, ref int pdwDataLen, int dwFlags)1554 public static extern bool CryptGetKeyParam(SafeKeyHandle safeKeyHandle, int dwParam, byte[] pbData, 1555 ref int pdwDataLen, int dwFlags); 1556 1557 [DllImport(Libraries.Advapi32, SetLastError = true)] 1558 [return: MarshalAs(UnmanagedType.Bool)] CryptSetKeyParam(SafeKeyHandle safeKeyHandle, int dwParam, byte[] pbData, int dwFlags)1559 public static extern bool CryptSetKeyParam(SafeKeyHandle safeKeyHandle, int dwParam, byte[] pbData, int dwFlags); 1560 1561 [DllImport(Libraries.Advapi32, SetLastError = true, EntryPoint = "CryptSetKeyParam")] 1562 [return: MarshalAs(UnmanagedType.Bool)] CryptSetKeyParamInt(SafeKeyHandle safeKeyHandle, int dwParam, ref int pdw, int dwFlags)1563 public static extern bool CryptSetKeyParamInt(SafeKeyHandle safeKeyHandle, int dwParam, ref int pdw, int dwFlags); 1564 1565 [DllImport(Libraries.Advapi32, SetLastError = true, EntryPoint = "CryptGenKey")] _CryptGenKey(SafeProvHandle safeProvHandle, int Algid, int dwFlags, out SafeKeyHandle safeKeyHandle)1566 private static extern bool _CryptGenKey(SafeProvHandle safeProvHandle, int Algid, int dwFlags, out SafeKeyHandle safeKeyHandle); 1567 1568 [DllImport(Libraries.Advapi32, SetLastError = true)] CryptReleaseContext(IntPtr safeProvHandle, int dwFlags)1569 public static extern bool CryptReleaseContext(IntPtr safeProvHandle, int dwFlags); 1570 1571 [DllImport(Libraries.Advapi32, SetLastError = true)] CryptDecrypt(SafeKeyHandle safeKeyHandle, SafeHashHandle safeHashHandle, bool Final, int dwFlags, byte[] pbData, ref int pdwDataLen)1572 public static extern bool CryptDecrypt(SafeKeyHandle safeKeyHandle, SafeHashHandle safeHashHandle, bool Final, 1573 int dwFlags, byte[] pbData, ref int pdwDataLen); 1574 1575 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] 1576 [return: MarshalAs(UnmanagedType.Bool)] CryptEncrypt(SafeKeyHandle safeKeyHandle, SafeHashHandle safeHashHandle, bool Final, int dwFlags, byte[] pbData, ref int pdwDataLen, int dwBufLen)1577 public static extern bool CryptEncrypt(SafeKeyHandle safeKeyHandle, SafeHashHandle safeHashHandle, 1578 bool Final, int dwFlags, byte[] pbData, ref int pdwDataLen, 1579 int dwBufLen); 1580 1581 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CryptDeriveKey")] 1582 [return: MarshalAs(UnmanagedType.Bool)] _CryptDeriveKey(SafeProvHandle safeProvHandle, int algId, SafeHashHandle phHash, int dwFlags, out SafeKeyHandle phKey)1583 private static extern bool _CryptDeriveKey(SafeProvHandle safeProvHandle, int algId, SafeHashHandle phHash, int dwFlags, out SafeKeyHandle phKey); 1584 1585 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] 1586 [return: MarshalAs(UnmanagedType.Bool)] CryptExportKey(SafeKeyHandle hKey, SafeKeyHandle hExpKey, int dwBlobType, int dwFlags, [In, Out] byte[] pbData, ref int dwDataLen)1587 public static extern bool CryptExportKey(SafeKeyHandle hKey, SafeKeyHandle hExpKey, int dwBlobType, 1588 int dwFlags, [In, Out] byte[] pbData, ref int dwDataLen); 1589 1590 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CryptImportKey")] 1591 [return: MarshalAs(UnmanagedType.Bool)] _CryptImportKey(SafeProvHandle hProv, byte[] pbData, int dwDataLen, SafeKeyHandle hPubKey, int dwFlags, out SafeKeyHandle phKey)1592 private static extern bool _CryptImportKey(SafeProvHandle hProv, byte[] pbData, int dwDataLen, SafeKeyHandle hPubKey, int dwFlags, out SafeKeyHandle phKey); 1593 1594 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CryptCreateHash")] 1595 [return: MarshalAs(UnmanagedType.Bool)] _CryptCreateHash(SafeProvHandle hProv, int algId, SafeKeyHandle hKey, CryptCreateHashFlags dwFlags, out SafeHashHandle phHash)1596 private static extern bool _CryptCreateHash(SafeProvHandle hProv, int algId, SafeKeyHandle hKey, CryptCreateHashFlags dwFlags, out SafeHashHandle phHash); 1597 1598 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] 1599 [return: MarshalAs(UnmanagedType.Bool)] CryptHashData(SafeHashHandle hHash, byte[] pbData, int dwDataLen, int dwFlags)1600 public static extern bool CryptHashData(SafeHashHandle hHash, byte[] pbData, int dwDataLen, int dwFlags); 1601 1602 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] 1603 [return: MarshalAs(UnmanagedType.Bool)] CryptGetHashParam(SafeHashHandle hHash, CryptHashProperty dwParam, out int pbData, [In, Out] ref int pdwDataLen, int dwFlags)1604 public static extern bool CryptGetHashParam(SafeHashHandle hHash, CryptHashProperty dwParam, out int pbData, [In, Out] ref int pdwDataLen, int dwFlags); 1605 1606 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] 1607 [return: MarshalAs(UnmanagedType.Bool)] CryptSetHashParam(SafeHashHandle hHash, CryptHashProperty dwParam, byte[] buffer, int dwFlags)1608 public static extern bool CryptSetHashParam(SafeHashHandle hHash, CryptHashProperty dwParam, byte[] buffer, int dwFlags); 1609 1610 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CryptSignHashW")] 1611 [return: MarshalAs(UnmanagedType.Bool)] CryptSignHash(SafeHashHandle hHash, KeySpec dwKeySpec, String sDescription, CryptSignAndVerifyHashFlags dwFlags, [Out] byte[] pbSignature, [In, Out] ref int pdwSigLen)1612 public static extern bool CryptSignHash(SafeHashHandle hHash, KeySpec dwKeySpec, String sDescription, CryptSignAndVerifyHashFlags dwFlags, [Out] byte[] pbSignature, [In, Out] ref int pdwSigLen); 1613 1614 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CryptVerifySignatureW")] 1615 [return: MarshalAs(UnmanagedType.Bool)] CryptVerifySignature(SafeHashHandle hHash, byte[] pbSignature, int dwSigLen, SafeKeyHandle hPubKey, String sDescription, CryptSignAndVerifyHashFlags dwFlags)1616 public static extern bool CryptVerifySignature(SafeHashHandle hHash, byte[] pbSignature, int dwSigLen, SafeKeyHandle hPubKey, String sDescription, CryptSignAndVerifyHashFlags dwFlags); 1617 1618 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] 1619 [return: MarshalAs(UnmanagedType.Bool)] CryptDestroyKey(IntPtr hKey)1620 public static extern bool CryptDestroyKey(IntPtr hKey); 1621 1622 [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] 1623 [return: MarshalAs(UnmanagedType.Bool)] CryptDestroyHash(IntPtr hHash)1624 public static extern bool CryptDestroyHash(IntPtr hHash); 1625 CryptGetUserKey( SafeProvHandle safeProvHandle, int dwKeySpec, out SafeKeyHandle safeKeyHandle)1626 public static bool CryptGetUserKey( 1627 SafeProvHandle safeProvHandle, 1628 int dwKeySpec, 1629 out SafeKeyHandle safeKeyHandle) 1630 { 1631 bool response = _CryptGetUserKey(safeProvHandle, dwKeySpec, out safeKeyHandle); 1632 1633 safeKeyHandle.SetParent(safeProvHandle); 1634 1635 return response; 1636 } 1637 CryptGenKey( SafeProvHandle safeProvHandle, int algId, int dwFlags, out SafeKeyHandle safeKeyHandle)1638 public static bool CryptGenKey( 1639 SafeProvHandle safeProvHandle, 1640 int algId, 1641 int dwFlags, 1642 out SafeKeyHandle safeKeyHandle) 1643 { 1644 bool response = _CryptGenKey(safeProvHandle, algId, dwFlags, out safeKeyHandle); 1645 1646 safeKeyHandle.SetParent(safeProvHandle); 1647 1648 return response; 1649 } 1650 CryptImportKey( SafeProvHandle hProv, byte[] pbData, int dwDataLen, SafeKeyHandle hPubKey, int dwFlags, out SafeKeyHandle phKey)1651 public static bool CryptImportKey( 1652 SafeProvHandle hProv, 1653 byte[] pbData, 1654 int dwDataLen, 1655 SafeKeyHandle hPubKey, 1656 int dwFlags, 1657 out SafeKeyHandle phKey) 1658 { 1659 bool response = _CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, out phKey); 1660 1661 phKey.SetParent(hProv); 1662 1663 return response; 1664 } 1665 CryptCreateHash( SafeProvHandle hProv, int algId, SafeKeyHandle hKey, CryptCreateHashFlags dwFlags, out SafeHashHandle phHash)1666 public static bool CryptCreateHash( 1667 SafeProvHandle hProv, 1668 int algId, 1669 SafeKeyHandle hKey, 1670 CryptCreateHashFlags dwFlags, 1671 out SafeHashHandle phHash) 1672 { 1673 bool response = _CryptCreateHash(hProv, algId, hKey, dwFlags, out phHash); 1674 1675 phHash.SetParent(hProv); 1676 1677 return response; 1678 } 1679 CryptDeriveKey( SafeProvHandle hProv, int algId, SafeHashHandle phHash, int dwFlags, out SafeKeyHandle phKey)1680 public static bool CryptDeriveKey( 1681 SafeProvHandle hProv, 1682 int algId, 1683 SafeHashHandle phHash, 1684 int dwFlags, 1685 out SafeKeyHandle phKey) 1686 { 1687 bool response = _CryptDeriveKey(hProv, algId, phHash, dwFlags, out phKey); 1688 1689 phKey.SetParent(hProv); 1690 1691 return response; 1692 } 1693 } 1694 } //End CapiHelper : Pinvokes 1695 1696 /// <summary> 1697 /// All the Crypto flags are capture in following 1698 /// </summary> 1699 internal static partial class CapiHelper 1700 { 1701 internal const int CALG_DES = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 1); 1702 internal const int CALG_RC2 = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 2); 1703 internal const int CALG_MD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | 3); 1704 internal const int CALG_SHA1 = (ALG_CLASS_HASH | ALG_TYPE_ANY | 4); 1705 internal const int CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | 12); 1706 internal const int CALG_SHA_384 = (ALG_CLASS_HASH | ALG_TYPE_ANY | 13); 1707 internal const int CALG_SHA_512 = (ALG_CLASS_HASH | ALG_TYPE_ANY | 14); 1708 1709 internal const string OID_OIWSEC_SHA256 = "2.16.840.1.101.3.4.2.1"; 1710 internal const string OID_OIWSEC_SHA384 = "2.16.840.1.101.3.4.2.2"; 1711 internal const string OID_OIWSEC_SHA512 = "2.16.840.1.101.3.4.2.3"; 1712 1713 // MS provider names. 1714 internal const string MS_DEF_DH_SCHANNEL_PROV = "Microsoft DH Schannel Cryptographic Provider"; 1715 internal const string MS_DEF_DSS_DH_PROV = "Microsoft Base DSS and Diffie-Hellman Cryptographic Provider"; 1716 internal const string MS_DEF_DSS_PROV = "Microsoft Base DSS Cryptographic Provider"; 1717 internal const string MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"; 1718 internal const string MS_DEF_RSA_SCHANNEL_PROV = "Microsoft RSA Schannel Cryptographic Provider"; 1719 internal const string MS_DEF_RSA_SIG_PROV = "Microsoft RSA Signature Cryptographic Provider"; 1720 internal const string MS_ENH_DSS_DH_PROV = "Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider"; 1721 internal const string MS_ENH_RSA_AES_PROV = "Microsoft Enhanced RSA and AES Cryptographic Provider"; 1722 internal const string MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0"; 1723 internal const string MS_SCARD_PROV = "Microsoft Base Smart Card Crypto Provider"; 1724 internal const string MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider"; 1725 1726 internal enum CryptDecryptFlags : int 1727 { 1728 CRYPT_OAEP = 0x00000040, 1729 CRYPT_DECRYPT_RSA_NO_PADDING_CHECK = 0x00000020 1730 } 1731 internal enum GetDefaultProviderFlags : int 1732 { 1733 CRYPT_MACHINE_DEFAULT = 0x00000001, 1734 CRYPT_USER_DEFAULT = 0x00000002 1735 } 1736 1737 internal enum CryptGetKeyParamFlags : int 1738 { 1739 CRYPT_EXPORT = 0x0004, 1740 KP_IV = 1, 1741 KP_PERMISSIONS = 6, 1742 } 1743 1744 [Flags] 1745 internal enum CryptGetProvParamPPImpTypeFlags : int 1746 { 1747 CRYPT_IMPL_HARDWARE = 0x1, 1748 CRYPT_IMPL_SOFTWARE = 0x2, 1749 CRYPT_IMPL_MIXED = 0x3, 1750 CRYPT_IMPL_UNKNOWN = 0x4, 1751 CRYPT_IMPL_REMOVABLE = 0x8 1752 } 1753 //All the flags are capture here 1754 [Flags] 1755 internal enum CryptAcquireContextFlags : uint 1756 { 1757 None = 0x00000000, 1758 CRYPT_NEWKEYSET = 0x00000008, // CRYPT_NEWKEYSET 1759 CRYPT_DELETEKEYSET = 0x00000010, // CRYPT_DELETEKEYSET 1760 CRYPT_MACHINE_KEYSET = 0x00000020, // CRYPT_MACHINE_KEYSET 1761 CRYPT_SILENT = 0x00000040, // CRYPT_SILENT 1762 CRYPT_VERIFYCONTEXT = 0xF0000000 // CRYPT_VERIFYCONTEXT 1763 } 1764 1765 internal enum CryptGetKeyParamQueryType : int 1766 { 1767 KP_IV = 1, 1768 KP_MODE = 4, 1769 KP_MODE_BITS = 5, 1770 KP_EFFECTIVE_KEYLEN = 19, 1771 KP_KEYLEN = 9, // Length of key in bits 1772 KP_ALGID = 7 // Key algorithm 1773 } 1774 internal enum CryptGenKeyFlags : int 1775 { 1776 // dwFlag definitions for CryptGenKey 1777 CRYPT_EXPORTABLE = 0x00000001, 1778 CRYPT_USER_PROTECTED = 0x00000002, 1779 CRYPT_CREATE_SALT = 0x00000004, 1780 CRYPT_UPDATE_KEY = 0x00000008, 1781 CRYPT_NO_SALT = 0x00000010, 1782 CRYPT_PREGEN = 0x00000040, 1783 CRYPT_RECIPIENT = 0x00000010, 1784 CRYPT_INITIATOR = 0x00000040, 1785 CRYPT_ONLINE = 0x00000080, 1786 CRYPT_SF = 0x00000100, 1787 CRYPT_CREATE_IV = 0x00000200, 1788 CRYPT_KEK = 0x00000400, 1789 CRYPT_DATA_KEY = 0x00000800, 1790 CRYPT_VOLATILE = 0x00001000, 1791 CRYPT_SGCKEY = 0x00002000, 1792 CRYPT_ARCHIVABLE = 0x00004000 1793 } 1794 1795 1796 internal enum CspAlgorithmType 1797 { 1798 Rsa = 0, 1799 Dss = 1 1800 } 1801 1802 [Flags] 1803 internal enum CryptCreateHashFlags : int 1804 { 1805 None = 0, 1806 } 1807 1808 internal enum CryptHashProperty : int 1809 { 1810 HP_ALGID = 0x0001, // Hash algorithm 1811 HP_HASHVAL = 0x0002, // Hash value 1812 HP_HASHSIZE = 0x0004, // Hash value size 1813 HP_HMAC_INFO = 0x0005, // information for creating an HMAC 1814 HP_TLS1PRF_LABEL = 0x0006, // label for TLS1 PRF 1815 HP_TLS1PRF_SEED = 0x0007, // seed for TLS1 PRF 1816 } 1817 1818 internal enum KeySpec : int 1819 { 1820 AT_KEYEXCHANGE = 1, 1821 AT_SIGNATURE = 2, 1822 } 1823 1824 [Flags] 1825 internal enum CryptSignAndVerifyHashFlags : int 1826 { 1827 None = 0x00000000, 1828 CRYPT_NOHASHOID = 0x00000001, 1829 CRYPT_TYPE2_FORMAT = 0x00000002, // Not supported 1830 CRYPT_X931_FORMAT = 0x00000004, // Not supported 1831 } 1832 } //End CapiHelper:Flags 1833 } //End Namespace Internal.NativeCrypto 1834