Невозможно проверить подпись EDSCSA SHA-256

Я пытаюсь проверить ключ ECDSA, SHA-256. Но я не могу сделать это с помощью API веб-криптографии. Мой код выглядит так:

export async function verifySignature(
    requestData: string,
    receivedSignature: string,
    publicKey: string
): Promise<boolean> {
    try {
        const textEncoder = new TextEncoder();

        const digest = await crypto.subtle.digest('SHA-256', textEncoder.encode(requestData));
        // using digest

        // Import the public key
        if (importedKey == null) {
            importedKey = await crypto.subtle.importKey(
                'spki',
                stringToArrayBuffer(atob(publicKey)),
                { name: 'ECDSA', namedCurve: 'P-256' },
                true,
                ['verify']
            );
        }

        // Verify the signature
        const isValid = await crypto.subtle.verify(
            { name: 'ECDSA', hash: 'SHA-256' },
            importedKey,
            stringToArrayBuffer(atob(receivedSignature)),
            digest
        );
        
        return isValid;
    } catch (error) {
        console.error('Error verifying signature:', error);
        return false;
    }
}

Я могу проверить подпись с помощью команды openssl. openssl dgst -sha256 -verify public.pem -signature signature.der data.txt

Вот ссылка на песочницу кода с необходимой информацией — https://codesandbox.io/p/sandbox/beautiful-maria-2qkzxq

Любая помощь очень ценится. Я уже потратил на это день.. :( Заранее спасибо.

Не делайте дайджест самостоятельно; передать фактические данные в качестве четвертого аргумента .verify()

dave_thompson_085 21.05.2024 08:19
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть две ошибки:

  • ECDSA применяет различные форматы подписей: для вашего оператора OpenSSL требуется подпись ECDSA в кодировке ASN.1/DER, для API WebCrypto требуется подпись ECDSA в формате IEEE P1363. Последнее представляет собой объединение значений r и s (по 32 байта для P-256): r|s.

    Здесь вы можете найти пост с описанием двух форматов (также рассмотрите это для более крупных кривых, таких как P-521).

    Поскольку я не могу выполнить ваш онлайн-пример (даже после входа в систему: Песочница не найдена: ... Песочница... не существует или у вас нет необходимых разрешений...), я использую следующий ASN в шестнадцатеричной кодировке. Для иллюстрации закодирована подпись .1/DER, которую можно проверить с помощью вашего оператора OpenSSL с соответствующим открытым ключом (пробелы предназначены только для отображения).

    Согласно описанию в ссылках выше, он содержит r и s:

               r                                                                     s
    3045022100 926B0A95405429BBEE633F7E3377532F9BF9331DE67053C94793B2C21CEB0162 0220 473881D69AD9907CD87B047096C048ED387F12DC79D200E8E80C674F440ADFD5
    

    которые можно извлечь и объединить, r|s:

    926B0A95405429BBEE633F7E3377532F9BF9331DE67053C94793B2C21CEB0162473881D69AD9907CD87B047096C048ED387F12DC79D200E8E80C674F440ADFD5
    

    или в кодировке Base64:

    kmsKlUBUKbvuYz9+M3dTL5v5Mx3mcFPJR5OywhzrAWJHOIHWmtmQfNh7BHCWwEjtOH8S3HnSAOjoDGdPRArf1Q==
    

    это подпись в кодировке Base64 в формате IEEE P1363.

    Программное преобразование вместо ручного преобразования удобнее всего использовать с помощью библиотеки или кодера/декодера ASN.1/DER.

  • Как уже отмечалось в комментариях, API WebCrypto хеширует неявно.

Если оба фактора будут приняты во внимание, подпись можно будет успешно проверить с помощью вашего кода и соответствующего ключа (с использованием моей собственной функции b642ab(), поскольку stringToArrayBuffer() не было опубликовано):

(async () => {

var requestData = 'The quick brown fox jumps over the lazy dog';
var publicKey = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMpHT+HNKM7zjhx0jZDHyzQlkbLV0xk0H/TFo6gfT23ish58blPNhYrFI51Q/czvkAwCtLZz/6s1n/M8aA9L1Vg==';
var receivedSignature = 'kmsKlUBUKbvuYz9+M3dTL5v5Mx3mcFPJR5OywhzrAWJHOIHWmtmQfNh7BHCWwEjtOH8S3HnSAOjoDGdPRArf1Q=='; // Fix 1: apply signature in P1363 format

function b642ab(base64_string){  
    return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0));
}

// UTF8 encode message
const textEncoder = new TextEncoder();
const message = textEncoder.encode(requestData);

// Import the public key
var importedKey = null;
if (importedKey == null) {
    importedKey = await crypto.subtle.importKey(
        'spki',
        b642ab(publicKey),
        { name: 'ECDSA', namedCurve: 'P-256' },
        true,
        ['verify']
    );
}

// Verify the signature
const isValid = await crypto.subtle.verify(
    { name: 'ECDSA', hash: 'SHA-256' },
    importedKey,
    b642ab(receivedSignature),
    message // Fix 2: apply message instead of message hash
);

console.info("Verified: ", isValid);
    
})();

Похоже, у меня есть такой же код, как вы добавили, но с дайджестом. Я только что опубликовал коды и коробку @Topaco.

Suman Maharjan 21.05.2024 09:43

@SumanMaharjan — Код — это ваш код (кроме b642ab() и использования самого сообщения вместо хеша). Ключевым моментом является то, что вам необходимо преобразовать подпись OpenSSL, закодированную ASN.1/DER, в формат P1363, чтобы проверка прошла успешно. Это продемонстрировано на примере.

Topaco 21.05.2024 09:57

Другие вопросы по теме