示例#1
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);
                    }
                }
            }
        }
示例#2
0
        // Conveniently, Encrypt() and Decrypt() are identical save for the actual P/Invoke call to CNG. Thus, both
        // array-based APIs invoke this common helper with the "encrypt" parameter determining whether encryption or decryption is done.
        private unsafe byte[] EncryptOrDecrypt(byte[] data, RSAEncryptionPadding padding, bool encrypt)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }
            if (padding == null)
            {
                throw new ArgumentNullException(nameof(padding));
            }

            using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
            {
                switch (padding.Mode)
                {
                case RSAEncryptionPaddingMode.Pkcs1:
                    return(EncryptOrDecrypt(keyHandle, data, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, null, encrypt));

                case RSAEncryptionPaddingMode.Oaep:
                    IntPtr namePtr = Marshal.StringToHGlobalUni(padding.OaepHashAlgorithm.Name);
                    try
                    {
                        var paddingInfo = new BCRYPT_OAEP_PADDING_INFO()
                        {
                            pszAlgId = namePtr,

                            // 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, encrypt));
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(namePtr);
                    }

                default:
                    throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode);
                }
            }
        }
示例#3
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);
                    }
                }
            }
        }
示例#4
0
        // Conveniently, Encrypt() and Decrypt() are identical save for the actual P/Invoke call to CNG. Thus, both
        // array-based APIs invoke this common helper with the "encrypt" parameter determining whether encryption or decryption is done.
        private unsafe byte[] EncryptOrDecrypt(byte[] data, RSAEncryptionPadding padding, bool encrypt)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }
            if (padding == null)
            {
                throw new ArgumentNullException(nameof(padding));
            }

            int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);

            if (!encrypt && data.Length != modulusSizeInBytes)
            {
                throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize);
            }

            if (encrypt &&
                padding.Mode == RSAEncryptionPaddingMode.Pkcs1 &&
                data.Length > modulusSizeInBytes - Pkcs1PaddingOverhead)
            {
                throw new CryptographicException(
                          SR.Format(SR.Cryptography_Encryption_MessageTooLong, modulusSizeInBytes - Pkcs1PaddingOverhead));
            }

            using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
            {
                if (encrypt && data.Length == 0)
                {
                    byte[]      rented        = CryptoPool.Rent(modulusSizeInBytes);
                    Span <byte> paddedMessage = new Span <byte>(rented, 0, modulusSizeInBytes);

                    try
                    {
                        if (padding == RSAEncryptionPadding.Pkcs1)
                        {
                            RsaPaddingProcessor.PadPkcs1Encryption(data, paddedMessage);
                        }
                        else if (padding.Mode == RSAEncryptionPaddingMode.Oaep)
                        {
                            RsaPaddingProcessor processor =
                                RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm);

                            processor.PadOaep(data, paddedMessage);
                        }
                        else
                        {
                            throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode);
                        }

                        return(EncryptOrDecrypt(keyHandle, paddedMessage, AsymmetricPaddingMode.NCRYPT_NO_PADDING_FLAG, null, encrypt));
                    }
                    finally
                    {
                        CryptographicOperations.ZeroMemory(paddedMessage);
                        CryptoPool.Return(rented, clearSize: 0);
                    }
                }

                switch (padding.Mode)
                {
                case RSAEncryptionPaddingMode.Pkcs1:
                    return(EncryptOrDecrypt(keyHandle, data, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, null, encrypt));

                case RSAEncryptionPaddingMode.Oaep:
                    IntPtr namePtr = Marshal.StringToHGlobalUni(padding.OaepHashAlgorithm.Name);
                    try
                    {
                        var paddingInfo = new BCRYPT_OAEP_PADDING_INFO()
                        {
                            pszAlgId = namePtr,

                            // 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, encrypt));
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(namePtr);
                    }

                default:
                    throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode);
                }
            }
        }
示例#5
0
        // Conveniently, Encrypt() and Decrypt() are identical save for the actual P/Invoke call to CNG. Thus, both
        // span-based APIs invoke this common helper with the "encrypt" parameter determining whether encryption or decryption is done.
        private unsafe bool TryEncryptOrDecrypt(ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, bool encrypt, out int bytesWritten)
        {
            if (padding == null)
            {
                throw new ArgumentNullException(nameof(padding));
            }

            using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
            {
                if (encrypt && data.Length == 0)
                {
                    int    bufSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
                    byte[] rented  = ArrayPool <byte> .Shared.Rent(bufSize);

                    Span <byte> paddedMessage = new Span <byte>(rented, 0, bufSize);

                    try
                    {
                        if (padding == RSAEncryptionPadding.Pkcs1)
                        {
                            RsaPaddingProcessor.PadPkcs1Encryption(data, paddedMessage);
                        }
                        else if (padding.Mode == RSAEncryptionPaddingMode.Oaep)
                        {
                            RsaPaddingProcessor processor =
                                RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm);

                            processor.PadOaep(data, paddedMessage);
                        }
                        else
                        {
                            throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode);
                        }

                        return(TryEncryptOrDecrypt(keyHandle, paddedMessage, destination, AsymmetricPaddingMode.NCRYPT_NO_PADDING_FLAG, null, encrypt, out bytesWritten));
                    }
                    finally
                    {
                        CryptographicOperations.ZeroMemory(paddedMessage);
                        ArrayPool <byte> .Shared.Return(rented);
                    }
                }

                switch (padding.Mode)
                {
                case RSAEncryptionPaddingMode.Pkcs1:
                    return(TryEncryptOrDecrypt(keyHandle, data, destination, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, null, encrypt, out bytesWritten));

                case RSAEncryptionPaddingMode.Oaep:
                    IntPtr namePtr = Marshal.StringToHGlobalUni(padding.OaepHashAlgorithm.Name);
                    try
                    {
                        var paddingInfo = new BCRYPT_OAEP_PADDING_INFO()
                        {
                            pszAlgId = namePtr,
                            pbLabel  = IntPtr.Zero,    // It would nice to put randomized data here but RSAEncryptionPadding does not at this point provide support for this.
                            cbLabel  = 0,
                        };
                        return(TryEncryptOrDecrypt(keyHandle, data, destination, AsymmetricPaddingMode.NCRYPT_PAD_OAEP_FLAG, &paddingInfo, encrypt, out bytesWritten));
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(namePtr);
                    }

                default:
                    throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode);
                }
            }
        }