2015-06-09 38 views
2

我有一個只有RSA密鑰的公共部分的EVP_PKEY。我從DER編碼中的SubjectPublicKeyInfo結構中提取公共部分。這是我現在有:驗證OpenSSL中的RSA公鑰?

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 to verify a RSA private key但該文檔說,「它不會對RSA的工作,只有模量和填充公開指數元素公共密鑰」。

那麼,是否有可能驗證密鑰沒有私人部分?因爲你可以看到我只有這個公共部分的EVP_PKEY。我想知道,這甚至有可能嗎?你會在EVP_PKEY的公共部分驗證什麼?

你可以看到這個問題的答案Programmatically verify a X509 certificate and private key match但是在那裏驗證了完整的密鑰(私人和公共部分)。

謹防 張貼在這個問題的原代碼有缺陷。這是因爲內部d2i_RSA_PUBKEY使用d2i_PUBKEYd2i_PUBKEY使用d2i_X509_PUBKEY(在x_pubkey.c)。如果您閱讀documentation for d2i_X509,您將看到下一個「警告:必須使用臨時變量。常見錯誤是嘗試直接使用緩衝區...」。 因此更正後的代碼將不得不使用的publicKeyCopy臨時副本和使用後,你可以安全地刪除publicKeyCopy

+0

您發佈的內容看起來像(開始的)512位RSA公鑰。當你說「驗證」時,你的意思是說它是完好的?或者你的意思是將它建立爲特定公共/私人配對的「公鑰」。後者涉及私鑰加密的已知值(通常是簽名)。澄清你正在驗證的是什麼? 「公鑰」不是答案。 「關於......的公鑰」將有助於瞭解。 – WhozCraig

+0

感謝您的回覆。我想知道公鑰是否格式良好,使用這個密鑰的客戶端只知道這是一個公鑰,他會用它來加密一些數據。這是DER格式的關鍵http://lapo.it/asn1js/#305A300D06092A864886F70D01010105000349003046024100832E2AE6E38F9C69928DAD2D9DABEFEB6DA8E5F48F114EBC283B838F7DA2B306E6D677414A86E2D2137F397F422C43DB5F8453D2AB12EEF5C5AFFDDD5C267B13020103。 – lmiguelmh

回答

0

隨着@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); 
} 
+0

世界上有什麼會給你一個C++答案的想法可以解決C問題?它不會。他們是兩種不同的語言(出於很好的理由)。那些想要/需要c解決方案的人會這樣做是出於這些理由。 –

+0

我認爲將此代碼更改爲C代碼很簡單,實際上您可以編輯答案。但是,爲什麼我不應該使用C++?你能提供一些建議嗎? – lmiguelmh

+0

然後用C語言重寫它。特別是你的條件語句(即'bool Crypto :: isValidRSAPublicKeyOnly(RSA * rsa)' –

1

謹防張貼在這個問題的原代碼有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解析下一個密鑰。

沒有必要複製數據。


我認爲第二個選項是使用內存BIOd2i_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顛簸的引用計數,所以你需要調用freeEVP_PKEY*RSA*兩者。