// // Common helper for SignHash() and VerifyHash(). Creates the necessary PADDING_INFO structure based on the chosen padding mode and then passes it // to "signOrVerify" which performs the actual signing or verification. // private static unsafe void SignOrVerify(RSASignaturePadding padding, HashAlgorithmName hashAlgorithm, byte[] hash, SignOrVerifyAction signOrVerify) { string hashAlgorithmName = hashAlgorithm.Name; if (string.IsNullOrEmpty(hashAlgorithmName)) throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, "hashAlgorithm"); if (padding == null) throw new ArgumentNullException("padding"); switch (padding.Mode) { case RSASignaturePaddingMode.Pkcs1: { using (SafeUnicodeStringHandle safeHashAlgorithmName = new SafeUnicodeStringHandle(hashAlgorithmName)) { BCRYPT_PKCS1_PADDING_INFO paddingInfo = new BCRYPT_PKCS1_PADDING_INFO() { pszAlgId = safeHashAlgorithmName.DangerousGetHandle(), }; signOrVerify(AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, &paddingInfo); } break; } case RSASignaturePaddingMode.Pss: { using (SafeUnicodeStringHandle safeHashAlgorithmName = new SafeUnicodeStringHandle(hashAlgorithmName)) { BCRYPT_PSS_PADDING_INFO paddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = safeHashAlgorithmName.DangerousGetHandle(), cbSalt = hash.Length, }; signOrVerify(AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &paddingInfo); } break; } default: throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } }
// // Conveniently, Encrypt() and Decrypt() are identical save for the actual P/Invoke call to CNG. Thus, both // APIs invoke this common helper with the "transform" parameter determining whether encryption or decryption is done. // private byte[] EncryptOrDecrypt(byte[] data, RSAEncryptionPadding padding, EncryptOrDecryptAction encryptOrDecrypt) { if (data == null) throw new ArgumentNullException(nameof(data)); if (padding == null) throw new ArgumentNullException(nameof(padding)); unsafe { using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle()) { switch (padding.Mode) { case RSAEncryptionPaddingMode.Pkcs1: return EncryptOrDecrypt(keyHandle, data, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, null, encryptOrDecrypt); case RSAEncryptionPaddingMode.Oaep: { using (SafeUnicodeStringHandle safeHashAlgorithmName = new SafeUnicodeStringHandle(padding.OaepHashAlgorithm.Name)) { BCRYPT_OAEP_PADDING_INFO paddingInfo = new BCRYPT_OAEP_PADDING_INFO() { pszAlgId = safeHashAlgorithmName.DangerousGetHandle(), // It would nice to put randomized data here but RSAEncryptionPadding does not at this point provide support for this. pbLabel = IntPtr.Zero, cbLabel = 0, }; return EncryptOrDecrypt(keyHandle, data, AsymmetricPaddingMode.NCRYPT_PAD_OAEP_FLAG, &paddingInfo, encryptOrDecrypt); } } default: throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } } } }
internal static SafeNCryptKeyHandle ImportKeyBlob(string blobType, byte[] keyBlob, string curveName, SafeNCryptProviderHandle provider) { ErrorCode errorCode; SafeNCryptKeyHandle keyHandle; using (SafeUnicodeStringHandle safeCurveName = new SafeUnicodeStringHandle(curveName)) { var desc = new Interop.BCrypt.BCryptBufferDesc(); var buff = new Interop.BCrypt.BCryptBuffer(); IntPtr descPtr = IntPtr.Zero; IntPtr buffPtr = IntPtr.Zero; try { descPtr = Marshal.AllocHGlobal(Marshal.SizeOf(desc)); buffPtr = Marshal.AllocHGlobal(Marshal.SizeOf(buff)); buff.cbBuffer = (curveName.Length + 1) * 2; // Add 1 for null terminator buff.BufferType = Interop.BCrypt.NCryptBufferDescriptors.NCRYPTBUFFER_ECC_CURVE_NAME; buff.pvBuffer = safeCurveName.DangerousGetHandle(); Marshal.StructureToPtr(buff, buffPtr, false); desc.cBuffers = 1; desc.pBuffers = buffPtr; desc.ulVersion = Interop.BCrypt.BCRYPTBUFFER_VERSION; Marshal.StructureToPtr(desc, descPtr, false); errorCode = Interop.NCrypt.NCryptImportKey(provider, IntPtr.Zero, blobType, descPtr, out keyHandle, keyBlob, keyBlob.Length, 0); } finally { Marshal.FreeHGlobal(descPtr); Marshal.FreeHGlobal(buffPtr); } } if (errorCode != ErrorCode.ERROR_SUCCESS) { Exception e = errorCode.ToCryptographicException(); if (errorCode == ErrorCode.NTE_INVALID_PARAMETER) { throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, curveName), e); } throw e; } return keyHandle; }
internal static unsafe bool ExportPkcs8KeyBlob( bool allocate, SafeNCryptKeyHandle keyHandle, ReadOnlySpan <char> password, int kdfCount, Span <byte> destination, out int bytesWritten, out byte[]?allocated) { using (SafeUnicodeStringHandle stringHandle = new SafeUnicodeStringHandle(password)) { fixed(byte *oidPtr = s_pkcs12TripleDesOidBytes) { Interop.NCrypt.NCryptBuffer *buffers = stackalloc Interop.NCrypt.NCryptBuffer[3]; Interop.NCrypt.PBE_PARAMS pbeParams = default; Span <byte> salt = new Span <byte>(pbeParams.rgbSalt, Interop.NCrypt.PBE_PARAMS.RgbSaltSize); RandomNumberGenerator.Fill(salt); pbeParams.Params.cbSalt = salt.Length; pbeParams.Params.iIterations = kdfCount; buffers[0] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsSecret, cbBuffer = checked (2 * (password.Length + 1)), pvBuffer = stringHandle.DangerousGetHandle(), }; if (buffers[0].pvBuffer == IntPtr.Zero) { buffers[0].cbBuffer = 0; } buffers[1] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsAlgOid, cbBuffer = s_pkcs12TripleDesOidBytes.Length, pvBuffer = (IntPtr)oidPtr, }; buffers[2] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsAlgParam, cbBuffer = sizeof(Interop.NCrypt.PBE_PARAMS), pvBuffer = (IntPtr)(&pbeParams), }; Interop.NCrypt.NCryptBufferDesc desc = new Interop.NCrypt.NCryptBufferDesc { cBuffers = 3, pBuffers = (IntPtr)buffers, ulVersion = 0, }; Span <byte> empty = default; ErrorCode errorCode = Interop.NCrypt.NCryptExportKey( keyHandle, IntPtr.Zero, Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB, ref desc, ref MemoryMarshal.GetReference(empty), 0, out int numBytesNeeded, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } allocated = null; if (allocate) { allocated = new byte[numBytesNeeded]; destination = allocated; } else if (numBytesNeeded > destination.Length) { bytesWritten = 0; return(false); } errorCode = Interop.NCrypt.NCryptExportKey( keyHandle, IntPtr.Zero, Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB, ref desc, ref MemoryMarshal.GetReference(destination), destination.Length, out numBytesNeeded, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } if (allocate && numBytesNeeded != destination.Length) { byte[] trimmed = new byte[numBytesNeeded]; destination.Slice(0, numBytesNeeded).CopyTo(trimmed); Array.Clear(allocated !, 0, numBytesNeeded); allocated = trimmed; } bytesWritten = numBytesNeeded; return(true); } } }
internal static CngKey Import(byte[] keyBlob, ECCurve?curve, CngKeyBlobFormat format, CngProvider provider) { #endif //!NETNATIVE if (keyBlob == null) { throw new ArgumentNullException(nameof(keyBlob)); } if (format == null) { throw new ArgumentNullException(nameof(format)); } if (provider == null) { throw new ArgumentNullException(nameof(provider)); } SafeNCryptProviderHandle providerHandle = provider.OpenStorageProvider(); SafeNCryptKeyHandle keyHandle; ErrorCode errorCode; #if !NETNATIVE if (curve == null) #endif //!NETNATIVE { errorCode = Interop.NCrypt.NCryptImportKey(providerHandle, IntPtr.Zero, format.Format, IntPtr.Zero, out keyHandle, keyBlob, keyBlob.Length, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } #if !NETNATIVE else { // Call with Oid.FriendlyName because .Value will result in an invalid parameter error Debug.Assert(curve.Value.IsNamed); string curveName = curve.Value.Oid.FriendlyName; using (SafeUnicodeStringHandle safeCurveName = new SafeUnicodeStringHandle(curveName)) { var desc = new Interop.BCrypt.BCryptBufferDesc(); var buff = new Interop.BCrypt.BCryptBuffer(); IntPtr descPtr = IntPtr.Zero; IntPtr buffPtr = IntPtr.Zero; try { descPtr = Marshal.AllocHGlobal(Marshal.SizeOf(desc)); buffPtr = Marshal.AllocHGlobal(Marshal.SizeOf(buff)); buff.cbBuffer = (curveName.Length + 1) * 2; // Add 1 for null terminator buff.BufferType = Interop.BCrypt.NCryptBufferDescriptors.NCRYPTBUFFER_ECC_CURVE_NAME; buff.pvBuffer = safeCurveName.DangerousGetHandle(); Marshal.StructureToPtr(buff, buffPtr, false); desc.cBuffers = 1; desc.pBuffers = buffPtr; desc.ulVersion = Interop.BCrypt.BCRYPTBUFFER_VERSION; Marshal.StructureToPtr(desc, descPtr, false); errorCode = Interop.NCrypt.NCryptImportKey(providerHandle, IntPtr.Zero, format.Format, descPtr, out keyHandle, keyBlob, keyBlob.Length, 0); } finally { Marshal.FreeHGlobal(descPtr); Marshal.FreeHGlobal(buffPtr); } } if (errorCode != ErrorCode.ERROR_SUCCESS) { Exception e = errorCode.ToCryptographicException(); if (errorCode == ErrorCode.NTE_INVALID_PARAMETER) { throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, curveName), e); } throw e; } } #endif //!NETNATIVE CngKey key = new CngKey(providerHandle, keyHandle); // We can't tell directly if an OpaqueTransport blob imported as an ephemeral key or not key.IsEphemeral = format != CngKeyBlobFormat.OpaqueTransportBlob; return(key); }
OpenNCryptProvider("Microsoft Software Key Storage Provider"); // MS_KEY_STORAGE_PROVIDER internal static unsafe SafeNCryptKeyHandle ImportKeyBlob( string blobType, ReadOnlySpan <byte> keyBlob, bool encrypted = false, ReadOnlySpan <char> password = default) { SafeNCryptKeyHandle keyHandle; ErrorCode errorCode; if (encrypted) { using (var stringHandle = new SafeUnicodeStringHandle(password)) { Interop.NCrypt.NCryptBuffer *buffers = stackalloc Interop.NCrypt.NCryptBuffer[1]; buffers[0] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsSecret, cbBuffer = checked (2 * (password.Length + 1)), pvBuffer = stringHandle.DangerousGetHandle(), }; if (buffers[0].pvBuffer == IntPtr.Zero) { buffers[0].cbBuffer = 0; } Interop.NCrypt.NCryptBufferDesc desc = new Interop.NCrypt.NCryptBufferDesc { cBuffers = 1, pBuffers = (IntPtr)buffers, ulVersion = 0, }; errorCode = Interop.NCrypt.NCryptImportKey( s_microsoftSoftwareProviderHandle, IntPtr.Zero, blobType, ref desc, out keyHandle, ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, 0); } } else { errorCode = Interop.NCrypt.NCryptImportKey( s_microsoftSoftwareProviderHandle, IntPtr.Zero, blobType, IntPtr.Zero, out keyHandle, ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, 0); } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Debug.Assert(keyHandle != null); SetExportable(keyHandle); return(keyHandle); }