I'm trying to figure out how to generate and use an RSA key with Crypto++. To be precise, I am being asked to:
You will implement secure communications between two parties, Alice and
Bob.
For simplicity, the sending of a message from the sender to the receiver will be simulated
through writing the message into a file by the sender and reading the message
from the file by the receiver.
This assignment is designed to practice key distribution, encryption/decryption,
and integrity protection
with secret key cryptography and public key cryptography.
Communication scenario: Alice (as a Client) needs to send messages to Bob (as a Server). Alice and Bob each have
a pair of under the RSA cryptosystem
(their key
pairs are different), and they know each other’s public key beforehand
(the public keys can be hard coded into the program
or read from a file). Step 1: Set
up a shared secret key: Alice and Bob set up a shared secret key using the following
method: Alice generates
a random key k, encrypts it using Bob’s public key with the RSA
algorithm, and sends the ciphertext to Bob. Bob receives the ciphertext and then decrypts it
to get the key k.
So, I've spent a few hours trying to set this up properly, and it seems like I've finally gotten Eclipse to accept the Crypto++ library itself, as it has compiled up to this point. Here is the complete code I have so far:
#include <iostream>
#include "cryptlib.h"
#include <rsa.h>
#include <osrng.h>
#include <base64.h>
#include <files.h>
using namespace CryptoPP;
int main()
{
std::cout << "!!!Hello World!!!" << std::endl; // prints !!!Hello World!!!
// InvertibleRSAFunction is used directly only because the private key
// won't actually be used to perform any cryptographic operation;
// otherwise, an appropriate typedef'ed type from rsa.h would have been used.
AutoSeededRandomPool rng;
InvertibleRSAFunction privkey;
privkey.Initialize(rng, 1024); <--
// With the current version of Crypto++, MessageEnd() needs to be called
// explicitly because Base64Encoder doesn't flush its buffer on destruction.
Base64Encoder privkeysink(new FileSink("c:\\privkey.txt"));
privkey.DEREncode(privkeysink);
privkeysink.MessageEnd();
// Suppose we want to store the public key separately,
// possibly because we will be sending the public key to a third party.
RSAFunction pubkey(privkey);
Base64Encoder pubkeysink(new FileSink("c:\\pubkey.txt"));
pubkey.DEREncode(pubkeysink); <--
pubkeysink.MessageEnd();
return 0;
}
Some of this I have pulled from here in an attempt to understand exactly how this library works:
https://www.cryptopp.com/wiki/User_Guide:_rsa.h
(We were given no sort of primer, and I find the site a little confusing)
The current issue I'm having at the moment is that the two lines I've marked with '<--' do not compile.
Specifically:
undefined reference to CryptoPP::InvertibleRSAFunction::Initialize(CryptoPP::RandomNumberGenerator&, unsigned int, CryptoPP::Integer const&)
undefined reference to CryptoPP::X509PublicKey::DEREncode(CryptoPP::BufferedTransformation&) const
I would ask what I would need to do to make these two compile, but I'm not even sure this sample code even does what I want it to. How would I generate the keys I need for this?
Related
I'm developing a WebService client in C++ for "Electronic Invoice" in Argentina. The webservice client and the xml treatment is not a problem but the cryptographic part give some headache (I'm quite new in this topic).
I'm reading the Botan documentation and found an example somewhat similar to what I need but I'm having difficulties adapting it.
I need to encrypt the XML in SHA1+RSA using the certificates and encode the result in Base64.
The official documentation provide examples in many languages unfortunately C++ is not one of them, I use the php example as start point to create my PoC code in C++.
The exact problem is this.
I have this XML example:
<loginTicketRequest version="1.0"><header><uniqueId>1560949868</uniqueId><generationTime>2019-06-19T10:10:08-03:00</generationTime><expirationTime>2019-06-19T10:12:08-03:00</expirationTime></header><service>wsfe</service></loginTicketRequest>
this XML became in this Base64 string
MIIHDgYJKoZIhvcNAQcCoIIG/zCCBvsCAQExDzANBglghkgBZQMEAgEFADCCAS8G
CSqGSIb3DQEHAaCCASAEggEcPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0i
VVRGLTgiPz4NCjxsb2dpblRpY2tldFJlcXVlc3QgdmVyc2lvbj0iMS4wIj48aGVh
ZGVyPjx1bmlxdWVJZD4xNTYwOTQ5ODY4PC91bmlxdWVJZD48Z2VuZXJhdGlvblRp
bWU+MjAxOS0wNi0xOVQxMDoxMDowOC0wMzowMDwvZ2VuZXJhdGlvblRpbWU+PGV4
cGlyYXRpb25UaW1lPjIwMTktMDYtMTlUMTA6MTI6MDgtMDM6MDA8L2V4cGlyYXRp
b25UaW1lPjwvaGVhZGVyPjxzZXJ2aWNlPndzZmU8L3NlcnZpY2U+PC9sb2dpblRp
Y2tldFJlcXVlc3Q+DQqgggPMMIIDyDCCArCgAwIBAgIISL4VMzAJIDswDQYJKoZI
hvcNAQEFBQAwQzElMCMGA1UEAwwcQUZJUCBUZXN0aW5nIENvbXB1dGFkb3JlcyBD
QTENMAsGA1UECgwEQUZJUDELMAkGA1UEBhMCQVIwHhcNMTQxMDE2MTk0NTA2WhcN
MTcwNzEyMTk0NTA2WjBmMRkwFwYDVQQDDBBNYXJpYW5vIFJlaW5nYXJ0MRkwFwYD
VQQFExBDVUlUIDIwMjY3NTY1MzkzMSEwHwYDVQQKDBhQeUFmaXBXcy1TaXN0ZW1h
cyBBZ2lsZXMxCzAJBgNVBAYTAkFSMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQCa+TDQaSgL1/wcMzFJXi1ipc2VurFOx4LlP13pIrC0hX2xP+I+qNeD2vZlaiA0
bMAZfx6w/+KjOPsJaQXre+TC6NU7Ed7FV6GZO6a2ZM/KjkoJSJIG/aVn+jljOkkl
2ANiTghi9tT3hPK1k6KQz6X2uBHaInKMrvi2Cj9/Tvi6UQIDAQABo4IBHzCCARsw
DAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0OBBYEFJ61KivCQwKv
/FnE6OJhBgz4nzjsMB8GA1UdIwQYMBaAFER07rScJt9W4cEN61cLkBk2PZYBMIG6
BgNVHSAEgbIwga8wgawGDisGAQQBgbtjAQIBAgEBMIGZMIGWBggrBgEFBQcCAjCB
iR6BhgBDAGUAcgB0AGkAZgBpAGMAYQBkAG8AIABwAGEAcgBhACAAYwBvAG0AcAB1
AHQAYQBkAG8AcgBlAHMAIABzAG8AbABvACAAdgBhAGwAaQBkAG8AIABlAG4AIABl
AG4AdABvAHIAbgBvAHMAIABkAGUAIABkAGUAcwBhAHIAcgBvAGwAbABvMA0GCSqG
SIb3DQEBBQUAA4IBAQCM/PmA6htlY/X8XK98XOtQxjOaLt5MgFdGiwyop13Xyh3n
c9ak4KFP6qbz6gKzCelkYoPgFLreP+lvL62EYrNaLacNLZUbko7wZotjRRxZo0+f
OkjJMIafgM5mycdVvcI1uzIKPWba5F5w8NawcL8bloSqDWX1dJRwvhs2hmcN3iIf
aYosbVUI/DMLys1xFqCMSBrTX4xtfL82TOg+mSVaRW37aED8ta7jTcBTn+001nos
c/1rXrB0qBQa7EKD7VJKSLkn4RV/HwO8R1POVexyrk7TzNeamcQMIKjkhHzXSsOb
BROqptCxUDh4QUdLQNRtwsJClufr6Bgidg37JK+4MYIB4DCCAdwCAQEwTzBDMSUw
IwYDVQQDDBxBRklQIFRlc3RpbmcgQ29tcHV0YWRvcmVzIENBMQ0wCwYDVQQKDARB
RklQMQswCQYDVQQGEwJBUgIISL4VMzAJIDswDQYJYIZIAWUDBAIBBQCggeQwGAYJ
KoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkwNjE5MTMx
MTA4WjAvBgkqhkiG9w0BCQQxIgQgPhDZEOopRNlv7JVKSyLZ2AWdNb81O6zm3hgM
BADUI34weQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJYIZIAWUDBAEW
MAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgICAIAwDQYIKoZI
hvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZIhvcNAQEBBQAE
gYAaqEV7X2WqmODhoqV64aLmM1mkUuVsGxgBDc09IRwUtD6wQAoMd87iIVeQ0n2X
qHHjmAz8QLp5tCApSPLjdaXbzufJ6vfOhpuHzu2QuOZh7AM9g8+zLubcs/+aRGC8
RUXoVaHajVOeHN4iR5pIJ3n2zuIWgowyK1sH3Q33i0A+MQ==
using this PHP function
$STATUS=openssl_pkcs7_sign("TRA.xml", "TRA.tmp", "file://".CERT,
array("file://".PRIVATEKEY, PASSPHRASE),
array(),
!PKCS7_DETACHED
);
Where CERT and PRIVATEKEY are the public and private keys, PASSPHRASE is an empty string and the file TRA.xml contains the XML example provided above.
You can download the public and private key from this link
Example Certificates
Botan Example in C++
#include <botan/pkcs8.h>
#include <botan/hex.h>
#include <botan/pk_keys.h>
#include <botan/pubkey.h>
#include <botan/auto_rng.h>
#include <botan/rng.h>
#include <iostream>
int main (intargc,char*argv[])
{
if(argc!=2)
return1;
std::string plaintext("Your great-grandfather gave this watch to your granddad for good luck. Unfortunately, Dane's luck wasn't as good as his old man's.");
std::vector<uint8_t> pt(plaintext.data(),plaintext.data()+plaintext.length());
std::unique_ptr<Botan::RandomNumberGenerator> rng(newBotan::AutoSeeded_RNG);
//load keypair
std::unique_ptr<Botan::Private_Key> kp(Botan::PKCS8::load_key(argv[1],*rng.get()));
//encrypt with pk
Botan::PK_Encryptor_EME enc(*kp,*rng.get(), "EME1(SHA-256)");
std::vector<uint8_t> ct = enc.encrypt(pt,*rng.get());
//decrypt with sk
Botan::PK_Decryptor_EME dec(*kp,*rng.get(), "EME1(SHA-256)");
std::cout << std::endl << "enc: " << Botan::hex_encode(ct) << std::endl << "dec: "<< Botan::hex_encode(dec.decrypt(ct));
return 0; //Edited :D, Thanks jww
}
I need to encrypt the XML in SHA1+RSA using the certificates and encode the result in Base64. Any help will be very appreciated.
I'm a little bit confused about your main question. Guess you have to mention it more obvious. But as I noticed the problem is how to encrypt using your public RSA key and SHA-1 hash function! (Am I right?)
So in that case I would say the EME1(SHA-256) that you could see in encryptor/decryptor objects aren't the bulk encryption algorithm and hash function used for encryption. They are padding algorithms!
In Botan there are tls_channel and tls_callbacks which handle the whole process of encryption and decryption between two sides. Take a further look at them.
Also if Botan is not mandatory I suggest you to use Openssl in evp.h file the function EVP_SealInit will may help you by letting pick your desired algorithm with const EVP_CIPHER *type input. For more info check this link
I am trying to RSA public key decrypt a signed file using wolfcrypt - yes, I may or may not be abusing the "sign/verify" power of RSA to encrypt a separate AES key using the private key and decrypt using the public key.
Unfortunately, I am stuck at wc_RsaSSL_Verify() - for the life of me I can't figure out why it is returning BAD_FUNC_ARG - I figured an error like that should be immediately visible to somebody else so I'm deciding to call upon the collective powers of StackOverflow.
As far as I can tell, I'm giving the function what it's asking for - an input buffer, an output buffer, the size of each, and a pointer to the RsaKey struct. Here is a code snippet from the function in question:
bool VerifyWorker::GetAESKey()
{
bool result = true;
uint8_t en_aes_file_buff[VerifyWorkerLocal::RSA_KEY_SIZE];
uint8_t de_aes_file_buff[VerifyWorkerLocal::RSA_KEY_SIZE];
uint8_t* aes_iv_ptr = NULL;
// keyfile filestream
std::fstream aes_file;
// rsa_key must be initialized
if(rsa_key == NULL)
{
result = false;
}
// Open the key file and read it into a local buffer, then decrypt it and use it to initialize the
// aes struct
if(result)
{
aes_file.open(this->aes_key_file, std::ios_base::in | std::ios_base::binary);
if(aes_file.fail())
{
// Unable to open file - perror?
perror("GetAESKey");
result = false;
}
else
{
aes_file.read(reinterpret_cast<char*>(en_aes_file_buff), VerifyWorkerLocal::RSA_KEY_SIZE + 1);
if(!aes_file.eof())
{
// we didn't have enough space to read the whole signature!
std::cerr << "aes_file read failed! " << aes_file.rdstate() << std::endl;
result = false;
}
}
}
// "Unsign" the aes key file with RSA verify, and load the aes struct with the result
if(result)
{
int wc_ret = 0;
wc_ret = wc_RsaSSL_Verify(const_cast<const byte*>(en_aes_file_buff),
VerifyWorkerLocal::RSA_KEY_SIZE, reinterpret_cast<byte*>(&de_aes_file_buff),
VerifyWorkerLocal::RSA_KEY_SIZE, rsa_key);
The rsa_key is a private member initialized (successfully, using wc_PublicKeyDecode()) in a separate function with a public key DER file. I generated both the public and private key using OpenSSL - which should properly pad my AES key and iv file using PKCS#1 v1.5 b default.
I should also mention that I am using wolfssl version 3.9.8. Thanks!
The issue, I found, was that the file that I had signed with my RSA key was not signed correctly. When I signed the file using OpenSSL, my cli invocation was
openssl rsautl -in keyfile -out keyfile -inkey private.pem -sign
Apparently, openssl does not like you to specify the same file for -in and -out. When I changed it to something like
openssl rsautl -in keyfile -out keyfile_signed -inkey private.pem -sign
I was actually able to verify the file using wc_RsaSSL_Verify.
So, like most stupid late-night, last hour software problems, I was looking in the wrong place entirely. I was a bit thrown off by the BAD_FUNC_ARG being returned and thought that it had to do explicitly with the format of the function arguments, not necessarily their content. Hopefully this answer is useful for somebody else, too.
It sounds like you are trying to use RSA_Sign to perform an "Encrypt" of an AES key. Then I assume you are sending to a remote partner or computer who will then run an RSA_Verify operation to decrypt the AES key do I understand the scenario correctly?
If so I apologize it did not show up if you searched on how to do this initially but we actually have an example of doing exactly that here:
https://github.com/wolfSSL/wolfssl-examples/tree/master/signature/encryption-through-signing
That example includes two separate applications. The first app, "rsa-private-encrypt-app.c", will sign (encrypt) the "fake Aes Key" and output the result to a file. The second app, "rsa-public-decrypt-app.c", then opens the file that was output and does a verify (decrypt) on the data contained in the file to recover the original "fake Aes Key".
I may or may not be abusing the "sign/verify" power of RSA to encrypt a separate AES key using the private key and decrypt using the public key.
No not at all, that is a valid use of RSA sign/verify ASSUMING you are working with fixed-length inputs such as an AES key.
That's why we created the example! We actually had a user ask a very similar question on our forums awhile back which led to us making the example.
One thing to make note of though on the issues you encountered with openssl and wolfssl is actually talked about in the README:
https://github.com/wolfSSL/wolfssl-examples/blob/master/signature/encryption-through-signing/README.md
... Keep in mind this is not a TRUE RSA ENCRYPT and will likely not inter-op with other libraries that offer a RSA_PRIVATE_ENCRYPT type API.
This is a true SIGN operation.
If you have any other questions feel free to post them here (and add the wolfssl tag of course) or you can also send us an email anytime at support#wolfssl.com
Disclaimer: I work for wolfSSL Inc.
I am struggling with the OpenSSL API for C++ at the moment. I'm using the EVP functions to generate a RSA keypair which then is used to encrypt the AES key that was used for encrypting the data (hybrid encryption).
Key generation:
EVP_PKEY* keypair = NULL;
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 4096);
EVP_PKEY_keygen(ctx, &keypair);
EVP_PKEY_CTX_free(ctx);
Now I have a keypair. When Encrypting a message on my own machine via EVP_SealInit / EVP_SealUpdate / EVP_SealFinal there is no problem. Same for the decrypting process. I simply give keypair as an argument to the SealInit / OpenInit function.
But consider that I want to generate a keypair and send the public or private key as a char* over a socket to another person: how do I do that?
One way I found in the Internet is using PEM_write_bio_PUBKEY or PEM_write_bio_PrivateKey to convert the Keys to char*. When trying it seemed to work. But I'm still not 100% sure. So Please look at my code and tell me if those functions are the way to go:
unsigned char* publicKey;
BIO* bio = BIO_new(BIO_s_mem());
PEM_write_bio_PUBKEY(bio, keypair);
RSAmakeString(&publicKey, bio);
unsigned char* privateKey;
BIO* bio = BIO_new(BIO_s_mem());
PEM_write_bio_PrivateKey(bio, keypair, NULL, NULL, 0, 0, NULL);
RSAmakeString(&privateKey, bio);
The other thing is how do I convert the char* back to EVP_PKEY*? Are there any functions? Because if I want to use SealInit with my public Key on another computer I have to convert it back from a char* to an EVP_PKEY*, so I can use it in the function. Any suggestions?
But consider that I want to generate a keypair and send the public or private key as a char* over a socket to another person: how do I do that?
You need something for serialization and wire formats or a presentation format. Your public key and encrypted messages will likely have 0 characters, which appear as embedded NULL. So you need to have both a buffer and explicit length .
Use Google's ProtocolBuffers, Binary JSON, or even ASN.1/DER encoding. I think Google's ProtocolBuffers are message oriented, so they won't return a message until the complete message is available.
You could also Hex, Base32 or Base64 encode it. But you still need to communicate a length so the receiving party knows they got the whole message. On a local LAN you will probably never experience a problem. Over the Internet you will probably get occasional failures as your perform short reads on occasion.
Your thoughts on PEM_write_bio_PUBKEY are effectively Base64 encoding the key, so it suffers the same potential problem as Hex, Base32 or Base64 encoding.
how do I convert the char* back to EVP_PKEY
Well, you probably won't be using a char* based on your changes above. Once you refine the design, you should probably ask a new question.
But at the moment, and given you saved the key with PEM_write_bio_PUBKEY and PEM_write_bio_PrivateKey, then you would use PEM_read_bio_PUBKEY or PEM_read_bio_PrivateKey, respectively. Also see OpenSSL's PEM man page.
Related to C++, here are some tricks when working with OpenSSL. If you are using C++11, then unique_ptr really makes it easy to work with some OpenSSL objects.
unique_ptr and OpenSSL's STACK_OF(X509)*
How to get PKCS7_sign result into a char * or std::string
Non-printable character after generating random n-byte Base64 string
EVP Symmetric Encryption and Decryption | C++ Programs on the OpenSSL wiki
So I am using the Crypto++ Library to encrypt a file. I need to save the key and iv for future use. I am following this tutorial. Here is my function :
void AESUtil::encrypt(string filename,bool savekeys,string savefilename){
AutoSeededRandomPool rnd;
// Generate a random key
byte key[AES::DEFAULT_KEYLENGTH];
rnd.GenerateBlock(key, AES::DEFAULT_KEYLENGTH);
// Generate a random IV
byte iv[AES::BLOCKSIZE];
rnd.GenerateBlock(iv, AES::BLOCKSIZE);
Binary b;
string plaintext = b.decoder(filename);
unsigned char *ciphertext= new unsigned char[plaintext.size()+1];
ciphertext[plaintext.size()]='\0';
if(savekeys){
ofstream("key.bin", ios::binary).write((char*)key, sizeof(key));
}
CFB_Mode<AES>::Encryption cfbEncryption(key, AES::DEFAULT_KEYLENGTH, iv);
cfbEncryption.ProcessData(ciphertext,reinterpret_cast<const unsigned char*>(plaintext.c_str()),plaintext.size()+1);
ofstream outfile(savefilename.c_str());
outfile.write((char*)ciphertext,sizeof(ciphertext));
}
The files contain data in �/���� format. I want to know the best method to save the key and iv programmatically which are a byte array to a file and the ciphertext which is a unsigned char* to a separate file.
The key could be saved in a separate file. Normally the key is established between sender / receiver in advance, or it is encrypted using a public key of the receiver. Note that it doesn't make sense to save the key next to the ciphertext, as it would provide no protection whatsoever. The handling of keys is called key management and entire books have been written about it.
The IV is a different animal. The IV should be randomly generated. For CFB it should at least be unique and identical at both sides. Usually the IV is simply prefixed to the ciphertext, it doesn't have to be kept secret.
Your key and iv variables are the key and IV used to encrypt the plain text.
You didn't fill either; you're actually using an array filled with 0 bytes as both the key and IV for your encryption.
The IV is public information. You don't need to hide it. Save it the way you want.
The KEY is what you must keep safe. To do that you may decide how much effort you want to put on it to hide it from the external factors.
I have some keys that I don't care to leave them as a "plain text" in the binary code. (NO SECURITY, but my mom can't figure out what to do, but a beginner in reverse engineer will laugh at it.)
Some keys I do a play with the bytes, like inverting parts, separating them, XOR with something. (Very unsafe, but better than nothing, a programmer with decent knowledge in reverse engineering will be able to spend some time and eventually break the security)
Some other cases I use 3rd party advanced obfuscation... If possible, depending on what you want, you may even replace your encryption engine with some "white-box" cryptography. Then you will have your keys very well protected. But this is usually hard/expensive. It doesn't seem to be your case. (Yes, even a very advanced assembly guru will not be happy to start reverse engineer this case.)
Another solution, if you don't need the key on your binary, is to give it to the system's password manager. On Windows, it's called "Data Protection API", and on Mac, it's called "Keychain". Take a look at these, and then you will understand why this is considered security. But it's because all the passwords here are encrypted with the "user password" so nothing is stored "on disk". A turned-off device in this scenario is considered very secure.
I want to license my software using RSA encryption. My software has several executables and I plan to have each check the signature of a common license file before they proceed to do what it is they do. My goal is not to make it impossible to circumvent the licensing protection, just make it very difficult. I know that no one can make it impossible.
The executables currently run in a Windows environment, but they will only be released to work in a Linux environment.
My current plan is to put the public key within each executable for signature verification. The programs already have a 'safe' encrypted area in which to put the key.
My question for this post is, does my implementation method make sense? Is there another alternative? The alternative to have the public key in a separate file would allow a hacker to replace that file and use their own license file and signature. That doesn't seem as safe.
Additionally I've been reading through the crypto++ documentation and running the example code to try and accomplish this task. I cannot get any code to work that puts the key into a non-file sink and back again. All the examples write and read to files. I need to be able to save and load from a string or a byte queue. A simple attempt to do this is below, but when it runs I get this error, when r2.BERDecodePrivateKey() executes:
Unhandled exception at 0x7630c41f in MyRSA.exe: Microsoft C++ exception: CryptoPP::BERDecodeErr at memory location 0x002ef32c..
#include <osrng.h>
#include "rsa.h"
using CryptoPP::RSA;
#include <queue.h>
using CryptoPP::ByteQueue;
int myCode_key2ByteQueueToKey(void)
{
////////////////////////////////////////////////////////////////////////
// Generate the keys
AutoSeededRandomPool rnd;
CryptoPP::RSA::PrivateKey r1;
r1.GenerateRandomWithKeySize(rnd, 2048);
CryptoPP::RSA::PublicKey rsaPublic(r1);
////////////////////////////////////////////////////////////////////////
// Put the 'inner' part of the key into a ByteQueue - whatever that is.
ByteQueue queue;
r1.DEREncodePublicKey(queue);
////////////////////////////////////////////////////////////////////////
// Copy the byte queued inner key into another key
CryptoPP::RSA::PrivateKey r2;
r2.BERDecodePrivateKey(queue, false /*optParams*/, queue.MaxRetrievable());
////////////////////////////////////////////////////////////////////////
// Validate the key made the trip in and out of a byte queue ok.
if(!r1.Validate(rnd, 3)) printf("Validation of oringal key failed.\n");
if(!r2.Validate(rnd, 3)) printf("Validation of reloaded key failed.\n");
if(r1.GetModulus() != r2.GetModulus() ||
r1.GetPublicExponent() != r2.GetPublicExponent() ||
r1.GetPrivateExponent() != r2.GetPrivateExponent())
{
printf("Key didn't survive round trip in and out of a byte queue.");
}
return 0;
}
I do not have a fix for the above code. There's something I don't understand about library and as a result something's missing, but I've got to get a move on.
I thought I'd post an alternative I've found. Its an example on the Crypto++ wiki that puts the keys into strings (and not files) and back again. The round trip is shown to work.
http://www.cryptopp.com/wiki/BERDecode
Instead of
CryptoPP::RSA::PrivateKey
it uses
CryptoPP::RSAES_OAEP_SHA_Decryptor
and similarly for the public key. This allows the use of a member function AccessKey() which isn't available for the PrivateKey class.
If anyone has a fix for the original code, I urge you to please post it as it would help me better understand this library.
So basically you do this:
Generate 2048 bits private key
Encode a public key in DER format from the exponents of your private key to your bytequeue
Try to decode it as a private key from the bytequeue <-- here is the error
Validate the key...
You cannot decode a public key to a private key, some encoding flags differs.
As for CryptoPP::RSAES_OAEP_SHA_Decryptor
it's a good practice to use it for key generation as it is aware of safe primes.
It is also simpler to use for general decryption task as it includes everything you need in one object.
See http://www.cryptopp.com/wiki/Keys_and_Formats#High_Level_Objects
Hope it helped even it's a late answer ;)