Создание подписанных объявлений для SKAdnetwork в c# .net

После Apple SKADNetwork я сгенерировал закрытый ключ и открытый ключ с помощью этой команды.

openssl ecparam -name prime192v1 -genkey -noout -out private_key.pem

openssl ec -in private_key.pem -pubout -out public_key.pem

я могу сгенерировать действительную подпись с помощью python после этого проекта https://github.com/singular-labs/Singular-SKAdNetwork-App/tree/master/skadnetwork-server

Но когда я пытаюсь сгенерировать подпись с помощью библиотеки С# bouncycastle, у меня разные результаты, если я использую одни и те же данные.

ТЕСТ БАУНЦИКАСЛА

 public static AsymmetricCipherKeyPair ReadAsymmetricPrivateKeyParameter(string pemFilename)
    {
        var fileStream = System.IO.File.OpenText(pemFilename);
        var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(fileStream);
        var KeyParameter = (AsymmetricCipherKeyPair)pemReader.ReadObject();
        return (AsymmetricCipherKeyPair)KeyParameter;
    }

    static void Main(string[] args)
    {
        AsymmetricCipherKeyPair pkey = ReadAsymmetricPrivateKeyParameter("private_key.pem");

        string pars = getParamsSignature("2.0", "xxxxxxx.skadnetwork", "10", "302584613", "0a97ad57-87d1-49e7-b166-9152c708251b", "1613749507007", "0");

        Sign(pkey, "", pars);
        Console.Read();
    }

    static string getParamsSignature(string version, string ad_network_id, string campaign_id, string target_app_id, string nonce, string timestamp, string source_app_id)
    {
        string[] p = new string[] {
        version,
        ad_network_id,
        campaign_id,
        target_app_id,
        nonce,
        source_app_id,
        timestamp
        };
        return string.Join("\u2063", p);
    }

    public static bool Sign(AsymmetricCipherKeyPair pubKey,  string msg)
    {
        try
        {

            ECDomainParameters aa;
            byte[] msgBytes = Encoding.UTF8.GetBytes(msg);

            ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");

            signer.Init(true, pubKey.Private);

            signer.BlockUpdate(msgBytes, 0, msgBytes.Length);

            byte[] sigBsdytes = signer.GenerateSignature();

           
            var signature = Convert.ToBase64String(sigBsdytes);



            //MDUCGQDgqw1YQN/vvHTxXXTpovNYUnACzkFrXJwCGCXAnr3TUbbqIUr6cBamymrypcQET5RR7Q==


        }
        catch (Exception exc)
        {
            Console.WriteLine("Verification failed with the error: " + exc.ToString());
            return false;
        }
        return false;
    }

ТЕСТ .NET CORE 3

static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");


            string pars = getParamsSignature("2.0", "xxxxx.skadnetwork", "10", "302584613", "0a97ad57-87d1-49e7-b166-9152c708251b", "1613749507007", "0");

            //bool aaaaa = VerifySignature(aa, attribution_signature, pars);
            string eccPem = File.ReadAllText("private_key.pem");


            var key = ECDsa.Create(ECCurve.CreateFromValue("1.2.840.10045.3.1.1"));
            key.ImportECPrivateKey(Convert.FromBase64String(eccPem), out _);
         
            var signed = key.SignData(Encoding.UTF8.GetBytes(pars), HashAlgorithmName.SHA256);
            var hash = Convert.ToBase64String(signed);

        }

С тестом .net.core результат еще хуже, так как токен меняется при каждом выполнении. Я думаю, что это случайное поведение.

#BOUNCYCASTLE ДЕТЕРМИНИСТИЧЕСКИЙ ТЕСТ ФОРМАТ R|S и ASN1

            byte[] msgBytes = Encoding.UTF8.GetBytes(msg);


            ECDsaSigner signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha256Digest()));
            signer.Init(true, pubKey.Private);
            var sigBsdytes = signer.GenerateSignature(msgBytes);


            //SIGNATURE (R|S)
            Console.WriteLine( Convert.ToBase64String(sigBsdytes.SelectMany(a => a.ToByteArray()).ToArray()));


            //SIGNATURE (ASN1)
            var s = new MemoryStream();
            try
            {
                DerSequenceGenerator seq = new DerSequenceGenerator(s);

                seq.AddObject(new DerInteger(sigBsdytes[0]));
                seq.AddObject(new DerInteger(sigBsdytes[1]));
                seq.Close();

                
                var signature = Convert.ToBase64String(s.ToArray());

                Console.WriteLine(signature);
            }
            catch (IOException e)
            {
            }

Все еще имеет другой результат из библиотеки python FastECDSA, если входная строка та же самая.

ОБНОВЛЕНИЕ РЕШЕНИЯ: благодаря комментарию @topaco

            var crypt = new System.Security.Cryptography.SHA256Managed();
            byte[] msgBytes = crypt.ComputeHash(Encoding.UTF8.GetBytes(msg));

            ECDsaSigner signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha256Digest()));
            signer.Init(true, pubKey.Private);
            var sigBsdytes = signer.GenerateSignature(msgBytes);

            //SIGNATURE (ASN1)
            var s = new MemoryStream();
            try
            {
                DerSequenceGenerator seq = new DerSequenceGenerator(s);

                seq.AddObject(new DerInteger(sigBsdytes[0]));
                seq.AddObject(new DerInteger(sigBsdytes[1]));
                seq.Close();


                var signature = Convert.ToBase64String(s.ToArray());

                Console.WriteLine(signature);
            }
            catch (IOException e)
            {
            }

person Riccardo    schedule 22.02.2021    source источник
comment
Предоставляет ли код Python одну и ту же подпись (как код BC) при каждом выполнении или другую (как код .NET)? Обратите внимание, что существует детерминированный (RFC6979) и недетерминированный ECDSA. Оба являются надежными и обеспечивают действительные подписи.   -  person user 9014097    schedule 22.02.2021
comment
@topaco Я предполагаю, что python использует RFC6979, поскольку он каждый раз предоставляет одну и ту же подпись. я нашел этот способ использовать детерминированный ECDSA ECDsaSigner signer = new ECDsaSigner (новый HMacDsaKCalculator (новый Sha256Digest())); stackoverflow.com/ вопросы/51592748/   -  person Riccardo    schedule 22.02.2021
comment
@Topaco, если я использую RFC6979 как в системе Python, так и в C#, у меня будут разные результаты (но тот же результат с одним и тем же вводом в той же системе): это ожидаемое поведение?   -  person Riccardo    schedule 22.02.2021
comment
Обе реализации из вашего вопроса используют недетерминированный вариант, поскольку каждый раз они возвращают разные подписи. Но обе реализации применяют разные форматы подписи, код .NET/BC использует ASN.1 DER, чистый код .NET (r|s). Подход, опубликованный в вашем первом комментарии, действительно применяет детерминированный алгоритм в формате (r|s). Если код Python также использует детерминированный вариант, я ожидаю, что сигнатуры совпадают. Однако для сравнения форматы должны совпадать, поэтому в зависимости от формата Python может потребоваться преобразование.   -  person user 9014097    schedule 22.02.2021
comment
Python использует библиотеку FastECDSA github.com /singular-labs/Singular-SKAdNetwork-App/blob/master/ Поскольку результаты все еще различаются между системой python и comment1 (bouncycastle deterministic (r|s)) я попытаюсь нормализовать до тех же форматов   -  person Riccardo    schedule 22.02.2021
comment
@Topaco все ясно, спасибо. я обновил вопрос с последним тестом, но я все еще не могу получить тот же результат, что и на сервере python.   -  person Riccardo    schedule 22.02.2021
comment
ECDsaSigner не хеширует неявно, т. е. вы должны хешировать сообщение в коде C# явно с помощью SHA256 перед подписанием. Тогда результаты кода Python и C# на моей машине идентичны.   -  person user 9014097    schedule 22.02.2021
comment
@Topaco большое спасибо, теперь это работает!   -  person Riccardo    schedule 22.02.2021