'dgst проверит и подпишет' эквивалентно 'RSA_Verify()'

Я использую функцию RSA_verify() для проверки SHA, который я подписал с помощью программы openssl (через консоль). RSA_verify() всегда возвращает неудачную проверку, поэтому я думаю, что отправляю ему неверные параметры.

Следующие консольные команды выполняются в Linux Ubuntu с OpenSSL 0.9.8k.

Насколько я помню, функции C скомпилированы для Android с использованием OpenSSL 1.0.1...c. Это определенно 1.0.1 (мы обновляем его, чтобы избежать проблемы с Heartbleed).

Это то, что я делаю ... пожалуйста, простите любую ошибку, поскольку я учусь этому сам.

  1. Сгенерировать закрытый ключ

    openssl genrsa -out private.key 2048
    
  2. Извлечь открытый ключ из закрытого ключа

    openssl rsa -in private.key -out public.key -outform PEM -pubout
    
  3. Рассчитайте SHA из файла с именем разрешения, а затем подпишите его с помощью private.key, на выходе будет SHA, но с шифрованием RSA (permissions.sign)

    openssl dgst -sha256 -sign private.key -out permissions.sign permissions
    
  4. Проверить полученную подпись SHA на соответствие файлу разрешений (успешно в консоли Ubuntu)

    openssl dgst -sha256 -verify public.key -signature permissions.sign permissions
    
  5. Я копирую файл разрешений, файл permissions.sign и файл public.key в файловую систему Android.

  6. Я проверяю, что permissions.sign был создан с разрешениями и с соответствующим private.key... все это с моим public.key (у меня нет закрытого ключа в Android).

Это функция С.

#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>

...

/* Initialize the public key */
RSA *pub_key = RSA_new();

if(NULL == pub_key)
{
   ANDROID_LOGE("RSA_new failed");
   result = 0;
}
else
{
   FILE* fp = fopen(public_key, "r");

   if(NULL == fp)
   {
      ANDROID_LOGE_P("fopen [%s] failed", public_key);
      result = 0;
   }
   else
   {
      /* Read it from the passed path */
      if(PEM_read_RSA_PUBKEY(fp, &pub_key, NULL, NULL) == NULL)
      {
         ANDROID_LOGE_P("[%s] can't be read", public_key);
         result = 0;
         fclose(fp);
      }
      else
      {
         /* Verify the file and its SHA with the public key */
         int verified = RSA_verify(
             NID_sha256,
             file, /* message digest (message to validate) */
             file_size, /* message size */
             sign, /* signature (signed SHA) */
             sign_size, /* signature size */
             pub_key);
         ANDROID_LOGD("NID_sha256");

         if(verified)
         {
            result = 1;
            ANDROID_LOGD_P("[%s] is valid", file_to_verify);
         }
         else
         {
            ANDROID_LOGE_P("[%s] is NOT valid", file_to_verify);
         }

         fclose(fp);
      }

      RSA_free(pub_key);
   }
}
  • public_key — это путь к public.key
  • PEM_read_RSA_PUBKEY завершается успешно
  • NID_sha256 - это то, что я думаю, я должен использовать для проверки
  • файл представляет собой массив байтов с содержимым разрешений
  • file_size - размер массива файла
  • sign — массив байтов с содержимым разрешения.sign
  • sign_size — размер массива знаков
  • RSA_verify() не работает, возвращает 0

Отсюда вопрос, правильно ли:

  • сгенерировать ключи с помощью команд, которые я использовал,

  • подпишите файл разрешений (который генерирует разрешения.sign),

  • а затем попытаться проверить файлы с помощью PEM_read_RSA_PUBKEY() и RSA_verify()?

Эквивалентны ли команды, которые я использовал для процесса подписи, функциям C, которые я использовал для процесса проверки?

Пожалуйста, дайте мне знать, если требуется дополнительная информация или где я могу узнать больше об этом.

Спасибо!

РЕДАКТИРОВАТЬ: я добавил печать ошибок после вызова RSA_Verify():

ANDROID_LOGE_P("openssl: %s", ERR_reason_error_string(ERR_get_error()));

Он печатает:

openssl: плохая подпись

Все еще исследую.


person Santiago Villafuerte    schedule 09.04.2015    source источник
comment
возможно ошибка в чтении в файлах?   -  person Hans Z.    schedule 10.04.2015
comment
Я проверил их, процесс чтения в порядке. Спасибо.   -  person Santiago Villafuerte    schedule 12.04.2015
comment
Команда OpenSSL рекомендует использовать функции EVP_DigestSign* и EVP_DigestVerify*. См. Подписание и проверка EVP. Вики также предоставляет код, который вы можете скопировать/вставить, чтобы сделать это.   -  person jww    schedule 12.04.2015


Ответы (1)


В моем процессе чтения открытого ключа было пропущено несколько шагов.

Правильные команды для генерации закрытых и открытых ключей следующие:

Создайте закрытый ключ "openssl genrsa -out private.key 2048"

Извлеките открытый ключ (форма сертификата DER) из закрытого ключа (необходимого для RSA_SHA_Verify()) «openssl req -outform DER -new -x509 -key private.key -out public.key -days 30000"

Создайте открытый ключ без информации о сертификате (требуется только для «openssl dgst -sha1 -verify...») «openssl x509 -inform DER -in public.key -pubkey -noout > public_no_cert.key"

Подпишите файл закрытым ключом «openssl dgst -sha1 -sign private.key -out разрешения.подписать разрешения»

Проверьте файл с открытым ключом (без информации о сертификате) «openssl dgst -sha1 -verify public_no_cert.key -signature разрешения.подписать разрешения»

Подробную информацию см. в документации на OpenSSL.org. Мне требовался сертификат DER X509, который содержал открытый ключ для проверки подписанного SHA с помощью RSA_verify().

Эквивалентность RSA_verify() в командном режиме:

openssl dgst -sha1 -verify public.key -signature разрешения.подписать разрешения

Для получения исходного кода перейдите по этой ссылке: http://www.bmt-online.org/geekisms/RSA_verify

Он НЕ компилируется с первого взгляда, его нужно настроить. Вызовите функции там следующим образом:

   result = sign_data(
         input_file_buffer,
         input_file_size,
         private_key_buffer,
         private_key_size,
         (void**)&signature,
         &signature_size);

   result = verify_data(
         input_file_buffer,
         input_file_size,
         signature_buffer,
         signature_size,
         public_key_buffer,
         public_key_size);

Все должно быть в оперативной памяти, передавать их как указатели.

Функция подписи ожидает, что указатель на указатель (**) сохранит в нем подписанный SHA. Позже вы можете сохранить его в файл.

Протестировано под Ubuntu openssl 0.9.8k.

Если вы видите, что чего-то не хватает, пожалуйста, дайте мне знать. Спасибо за чтение!

РЕДАКТИРОВАТЬ: Вот ссылка на исходный код... http://migsantiago.com/index.php/tutoriales/32-firma-y-valida-archivos-con-openssl

person Santiago Villafuerte    schedule 12.04.2015