我将如何从字符串/字节数组或任何其他容器加载 Private / Public 键
How would I load a Private / Public Key from a string / byte array or any other container
是否可以在源中存储 RSA Private/Public 密钥,例如 byte[]
或 string
或任何其他 container
并使用此密钥进行加密/解密?
文件中的解码函数如下所示:
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
创建密钥。
我只是不知道如何使用现有的。
也许我忽略了文档中的这一部分。
可能会对 Crypto++ Keys and Formats and Crypto++ RSA Cryptography 个页面感兴趣。
如果您像这样生成 RSA 参数:
AutoSeededRandomPool rng;
InvertibleRSAFunction params;
params.GenerateRandomWithKeySize(rng, 2048);
您可以使用InvertibleRSAFunction
的DEREncode
和BERDecode
方法分别对所有参数进行编码和解码:
{
FileSink output("rsaparams.dat");
params.DEREncode(output);
}
InvertibleRSAFunction params2;
{
FileSource input("rsaparams.dat", true);
params2.BERDecode(input);
}
将encode/decode私有和publicmaterial分开,在RSA::PrivateKey
和[=]上使用DEREncode
和BERDecode
方法22=] 对象本身:
// 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
只是您可以使用的示例源和接收器对象。 encode/decode 例程将 BufferedTransformation
个对象作为参数,因此您可以使用该接口的任何其他合适的实现。
例如,ArraySink
can be used to write data into a memory buffer you supply, and StringSource
(also aliased as ArraySource
) 可用于从缓冲区读取。
这里有一些代码显示了使用 ArraySink
和 ArraySource
通过 std::vector<byte>
:
往返私钥 material
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
存储密钥 material 并使用 StringSink
class 写入此,这避免了一些缓冲区管理(字符串将自动调整大小以匹配编码的数据量)。请注意,这仍然是二进制数据,即使它位于 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);
或者,如果您想自己控制格式,可以使用 InvertibleRSAFunction
对象或关键对象的方法来提取各个参数(如 "Crypto++ RSA Cryptography" link 以上)并使用它以您自己的格式提取要存储的值:
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::*Key
实例,方法是使用相应的 setter 方法(SetModulus()
, SetPrime1()
,等等)。
How would I load a Private / Public Key from a string / byte array or any other container
Crypto++ 库内置了对 std:strings
的支持。但是其他 C++ 容器会更加棘手。 ArraySource
是在 Crypto++ 5.6 中添加的,但它只是 StringSource
的 typedef
。
如果您使用的是敏感 material,那么您还应该考虑使用 SecByteBlock
。当析构函数运行时,它将擦除或归零敏感 material。
字符串和 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);
字符串和 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
,这只是需要一些工作。您可以通过查看 filters.h and filters.cpp.
中的 StringSource
和 StringSink
源代码了解所涉及的工作
如果您按如下方式创建 DSA 密钥,您最终会得到两个文件,一个包含私钥,另一个包含 public 密钥。
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 私钥("3082014C0201003...0B8E805D83E9708");
然后您可以使用 HexDecoder 将字符串转换为字节并使用这些字节创建 public 和私钥:
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);
}
How would I load a Private / Public Key from a string / byte array or
any other container
//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 > 这应该在这里达到目的。
是否可以在源中存储 RSA Private/Public 密钥,例如 byte[]
或 string
或任何其他 container
并使用此密钥进行加密/解密?
文件中的解码函数如下所示:
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
创建密钥。
我只是不知道如何使用现有的。
也许我忽略了文档中的这一部分。
可能会对 Crypto++ Keys and Formats and Crypto++ RSA Cryptography 个页面感兴趣。
如果您像这样生成 RSA 参数:
AutoSeededRandomPool rng;
InvertibleRSAFunction params;
params.GenerateRandomWithKeySize(rng, 2048);
您可以使用InvertibleRSAFunction
的DEREncode
和BERDecode
方法分别对所有参数进行编码和解码:
{
FileSink output("rsaparams.dat");
params.DEREncode(output);
}
InvertibleRSAFunction params2;
{
FileSource input("rsaparams.dat", true);
params2.BERDecode(input);
}
将encode/decode私有和publicmaterial分开,在RSA::PrivateKey
和[=]上使用DEREncode
和BERDecode
方法22=] 对象本身:
// 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
只是您可以使用的示例源和接收器对象。 encode/decode 例程将 BufferedTransformation
个对象作为参数,因此您可以使用该接口的任何其他合适的实现。
例如,ArraySink
can be used to write data into a memory buffer you supply, and StringSource
(also aliased as ArraySource
) 可用于从缓冲区读取。
这里有一些代码显示了使用 ArraySink
和 ArraySource
通过 std::vector<byte>
:
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
存储密钥 material 并使用 StringSink
class 写入此,这避免了一些缓冲区管理(字符串将自动调整大小以匹配编码的数据量)。请注意,这仍然是二进制数据,即使它位于 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);
或者,如果您想自己控制格式,可以使用 InvertibleRSAFunction
对象或关键对象的方法来提取各个参数(如 "Crypto++ RSA Cryptography" link 以上)并使用它以您自己的格式提取要存储的值:
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::*Key
实例,方法是使用相应的 setter 方法(SetModulus()
, SetPrime1()
,等等)。
How would I load a Private / Public Key from a string / byte array or any other container
Crypto++ 库内置了对 std:strings
的支持。但是其他 C++ 容器会更加棘手。 ArraySource
是在 Crypto++ 5.6 中添加的,但它只是 StringSource
的 typedef
。
如果您使用的是敏感 material,那么您还应该考虑使用 SecByteBlock
。当析构函数运行时,它将擦除或归零敏感 material。
字符串和 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);
字符串和 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
,这只是需要一些工作。您可以通过查看 filters.h and filters.cpp.
StringSource
和 StringSink
源代码了解所涉及的工作
如果您按如下方式创建 DSA 密钥,您最终会得到两个文件,一个包含私钥,另一个包含 public 密钥。
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 私钥("3082014C0201003...0B8E805D83E9708");
然后您可以使用 HexDecoder 将字符串转换为字节并使用这些字节创建 public 和私钥:
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);
}
How would I load a Private / Public Key from a string / byte array or any other container
//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 > 这应该在这里达到目的。