File: src\libraries\Common\src\Interop\Unix\System.Security.Cryptography.Native\Interop.Bignum.cs
Web Access
Project: src\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
 
internal static partial class Interop
{
    internal static partial class Crypto
    {
        [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BigNumDestroy")]
        internal static partial void BigNumDestroy(IntPtr a);
 
        [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BigNumFromBinary")]
        private static unsafe partial SafeBignumHandle BigNumFromBinary(ReadOnlySpan<byte> bigEndianValue, int len);
 
        [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BigNumToBinary")]
        private static unsafe partial int BigNumToBinary(SafeBignumHandle a, byte* to);
 
        [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetBigNumBytes")]
        private static partial int GetBigNumBytes(SafeBignumHandle a);
 
        internal static SafeBignumHandle CreateBignum(ReadOnlySpan<byte> bigEndianValue)
        {
            SafeBignumHandle ret = BigNumFromBinary(bigEndianValue, bigEndianValue.Length);
            if (ret.IsInvalid)
            {
                Exception e = CreateOpenSslCryptographicException();
                ret.Dispose();
                throw e;
            }
 
            return ret;
        }
 
        internal static byte[]? ExtractBignum(IntPtr bignum, int targetSize)
        {
            // Given that the only reference held to bignum is an IntPtr, create an unowned SafeHandle
            // to ensure that we don't destroy the key after extraction.
            using (SafeBignumHandle handle = new SafeBignumHandle(bignum, ownsHandle: false))
            {
                return ExtractBignum(handle, targetSize);
            }
        }
 
        internal static unsafe byte[]? ExtractBignum(SafeBignumHandle? bignum, int targetSize)
        {
            if (bignum == null || bignum.IsInvalid)
            {
                return null;
            }
 
            int compactSize = GetBigNumBytes(bignum);
 
            if (targetSize < compactSize)
            {
                targetSize = compactSize;
            }
 
            // OpenSSL BIGNUM values do not record leading zeroes.
            // Windows Crypt32 does.
            //
            // Since RSACryptoServiceProvider already checks that RSAParameters.DP.Length is
            // exactly half of RSAParameters.Modulus.Length, we need to left-pad (big-endian)
            // the array with zeroes.
            int offset = targetSize - compactSize;
 
            byte[] buf = new byte[targetSize];
 
            fixed (byte* to = buf)
            {
                byte* start = to + offset;
                BigNumToBinary(bignum, start);
            }
 
            return buf;
        }
    }
}