Подпись ECDSA усекается

Я пытаюсь создать подпись ECDSA, и большую часть времени она создается идеально, но иногда она усекается случайным образом, например, значения r и s должны быть равны 48, но иногда я получаю 47 для одного и 48 для другого. Я не могу сказать, в чем проблема: проблема с подписью или проблема с процедурой, используемой для получения значений r и s из подписи?

    const BIGNUM *r;
    const BIGNUM *s;
    ECDSA_SIG_get0(signature, &r, &s);
    char *R = BN_bn2hex(r);
    char *S = BN_bn2hex(s);
    int r_len = BN_num_bytes(r);
    int s_len = BN_num_bytes(s);
    uint8_t *r_bytes = (uint8_t *)malloc(r_len);
    uint8_t *s_bytes = (uint8_t *)malloc(s_len);
    BN_bn2bin(r, r_bytes);
    BN_bn2bin(s, s_bytes);
    int signature_len = r_len + s_len;
    uint8_t *signature2 = (uint8_t *)malloc(signature_len);
    memcpy(signature2, r_bytes, r_len);
    memcpy(signature2 + r_len, s_bytes, s_len);
    int max_encoded_len = EVP_ENCODE_LENGTH(signature_len);
    *ppcSignature1 = (char *)calloc(max_encoded_len,1);

Я попытался снова получить значения r и s из той же сигнатуры, добавив этот блок кода:

if (r_len != 48 || s_len != 48){
    const BIGNUM *r_temp = ECDSA_SIG_get0_r(signature);
    const BIGNUM *s_temp = ECDSA_SIG_get0_s(signature);
    char *R_temp = BN_bn2hex(r_temp);
    char *S_temp = BN_bn2hex(s_temp);
    printf("R_LEN : %s\n",R_temp);
    printf("S_LEN : %s\n",S_temp);
}

И все же значения рлена и слена были одинаковыми.

Как часто кажется, что его усекают? Может ли это быть 1 раз из 256? Вы не считаете «размер» подписи, BN_num_bytes дает количество значащих байтов. Если самый старший байт окажется равным 0, чего вы ожидаете?

Thomas Jager 15.07.2024 13:25

@ThomasJager Я думаю, что это примерно 1 раз из 256.

Ajith Nair 15.07.2024 13:57
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Похоже, проблема не в усечении подписи, а скорее в интерпретации значения, возвращаемого BN_num_bytes (обратите внимание, что это макрос, похожий на функцию).

BN_num_bytes указывает, сколько байтов потребуется целочисленному значению для хранения числа в BIGNUM. Это не означает, что подпись состоит из меньшего количества байт, это все равно 48-байтовое значение. Но если BN_num_bytes возвращает 47, то вы знаете, что при интерпретации этого числа как имеющего 48 байт старшие 8–15 бит значения будут равны 0.

Если у вас есть подпись со значением 0x34529, вы получите значение 3 из BN_num_bytes, поскольку для представления этого числа вам нужно всего три байта. Другими словами, он имеет 3 значащих байта.


Из примечаний на странице с описанием BN_num_bytes:

Некоторые пытались использовать BN_num_bits() для отдельных чисел в ключах RSA, ключах DH и ключах DSA и обнаружили, что они не всегда получают ожидаемое количество бит (что-то вроде 512, 1024, 2048,...). . Это связано с тем, что генерация числа с определенным количеством битов не всегда устанавливает старшие биты, тем самым делая количество значимых битов немного меньшим. Если вы хотите узнать «размер ключа» такого ключа, либо используйте такие функции, как RSA_size(), DH_size() и DSA_size(), либо используйте BN_num_bytes() и умножьте на 8 (хотя нет реальной гарантии, что это будет соответствовать размеру ключа). «размер ключа», просто гораздо больше вероятности).

В документации отмечается проблема с использованием BN_num_bits для получения размера ключа в битах, что имеет вероятность 50/50 фактического соответствия ожидаемому размеру ключа. Затем он отмечает, что вы можете использовать BN_num_bytes, но это лишь с большей вероятностью даст вам правильный результат, а не гарантировано (вероятность неправильного результата от 1/2 до 1/256).


BN_num_bytes может быть полезен для распределения места, но не даст вам информации о характере подписи. Это универсальный инструмент, связанный с BIGNUM, он не «знает», насколько велика ваша подпись, он просто видит число.

Спасибо за вашу помощь! Я хотел получить значения BIGNUM r и s подписи ecdsa в структуре ECDSA_SIG, как мне тогда это сделать? Есть ли альтернативный способ?

Ajith Nair 16.07.2024 11:29

@AjithNair Разве ты не этим уже занимаешься? Я сосредоточился на проблеме BN_num_bytes, но похоже, что вы правильно получаете подписи в первом блоке кода. Если проблема в том, что разные размеры нарушают кодировку, которую вы делаете после этого, я бы предложил вместо этого выделить новый signature2 для подписей размером 48 байт (игнорируя значения, которые вы получаете от BN_num_bytes, вместо этого signature_len = 48 + 48), а затем скопировать что-то вроде signature2 + (48 - r_len) и signature2 + r_len + (48 - s_len) (или какой-нибудь более чистый вариант).

Thomas Jager 16.07.2024 12:30

(Также обязательно обнулите те байты, которые не заполнены подписями.)

Thomas Jager 16.07.2024 12:58

@AjithNair Что вы подразумеваете под словом «усечено»? Было ли около 96 символов? Вы также не используете значения, возвращаемые BN_bn2hex, они показаны только для использования во втором блоке кода.

Thomas Jager 16.07.2024 14:08

Да, вы правы, спасибо за помощь

Ajith Nair 16.07.2024 14:31

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