Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a RSA public key from a unsigned char * modulus and exponent 65537(RSA_F4)

Tags:

c++

c

linux

openssl

I'm trying generate a rsa public key from a modulus type char[], and I now the exponent is RSA_F4(65537); But when I'm trying generate my public key using this values for "n" and "e", the RSA_public_encrypt, return -1;

Thanks!

My code:

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <crypt.h>
#include <iostream>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/opensslconf.h>
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/rc4.h>

using namespace std;
int main(void)
{

//modulus in format char hex;
char key[] = "C0E7FC730EB5CF85B040EC25DAEF288912641889AD651B3707CFED9FC5A1D3F6C40062AD46E3B3C3E21D4E71CC4800C80226D453242AEB2F86D748B41DDF35FD";

    char palavra[] = "teste";
    char crip[512];
    int ret;
    RSA * pubkey = RSA_new();
    BIGNUM * modul = BN_new();
    BIGNUM * expon = BN_new();

    BN_hex2bn(&modul, (const char *) key);
    BN_hex2bn(&expon, "010001");

    cout << "N KEY: " << BN_bn2hex(modul) << endl;
    cout << "E KEY: " << BN_bn2hex(expon) << endl;

    pubkey->n = modul;
    pubkey->e = expon;

    cout << "N PUB KEY: " << BN_bn2hex(pubkey->n) << endl;
    cout << "E PUB KEY: " << BN_bn2hex(pubkey->e) << endl;

    if (RSA_public_encrypt(strlen((const char *) palavra), (const unsigned char *) palavra, (unsigned char *) crip, pubkey, RSA_PKCS1_PADDING ))
    {
        printf("ERRO encrypt\n");
    }
    else
    {
        printf("SUC encrypt\n");
    }
return 0;
}
like image 894
David Viana Avatar asked May 24 '12 17:05

David Viana


People also ask

What is modulus and exponent in RSA public key?

Public key contains modulus and public exponent. Modulus (n) is the product of two prime numbers used to generate the key pair. Public exponent (d) is the exponent used on signed / encoded data to decode the original value.

How is RSA modulus calculated?

At the center of the RSA cryptosystem is the RSA modulus N. It is a positive integer which equals the product of two distinct prime numbers p and q: RSA modulus: N = pq.


2 Answers

You probably want something that looks more like:

RSA *pubkey = RSA_new();
int len = BN_hex2bn(&pubkey->n, (const char *)p);
if (len == 0 || p[len])
    fprintf(stderr, "'%s' does not appear to be a valid modulus\n", p);
BN_hex2bn(&pubkey->e, "010001");

edit

Your code works fine, except for the error check. RSA_public_encrypt returns the size of the ciphertext on success, not 0, so to make the code above work, add a <= 0 test to if line:

if (RSA_public_encrypt(....) <= 0)
like image 190
Chris Dodd Avatar answered Oct 17 '22 01:10

Chris Dodd


Here is some C code, that does the trick:

#include <string.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/pem.h>

// cheating, .. ignoring deprecation warnings
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

unsigned char *base64_decode(const char* base64data, int* len) {
   BIO *b64, *bmem;
   size_t length = strlen(base64data);
   unsigned char *buffer = (unsigned char *)malloc(length);
   b64 = BIO_new(BIO_f_base64());
   BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
   bmem = BIO_new_mem_buf((void*)base64data, length);
   bmem = BIO_push(b64, bmem);
   *len = BIO_read(bmem, buffer, length);
   BIO_free_all(bmem);
   return buffer;
}

BIGNUM* bignum_base64_decode(const char* base64bignum) {
   BIGNUM* bn = NULL;
   int len;
   unsigned char* data = base64_decode(base64bignum, &len);
   if (len) {
       bn = BN_bin2bn(data, len, NULL);
   }
   free(data);
   return bn;
}

EVP_PKEY* RSA_fromBase64(const char* modulus_b64, const char* exp_b64) {
   BIGNUM *n = bignum_base64_decode(modulus_b64);
   BIGNUM *e = bignum_base64_decode(exp_b64);

   if (!n) printf("Invalid encoding for modulus\n");
   if (!e) printf("Invalid encoding for public exponent\n");

   if (e && n) {
       EVP_PKEY* pRsaKey = EVP_PKEY_new();
       RSA* rsa = RSA_new();
       rsa->e = e;
       rsa->n = n;
       EVP_PKEY_assign_RSA(pRsaKey, rsa);
       return pRsaKey;
   } else {
       if (n) BN_free(n);
       if (e) BN_free(e);
       return NULL;
   }
}

void assert_syntax(int argc, char** argv) {
   if (argc != 4) {
      fprintf(stderr, "Description: %s takes a RSA public key modulus and exponent in base64 encoding and produces a public key file in PEM format.\n", argv[0]);
      fprintf(stderr, "syntax: %s <modulus_base64> <exp_base64> <output_file>\n", argv[0]);
      exit(1);
   }
}

int main(int argc, char** argv) {
   assert_syntax(argc, argv);

   const char* modulus = argv[1];
   const char* exp = argv[2];
   const char* filename = argv[3];

   EVP_PKEY* pkey = RSA_fromBase64(modulus, exp);

   if (pkey == NULL) {
      fprintf(stderr, "an error occurred :(\n");
      return 2;
    } else {
       printf("success decoded into RSA public key\n");
       FILE* file = fopen(filename, "w");
       PEM_write_PUBKEY(file, pkey);
       fflush(file);
       fclose(file);
       printf("written to file: %s\n", filename);
    }

    return 0;
}

See this link for further info: http://www.techper.net/2012/06/01/converting-rsa-public-key-modulus-and-exponent-into-pem-file/

like image 34
polesen Avatar answered Oct 17 '22 01:10

polesen