Repository: dotnet/runtime
File: src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesImplementation.OpenSsl.cs (C#)

Code before:

        private int KeyWrap(ReadOnlySpan<byte> source, Span<byte> destination, int enc)
        {
            Debug.Assert(enc is 0 or 1);

            SafeEvpCipherCtxHandle ctx = GetKey().UseKey(
                state: enc,
                static (enc, key) =>
                {
                    int keySizeInBits = key.Length * 8;

                    IntPtr algorithm = GetKeyWrapAlgorithm(keySizeInBits);

                    return Interop.Crypto.EvpCipherCreate(
                        algorithm,
                        ref MemoryMarshal.GetReference(key),
                        key.Length * 8,
                        ref MemoryMarshal.GetReference(ReadOnlySpan<byte>.Empty),
                        enc);
                });

            int written;

            using (ctx)
            {
                bool ret = Interop.Crypto.EvpCipherUpdate(
                    ctx,
                    destination,
                    out written,
                    source);

                if (!ret)
                {
                    throw Interop.Crypto.CreateOpenSslCryptographicException();
                }
            }

            return written;
        }

        private static IntPtr GetAlgorithm(int keySize, int feedback, CipherMode cipherMode) =>
            (keySize, cipherMode) switch
            {
                // Neither OpenSSL nor Cng Aes support CTS mode.

                (128, CipherMode.CBC) => Interop.Crypto.EvpAes128Cbc(),
                (128, CipherMode.ECB) => Interop.Crypto.EvpAes128Ecb(),
                (128, CipherMode.CFB) when feedback == 8 => Interop.Crypto.EvpAes128Cfb8(),
                (128, CipherMode.CFB) when feedback == 128 => Interop.Crypto.EvpAes128Cfb128(),

                (192, CipherMode.CBC) => Interop.Crypto.EvpAes192Cbc(),

Review comment (suggestion):
We don't need to call `EVP_CipherFinal_ex`? If not it would be good to leave a comment explaining why, or at least that it is intentionally omitted.

Code after:

        private int KeyWrap(ReadOnlySpan<byte> source, Span<byte> destination, int enc)
        {
            Debug.Assert(enc is 0 or 1);

            SafeEvpCipherCtxHandle ctx = GetKey().UseKey(
                state: enc,
                static (enc, key) =>
                {
                    int keySizeInBits = key.Length * 8;

                    IntPtr algorithm = GetKeyWrapAlgorithm(keySizeInBits);

                    SafeEvpCipherCtxHandle ctx = Interop.Crypto.EvpCipherCreate(
                        algorithm,
                        ref MemoryMarshal.GetReference(key),
                        key.Length * 8,
                        ref MemoryMarshal.GetReference(ReadOnlySpan<byte>.Empty),
                        enc);

                    if (ctx.IsInvalid)
                    {
                        ctx.Dispose();
                        throw Interop.Crypto.CreateOpenSslCryptographicException();
                    }

                    return ctx;
                });

            int written;

            using (ctx)
            {
                // OpenSSL AES-KWP requires that the destination be at least as large as the source length plus the block size.
                const int AesBlockSizeBytes = 16;
                using (CryptoPoolLease lease = CryptoPoolLease.RentConditionally(
                    checked(source.Length + AesBlockSizeBytes),
                    destination,
                    skipClearIfNotRented: true))
                {
                    bool ret = Interop.Crypto.EvpCipherUpdate(
                        ctx,
                        lease.Span,
                        out written,
                        source);

                    if (!ret)
                    {
                        throw Interop.Crypto.CreateOpenSslCryptographicException();
                    }