Title: Code to convert any PGP key (public AND private) into OpenSSL format [60 BTC]
Post by: da2ce7 on March 26, 2011, 06:24:07 AM
I want an easy function call(s) that will take PGP keys (PUBLIC AND PRIVATE) and convert them in/out of OpenSSL keys and give me some basic info about the key like size, algorithm, etc
1. Free (BSD like licence) 2. C++ or C
Easy to integrate into existing open source projects.
For more details talk to FellowTraveler
Title: Re: Code to convert any PGP key (public AND private) into OpenSSL format [60 BTC]
Post by: genjix on March 26, 2011, 08:24:57 AM
There's actually no easy way to do this. You can call a program called gpgsm using: gpgsm -o secret-gpg-key.p12 --export-secret-key-p12 0xXXXXXXXX openssl pkcs12 -in secret-gpg-key.p12 -nocerts -out gpg-key.pem openssl pkcs12 -in secret-gpg-key.p12 -nokeys -out gpg-certs.pem If you insist, then you should look at the gpgsm sourcecode as it's a specially built tool for the job. The last 2 lines can be done in C++ easily. To load RSA keys you can do: static int pass_cb(char* buf, int size, int rwflag, void* u) { const string pass = reinterpret_cast<char*>(u); int len = pass.size(); // if too long, truncate if (len > size) len = size; pass.copy(buf, len); return len; } RSA* LoadPrivateKey(const string& pem, const string& pass) { BIO_free(bio); BIO* bio = BIO_new_mem_buf(StringAsVoid(str), -1); if (!bio) throw ReadError(); RSA* keypair = PEM_read_bio_RSAPrivateKey(bio, NULL, pass_cb, StringAsVoid(pass)); if (!keypair) throw NoKeypairLoaded(); return keypair; }
If it's a public key then use PEM_read_bio_PKCS7 instead. The above function should recognise it's PKCS. Maybe sometimes you'll need an EVP object: class EvpBox { public: EvpBox(RSA* keyp); ~EvpBox(); EVP_PKEY* Key(); private: EVP_PKEY* evpkey; };
...
EvpBox::EvpBox(RSA* keyp) { evpkey = EVP_PKEY_new(); if (!EVP_PKEY_set1_RSA(evpkey, keyp)) { throw ReadError(); } } EvpBox::~EvpBox() { EVP_PKEY_free(evpkey); } EVP_PKEY* EvpBox::Key() { return evpkey; }
1HmskBCwhnV8DRvYdpBmDyyTwGc28otPeZ
Title: Re: Code to convert any PGP key (public AND private) into OpenSSL format [60 BTC]
Post by: da2ce7 on March 26, 2011, 01:33:27 PM
1HmskBCwhnV8DRvYdpBmDyyTwGc28otPeZ
Thank you, will test.
Title: Re: Code to convert any PGP key (public AND private) into OpenSSL format [60 BTC]
Post by: da2ce7 on March 27, 2011, 07:54:00 AM
1HmskBCwhnV8DRvYdpBmDyyTwGc28otPeZ
Thank you, will test. I'm sorry genjix, it doesn't seem to work, can you please guide me where I have made a mistake. http://pastebin.com/3pbC5e7N (http://pastebin.com/3pbC5e7N)
Title: Re: Code to convert any PGP key (public AND private) into OpenSSL format [60 BTC]
Post by: fellowtraveler on March 27, 2011, 08:00:41 AM
The pastebin says "public key" all over its comments, but really what we're looking for here is the private key. (Sorry for any confusion.)
In fact, I already have code that derives the public key, which you can see between lines 246 - 612 in this file: https://github.com/FellowTraveler/Open-Transactions/blob/master/OTLib/OTAsymmetricKey.cpp
So really I'm more interested in the private key, although the best solution (such as your proposal) will supply both.
I tried your code BTW, see the pastebin link above and please help me to correct it, thank you.
-FT
Title: Re: Code to convert any PGP key (public AND private) into OpenSSL format [60 BTC]
Post by: genjix on March 27, 2011, 08:30:12 AM
EDIT: Did you actually read what I wrote above? Re-read it. Try this: #include <string> #include <exception> using std::string;
//typedef struct RSA; #include <openssl/rsa.h>
class ReadError : public std::exception { public: virtual const char* what() const throw(); };
class NoKeypairLoaded : public std::exception { public: virtual const char* what() const throw(); };
class AccessCard { public: AccessCard(); ~AccessCard(); void Generate(); void Load(const string& pem, const string& pass); void PublicKey(string& pem) const; void PrivateKey(string& pem, const string& passphrase) const;
private: void CheckKey() const;
RSA* keypair; };
class BioBox { public: struct Buffer { void* buf; int size; };
BioBox(); ~BioBox(); void ConstructSink(const string& str); void NewBuffer(); BIO* Bio() const; Buffer ReadAll(); private: BIO* bio; Buffer buf; };
class EvpBox { public: EvpBox(RSA* keyp); ~EvpBox(); EVP_PKEY* Key(); private: EVP_PKEY* evpkey; };
//-------------------- #include <openssl/pem.h>
const char* ReadError::what() const throw() { return "Problem reading BIO."; } const char* NoKeypairLoaded::what() const throw() { return "No keypair loaded."; }
AccessCard::AccessCard() : keypair(NULL) { if (EVP_get_cipherbyname("aes-256-cbc") == NULL) OpenSSL_add_all_algorithms(); } AccessCard::~AccessCard() { RSA_free(keypair); } void AccessCard::CheckKey() const { if (!keypair) throw NoKeypairLoaded(); }
void AccessCard::Generate() { RSA_free(keypair); keypair = RSA_generate_key(2048, RSA_F4, NULL, NULL); CheckKey(); }
static char *LoseStringConst(const string& str) { return const_cast<char*>(str.c_str()); } static void* StringAsVoid(const string& str) { return reinterpret_cast<void*>(LoseStringConst(str)); }
BioBox::BioBox() : bio(NULL) { buf.buf = NULL; buf.size = 0; } BioBox::~BioBox() { BIO_free(bio); free(buf.buf); } void BioBox::ConstructSink(const string& str) { BIO_free(bio); bio = BIO_new_mem_buf(StringAsVoid(str), -1); if (!bio) throw ReadError(); } void BioBox::NewBuffer() { BIO_free(bio); bio = BIO_new(BIO_s_mem()); if (!bio) throw ReadError(); } BIO* BioBox::Bio() const { return bio; } BioBox::Buffer BioBox::ReadAll() { buf.size = BIO_ctrl_pending(bio); buf.buf = malloc(buf.size); if (BIO_read(bio, buf.buf, buf.size) < 0) { //if (ERR_peek_error()) { // ERR_reason_error_string(ERR_get_error()); // return NULL; //} throw ReadError(); } return buf; }
EvpBox::EvpBox(RSA* keyp) { evpkey = EVP_PKEY_new(); if (!EVP_PKEY_set1_RSA(evpkey, keyp)) { throw ReadError(); } } EvpBox::~EvpBox() { EVP_PKEY_free(evpkey); } EVP_PKEY* EvpBox::Key() { return evpkey; }
static int pass_cb(char* buf, int size, int rwflag, void* u) { const string pass = reinterpret_cast<char*>(u); int len = pass.size(); // if too long, truncate if (len > size) len = size; pass.copy(buf, len); return len; } void AccessCard::Load(const string& pem, const string& pass) { RSA_free(keypair); BioBox bio; bio.ConstructSink(pem); keypair = PEM_read_bio_RSAPrivateKey(bio.Bio(), NULL, pass_cb, StringAsVoid(pass)); CheckKey(); } void AccessCard::PublicKey(string& pem) const { CheckKey(); BioBox bio; bio.NewBuffer(); int ret = PEM_write_bio_RSA_PUBKEY(bio.Bio(), keypair); if (!ret) throw ReadError(); const BioBox::Buffer& buf = bio.ReadAll(); pem = string(reinterpret_cast<const char*>(buf.buf), buf.size); }
void AccessCard::PrivateKey(string& pem, const string& passphrase) const { CheckKey(); BioBox bio; bio.NewBuffer();
EvpBox evp(keypair); int ret = PEM_write_bio_PKCS8PrivateKey(bio.Bio(), evp.Key(), EVP_aes_256_cbc(), LoseStringConst(passphrase), passphrase.size(), NULL, NULL); if (!ret) throw ReadError(); const BioBox::Buffer& buf = bio.ReadAll(); pem = string(reinterpret_cast<const char*>(buf.buf), buf.size); }
//------------------------------------------------------------------- // this wont be in the final file... it's our unit test //------------------------------------------------------------------- #include <iostream> #include <assert.h> using std::cout;
int main() { AccessCard acc; // New key acc.Generate(); string pem; // Get public key acc.PublicKey(pem); cout << pem << "\n"; // Get private key acc.PrivateKey(pem, "hello"); cout << pem << "\n"; // Load a private key using pass 'hello' acc.Load(pem, "hello"); acc.PublicKey(pem); cout << pem << "\n"; return 0; }
|