~aritra1911/openssl_madness

221681fad12f2ac63cfe85f9d8ba33e799d68e5b — Aritra Sarkar 2 years ago b7bbc42 openssl-3.0
Make RSA work with OpenSSL 1.1.1l as well
2 files changed, 85 insertions(+), 146 deletions(-)

M Makefile
M madness.c
M Makefile => Makefile +1 -0
@@ 8,6 8,7 @@ ifdef OPENSSLDIR
endif

CFLAGS += -Wall -Wextra -pedantic -std=c99
CPPFLAGS += -DPURIFY
LDFLAGS += $(LIBS)

ifneq ($(strip $(DEBUG)),)

M madness.c => madness.c +84 -146
@@ 9,11 9,14 @@
#include <openssl/engine.h>
#include <openssl/err.h>

int rsa_encrypt(EVP_PKEY*, FILE*, FILE*, const int);
int rsa_decrypt(EVP_PKEY*, FILE*, FILE*, const int);
void print_usage(const char*);
#define BUF_SZ 1024

void print_usage(const char* bin) {
int rsa_encrypt(EVP_PKEY *, FILE *, FILE *, int);
int rsa_decrypt(EVP_PKEY *, FILE *, FILE *, int);
void print_usage(const char *);

void print_usage(const char *bin)
{
    printf("Usage : %s [-i FILE] -k PEM_FILE -(e|d) [-o FILE] [-v]\n"
           "RSA Encryption / Decryption Tool using OpenSSL API\n\n"



@@ 36,7 39,8 @@ void print_usage(const char* bin) {
           "    -v, --verbose     Show RSA size, blocks of data read, encrypted / decrypted, written.\n", bin);
}

int main(int argc, char* argv[]) {
int main(int argc, char **argv)
{
    EVP_PKEY *private_key, *public_key;
    FILE *fp, *fpin, *fpout;
    char *input_filename = NULL, *key_filename = NULL, *output_filename = NULL;


@@ 59,7 63,7 @@ int main(int argc, char* argv[]) {
            { "verbose", no_argument,       NULL, 'v' },
            { "outfile", required_argument, NULL, 'o' },
            { "help",    no_argument,       NULL, 'h' },
            { NULL,      0,                 NULL,  0  }
            { NULL,      0,                 NULL,  0  },
        };

        int c;


@@ 262,201 266,135 @@ int main(int argc, char* argv[]) {
    return (ret_status == -1) ? EXIT_FAILURE : EXIT_SUCCESS;
}

int rsa_encrypt(EVP_PKEY* public_key, FILE* infile, FILE* outfile, const int verbose) {
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    int key_size = EVP_PKEY_size(public_key);
#else
    int key_size = EVP_PKEY_get_size(public_key);
#endif
int rsa_encrypt(EVP_PKEY* public_key, FILE* infile, FILE* outfile, int verbose)
{
    size_t flen, len;
    unsigned char *buf, *encbuf;
    unsigned char buf[BUF_SZ], *encbuf;   /* TODO: malloc() buf ? */
    EVP_PKEY_CTX* ctx;

    /* Get default RSA context from `public_key` */
    if ( !(ctx = EVP_PKEY_CTX_new(public_key, NULL)) ) {
        fprintf(stderr, " ERR : ");
        fprintf(stderr, " ERR : EVP_PKEY_CTX_new: ");
report_free_return_err:
        ERR_print_errors_fp(stderr);
free_and_return_err:
        EVP_PKEY_CTX_free(ctx);
        return -1;
    }

    /* Initialize the context for encryption */
    if ( EVP_PKEY_encrypt_init(ctx) <= 0 ) {
        fprintf(stderr, " ERR : ");
        ERR_print_errors_fp(stderr);
        EVP_PKEY_CTX_free(ctx);
        return -1;
        fprintf(stderr, " ERR : EVP_PKEY_encrypt_init: ");
        goto report_free_return_err;
    }

    /* Set padding type for context */
    if ( EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 ) {
        fprintf(stderr, " ERR : ");
        ERR_print_errors_fp(stderr);
        EVP_PKEY_CTX_free(ctx);
        return -1;
        fprintf(stderr, " ERR : EVP_PKEY_CTX_set_rsa_padding: ");
        goto report_free_return_err;
    }

    // Quoting from man page of RSA_PUBLIC_ENCRYPT(3):
    // "flen must not be more than RSA_size(rsa) - 42 for RSA_PKCS1_OAEP_PADDING"
    if ( !(buf = OPENSSL_malloc(key_size - 42)) ) {
        fprintf(stderr, " ERR : Failed to allocate memory for input buffer\n");
        EVP_PKEY_CTX_free(ctx);
        return -1;
    /* Read input stream */
    if ( !(flen = fread(buf, 1, BUF_SZ, infile)) ) {
        fprintf(stderr, " ERR : fread: read 0 bytes from input stream\n");
        goto free_and_return_err;
    }

    // Encrypted block with padding will be `key_size' bytes long
    if ( !(encbuf = OPENSSL_malloc(key_size)) ) {
        fprintf(stderr, " ERR : Failed to allocate memory for output buffer\n");
        OPENSSL_free(buf);
        EVP_PKEY_CTX_free(ctx);
        return -1;
    if ( verbose ) printf("INFO : %lu bytes read for encryption\n", flen);

    /* Determine output (encrypted) buffer length */
    if ( EVP_PKEY_encrypt(ctx, NULL, &len, buf, flen) <= 0 ) {
        fprintf(stderr, " ERR : EVP_PKEY_encrypt: ");
        goto report_free_return_err;
    }

    do {
        // Read blocks of data from `infile' and encrypt them and write them out to `outfile', one block at a time.
        // Each block is at most (`key_size' - 42) bytes long. Do this in a loop until eof(infile) is encountered.

        // Quoting from man page of FREAD(3):
        // "If the end of the file is reached, the return value is a short item count (or zero)"
        // Hence, if 0 bytes were read, that's definitely an EOF, implying that we must stop
        if (!(flen = fread(buf, 1, key_size - 42, infile))) break;
        if (verbose) printf("INFO : %lu bytes read for encryption\n", flen);

        /* Now encrypt `flen` bytes which should produce `len` bytes */
        if ( EVP_PKEY_encrypt(ctx, encbuf, &len, buf, flen) <= 0 ) {
            fprintf(stderr, " ERR : ");
            ERR_print_errors_fp(stderr);
            OPENSSL_free(buf);
            OPENSSL_free(encbuf);
            EVP_PKEY_CTX_free(ctx);
            return -1;
        }
    /* Malloc `len` bytes for output buffer */
    if ( !(encbuf = OPENSSL_malloc(len)) ) {
        OPENSSL_free(encbuf);
        fprintf(stderr, " ERR : Failed to allocate memory for output buffer\n");
        goto free_and_return_err;
    }

        if (verbose) printf("INFO : %lu bytes encrypted\n", flen);
    /* Encrypt `flen` bytes in `buf` into `len` bytes in `encbuf` */
    if ( EVP_PKEY_encrypt(ctx, encbuf, &len, buf, flen) <= 0 ) {
        OPENSSL_free(encbuf);
        fprintf(stderr, " ERR : EVP_PKEY_encrypt: ");
        goto report_free_return_err;
    }

        // Write it to outfile
        len = fwrite(encbuf, 1, len, outfile);
        if (verbose) printf("INFO : %lu bytes written\n", len);
    if ( verbose ) printf("INFO : %lu bytes encrypted\n", flen);

    } while (!feof(infile));
    /* Finally write `len` bytes from `encbuf` to the output stream */
    len = fwrite(encbuf, (size_t) 1, len, outfile);
    if ( verbose ) printf("INFO : %lu bytes written\n", len);

    OPENSSL_free(buf);
    OPENSSL_free(encbuf);
    EVP_PKEY_CTX_free(ctx);

    return 0;
}

int rsa_decrypt(EVP_PKEY* private_key, FILE* infile, FILE* outfile, const int verbose) {
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    int key_size = EVP_PKEY_size(private_key);
#else
    int key_size = EVP_PKEY_get_size(private_key);
#endif
    size_t flen, len, declen;
    unsigned char *buf, *decbuf;
int rsa_decrypt(EVP_PKEY* private_key, FILE* infile, FILE* outfile, int verbose)
{
    size_t flen, len;
    unsigned char buf[BUF_SZ], *decbuf;
    EVP_PKEY_CTX* ctx;

    /* Get default RSA context from `private_key` */
    if ( !(ctx = EVP_PKEY_CTX_new(private_key, NULL)) ) {
        fprintf(stderr, " ERR : ");
        fprintf(stderr, " ERR : EVP_PKEY_CTX_new: ");
report_free_return_err:
        ERR_print_errors_fp(stderr);
free_and_return_err:
        EVP_PKEY_CTX_free(ctx);
        return -1;
    }

    /* Initialize the context for decryption */
    if ( EVP_PKEY_decrypt_init(ctx) <= 0 ) {
        fprintf(stderr, " ERR : ");
        ERR_print_errors_fp(stderr);
        EVP_PKEY_CTX_free(ctx);
        return -1;
        fprintf(stderr, " ERR : EVP_PKEY_decrypt_init: ");
        goto report_free_return_err;
    }

    /* Set padding type for context */
    if ( EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 ) {
        fprintf(stderr, " ERR : ");
        ERR_print_errors_fp(stderr);
        EVP_PKEY_CTX_free(ctx);
        return -1;
        fprintf(stderr, " ERR : EVP_PKEY_CTX_set_rsa_padding: ");
        goto report_free_return_err;
    }

    // Encrypted blocks come in `key_size' bytes each
    if ( !(buf = OPENSSL_malloc(key_size)) ) {
        fprintf(stderr, " ERR : Failed to allocate memory for input buffer\n");
        EVP_PKEY_CTX_free(ctx);
        return -1;
    if ( !(flen = fread(buf, 1, BUF_SZ, infile)) ) {
        fprintf(stderr, " ERR : fread: read 0 bytes from input stream\n");
        goto free_and_return_err;
    }

    /* Refer to this part of `rsa_encrypt()'.
     * Each block of `key_size' bytes will be decrypted to (`key_size' - 42) bytes.
     *
     * Despite the above comment, a little experimentation has revealed that
     * during determination of output buffer length (i.e. passing `out` = NULL
     * into `EVP_PKEY_decrypt()`, we get `len` = `key_size`. So here we assume
     * that'll be the case everytime. `declen` is set to keep track of the
     * number of bytes `malloc()`ed for `decbuf`. */
    declen = key_size;
    if ( !(decbuf = OPENSSL_malloc(declen)) ) {
        fprintf(stderr, " ERR : Failed to allocate memory for output buffer\n");
        OPENSSL_free(buf);
        EVP_PKEY_CTX_free(ctx);
        return -1;
    }
    if ( verbose ) printf("INFO : %lu bytes read for decryption\n", flen);

    do {
        // Read blocks of data, each `key_size' bytes long, from `infile' and decrypt them and write them out to
        // `outfile', one block at a time. Each decrypted block is at most (`keysize' - 42) bytes long.
        // Do this in a loop until eof(infile) is encountered.

        // Quoting from man page of FREAD(3):
        // "If the end of the file is reached, the return value is a short item count (or zero)"
        // Hence, if 0 bytes were read, that's definitely an EOF, implying that we must stop
        if (!(flen = fread(buf, (size_t) 1, key_size, infile))) break;
        if (verbose) printf("INFO : %lu bytes read for decryption\n", flen);

        /* Determine length of required output buffer */
        if ( EVP_PKEY_decrypt(ctx, NULL, &len, buf, flen) <= 0 ) {
            fprintf(stderr, " ERR : ");
            ERR_print_errors_fp(stderr);
            OPENSSL_free(buf);
            OPENSSL_free(decbuf);
            EVP_PKEY_CTX_free(ctx);
            return -1;
        }

        if ( len > declen ) {
            /* If we find that our previous assumption of the size of `decbuf`
             * was terribly wrong, we `realloc()` adequate amount of memory for
             * `decbuf`, as determined by the previous successful call to
             * `EVP_PKEY_decrypt()` */
            if ( !(decbuf = OPENSSL_realloc(decbuf, len)) ) {
                fprintf(stderr, " ERR : Failed to reallocate memory"
                                " for output buffer\n");
                OPENSSL_free(buf);
                EVP_PKEY_CTX_free(ctx);
                return -1;
            }
            declen = len;
        }
    /* Determine output (decrypted) buffer length */
    if ( EVP_PKEY_decrypt(ctx, NULL, &len, buf, flen) <= 0 ) {
        fprintf(stderr, " ERR : EVP_PKEY_decrypt: ");
        goto report_free_return_err;
    }

        /* Now decrypt `flen` bytes which should produce `len` bytes */
        if ( EVP_PKEY_decrypt(ctx, decbuf, &len, buf, flen) <= 0 ) {
            fprintf(stderr, " ERR : ");
            ERR_print_errors_fp(stderr);
            OPENSSL_free(buf);
            OPENSSL_free(decbuf);
            EVP_PKEY_CTX_free(ctx);
            return -1;
        }
    /* Malloc `len` bytes for output buffer */
    if ( !(decbuf = OPENSSL_malloc(len)) ) {
        OPENSSL_free(decbuf);
        fprintf(stderr, " ERR : Failed to allocate memory for output buffer\n");
        goto free_and_return_err;
    }

        if (verbose) printf("INFO : %lu bytes decrypted\n", flen);
    /* Now decrypt `flen` bytes which should produce `len` bytes */
    if ( EVP_PKEY_decrypt(ctx, decbuf, &len, buf, flen) <= 0 ) {
        OPENSSL_free(decbuf);
        fprintf(stderr, " ERR : EVP_PKEY_decrypt: ");
        goto report_free_return_err;
    }

        // Write it to outfile
        len = fwrite(decbuf, (size_t) 1, len, outfile);
        if (verbose) printf("INFO : %lu bytes written\n", len);
    if ( verbose ) printf("INFO : %lu bytes decrypted\n", flen);

    } while (!feof(infile));
    /* Write it to outfile */
    len = fwrite(decbuf, (size_t) 1, len, outfile);
    if ( verbose ) printf("INFO : %lu bytes written\n", len);

    OPENSSL_free(buf);
    OPENSSL_free(decbuf);
    EVP_PKEY_CTX_free(ctx);