如何从字符串/字节数组或任何其他容器加载私钥/公钥

时间:2015-03-14 15:23:28

标签: c++ cryptography rsa public-key-encryption crypto++

是否可以在源代码中存储RSA私钥/公钥,例如byte[]string或任何其他container,并使用此密钥进行加密/解密?< / p>

文件中的解码函数如下所示:

void Decode(const string& filename, BufferedTransformation& bt)
{
    // http://www.cryptopp.com/docs/ref/class_file_source.html
    FileSource file(filename.c_str(), true /*pumpAll*/);

    file.TransferTo(bt);
    bt.MessageEnd();
}

从文件中加载不是我想要的密钥。

我知道它是可能的,因为我可以使用AutoSeededRandomPool创建密钥。

我只是不知道如何使用现有的。

也许我在文档中忽略了这一部分。

4 个答案:

答案 0 :(得分:14)

Crypto++ Keys and FormatsCrypto++ RSA Cryptography页面可能很有用。

如果您正在生成如下的RSA参数:

AutoSeededRandomPool rng;

InvertibleRSAFunction params;
params.GenerateRandomWithKeySize(rng, 2048);

您可以使用DEREncode的{​​{1}}和BERDecode方法分别对所有参数进行编码和解码:

InvertibleRSAFunction

要分别对私有和公共资料进行编码/解码,请使用{ FileSink output("rsaparams.dat"); params.DEREncode(output); } InvertibleRSAFunction params2; { FileSource input("rsaparams.dat", true); params2.BERDecode(input); } DEREncode对象本身的BERDecodeRSA::PrivateKey方法:

RSA::PublicKey

// Initialize keys from generated params RSA::PrivateKey rsaPrivate(params); RSA::PublicKey rsaPublic(params); // Write keys to file { FileSink output("rsaprivate.dat"); rsaPrivate.DEREncode(output); } { FileSink output("rsapublic.dat"); rsaPublic.DEREncode(output); } // Read keys from file into new objects RSA::PrivateKey rsaPrivate2; RSA::PublicKey rsaPublic2; { FileSource input("rsaprivate.dat", true); rsaPrivate2.BERDecode(input); } { FileSource input("rsapublic.dat", true); rsaPublic2.BERDecode(input); } FileSource只是您可以使用的示例源和接收对象。编码/解码例程将FileSink个对象作为参数,因此您可以使用该接口的任何其他合适的实现。

例如,ArraySink可用于将数据写入您提供的内存缓冲区,StringSource (also aliased as ArraySource)可用于从缓冲区读取数据。

以下是一些代码,显示使用BufferedTransformationArraySink通过ArraySource往返私钥材料:

std::vector<byte>

(另请参阅@jww's answer以获取使用RSA::PrivateKey rsaPrivate(params); std::vector<byte> buffer(8192 /* buffer size */); ArraySink arraySink(&buffer[0], buffer.size()); rsaPrivate.DEREncode(arraySink); // Initialize variable with the encoded key material // (excluding unwritten bytes at the end of our buffer object) std::vector<byte> rsaPrivateMaterial( &buffer[0], &buffer[0] + arraySink.TotalPutLength()); RSA::PrivateKey rsaPrivate2; ArraySource arraySource( &rsaPrivateMaterial[0], rsaPrivateMaterial.size(), true); rsaPrivate2.BERDecode(arraySource); 避免使用固定大小缓冲区的示例。

另一个使用ByteQueue来存储密钥材料并使用std::string类写入此内容的示例,这避免了一些缓冲区管理(字符串将自动调整大小以匹配金额被编码的数据)。请注意,即使它位于StringSink对象中,它仍然是二进制数据。

std::string

或者,如果您想自己控制格式,可以使用RSA::PrivateKey rsaPrivate(params); std::string rsaPrivateMaterial; StringSink stringSink(rsaPrivateMaterial); rsaPrivate.DEREncode(stringSink); RSA::PrivateKey rsaPrivate2; StringSource stringSource(rsaPrivateMaterial, true); rsaPrivate2.BERDecode(stringSource); 对象或关键对象的方法来提取各个参数(如上面的“Crypto ++ RSA Cryptography”链接所示)和用它来以您自己的格式提取存储值:

InvertibleRSAFunction

当从文件或容器中读取时,可以使用相应的setter方法(const Integer& n = params.GetModulus(); const Integer& p = params.GetPrime1(); const Integer& q = params.GetPrime2(); const Integer& d = params.GetPrivateExponent(); const Integer& e = params.GetPublicExponent(); InvertibleRSAFunction将这些实例恢复为新的RSA::*KeySetModulus()实例,等)。

答案 1 :(得分:4)

  

如何从字符串/字节数组或任何其他容器

加载私钥/公钥

Crypto ++库内置了对std:strings的支持。但是其他C ++容器会变得更加棘手。 Crypto ++ 5.6中添加了ArraySource,但typedef仅为StringSource

如果您使用的是敏感材料,那么您还应该考虑使用SecByteBlock。当析构函数运行时,它会擦除​​或归零敏感材料。

string和StringSource(加载)

string spki = ...;
StringSource ss(spki, true /*pumpAll*/);

RSA::PublicKey publicKey;
publicKey.Load(ss);

vector和ArraySource(加载)

vector<byte> spki = ...;
ArraySource as(&spki[0], spki.length(), true /*pumpAll*/);

RSA::PublicKey publicKey;
publicKey.Load(as);

string和StringSink(保存)

string spki;
StringSink ss(spki);

RSA::PublicKey publicKey(...);
publicKey.Save(ss);

矢量(保存)

见下面的代码。


以下是保存到std::vector并从ByteQueue加载的示例。您必须使用中间VectorSink进行保存,因为您无法轻松创建AutoSeededRandomPool prng; RSA::PrivateKey pk1, pk2; pk1.Initialize(prng, 1024); ByteQueue queue; pk1.Save(queue); vector<byte> spki; spki.resize(queue.MaxRetrievable()); ArraySink as1(&spki[0], spki.size()); queue.CopyTo(as1); ArraySource as2(&spki[0], spki.size(), true); pk2.Load(as2); bool valid = pk2.Validate(prng, 3); if(valid) cout << "Validated private key" << endl; else cout << "Failed to validate private key" << endl;

VectorSink

我们没有明确的traits_type::char_type,因为using CryptoPP::StringSinkTemplate; typedef StringSinkTemplate< std::vector<byte> > VectorSink; In file included from cryptopp-test.cpp:65: In file included from /usr/local/include/cryptopp/files.h:5: /usr/local/include/cryptopp/filters.h:590:22: error: no member named 'traits_type' in 'std::vector<unsigned char, std::allocator<unsigned char> >' typedef typename T::traits_type::char_type char_type; ~~~^ cryptopp-test.cpp:243:20: note: in instantiation of template class 'CryptoPP::StringSinkTemplate<std::vector<unsigned char, std::allocator<unsigned char> > >' requested here VectorSink vs(spki); 的隐含期望,我们无法轻易创建一个VectorSource。例如:

VectorSink

您可以创建StringSourceStringSink,它只需要做一些工作。通过查看filters.hfilters.cpp中的{{1}}和{{1}}源代码,您可以了解所涉及的工作。

答案 2 :(得分:0)

如果按如下方式创建DSA密钥,最终将得到两个文件,一个包含私钥,另一个包含公钥。

void CreateDsaKeys(std::string folder)
{
    AutoSeededRandomPool rng;
    // Generate Private Key
    DSA::PrivateKey privateKey;
    privateKey.GenerateRandomWithKeySize(rng, 1024);

    // Generate Public Key
    DSA::PublicKey publicKey;
    publicKey.AssignFrom(privateKey);
    if (!privateKey.Validate(rng, 3) || !publicKey.Validate(rng, 3))
    {
       throw runtime_error("DSA key generation failed");
    }
    std::string publicPath = folder + "/publickey.txt";
    std::string privatePath = folder + "/privatekey.txt";
    SaveHexPublicKey(publicPath, publicKey);
    SaveHexPrivateKey(privatePath, privateKey);
}

将这两个文件的内容复制到源代码中并将它们放入字符串中:

std :: string publickey(“308201B73082012C ... F752BB791”);

std :: string privatekey(“3082014C0201003 ... 0B8E805D83E9708”);

然后你可以使用HexDecoder将字符串转换为字节,并使用这些字节创建公钥和私钥:

bool LoadDsaKeysFromStringsAndTest()
{
    AutoSeededRandomPool rng;
    HexDecoder decoderPublic;
    decoderPublic.Put((byte*)publickey.data(), publickey.size());
    decoderPublic.MessageEnd();
    HexDecoder decoderPrivate;
    decoderPrivate.Put((byte*)privatekey.data(), privatekey.size());
    decoderPrivate.MessageEnd();
    DSA::PublicKey publicKey;
    publicKey.Load(decoderPublic);
    DSA::PrivateKey privateKey;
    privateKey.Load(decoderPrivate);
    string message = "DSA Signature";
    string signature;
    try {
        DSA::Signer signer( privateKey );
        StringSource ss1( message, true,
            new SignerFilter( rng, signer,
                new StringSink( signature )
            ) // SignerFilter
        ); // StringSource

        bool result = false;
        DSA::Verifier verifier1( publicKey );
        StringSource ss(message+signature, true,
                new SignatureVerificationFilter(verifier1,
                        new ArraySink((uint8_t*)&result, sizeof(result)),
                        SignatureVerificationFilter::PUT_RESULT | SignatureVerificationFilter::SIGNATURE_AT_END)
                );
        return result;
    }
    catch(const CryptoPP::Exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return false;
}

这些是保存密钥所需的其他例程

void Save(const string& filename, const BufferedTransformation& bt)
{
    FileSink file(filename.c_str());
    bt.CopyTo(file);
    file.MessageEnd();
}

void SaveHex(const string& filename, const BufferedTransformation& bt)
{
    HexEncoder encoder;
    bt.CopyTo(encoder);
    encoder.MessageEnd();
    Save(filename, encoder);
}

void SaveHexPrivateKey(const string& filename, const PrivateKey& key)
{
    ByteQueue queue;
    key.Save(queue);
    SaveHex(filename, queue);
}

void SaveHexPublicKey(const string& filename, const PublicKey& key)
{
    ByteQueue queue;
    key.Save(queue);
    SaveHex(filename, queue);
}

答案 3 :(得分:0)

  

如何从字符串/字节数组加载私钥/公钥   任何其他容器

//Create Cryptopp StringSource From Std::string
std::string PublicKeyString = "<Your key as std::string value>";
CryptoPP::StringSource PKeyStringSource(PublicKeyString, true);
CryptoPP::RSA::PublicKey publicKey;
publicKey.Load(PKeyStringSource);

尽管如此,我不确定cryptopp是否支持CryptoPP :: StringSource的本机容器。但我相信,将容器存储为std :: vector&gt;这应该是为了这个目的。