Проверка подписи OpenSSL RSA: хеш и заполнение?

Я пытаюсь написать код для проверки некоторых подписей RSA. Подписи были сделаны с использованием инструмента командной строки OpenSSL, используя эквивалент этой командной строки:

openssl dgst -sha1 -sign private_key_file.pem < binary_data_file > sig

Я пытаюсь использовать libtomcrypt сделать проверку:

http://www.libtom.org/

Вот вызывающая подпись функции проверки RSA в libtomcrypt:

int rsa_verify_hash_ex(
    const unsigned char *sig, unsigned long siglen,  // signature to verify
    const unsigned char *hash, unsigned long hashlen,  // hash value to check against sig
    int padding,  // defined constant value, see below
    int hash_idx,  // identifies which hash algorithm, see below
    unsigned long saltlen,  // specify salt length, see below
    int *stat,  // output parameter, returns whether verify succeeded or not
    rsa_key *key);  // RSA public key to use for verify

Эта функция возвращает 0, если работает без ошибок, в противном случае возвращает код ошибки. Если он работает без ошибок, stat Выходной параметр указывает, проверена ли подпись.

Большинство аргументов кажутся простыми: передайте подпись для проверки, значение хеш-функции для ее сравнения и ключ RSA для проверки. hash_idx ясно из примера кода, включенного в libtomcrypt; это индекс в таблице поддерживаемых алгоритмов хэширования, и я могу найти правильное значение для использования с этим фрагментом кода: hash_idx = find_hash("sha1")

Но мне интересно о padding а также saltlen ценности. padding меня это не сильно волнует, так как есть только два возможных значения, и я могу просто попробовать их оба. Но что я должен принять за saltlen?

Документация OpenSSL для функций OpenSSL для проверки RSA не показывает saltlen параметр. Справочная страница для openssl dgst (т.е. результат man dgst) не обсуждает соль.

Итак, мои вопросы:

  • Как я могу определить правильную длину соли для использования?
  • Есть ли OpenSSL dgst Команда вставляет любой дополнительный материал во входные данные, такие как: (stdin)=

(Я нашел это (stdin)= поиск с помощью Stackru: почему подписи RSA-SHA256, которые я генерирую с помощью OpenSSL и Java, отличаются?)

  • libtomcrypt также имеет функцию под названием pkcs_1_pss_decode() который задокументирован, чтобы "декодировать кодированный блок подписи PSS". Есть ли шанс, что эту функцию мне нужно вызвать?

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

РЕДАКТИРОВАТЬ: благодаря помощи ниже, от @Jonathan Ben-Avraham, я смог заставить это работать сегодня. Ответы на мои вопросы, соответственно:

  • Используйте длину 0 для соли, без соли вообще.
  • Нет, OpenSSL не вставил ничего лишнего, например (stdin)=
  • Мне нужно было позвонить rsa_verify_hash_ex()и мне нужно было указать padding аргумент как LTC_LTC_PKCS_1_V1_5,

2 ответа

Решение

Без соли:

Сначала сгенерируйте двоичный хэш SHA1 из ваших данных:

openssl dgst -sha1 -binary -out hash1 some_data_file

Это хеш SHA1 или дайджест. Там нет соли, добавленной к файлу some_data_file, openssl dgst -sha1 сама не добавляет соли. Обратите внимание, что выходной файл представляет собой 20-байтовый хэш SHA1 без соли. Если бы была соль, хэш должен был бы включать ее, вероятно, перед ее добавлением перед последними 20 байтами, которые содержат хэш SHA1.

Затем подпишите хеш-файл SHA1 hash1 с вашим закрытым ключом:

openssl pkeyutl -sign -in hash1 -inkey privkey.pem -pkeyopt digest:sha1 -out sig1

Теперь подпишите some_data_file с openssl dgst:

openssl dgst -sha1 -sign privkey.pem < some_data_file > sig2

Наконец, сравните две подписи:

diff sig1 sig2

и вы должны увидеть, что они одинаковы. Это говорит нам о том, что подписывание необработанного SHA1-хэша файла без соли аналогично использованию openssl dgst -sha1 -sign Команда подписать файл, поэтому должно быть, что openssl dgst -sha1 -sign Команда также не использовала соль при генерации хеша SHA1 для sig2,

Обратите внимание, что вы не можете достичь того же результата, используя устаревший rsautl:

openssl rsautl -sign -in hash1 -inkey privkey.pem -out sig1

вместо openssl pkeyutlвидимо потому что openssl rsautl -sign включает зашифрованный текст в вывод, а также подпись. Смотрите этот пост SE для деталей.

Стоит подчеркнуть одну вещь: обязательно передавайте хеш вместо реальных данных. Это отбросило меня на некоторое время. Вот фрагмент кода, который работает (но используйте sha256):

void
verify_tomcrypt(unsigned char *keyblob, size_t klen,
                unsigned char *payload, size_t dlen,
                unsigned char *signature, size_t slen)
{
    rsa_key key;
    int stat;
    unsigned long len;
    unsigned char digest2[SHA256_DIGEST_LENGTH];

    ltc_mp = ltm_desc;
    register_hash(&sha256_desc);

    /* try reading the key */
    if (rsa_import(keyblob, klen, &key) != CRYPT_OK) {
        printf("Error reading key\n");
        exit(-1);
    }

    int hash_idx = find_hash("sha256");
    if (hash_idx == -1) {
        printf("LTC_SHA256 not found...?\n");
        exit(-1);
    }
    len = sizeof(digest2);
    if (hash_memory(hash_idx, payload, dlen, digest2, &len) != CRYPT_OK) {
        printf("sha256 fails...?\n");
        exit(-1);
    }

    if (rsa_verify_hash_ex(signature, slen, digest2, sizeof(digest2), LTC_LTC_PKCS_1_V1_5, hash_idx, 0, &stat, &key) == CRYPT_OK) {
        if (stat == 1)
            printf("Tomcrypt: Signature OK!\n");
        else
            printf("Tomcrypt: Signature NOK?\n");
    } else {
        printf("Tomcrypt: Signature error\n");
    }
}
Другие вопросы по тегам