2015-09-04 59 views
3

對於學術網絡應用程序,我想在兩個虛擬機之間建立一個RSA密鑰交換。我正在使用Crypto ++生成RSA::PublicKey,現在我必須在自定義第2層框架內發送它(數據包將使用libcrafter製作)。發送數據包有效載荷中的公鑰

的事情是,我不知道的如何在網絡,如接收器將密鑰寫入,嗅探數據包,能夠重新構建,不知何故,RSA::PublicKey

我試圖把它保存在一個字符串,但正如他們所說herePublicKey類包含的其他數據,則只需將原始鍵(即我不需要數據)。不過,我管理的成功,但在接待我不能簡單地重建公鑰...

難道是可能的,不知何故,來連接模量,質數和公開指數,以重建publicKey在接待處?

發件人

這是我在發送端使用的代碼。這是重要的線路,但我的程序有其他功能,並且在這裏完全發佈它會太長)。

AutoSeededRandomPool rng; 
RSA::PrivateKey privateKey; 
privateKey.GenerateRandomWithKeySize(rng, 3072); 
RSA::PublicKey publicKey(privateKey); 
cout << ">> Key generated" <<endl; 

/* Convert key to string then to const char* */ 
std::string publicKeyString; 
publicKey.BEREncode(StringSink(publicKeyString).Ref()); 

const char * publicKeyChar = publicKeyString.c_str(); 
cout <<"key size : "<<publicKeyString.size()<< endl; 

/* Send Packet */ 
Crafter::RawLayer type1("K"); 
Crafter::RawLayer key_send(publicKeyChar); 
//Crafter::RawLayer key_send(publicKeyString.c_str(), publicKeyString.length()); 
Crafter::Packet packet_key (ether_header/type1/key_send); 
packet_key.Send(iface); 

接收機

這裏是我的嘗試恢復的關鍵。

/* Extract Payload */ 
PayloadLayer *payload_rcv = pack_recu.getLayerOfType<PayloadLayer>(); 
size_t payload_size = payload_rcv->getPayloadLen() ; 
Crafter::byte *payload = payload_rcv->getPayload(); 

cout << ">> Public Key recieved"<<endl; 

// Convert into RSA::PublicKey 
stringstream ss; 
for (int i=0; i< payload_size; i++) 
    ss << payload[i]; 
string payload_string = ss.str(); 
cout << "Payload Size: "<<payload_size<<endl; 
cin.get(); 
StringSource stringSource(payload_string, true); 
RSA::PublicKey publicKey2; 
publicKey2.BERDecode(stringSource); 

data->publicKey = publicKey2; 

這裏是程序運行的結果:

terminate called after throwing an instance of 'CryptoPP::BERDecodeErr' 
what(): BER decode error 

我敢肯定,錯誤來自從字符串到publicKey...BERDecode功能戰原本以爲恢復關鍵從轉換一個文件 ...

有沒有人有解決方案?我認爲把所有的元素分開來重建密鑰可能會更好,但我不知道該怎麼做...

+0

周圍的網頁不屑一顧庫看起來像我最糟糕的C++的噩夢。它似乎像DEREncode/BERDecode應該是使用的方法。 –

回答

3

publicKey.BEREncode(StringSink(publicKeyString).Ref());

const char * publicKeyChar = publicKeyString.c_str();

的BER編碼可能已經嵌入NULL,所以你不能用它慣用C-字符串操作:

const char * publicKeyChar = publicKeyString.c_str(); 
... 
Crafter::RawLayer key_send(publicKeyChar); 

當寫編碼的公鑰,下面看起來是正確的。您應該取消註釋並使用它(我使用datasize,因爲它在邏輯上與C字符串和長度分開)。

Crafter::RawLayer key_send(publicKeyString.data(), publicKeyString.size()); 

所以整個加密+事情看起來可能像下面這樣:

// Host's private key, generate or Load() it... 
RSA::PrivateKey privKey; 
... 

// Create a public key from the private key 
RSA::PublicKey pubKey(privKey); 

// Temporaries 
string spki; 
StringSink ss(spki); 

// Use Save to DER encode the Subject Public Key Info (SPKI) 
pubKey.Save(ss); 

Crafter::RawLayer key_send(spki.data(), spki.size()); 

然後,要重建它:

// Key payload 
const PayloadLayer& payload_rcv = *pack_recu.getLayerOfType<PayloadLayer>(); 

// Get a contiguous array (I don't know what this is called in Crafter) 
payload_rcv.PullUp(); 

// Use the array directly to avoid the copy 
ArraySource as(payload_rcv.data(), payload_rcv.size(), true /*pumpAll*/); 
RSA::PublicKey pubKey; 

// Use Load to BER decode the Subject Public Key Info (SPKI) 
pubKey.Load(as); 

// Validate it before using it 
AutoSeededRandomPool prng; 
pubKey.ThrowIfInvalid(prng); 

我想用主體公鑰信息(其重要SPKI)而不僅僅是公鑰。 SPKI通過OID包括算法標識符。這將使算法敏捷性稍後更容易一些。稍後,您可以切換到ECDSA密鑰或ed25519密鑰,並且密鑰類型將成爲密鑰負載的一部分。


terminate called after throwing an instance of 'CryptoPP::BERDecodeErr' 
what(): BER decode error 

很顯然,你應該建立一個try/catch,並趕上一個BERDecodeErr

try 
{ 
    // Use Load to BER decode the Subject Public Key Info (SPKI) 
    pubKey.Load(as); 

    // Validate it before using it 
    AutoSeededRandomPool prng; 
    pubKey.ThrowIfInvalid(prng); 
} 
catch(const BERDecodeErr& ex) 
{ 
    cerr << ex.what() << endl; 
} 
catch(const InvalidMaterial& ex) 
{ 
    cerr << ex.what() << endl; 
} 

這裏就是使用者公鑰信息樣子:

$ cat cryptopp-test.cpp 
... 
int main(int argc, char* argv[]) 
{ 
    AutoSeededRandomPool prng; 

    RSA::PrivateKey rsaPrivate; 
    rsaPrivate.GenerateRandomWithKeySize(prng, 3072); 

    RSA::PublicKey rsaPublic(rsaPrivate); 
    FileSink sink("rsa-public.der"); 
    rsaPublic.Save(sink); 

    return 0; 
} 

然後使用類似彼得古特曼的dumpasn1:在http://www.cryptopp.com

$ dumpasn1 rsa-public.der 
    0 416: SEQUENCE { 
    4 13: SEQUENCE { 
    6 9:  OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) 
17 0:  NULL 
     :  } 
19 397: BIT STRING, encapsulates { 
24 392:  SEQUENCE { 
28 385:  INTEGER 
     :   00 CE B0 19 0D 0C EB 87 BD 6B 51 6C BB 00 9C EE 
     :   1D 75 9C 28 DC 0E 8E 88 9A 95 8A 3B 6C BD 1F 3F 
     :   03 05 22 8E 3D 19 33 D7 C5 A3 28 4F 13 3D 9E BF 
     :   5A 54 51 AE D6 DA C3 AC 1D 9C 4C A3 47 C0 04 8F 
     :   9D 0A DD 38 60 56 E3 9C DB 7C EA A8 3F 52 93 99 
     :   40 90 14 41 0A 3B 58 F2 13 9F 38 64 18 DD 62 55 
     :   D2 32 53 A0 D5 1A 54 E7 8D 23 01 E0 97 ED F9 C7 
     :   68 9F E2 00 48 99 53 40 6E 7E 5C DA 47 39 4A 41 
     :     [ Another 257 bytes skipped ] 
417 1:  INTEGER 17 
     :  } 
     :  } 
     : } 

0 warnings, 0 errors. 
+0

'Crafter :: RawLayer key_send(spki.data(),spki.size());'需要一個'const byte *'所以我添加了'reinterpret_cast (spki.data())''。 – EisenHeim

+0

做什麼意思*獲取一個連續的數組* *?爲了使它工作,我使用'byte * payload = payload_rcv.getPayload();'(將有效載荷放在一個字節數組中),然後將所有這些放在一個向量中(使用'push_back')。 'ArraySource'只能用於一個vector(我試過'StringSource',...)。我應該發佈編輯與我的解決方案嗎?* – EisenHeim

+0

@Eisen - *「ArraySource只能與矢量(我試過StringSource,...) - 聽起來不太對勁。你應該問另一個問題來確定爲什麼'ArraySource'不適合你。 – jww

相關問題