[英]Verify a RSA public key in OpenSSL?
我有一個 EVP_PKEY,只有 RSA 密鑰的公共部分。 我從 DER 編碼的 SubjectPublicKeyInfo 結構中提取了公共部分。 這就是我現在所擁有的:
unsigned char publicKey[] = {0x30, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ...}
size_t publicKeyLength = 92;
unsigned char* publicKeyCopy = new unsigned char[publicKeyLength];
memcpy(publicKeyCopy, publicKey, publicKeyLength);
RSA *rsa;
rsa = d2i_RSA_PUBKEY(NULL, (unsigned char const **) &pubKey, pubKeyLen);
EVP_PKEY *pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
我知道您可以使用RSA_check_key 來驗證 RSA 私鑰,但文檔說“它不適用於僅填充模數和公共指數元素的 RSA 公鑰”。
那么,是否可以在沒有私有部分的情況下驗證密鑰? 因為如您所見,我只有EVP_PKEY 的公共部分。 我想知道,這甚至可能嗎? 你會在 EVP_PKEY 的公共部分驗證什么?
您可以查看此問題的答案以編程方式驗證 X509 證書和私鑰匹配,但會驗證完整密鑰(私有和公共部分)。
當心這個問題中發布的原始代碼有一個 BUG 。 這是因為內部d2i_RSA_PUBKEY
使用d2i_PUBKEY
並且d2i_PUBKEY
使用d2i_X509_PUBKEY
(在x_pubkey.c 中)。 如果您閱讀d2i_X509的文檔,您將看到下一個“警告:臨時變量的使用是強制性的。一個常見的錯誤是嘗試直接使用緩沖區...” 。 因此,更正后的代碼必須使用publicKeyCopy
的臨時副本,使用后您可以安全地刪除publicKeyCopy
:
當心這個問題中發布的原始代碼有一個 BUG...
我只是要對此發表評論,並向您展示如何處理它。
unsigned char publicKey[] = {0x30, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ...}
size_t publicKeyLength = sizeof(publicKey);
unsigned char* t = publicKey;
rsa = d2i_RSA_PUBKEY(NULL, &t, pubKeyLen);
在內部,臨時指針t
遞增,因此它被浪費了。 如果一切正常,它將指向緩沖區后的某個位置。 你應該找到的是(size_t)t - (size_t)publicKey == publicKeyLength
在函數執行后。
因為你用的是臨時指針,原來的指針publicKey
還是好的。 如果內存中有連續的鍵,您可以使用t
來解析下一個鍵。
無需復制數據。
我認為第二個選擇是使用內存BIO
和d2i_RSA_PUBKEY_bio
。 就像是:
BIO* bio = BIO_new_mem_buf(publicKey, (int)publicKeyLength);
ASSERT(bio != NULL);
RSA* rsa = d2i_RSA_PUBKEY_bio(bio, NULL);
ASSERT(rsa != NULL);
/* ... */
RSA_free(rsa);
BIO_free(bio);
get1
增加引用計數,因此您需要在EVP_PKEY*
和RSA*
上都調用free
。
在@jww 的幫助下,這個答案https://stackoverflow.com/a/29885771/2692914 。 我想出了這個解決方案,希望沒問題:
bool isValidPublicKeyOnly(EVP_PKEY *pkey) {
//EVP_PKEY_get_type from https://stackoverflow.com/a/29885771/2692914
int type = EVP_PKEY_get_type(pkey); //checks nullptr
if (type != EVP_PKEY_RSA && type != EVP_PKEY_RSA2) {
//not RSA
return false;
}
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
if (!rsa) {
return false;
}
bool isValid = isValidRSAPublicKeyOnly(rsa);
RSA_free(rsa);
return isValid;
}
bool isValidRSAPublicKeyOnly(RSA *rsa) {
//from rsa_ameth.c do_rsa_print : has a private key
//from rsa_chk.c RSA_check_key : doesn't have n (modulus) and e (public exponent)
if (!rsa || rsa->d || !rsa->n || !rsa->e) {
return false;
}
//from http://rt.openssl.org/Ticket/Display.html?user=guest&pass=guest&id=1454
//doesnt have a valid public exponent
return BN_is_odd(rsa->e) && !BN_is_one(rsa->e);
}
我有一個類似的問題,我認為展示我對這個問題的解決方案可能是明智的。 與 lmiguelmh 的解決方案不同,這個解決方案在 C 中確實有效。
int checkRsaPublic(RSA *rsa, int debug) {
if (!rsa) {
printf("ERROR: RSA key not defined!\n");
return 0;
}
//key
const BIGNUM *n;
const BIGNUM *e;
const BIGNUM *d;
//factors
const BIGNUM *p;
const BIGNUM *q;
//crt_params
const BIGNUM *dmp1;
const BIGNUM *dmq1;
const BIGNUM *iqmp;
RSA_get0_key(rsa, &n, &e, &d);
RSA_get0_factors(rsa, &p, &q);
RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
if (debug) {
if (n) {
printf("n is %s\n", BN_bn2hex(n));
}
if (e) {
printf("e is %s\n", BN_bn2hex(e));
}
if (d) {
printf("d is %s\n", BN_bn2hex(d));
}
if (p) {
printf("p is %s\n", BN_bn2hex(p));
}
if (q) {
printf("q is %s\n", BN_bn2hex(q));
}
if (dmp1) {
printf("dmp1 is %s\n", BN_bn2hex(dmp1));
}
if (dmq1) {
printf("dmq1 is %s\n", BN_bn2hex(dmq1));
}
if (iqmp) {
printf("iqmp is %s\n", BN_bn2hex(iqmp));
}
}
//RSA_check_key : doesn't have n (modulus) and e (public exponent)
if (d || !n || !e) {
printf("ERROR: RSA public key not well defined!\n");
return 0;
}
if (BN_is_odd(e) && !BN_is_one(e)) {
return 1;
}
printf("ERROR: Invalid public exponent.");
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.