Tradução de parâmetros da curva elíptica (BC para MS)

Estou tentando gerar um certificado autoassinado ECDSA, conforme descrito emgerar certificado usando ECDSA. Reunindo todas as partes da resposta de bartonjs e usandoNet.Framework 4.7 (ouNet.Core 2.0) o código a seguir parece estar funcionando, embora haja algumas ambiguidades (pelo menos uma) restantes:

Não sei como converter corretamente a chave privada (parâmetro 'D') deBC-BigInteger paraMS-byte[]. UsandoBigInteger.ToByteArray() lança exceção:

CryptographicException: Os parâmetros chave especificados não são válidos. Q.X e Q.Y são campos obrigatórios. Q.X, Q.Y deve ter o mesmo comprimento. Se D for especificado, ele deverá ter o mesmo comprimento que Q.X e Q.Y para curvas nomeadas ou o mesmo comprimento que Order para curvas explícitas.

ao validar parâmetros ECP (métodoECParameters.Validate()) UsandoBigInteger.ToByteArrayUnsigned() fornece resultados muito melhores (uma falha em várias centenas de pares de chaves gerados), mas ainda ...

Ao usarToByteArray() 'D' convertido é geralmente um byte mais longo ('D' tem 33 bytes vs D.X e D.Y tem 32 bytes). UsandoToByteArrayUnsigned() o 'D' às vezes é um byte mais curto.

Então, minha pergunta é se está ok para usarToByteArrayUnsigned().

private const string NCryptExportPolicyProperty = "Export Policy";
private const string SignatureAlgorithm = "Sha256WithECDSA";
private static readonly ECCurve MsCurve = ECCurve.NamedCurves.nistP256;
private static readonly DerObjectIdentifier BcCurve = SecObjectIdentifiers.SecP256r1; // must correspond with MsCurve

public static X509Certificate2 Create()
{    
    // 1. generate keys:
    IAsymmetricCipherKeyPairGenerator bcKeyGen = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
    bcKeyGen.Init(new ECKeyGenerationParameters(BcCurve, new SecureRandom()));

    ECPrivateKeyParameters bcPrivKey;
    ECPublicKeyParameters bcPublKey;

    bool validated;
    ECParameters msEcp;
    do
    {
        AsymmetricCipherKeyPair bcKeyPair = bcKeyGen.GenerateKeyPair();
        bcPrivKey = (ECPrivateKeyParameters)bcKeyPair.Private;
        bcPublKey = (ECPublicKeyParameters)bcKeyPair.Public;

        // 2. ensure generated bc-keys can be translated to cng (see exception below)
        msEcp = new ECParameters();
        msEcp.Curve = MsCurve;
        msEcp.D = bcPrivKey.D.ToByteArrayUnsigned(); // or bcPrivKey.D.ToByteArray() ??
        msEcp.Q.X = bcPublKey.Q.XCoord.GetEncoded();
        msEcp.Q.Y = bcPublKey.Q.YCoord.GetEncoded();

        try
        {
            msEcp.Validate();
            validated = true;
        }
        catch (Exception e)
        {
            // Validate() occasionally throws CryptographicException: 
            // The specified key parameters are not valid. Q.X and Q.Y are required fields. Q.X, Q.Y must be the same length. If D is specified it must be the same length as Q.X and Q.Y for named curves or the same length as Order for explicit curves.
            // e.g.: D = 31, Q.X = 32, Q.Y = 32.
            validated = false;
            Console.WriteLine("D = {0}, Q.X = {1}, Q.Y = {2}. {3}: {4}", msEcp.D.Length, msEcp.Q.X.Length, msEcp.Q.Y.Length, e.GetType().Name, e.Message);
        }
    } while (!validated);

    // 3. create x509 certificate:
    X509V3CertificateGenerator bcCertGen = new X509V3CertificateGenerator();
    bcCertGen.SetPublicKey(bcPublKey);
    // .. set subject, validity period etc
    ISignatureFactory sigFac = new Asn1SignatureFactory(SignatureAlgorithm, bcPrivKey);
    Org.BouncyCastle.X509.X509Certificate bcX509Cert = bcCertGen.Generate(sigFac);
    byte[] x509CertEncoded = bcX509Cert.GetEncoded();

    X509Certificate2 msNewCert;

    // 4. use translated (and validated) parameters:
    using (ECDsaCng msEcdsa = new ECDsaCng())
    {
        msEcdsa.ImportParameters(msEcp);

        CngKey msPrivateKey = msEcdsa.Key;

        // 5. make private key exportable:
        byte[] bytes = BitConverter.GetBytes((int)(CngExportPolicies.AllowExport | CngExportPolicies.AllowPlaintextExport));
        CngProperty pty = new CngProperty(NCryptExportPolicyProperty, bytes, CngPropertyOptions.Persist);
        msPrivateKey.SetProperty(pty);

        // 6. tie keys together:
        using (X509Certificate2 msPubCertOnly = new X509Certificate2(x509CertEncoded))
        {
            msNewCert = MateECDsaPrivateKey(msPubCertOnly, msPrivateKey); // method from bartonjs's answer
        }
    }

    return msNewCert;
}

Agradeço antecipadamente

questionAnswers(1)

yourAnswerToTheQuestion