在数据包有效负载

时间:2015-09-04 15:43:52

标签: c++ rsa ethernet crypto++

对于学术网络应用程序,我想在2台虚拟机之间建立RSA密钥交换。我正在使用Crypto ++生成RSA::PublicKey,现在我必须在自定义的第2层帧内发送它(该数据包将使用libcrafter制作。)

问题是,我不知道如何在网络中写入密钥,例如接收方,嗅探数据包,能够以某种方式重新构建{{1} }。

我尝试将 raw 保存在字符串中,但正如他们所说hereRSA::PublicKey类包含其他数据,然后只是原始密钥(我的数据)不需要)。然而,我成功了,但在接待处我不能简单地重建PublicKey ......

是否有可能以某种方式连接模数,素数和公共指数,以便在接待处重建PublicKey

发件人

这是我在发件人处使用的代码。这是必不可少的,但我的程序还有其他功能,而且完全发布它会太长了。)

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...函数war最初认为从文件中恢复密钥 ...

有没有人有解决方案?我认为将重建密钥的所有元素分开可能会更好,但我无法想象如何做到这一点......

1 个答案:

答案 0 :(得分: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());

所以整个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);

我认为使用主题公钥信息(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;
}

然后使用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.