У меня есть код, который анализирует пакеты OpenPGP, и у меня есть n
, e
пакета открытого ключа, а также s
пакета подписи в виде массивов байтов.Проверьте подпись RSA на OpenPGP с помощью WinCrypt/CryptoAPI
Для того, чтобы проверить подпись я первым инициализирует CryptAcquireContext
(я также попытался с PROV_RSA_FULL
вместо PROV_RSA_AES
)
HCRYPTPROV hCryptProv;
CryptAcquireContext(&hCryptProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
затем создать хэш
HCRYPTHASH hHash;
CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash); // as the digest algorithm of the signature was 2 => SHA1
и заполнить его с помощью CryptHashData
. Это работает так же хорошо, как разбор и импорт открытого ключа с использованием CryptImportKey
.
typedef struct _RSAKEY
{
BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE n[4096/8];
} RSAKEY;
static int verify_signature_rsa(HCRYPTPROV hCryptProv, HCRYPTHASH hHash, public_key_t &p_pkey, signature_packet_t &p_sig)
{
int i_n_len = mpi_len(p_pkey.key.sig.rsa.n); // = 512; p_pkey.key.sig.rsa.n is of type uint8_t n[2 + 4096/8];
int i_s_len = mpi_len(p_sig.algo_specific.rsa.s); // = 256; p_sig.algo_specific.rsa.s is of type uint8_t s[2 + 4096/8]
HCRYPTKEY hPubKey;
RSAKEY rsakey;
rsakey.blobheader.bType = PUBLICKEYBLOB; // 0x06
rsakey.blobheader.bVersion = CUR_BLOB_VERSION; // 0x02
rsakey.blobheader.reserved = 0;
rsakey.blobheader.aiKeyAlg = CALG_RSA_KEYX;
rsakey.rsapubkey.magic = 0x31415352;// ASCII for RSA1
rsakey.rsapubkey.bitlen = i_n_len * 8; // = 4096
rsakey.rsapubkey.pubexp = 65537;
memcpy(rsakey.n, p_pkey.key.sig.rsa.n + 2, i_n_len); // skip first two byte which are MPI length
std::reverse(rsakey.n, rsakey.n + i_n_len); // need to convert to little endian for WinCrypt
CryptImportKey(hCryptProv, (BYTE*)&rsakey, sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + i_n_len, 0, 0, &hPubKey); // no error
std::unique_ptr<BYTE[]> pSig(new BYTE[i_s_len]);
memcpy(pSig.get(), p_sig.algo_specific.rsa.s + 2, i_s_len); // skip first two byte which are MPI length
std::reverse(p_sig.algo_specific.rsa.s, p_sig.algo_specific.rsa.s + i_s_len); // need to convert to little endian for WinCrypt
if (!CryptVerifySignature(hHash, pSig.get(), i_s_len, hPubKey, nullptr, 0))
{
DWORD err = GetLastError(); // err=2148073478 -> INVALID_SIGNATURE
CryptDestroyKey(hPubKey);
return -1;
}
CryptDestroyKey(hPubKey);
return 0;
}
CryptVerifySignature
терпит неудачу с GetLastError()
декодирования в INVALID_SIGNATURE
.
На http://tools.ietf.org/html/rfc4880#section-5.2.2 я прочитал
With RSA signatures, the hash value is encoded using PKCS#1 encoding
type EMSA-PKCS1-v1_5 as described in Section 9.2 of RFC 3447. This
requires inserting the hash value as an octet string into an ASN.1
structure.
ли, что нужно или что делается автоматически CryptVerifySignature
? Если нет, как это сделать?
.NET немного лучше, но я не вижу, как компания может уйти с такой плохой документацией API. –
Спасибо за ваш ответ и ваш блеск. Ошибка была вызвана опечаткой и местом, где вы предполагали это ... – MrTux
Что вы имеете в виду под «где я это предполагал?», Было ли это связано с большим/маленьким эндиантом? –