Bitcoin Forum
May 08, 2024, 11:12:03 AM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Code to convert any PGP key (public AND private) into OpenSSL format [60 BTC]  (Read 9629 times)
da2ce7 (OP)
Legendary
*
Offline Offline

Activity: 1222
Merit: 1016


Live and Let Live


View Profile
March 26, 2011, 06:24:07 AM
 #1

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

One off NP-Hard.
1715166723
Hero Member
*
Offline Offline

Posts: 1715166723

View Profile Personal Message (Offline)

Ignore
1715166723
Reply with quote  #2

1715166723
Report to moderator
The Bitcoin software, network, and concept is called "Bitcoin" with a capitalized "B". Bitcoin currency units are called "bitcoins" with a lowercase "b" -- this is often abbreviated BTC.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1715166723
Hero Member
*
Offline Offline

Posts: 1715166723

View Profile Personal Message (Offline)

Ignore
1715166723
Reply with quote  #2

1715166723
Report to moderator
1715166723
Hero Member
*
Offline Offline

Posts: 1715166723

View Profile Personal Message (Offline)

Ignore
1715166723
Reply with quote  #2

1715166723
Report to moderator
genjix
Legendary
*
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 26, 2011, 08:24:57 AM
Last edit: March 26, 2011, 04:56:28 PM by genjix
 #2

There's actually no easy way to do this. You can call a program called gpgsm using:

Quote
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:
Quote
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:
Quote
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
da2ce7 (OP)
Legendary
*
Offline Offline

Activity: 1222
Merit: 1016


Live and Let Live


View Profile
March 26, 2011, 01:33:27 PM
 #3

1HmskBCwhnV8DRvYdpBmDyyTwGc28otPeZ

Thank you, will test.

One off NP-Hard.
da2ce7 (OP)
Legendary
*
Offline Offline

Activity: 1222
Merit: 1016


Live and Let Live


View Profile
March 27, 2011, 07:54:00 AM
 #4

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

One off NP-Hard.
fellowtraveler
Sr. Member
****
Offline Offline

Activity: 440
Merit: 250


View Profile
March 27, 2011, 08:00:41 AM
 #5

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

co-founder, Monetas
creator, Open-Transactions
genjix
Legendary
*
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 27, 2011, 08:30:12 AM
 #6

EDIT: Did you actually read what I wrote above? Re-read it.

Try this:

Code:
#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;
}
 
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!