3

I'm trying to use asymmetric encryption in a C program, to encrypt strings.

I chose to go with RSA, but if there's a less complicated yet secure way, do tell me.

OpenSSL is one library I've looked at and found no documentation on implementing it in C code. (I may just have been unlucky, I've been looking for many days)

No luck on YouTube/Google either...

Please point me to a detailed source of information on how how to do this...

I understand both C and the fundamental concepts of RSA pretty well, but I have no idea how to:

  1. Generate the large primes needed to generate the keys.
  2. Fix e = 65537 .
  3. Generate the public / private keys in an alphanumeric format (they are actually numbers, arent they ?) .
  4. Seamlessly combine (e,n) in the public key and (d,n) in the private key in the way tools like OpenSSL seem to do (in an alphanumeric string) .
6
  • Have you taken a look at mbedTLS? I have used it and it felt much more approachable than openssl. tls.mbed.org/kb/how-to/encrypt-and-decrypt-with-rsa Commented Aug 5, 2020 at 10:48
  • @th33lf it seems a bid skimpy with the detailing and perhaps if you could point me to a test/sample.c file so i can fully grasp it ? Commented Aug 5, 2020 at 10:57
  • I chose to go with RSA, but if there's a less complicated yet secure way, do tell me. Yes. A symmetric stream cipher such as AES is going to be a lot simpler. Securing the keys is going to be a bit more difficult because there's no public key that you can distribute, but the implementation will be simpler. You can use an ephemeral AES key to encrypt your data, use the RSA public key to encrypt the AES key, and then transmit the encrypted AES key and data to the recipient, who uses the RSA private key to decrypt the AES key, then the AES key to decrypt the data. Commented Aug 5, 2020 at 11:03
  • @AndrewHenle which AES library would you recommend ? Commented Aug 5, 2020 at 11:19
  • @th33lf Also, I want to generate keys within the program, while mbedTLS seems to to require pre-generated keys Commented Aug 5, 2020 at 11:31

1 Answer 1

4

Here's an example of what you're looking to do. First a utility function to print OpenSSL error messages:

void log_ssl_err(const char *mes)
{
    unsigned long err, found;
    char errstr[1000];

    found = 0;
    while ((err = ERR_get_error())) {
        ERR_error_string(err, errstr);
        printf("%s: %s", mes, errstr);
        found = 1;
    }
    if (!found) {
        printf("%s", mes);
    }
}

Generating a key with a given exponent:

RSA *rsa;
BIGNUM *e;
uint32_t exponent_bin, exponent_num;

exponent_num = 65537;
exponent_bin = htonl(exponent);
e = BN_bin2bn((const unsigned char *)&exponent_bin, 4, NULL);
if (e == NULL) {
    log_ssl_err("BN_bin2bn failed for e");
    exit(1);
}

if ((rsa = RSA_new()) == NULL) {
    log_ssl_err("RSA_new failed");
    BN_free(e);
    exit(1);
}
if (!RSA_generate_key_ex(rsa, 2048, e, NULL)) {
    log_ssl_err("couldn't generate rsa key");
    BN_free(e);
    exit(1);
}

Encrypting and decrypting:

unsigned char plaintext[] = "this is the plaintext";
unsigned char *ciphertext, *decrypted;
int cipher_len, decrypted_len;

ciphertext = malloc(RSA_size(rsa));
if ((cipher_len = RSA_public_encrypt(strlen(plaintext), plaintext, ciphertext, 
                                    rsa, RSA_PKCS1_OAEP_PADDING)) == -1) {
    log_ssl_err("RSA_public_encrypt failed");
    exit(1);
}

decrypted = malloc(RSA_size(rsa));
if ((decrypted_len = RSA_private_decrypt(cipher_len, ciphertext, decrypted, 
                                         rsa, RSA_PKCS1_OAEP_PADDING)) == -1) {
    log_ssl_err("RSA_private_decrypt failed");
    return 0;
}

The documentation for OpenSSL can be difficult to navigate, but the information you need can be found in the man pages. If you run man 3 rsa you'll see a list of all the RSA related functions. From there you can look at the man page for each function.

Sign up to request clarification or add additional context in comments.

5 Comments

From the manpage: "RSA_public_encrypt() [...] stores the ciphertext in to. to must point to RSA_size(rsa) bytes of memory." This implementation doesn't do that, so a suitably large plaintext will cause memory corruption and is thus a security vulnerability.
@AKX A 2048 bit key requires 256 bytes. This implementation supplies twice that.
That the arrays happen to be suitable for this use case is beside the point if you ask me. OP wouldn't have that tribal knowledge about required storage, so if they decided to increase their key size, they wouldn't know they also needed to increase the ciphertext buffer size.
@AKX Fair enough. Updated to use dynamically allocated buffers of the proper size.
Thanks :) One less possible buffer overflow in the world! :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.