private unsafe DiffieHellmanKey ExportKey(string keyType, DateTimeOffset?expiry)
        {
            int status = 0;

            status = BCryptExportKey(hPrivateKey, IntPtr.Zero, keyType, null, 0, out int pcbResult, 0);

            ThrowIfNotNtSuccess(status);

            DiffieHellmanKey key;

            using (var rental = CryptoPool.Rent <byte>(pcbResult))
            {
                var output = rental.Memory;

                fixed(byte *pbOutput = &MemoryMarshal.GetReference(output.Span))
                {
                    status = BCryptExportKey(hPrivateKey, IntPtr.Zero, keyType, pbOutput, pcbResult, out pcbResult, 0);

                    ThrowIfNotNtSuccess(status);

                    BCRYPT_DH_KEY_BLOB *param = (BCRYPT_DH_KEY_BLOB *)pbOutput;

                    key = new DiffieHellmanKey()
                    {
                        KeyLength   = param->header.cbKey,
                        Algorithm   = param->header.cbKey < 256 ? KeyAgreementAlgorithm.DiffieHellmanModp2 : KeyAgreementAlgorithm.DiffieHellmanModp14,
                        Type        = param->header.dwMagic == BCRYPT_DH_PRIVATE_MAGIC ? AsymmetricKeyType.Private : AsymmetricKeyType.Public,
                        CacheExpiry = expiry
                    };
                }

                var export = output.Span.Slice(sizeof(BCRYPT_DH_KEY_BLOB_HEADER));

                key.Modulus   = Copy(export.Slice(0, key.KeyLength));
                key.Generator = Copy(export.Slice(key.KeyLength, key.KeyLength));
                key.Public    = Copy(export.Slice(key.KeyLength + key.KeyLength, key.KeyLength));

                if (key.Type == AsymmetricKeyType.Private)
                {
                    key.Private = Copy(export.Slice(key.KeyLength + key.KeyLength + key.KeyLength, key.KeyLength));
                }

                key.Factor = Copy(Factor);
            }

            return(key);
        }
        private unsafe void ImportKey(DiffieHellmanKey incoming, ref IntPtr hKey)
        {
            DiffieHellmanKey key;

            string keyType;
            int    dwMagic;
            int    structSize;

            if (incoming.Type == AsymmetricKeyType.Private)
            {
                key = incoming;

                keyType    = BCRYPT_DH_PRIVATE_BLOB;
                dwMagic    = BCRYPT_DH_PRIVATE_MAGIC;
                structSize = sizeof(BCRYPT_DH_KEY_BLOB_HEADER) + (key.KeyLength * 4);
            }
            else
            {
                key = (DiffieHellmanKey)PublicKey;

                keyType    = BCRYPT_DH_PUBLIC_BLOB;
                dwMagic    = BCRYPT_DH_PUBLIC_MAGIC;
                structSize = sizeof(BCRYPT_DH_KEY_BLOB_HEADER) + (key.KeyLength * 3);
            }

            Factor = incoming.Factor.ToArray();

            using (var rented = CryptoPool.Rent <byte>(structSize))
            {
                rented.Memory.Span.Fill(0);

                fixed(byte *pbInput = &MemoryMarshal.GetReference(rented.Memory.Span))
                {
                    BCRYPT_DH_KEY_BLOB *param = (BCRYPT_DH_KEY_BLOB *)pbInput;

                    param->header.dwMagic = dwMagic;
                    param->header.cbKey   = key.KeyLength;

                    key.Modulus.CopyTo(
                        rented.Memory.Slice(sizeof(BCRYPT_DH_KEY_BLOB_HEADER))
                        );

                    key.Generator.CopyTo(
                        rented.Memory.Slice(sizeof(BCRYPT_DH_KEY_BLOB_HEADER) + key.Modulus.Length)
                        );

                    incoming.Public.CopyTo(
                        rented.Memory.Slice(sizeof(BCRYPT_DH_KEY_BLOB_HEADER) + key.Modulus.Length + key.Generator.Length)
                        );

                    if (incoming.Type == AsymmetricKeyType.Private && incoming.Private.Length > 0)
                    {
                        incoming.Private.CopyTo(
                            rented.Memory.Slice(sizeof(BCRYPT_DH_KEY_BLOB_HEADER) + key.Modulus.Length + key.Generator.Length + key.Public.Length)
                            );
                    }

                    var status = BCryptImportKeyPair(
                        hAlgorithm,
                        IntPtr.Zero,
                        keyType,
                        ref hKey,
                        pbInput,
                        structSize,
                        0
                        );

                    ThrowIfNotNtSuccess(status);
                }
            }
        }