Проверка подписи OpenSSL RSA: хеш и заполнение?
Я пытаюсь написать код для проверки некоторых подписей RSA. Подписи были сделаны с использованием инструмента командной строки OpenSSL, используя эквивалент этой командной строки:
openssl dgst -sha1 -sign private_key_file.pem < binary_data_file > sig
Я пытаюсь использовать libtomcrypt
сделать проверку:
Вот вызывающая подпись функции проверки 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");
}
}