在数据包负载中发送公钥
Sending PublicKey within packet payload
对于学术网络应用程序,我想在 2 个虚拟机之间设置 RSA 密钥交换。我正在使用 Crypto++ 生成 RSA::PublicKey
,我现在必须在自定义第 2 层帧中发送它(数据包将使用 libcrafter
制作)。
问题是,我不知道如何在网络中写入密钥,例如接收器,嗅探数据包,是否能够重新构建,不知何故, RSA::PublicKey
.
我试图将它 raw 保存在一个字符串中,但是正如他们所说 here,PublicKey
class 包含其他数据,然后只是原始密钥(我不需要的数据)。尽管如此,我还是成功了,但是在招待会上我不能简单地重建 PublicKey...
是否有可能以某种方式连接模数、素数和 public 指数,以便在接收处重建 publicKey
?
发件人
这是我在发件人处使用的代码。这是基本的几行,但我的程序还有其他功能,如果 post 完全放在这里就太长了。
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
函数 war 最初被认为是从文件中恢复密钥 ...
有人有解决办法吗?我认为将所有元素分开以重建密钥可能会更好,但我不知道该怎么做...
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);
写入编码的 public 密钥时,以下看起来是正确的。您应该取消注释并使用它(我使用 data
和 size
因为它在逻辑上与 C 字符串和长度分开)。
Crafter::RawLayer key_send(publicKeyString.data(), publicKeyString.size());
所以整个 Crypto++ 可能如下所示:
// 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);
我认为使用主题 Public 密钥信息 (SPKI) 而不仅仅是 Public 密钥很重要。 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;
}
下面是主题 Public 关键信息的样子:
$ 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;
}
然后使用类似于 Peter Gutmann 的 dumpasn1
:
$ 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.
对于学术网络应用程序,我想在 2 个虚拟机之间设置 RSA 密钥交换。我正在使用 Crypto++ 生成 RSA::PublicKey
,我现在必须在自定义第 2 层帧中发送它(数据包将使用 libcrafter
制作)。
问题是,我不知道如何在网络中写入密钥,例如接收器,嗅探数据包,是否能够重新构建,不知何故, RSA::PublicKey
.
我试图将它 raw 保存在一个字符串中,但是正如他们所说 here,PublicKey
class 包含其他数据,然后只是原始密钥(我不需要的数据)。尽管如此,我还是成功了,但是在招待会上我不能简单地重建 PublicKey...
是否有可能以某种方式连接模数、素数和 public 指数,以便在接收处重建 publicKey
?
发件人
这是我在发件人处使用的代码。这是基本的几行,但我的程序还有其他功能,如果 post 完全放在这里就太长了。
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
函数 war 最初被认为是从文件中恢复密钥 ...
有人有解决办法吗?我认为将所有元素分开以重建密钥可能会更好,但我不知道该怎么做...
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);
写入编码的 public 密钥时,以下看起来是正确的。您应该取消注释并使用它(我使用 data
和 size
因为它在逻辑上与 C 字符串和长度分开)。
Crafter::RawLayer key_send(publicKeyString.data(), publicKeyString.size());
所以整个 Crypto++ 可能如下所示:
// 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);
我认为使用主题 Public 密钥信息 (SPKI) 而不仅仅是 Public 密钥很重要。 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;
}
下面是主题 Public 关键信息的样子:
$ 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;
}
然后使用类似于 Peter Gutmann 的 dumpasn1
:
$ 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.