ECDsaCng Проверка подписи эллиптической кривой данных из Android WebAuthn через C # в Windows

Я не могу заставить метод C # ECDsaCng VerifyData возвращать значение true, что бы я ни делал. Аналогичный код работает с подписями RSA и данными, поступающими из Windows Hello, но шифрование EC от Android / Samsung сбивает меня с толку.

assertion.Signature: - MEYCIQDi0OGHK2CRFpel6RWq26IjyWmJCfJnnaYvGWL / NBC6awIhANzNweSdj5uzFxDkvHeNgYcKaEuzgjEykiVJGfF / SNyd

assertion.ClientDataJSON: - {Тип: webauthn.get, вызов: ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmxlSEFpT2pFMk1UVTVOak14TWpBc0ltbHpjeUk2SWxSbGMzUXVZMjl0SWl3aVlYVmtJam9pVkdWemRDNWpiMjBpZlEuNXRLR3RlR1dBcEpjNFZpYjRHdGNHS01mS1VPUkFXWFl0bDBRd1BkQUxJVQ, Происхождение: https: // локальный: 3000, androidPackageName: com.android.chrome}

pubKey.x: - CeE16bdD0ga / oiy / zFL1c70Cp / 9me + HZzggzlTooWzU =

pubKey.y: - N5l + MynIqzxgut + phBUNIOcI7DIv2uRXHkLCesK90Cg =

Вот сегмент кода: -

        byte[] data = new byte[authData.Length + hashValClientData.Length];
        Buffer.BlockCopy(authData, 0, data, 0, authData.Length);
        Buffer.BlockCopy(hashValClientData, 0, data, authData.Length, hashValClientData.Length);

        byte[] sig = Convert.FromBase64String(assertion.Signature);

        if (pubKey.kty == "EC")
        {
            byte[] ECDsaSig = convertFromASN1(sig);
            var keyType = new byte[] { 0x45, 0x43, 0x53, 0x31 }; // BCRYPT_ECDSA_PUBLIC_P256_MAGIC {E, C, S, 1}
            var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 }; // Key length 32
            byte[] keyImport = new byte [72];
            Buffer.BlockCopy(keyType, 0, keyImport, 0, keyType.Length);
            Buffer.BlockCopy(keyLength, 0, keyImport, keyType.Length, keyLength.Length);
            Buffer.BlockCopy(Convert.FromBase64String(pubKey.x), 0, keyImport, 8, 32);
            Buffer.BlockCopy(Convert.FromBase64String(pubKey.y), 0, keyImport, 40, 32);

            try
            {
                using (ECDsaCng dsa = new ECDsaCng(CngKey.Import(keyImport, CngKeyBlobFormat.EccPublicBlob)))
                {
                    dsa.HashAlgorithm = CngAlgorithm.Sha256;
                    if (dsa.VerifyData(data, ECDsaSig))
                    {
                        Console.WriteLine("The signature is valid.");
                    }
                    else
                    {
                        Console.WriteLine("The signature is not valid.");
                        return FAIL_STATUS;
                    }
                }
            }
            catch (Exception e)
            {
                return FAIL_STATUS;
            }
        } 

После прочтения StackOverflow Я понял, что мне нужно преобразовать подпись ASN.1 в формат, удобный для ECDsa, поэтому я сделал следующее:

    internal byte[] convertFromASN1(byte[] sig)
    {
        const int DER = 48;
        const int LENGTH_MARKER = 2;

        if (sig.Length < 6 || sig[0] != DER || sig[1] != sig.Length - 2 || sig[2] != LENGTH_MARKER || sig[sig[3] + 4] != LENGTH_MARKER)
            throw new ArgumentException("Invalid signature format.", "sig");

        int rLen = sig[3];
        int sLen = sig[rLen + 5];

        byte[] newSig = new byte[rLen + sLen];
        Buffer.BlockCopy(sig, 4, newSig, 0, rLen);
        Buffer.BlockCopy(sig, 6 + rLen, newSig, rLen, sLen);

        return newSig;
    }

Но все равно без радости :-( Что я делаю не так? Помогите пожалуйста. (ClientData хешируется с помощью SHA256)


person McMurphy    schedule 17.03.2021    source источник


Ответы (1)


Примерно так должно работать:

if (pubKey.kty == "EC")
{
    byte[] ecDsaSig = convertFromASN1(sig);

    var point = new ECPoint
    {
        X = Convert.FromBase64String(pubKey.x),
        Y = Convert.FromBase64String(pubKey.y),
    };

    var ecparams = new ECParameters
    {
        Q = point,
        Curve = ECCurve.NamedCurves.nistP256
    };

    try
    {
        using (ECDsa ecdsa = ECDsa.Create(ecparams))
        {
            if (ecdsa.VerifyData(data, ecDsaSig, HashAlgorithmName.SHA256)
            {
                Console.WriteLine("The signature is valid.");
            }
            else
            {
                Console.WriteLine("The signature is not valid.");
                return FAIL_STATUS;
            }
        }
    }
    catch (Exception e)
    {
        return FAIL_STATUS;
    }
} 

Преобразование ASN.1 в формат IEEE P-1363, который требуется .NET, может быть довольно сложным. Некоторые рекомендации здесь и здесь.

Если вы возьмете образец своего сигнатуры здесь, вы можете лучше начать визуализацию " 1025 и заканчивается 3227, а Y начинается с 9987 и заканчивается 1469.

здесь, как указано здесь, в настоящее время делаю то же самое.

person aseigler    schedule 17.03.2021
comment
Как всегда, Алекс, ты кровавая легенда !. Stackoverflow лучше, если вы здесь. - person McMurphy; 18.03.2021