Bitcoin Forum
May 12, 2024, 09:30:41 PM *
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 9631 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.
1715549441
Hero Member
*
Offline Offline

Posts: 1715549441

View Profile Personal Message (Offline)

Ignore
1715549441
Reply with quote  #2

1715549441
Report to moderator
1715549441
Hero Member
*
Offline Offline

Posts: 1715549441

View Profile Personal Message (Offline)

Ignore
1715549441
Reply with quote  #2

1715549441
Report to moderator
1715549441
Hero Member
*
Offline Offline

Posts: 1715549441

View Profile Personal Message (Offline)

Ignore
1715549441
Reply with quote  #2

1715549441
Report to moderator
Be very wary of relying on JavaScript for security on crypto sites. The site can change the JavaScript at any time unless you take unusual precautions, and browsers are not generally known for their airtight security.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
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!