示例#1
0
        //
        // 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);
            }
        }
示例#2
0
        //
        // 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);
                    }
                }
            }
        }
示例#3
0
        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;
        }
示例#4
0
        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);
                }
            }
        }
示例#5
0
        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);
        }
示例#6
0
            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);
        }