Подтвердить что ты не робот

Microsoft Crypto API Отключить использование RSAES-OAEP Key Transport Algorithm

Я использую CryptEncryptMessage для создания огибаемого сообщения PKCS#7. Я использую szOID_NIST_AES256_CBC как алгоритм шифрования.

Сгенерированное сообщение представляется допустимым, но это RSAES-OAEP для алгоритма транспорта ключей, который имеет ограниченную поддержку в дикой природе (Thunderbird, OpenSSL SMIME Module среди многих других не поддерживает его).

Мне бы хотелось, чтобы CAPI вернулась к старшему RSAencryption для транспорта ключей.

Есть ли какой-либо возможный способ сделать это, я мог бы вернуться к функциям обмена сообщениями низкого уровня, если есть способ, а не использовать CryptEncryptMessage, но я не могу найти способ сделать это, даже используя функции низкого уровня.

код:

CRYPT_ENCRYPT_MESSAGE_PARA EncryptMessageParams;
EncryptMessageParams.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);

EncryptMessageParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING;

EncryptMessageParams.ContentEncryptionAlgorithm.pszObjId = szOID_NIST_AES256_CBC;
EncryptMessageParams.ContentEncryptionAlgorithm.Parameters.cbData = 0;
EncryptMessageParams.ContentEncryptionAlgorithm.Parameters.pbData = 0;

EncryptMessageParams.hCryptProv = NULL;
EncryptMessageParams.pvEncryptionAuxInfo = NULL;
EncryptMessageParams.dwFlags = 0;
EncryptMessageParams.dwInnerContentType = 0;

BYTE pbEncryptedBlob[640000];
DWORD pcbEncryptedBlob = 640000;

BOOL retval =  CryptEncryptMessage(&EncryptMessageParams, cRecipientCert, pRecipCertContextArray, pbMsgText, dwMsgTextSize, pbEncryptedBlob, &pcbEncryptedBlob);
4b9b3361

Ответ 1

Ключевой транспортный алгоритм немного сложнее обрабатывать, и он может не служить своей цели (я вижу, вы заметили, что CAPI должен поддерживать RSAencryption, верьте мне, я тоже). Похоже, вы обнаружили, что alaready обнаружил основную часть вашей проблемы - Сгенерированное сообщение появляется, но ваш метод делает необходимым использовать CryptEncryptMessage, который не будет работать хорошо/вообще в конечном итоге.

Шаг 1 - Изучите код

CRYPT_ENCRYPT_MESSAGE_PARA EncryptMessageParams;
EncryptMessageParams.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);

EncryptMessageParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING;

EncryptMessageParams.ContentEncryptionAlgorithm.pszObjId = szOID_NIST_AES256_CBC;
EncryptMessageParams.ContentEncryptionAlgorithm.Parameters.cbData = 0;
EncryptMessageParams.ContentEncryptionAlgorithm.Parameters.pbData = 0;

EncryptMessageParams.hCryptProv = NULL;
EncryptMessageParams.pvEncryptionAuxInfo = NULL;
EncryptMessageParams.dwFlags = 0;
EncryptMessageParams.dwInnerContentType = 0;

BYTE pbEncryptedBlob[640000];
DWORD pcbEncryptedBlob = 640000;

BOOL retval =  CryptEncryptMessage(&EncryptMessageParams, cRecipientCert, pRecipCertContextArray, pbMsgText, dwMsgTextSize, pbEncryptedBlob, &pcbEncryptedBlob);

Довольно простой, не так ли? Хотя это и эффективно, на самом деле это не проблема. Если вы посмотрите на это:

EncryptMessageParams.dwFlags = 0;
EncryptMessageParams.dwInnerContentType = 0;

вы увидите, что он предварительно определен, но используется только в определении retval. Тем не менее, я определенно мог видеть это как микро-оптимизацию, и не очень полезно, если мы собираемся переписать код. Однако я изложил основные шаги, чтобы интегрировать это без полного повторения кода (чтобы вы могли продолжать использовать одни и те же параметры):

Шаг 2 - Редактирование параметров

Как отмечает @owlstead в своих комментариях, Crypto API не очень удобен для пользователя. Однако вы отлично справились с ограниченными ресурсами. Что бы вы хотели добавить, это Cryptographic Enumeration Provider, чтобы сузить ключи. Убедитесь, что вы используете Microsoft Base Cryptographic Provider версии 1.0 или Microsoft Enhanced Cryptographic Provider версии 1.0 для эффективного использования. В противном случае вам нужно добавить функцию так:

DWORD cbName;
DWORD dwType;
DWORD dwIndex;
CHAR *pszName = NULL;
(regular crypt calls here)

В основном это используется для предотвращения ошибки NTE_BAD_FLAGS, хотя технически вы можете избежать этого при более низкоуровневой декларации. Если вы хотите, вы также можете создать совершенно новый хеш (хотя это необходимо только в том случае, если вышеприведенная реализация не будет масштабироваться до необходимого коэффициента времени/скорости):

DWORD dwBufferLen = strlen((char *)pbBuffer)+1*(0+5);
HCRYPTHASH hHash;
HCRYPTKEY hKey;
HCRYPTKEY hPubKey;
BYTE *pbKeyBlob;
BYTE *pbSignature;
DWORD dwSigLen;
DWORD dwBlobLen;
(use hash as normal w/ crypt calls and the pbKeyBlobs/Signatures)

Обязательно запустите этот фрагмент, прежде чем двигаться дальше. Вы можете сделать так легко:

if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
     printf("CSP context acquired.\n");
}

Если вы документируете или выпускаете, возможно, захотите добавить void MyHandleError(char *s), чтобы поймать ошибку, чтобы кто-то, кто редактирует, но не смог, может быстро ее поймать.

Кстати, при первом запуске вам нужно будет создать новый набор, потому что нет значения по умолчанию. Ниже приведена хорошая однострочная линия, которая может быть вставлена ​​в if:

CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)

Помните, что синхронизация ресурсов сервера будет не столь же эффективной, как и повторная работа, предложенная на первом этапе. Вот что я объясню ниже:

Шаг 3 - Перекодирование и повторная передача

Как программист, повторное кодирование может показаться пустой тратой времени, но в конечном итоге это может помочь вам. Помните, что вам все равно придется кодировать пользовательские параметры при кодировании/синхронизации; Я не собираюсь подавать вам весь код, как ребенок. Это должно быть достаточно, чтобы показать вам основные очертания.

Я определенно предполагаю, что вы пытаетесь обращаться к контейнеру текущего пользователя внутри конкретного CSP; В противном случае я не вижу этого. Если нет, вы можете сделать некоторые основные изменения в соответствии с вашими потребностями.

Помните, что мы будем обходить CryptEncryptMessage с помощью CryptReleaseContext, который напрямую освобождает дескриптор, полученный функцией CryptAcquireContext. Стандарт Microsoft на CAC ниже:

BOOL WINAPI CryptAcquireContext(
  _Out_  HCRYPTPROV *phProv,
  _In_   LPCTSTR pszContainer,
  _In_   LPCTSTR pszProvider,
  _In_   DWORD dwProvType,
  _In_   DWORD dwFlags
);

Обратите внимание, что Microsoft ругает вас, если вы используете пользовательский интерфейс:

Если CSP должен отображать интерфейс для работы, вызов завершается с ошибкой, а код ошибки NTE_SILENT_CONTEXT устанавливается как последняя ошибка. Кроме того, если вызовы выполняются в CryptGenKey с флагом CRYPT_USER_PROTECTED с контекстом, который был получен с помощью флага CRYPT_SILENT, вызовы завершаются ошибками, а CSP устанавливает NTE_SILENT_CONTEXT.

Это главным образом код сервера, и ERROR_BUSY определенно будет отображаться для новых пользователей, когда есть несколько соединений, особенно с высокой задержкой. Выше 300 мс просто вызовет NTE_BAD_KEYSET_PARAM или аналогичный вызов из-за тайм-аута без получения надлежащей ошибки. (Проблемы с передачей, кто-нибудь со мной?)

Если вы не беспокоитесь о нескольких DLL (которые это не поддерживает из-за ошибок NTE_PROVIDER_DLL_FAIL), базовая настройка для доступа к услугам клиентов crypt будет такой, как показано ниже (скопирована непосредственно из примеров Microsoft):

if (GetLastError() == NTE_BAD_KEYSET)
 {
   if(CryptAcquireContext(
      &hCryptProv, 
      UserName, 
      NULL, 
      PROV_RSA_FULL, 
      CRYPT_NEWKEYSET)) 
    {
      printf("A new key container has been created.\n");
    }
    else
    {
      printf("Could not create a new key container.\n");
      exit(1);
    }
  }
  else
  {
      printf("A cryptographic service handle could not be "
          "acquired.\n");
      exit(1);
   }

Как бы просто это ни показалось, вы определенно не хотите зацикливаться на этом алгоритме обмена ключами (или что бы вы ни занимались с этим). Если вы не используете симметричные ключи сеанса (Diffie-Hellman/KEA), ключевую пару обмена можно использовать для шифрования ключей сеанса, чтобы их можно было безопасно хранить и обменивать с другими пользователями.

Кто-то по имени Джон Говард написал хорошую утилиту настройки удаленного управления Hyper-V (HVRemote), которая является большой компиляцией описанных здесь технологий. В дополнение к использованию основных склепов и клавиш, их можно использовать для разрешения ANONYMOUS LOGON удаленного доступа DCOM (cscript hvremote.wsf, чтобы быть конкретным). Вы можете увидеть многие функции и методы в своих последних криптах (вам придется сузить запрос) в своем блоге:

http://blogs.technet.com/b/jhoward/

Если вам нужна дополнительная помощь по основам, просто оставьте комментарий или попросите частный чат.

Заключение

Хотя это довольно просто, когда вы понимаете основные серверные методы хэширования и как клиент захватывает "крипты", вы будете подвергать сомнению, почему вы даже пробовали шифрование во время передачи. Однако, без шифрования клиентов, шифрование, безусловно, будет единственным безопасным способом передачи того, что уже было хэшировано.

Несмотря на то, что вы можете утверждать, что пакеты могут быть дешифрованы и удалены солями, учтите, что как входящие, так и исходящие должны обрабатываться и сохраняться в правильном времени и порядке, необходимых для повторного хеш-клиента.