Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[35.168.113.41] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте.
Необходимо генерировать закрытый и открытый ключ. Код собрал по найденным примерам в сети: int CreateKeys(CString& strPublicKey, CString& strPrivateKey) { const DWORD KEYLENGTH = 2048 << 16; HCRYPTPROV hCryptProv = NULL; HCRYPTKEY hKey = NULL; DWORD dwBlobLength = 0; LPBYTE ppbKeyBlob = NULL; if (!CryptAcquireContext(&hCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET)) { if (!CryptAcquireContext(&hCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0)) { return -1; } } if (!CryptGenKey(hCryptProv, CALG_RSA_KEYX, KEYLENGTH | CRYPT_EXPORTABLE | CRYPT_NO_SALT, &hKey)) { return -1; } HRESULT hr = CryptExportKeyHelper(hKey, NULL, PRIVATEKEYBLOB, &ppbKeyBlob, &dwBlobLength); if (FAILED(hr)) { return -1; } DWORD dwStringLength = 0; if (!CryptBinaryToString(ppbKeyBlob, dwBlobLength, CRYPT_STRING_BASE64HEADER, 0, &dwStringLength)) { return -1; } if (!CryptBinaryToString(ppbKeyBlob, dwBlobLength, CRYPT_STRING_BASE64HEADER, strPrivateKey.GetBuffer(dwStringLength), &dwStringLength)) { return -1; } CoTaskMemFree(ppbKeyBlob); strPrivateKey.ReleaseBuffer(); hr = CryptExportKeyHelper(hKey, NULL, PUBLICKEYBLOB, &ppbKeyBlob, &dwBlobLength); if (FAILED(hr)) { return -1; } dwStringLength = 0; if (!CryptBinaryToString(ppbKeyBlob, dwBlobLength, CRYPT_STRING_BASE64HEADER, 0, &dwStringLength)) { return -1; } if (!CryptBinaryToString(ppbKeyBlob, dwBlobLength, CRYPT_STRING_BASE64HEADER, strPublicKey.GetBuffer(dwStringLength), &dwStringLength)) { return -1; } CoTaskMemFree(ppbKeyBlob); strPublicKey.ReleaseBuffer(); CryptDestroyKey(hKey); return 0; } HRESULT CryptExportKeyHelper(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTKEY hExpKey, DWORD dwBlobType, _Outptr_result_bytebuffer_(*pcbBlob) BYTE **ppbBlob, _Out_ DWORD *pcbBlob) { *ppbBlob = nullptr; *pcbBlob = 0; DWORD cbBlob = 0; HRESULT hr = CryptExportKey(hKey, hExpKey, dwBlobType, 0, nullptr, &cbBlob) ? S_OK : HRESULT_FROM_WIN32(GetLastError()); if (SUCCEEDED(hr)) { BYTE *pbBlob = reinterpret_cast<BYTE *>(CoTaskMemAlloc(cbBlob)); hr = (pbBlob != nullptr) ? S_OK : E_OUTOFMEMORY; if (SUCCEEDED(hr)) { hr = CryptExportKey(hKey, hExpKey, dwBlobType, 0, pbBlob, &cbBlob) ? S_OK : HRESULT_FROM_WIN32(GetLastError()); if (SUCCEEDED(hr)) { *ppbBlob = pbBlob; *pcbBlob = cbBlob; pbBlob = nullptr; } CoTaskMemFree(pbBlob); } } return hr; } На выходе: Цитата -----BEGIN CERTIFICATE----- BgIAAACkAABSU0ExAAQAAAEAAQBxR/JTB6hqD86PaRQC/CagvUFfJOtap3ocEty4 KWh8KZR8mrYhquFhd1DRtz4a84Mu9CpIBzMFh1MPFRVebYFwqe11L6upzQCH2ryX dbOtcHWGVKRzwg6RhQyljJ9ZLtzD5VL/63HUAodO9xXNhB4eVmmPQ2ETVtrH4axv rgf+uA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- BwIAAACkAABSU0EyAAQAAAEAAQBxR/JTB6hqD86PaRQC/CagvUFfJOtap3ocEty4 KWh8KZR8mrYhquFhd1DRtz4a84Mu9CpIBzMFh1MPFRVebYFwqe11L6upzQCH2ryX dbOtcHWGVKRzwg6RhQyljJ9ZLtzD5VL/63HUAodO9xXNhB4eVmmPQ2ETVtrH4axv rgf+uAed5Ss2kY8iZJec5DKtjr+Jgv+ykcpmyngYkr5hfxESlPBySNCF61DtuJRy jGdHcxd5zeiE9MjoRHPR/vGqI+nHUYrYZS+aH12Q9VnsQc5FFG0fzsa+uS+qnEp/ S+FrTWFUJQeW4wfyw0WhYKa0PYk+vFiFZACswb7BH+bvwiHLV5DexDkNtOSTO+6Q hhBXc2NXGk3z+cSo4ilBnSMh/XrQSReusmzDtilcIqPRUPpPOtEGHIL2QQAFi5gC xvpJZWOth+zMuqu1iliA9iOQWsNkIyAuAocWvS/IabIs7mCEba+B+lWqeiRDi5eA hTTsRY6gKvhxgtXNDyFX1tbLsUdZCGexFvr7Ov0cSn/Iz5jsTPEWI0rIVyH+6jMl uK+eaA/4pvd6sNTirkw8ppEoCCFBvj7pwQx5wrsnv8AqF7OAXXdflCyOXCpA1A/e rTj7+2H315T2X6sQqdAXVoeZzQxbiMpYB7524KRXBo8XU1m8GbM2MbbSorSQnIHt 1t6gFIr2ZAdgRumeBpOSA7FEYbZNqBmRc4fob267KSOGwBsvayYXx5g2b5isJsK8 I0+EN48ox3zmqvc9empgGIG48Wo= -----END CERTIFICATE----- Что я упустил? |
Сообщ.
#2
,
|
|
|
Цитата WinAx @ Необходимо генерировать закрытый и открытый ключ. Что я упустил? А что, что-то не получается ? Судя по результатам, как будто бы, всё получилось. Однако, можно предложить: 1. всё это хозяйство оформить классом. 2. всё, что связано с получением/возвращением ресурсов, тоже обернуть классами. Например: HCRYPTPROV , HCRYPTKEY , CoTaskMemAlloc/CoTaskMemFree |
Сообщ.
#3
,
|
|
|
Должно быть:
Цитата -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArtBewZDcVXXw+dtoDbCR 6cZZZvkdbeQcNzKpNS8g6F4BuMuzjkrFyOT7HWGuF0nTd9rkgUM+nQu/zR1LClaV ............. -----END PUBLIC KEY----- -----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDGtt1MVGVT7K68 G1Vyvv6GugCMS2HER+K5hm6Ff+XYkV6WjLHIgEXBcDWHMIuGELUOYBRN2WsO01Nu ............. -----END PRIVATE KEY----- |
Сообщ.
#4
,
|
|
|
Цитата WinAx @ Должно быть: Цитата -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArtBewZDcVXXw+dtoDbCR 6cZZZvkdbeQcNzKpNS8g6F4BuMuzjkrFyOT7HWGuF0nTd9rkgUM+nQu/zR1LClaV ............. -----END PUBLIC KEY----- -----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDGtt1MVGVT7K68 G1Vyvv6GugCMS2HER+K5hm6Ff+XYkV6WjLHIgEXBcDWHMIuGELUOYBRN2WsO01Nu ............. -----END PRIVATE KEY----- Скорее всего, у Микрософта так не будет. я пробовал - у меня всегда получалось, что в качестве приватного ключа было объединение публичного и приватного. А публичный - отдельно. Поэтому, "приватный ключ" - длиннее. Почему так, я и сам бы хотел узнать. Поэтому "приватный" у Микрософта можно было использовать для обеих операций, а "публичный" - как положено. --- Проведи прямой эксперимент. Публичным зашифруй, приватным расшифруй. Тогда станет ясно, получилось или нет. |
Сообщ.
#5
,
|
|
|
Проблема не в длине.
Когда я генерировал ключи в php (там OpenSSL), ключи всегда были обернуты: Цитата -----BEGIN PUBLIC KEY----- -----END PUBLIC KEY----- -----BEGIN PRIVATE KEY----- -----END PRIVATE KEY----- И начинались с одинаковых символов. Предполагаю что это заголовки RSA ключей. В CryptoAPI получается сертификаты. Тоже начинаются с одинаковых символов, но других. |
Сообщ.
#6
,
|
|
|
Заменил флаг CRYPT_STRING_BASE64HEADER на CRYPT_STRING_BASE64.
Получается сам BASE64. Публичный шифрует, приватный дешифрует. Вроде все ок. |
Сообщ.
#7
,
|
|
|
Цитата WinAx @ Проблема не в длине. Когда я генерировал ключи в php (там OpenSSL), ключи всегда были обернуты: Цитата -----BEGIN PUBLIC KEY----- -----END PUBLIC KEY----- -----BEGIN PRIVATE KEY----- -----END PRIVATE KEY----- Такие заголовки, вероятно, результат деятельности "CryptBinaryToString". В двоичном образе ключа их вообще нет. Никогда не видел. К шифровке/расшифровке они отношения не имеют. Хотя у двоичных ключей тоже есть какой-то заголовок 16 байт. А зачем вообще в текст преобразовывать ? |
Сообщ.
#8
,
|
|
|
Цитата ЫукпШ @ А зачем вообще в текст преобразовывать ? По задумке сервер их должен был отправлять их клиенту по http. В общем, то с этим и проблема... Не силен я в шифровании. Прошу пояснить просвещенных. В чем была задумка: Сервер генерирует пару ключей. Клиент берет публичный ключ и шифрует данные. Другой клиент берез приватный ключ и дешифрует. При шифровании одних данных, одним ключом - результат всегда разный. Если шифрование/дешифрование производится одной программой последовательно - все норм. Если шифрует одни клиент, а дешифрует другой (одной парой ключей) - CryptDecrypt ERROR_INVALID_PARAMETER. Это особенность алгоритма или ошибка в программе? |
Сообщ.
#9
,
|
|
|
Цитата WinAx @ В чем была задумка: Сервер генерирует пару ключей. Клиент берет публичный ключ и шифрует данные. Другой клиент берез приватный ключ и дешифрует. Да, я тоже так делаю. Только в текст не преобразовывал никогда. Микрософтной реализацией, устойчиво работает. Добавлено Цитата WinAx @ При шифровании одних данных, одним ключом - результат всегда разный. Специально это я не проверял, надо будет попробовать. Теоретически это может быть - если сами функции шифрования добавляют к данным случайную последовательность. Не проверял. Если будет время, проверю. --- Но конечно, это полезная необходимость. Если этого нет, надо мастерить самому. Добавлено Цитата WinAx @ Если шифрует одни клиент, а дешифрует другой (одной парой ключей) - CryptDecrypt ERROR_INVALID_PARAMETER. Это особенность алгоритма или ошибка в программе? Это явная ошибка - поскольку ничего же не работает. Смысл в том, что разные программы на разных компах могут обмениваться шифрованными сообщениями. |
Сообщ.
#10
,
|
|
|
Цитата ЫукпШ @ Это явная ошибка - поскольку ничего же не работает. Смысл в том, что разные программы на разных компах могут обмениваться шифрованными сообщениями. Я просто подумал что расшифровать может только тот кто создал ключи. Это не так, да? Еще вопрос: В данном алгоритме можно обойтись без выравнивания? Если ключ 2048 выравнивание 256 |
Сообщ.
#11
,
|
|
|
Цитата WinAx @ Я просто подумал что расшифровать может только тот кто создал ключи. Это не так, да? Расшифровать может тот, у кого есть приватный ключ. Зашифровать тот, у кого есть публичный. А для цифровой подписи - наоборот. Добавлено Цитата WinAx @ Еще вопрос: В данном алгоритме можно обойтись без выравнивания? Если ключ 2048 выравнивание 256 Нет. Давно занимался, но насколько я помню, это блочный шифр. Но я никогда не считал это проблемой... надо ему столько-то байт, пусть возьмёт. --- Вообще RSA - это очень трудоёмкий шифр. Если предполагается большие объёмы информации, можно делать так: 1. При помощи RSA пересылаем ключ симметричного шифрования, сгенерированный случайно. Например, по алгоритму RC4. RC4 - быстрый алгоритм, фактически XOR. Очевидно, он потоковый, а не блочный. 2. Пользуемся всю сессию связи RC4. |
Сообщ.
#12
,
|
|
|
Понял. Спасибо!
Ошибку нашел. Все заработало нормально. |
Сообщ.
#13
,
|
|
|
Ты только не используй этот, уже засвеченный, ключ в продакшне.
|