I received an RSA-2048 bit public key (256 bytes) as a file which contains just those 256 bytes. Which function in SSL enables me to load this key as an RSA structure so I can convert it to another format? This is in C code using openssl source.
I think it's the DER format, but I'm not 100% certain.
I just put this together and it seems to work correctly:
https://github.com/JonathonReinhart/rawrsa
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
static const char* appname;
static void print_bn(const char *what, const BIGNUM *bn)
{
#ifdef DEBUG
char *str = BN_bn2hex(bn);
printf("%s (hex): %s\n", what, str);
OPENSSL_free(str);
#endif
}
static void usage(void)
{
fprintf(stderr, "Usage: %s modulus-file exponent\n", appname);
}
#define err(fmt, ...) \
fprintf(stderr, "%s: " fmt, appname, ##__VA_ARGS__)
int main(int argc, char *argv[])
{
appname = basename(argv[0]);
if (argc < 3) {
usage();
exit(1);
}
const char *modfile = argv[1];
const char *expstr = argv[2];
/* Read modulus */
FILE *mf = fopen(modfile, "rb");
if (!mf) {
err("Failed to open \"%s\": %m\n", modfile);
return 1;
}
unsigned char buf[256];
if (fread(buf, sizeof(buf), 1, mf) != 1) {
err("Failed to read %zu bytes of modulus\n", sizeof(buf));
return 1;
}
fclose(mf);
BIGNUM *mod = BN_bin2bn(buf, sizeof(buf), NULL);
if (!mod) {
err("BN_bin2bn() failed\n");
return 1;
}
print_bn("Modulus", mod);
/* Parse exponent */
BIGNUM *exp = NULL;
if (BN_dec2bn(&exp, expstr) == 0) {
err("BN_dec2bn() failed\n");
return 1;
}
print_bn("Exponent", exp);
/* Create RSA key */
RSA *rsa = RSA_new();
if (!rsa) {
err("RSA_new() failed\n");
return 1;
}
rsa->e = exp;
rsa->n = mod;
/* Write PEM-encoded RSA public key to stdout */
if (!PEM_write_RSAPublicKey(stdout, rsa)) {
err("PEM_write_RSAPublicKey() failed\n");
return 1;
}
return 0;
}
I use BN_bin2bn to create an OpenSSL bignum from raw binary data from a file. This is where we load your 256-byte modulus.
Then, I use BN_dec2bn to create a bignum from the exponent provided on the command line.
Next, I create an RSA object with RSA_new, and set the public exponent (rsa->e) and modulus (rsa->n).
Finally, I write the RSA public key to a PEM file with PEM_write_RSAPublicKey.
Example:
$ scons -Q
gcc -o main.o -c -Wall -Werror -g main.c
gcc -o rawrsa main.o -lcrypto
$ ./rawrsa key.bin 65537
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA9cFHSTQ6h1Ls/vx7B+V/84XVlLxUU1dU1mEr9ROAqWrZtfasvx2E
21lbva+AdJ/B4u6fGVhCEMgekXsRB65CqZfwL3DFL6tqam6GvrOyvZgAlQKrA54w
DaKMT8Kfg2I2K9W/HCkCOHczhuHhjFmeiV9BuQgpmcPcNz6UXBwU05d3g6oM/X4m
lEhEsaH4bqo1qsMX6jp6WnsR13GEfsYoYVmHgEbnKJyGpsoRVW6HQXLHvef9XLEJ
v9n7nLdHToya75svxJ3v9JugD3n6PiC48085/FWb9980o4hmG9iW5rehm4Dlui8c
TDnHkQSrvi9WLlZ+S8hdtwDRN/pVVTjgPAIDAQAB
-----END RSA PUBLIC KEY-----
Related
I want to use EVP and OpenSSL API to encrypt the binary data from a .exe file that I read into an unsigned char *. I'm not super familiar with this API and I'm afraid I'm doing something wrong that is causing the segmentation fault that I get when I compile. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/aes.h>
void handleErrors(void){
ERR_print_errors_fp(stderr);
abort();
}
int main(){
//read in the exe file and convert its bytes to a string
FILE *inFile;
inFile = fopen("Quasar.exe","rb");
if (inFile == NULL){
perror("Failed to read in file\n");
}
printf("File read in complete!\n");
if(fseek(inFile , 0 , SEEK_END) == -1){
perror("Offset error\n");
};
unsigned long lSize = ftell(inFile);
if (lSize == -1){
perror("Size error\n");
}
rewind(inFile);
unsigned char *unencryptedText = (unsigned char*) malloc (sizeof(unsigned char)*lSize);
fread(unencryptedText,1,lSize,inFile);
fclose(inFile);
unsigned char *encryptedText = (unsigned char*) malloc (3 *(sizeof(unsigned char)*lSize));
//encrypt these bytes with open ssl
printf("Encrypting...\n");
int outlen, tmplen;
unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
unsigned char iv[] = {1,2,3,4,5,6,7,8};
EVP_CIPHER_CTX *ctx = NULL;
EVP_CIPHER_CTX_init(ctx);
EVP_EncryptInit_ex(ctx, EVP_idea_cbc(), NULL, key, iv);
if(!EVP_EncryptUpdate(ctx, encryptedText, &outlen, unencryptedText, lSize)){
return 0;
}
if(!EVP_EncryptFinal_ex(ctx, encryptedText + outlen, &tmplen)){
return 0;
}
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(ctx);
return 0;
}
Here is the console output:
File read in complete!
Encrypting...
zsh: segmentation fault ./binary
Here is the Make script:
all: crypter.c
gcc -Wall -g -I/usr/local/include/openssl -L/usr/lib -lssl -lcrypto crypter.c -o binary
clean:
rm -f crypter
EVP_CIPHER_CTX *ctx = NULL;
EVP_CIPHER_CTX_init(ctx);
EVP_EncryptInit_ex(ctx, EVP_idea_cbc(), NULL, key, iv);
At no time do you assign ctx any value other than NULL. You pass a NULL to both of the functions above.
What you probably wanted was:
ECP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
Notice how this doesn't pass NULL to EVP_CIPHER_CTX_init?
You're passing a NULL object to EVP_CIPHER_CTX_init This function expects the address of an existing EVP_CIPHER_CTX object.
You can fix this by creating an instance of EVP_CIPHER_CTX and passing its address to each function that needs it, or if you want to minimize changes to your code you can assign the address of this object to the existing ctx pointer.
EVP_CIPHER_CTX ctx_obj;
EVP_CIPHER_CTX *ctx = &ctx_obj;
EDIT:
Based on the comments, it seems you're using OpenSSL 1.1 or later. In that case, you want to instead use EVP_CIPHER_CTX_new to instantiate a new context:
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
I want to create a simple program which would encrypt string using RSA algorithm and then decrypt it(cygwin, windows)
Here is my code
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
#define KEY_LENGTH 2048
#define PUB_EXP 3
#define PRINT_KEYS
#define WRITE_TO_FILE
int main(void) {
size_t pri_len; // Length of private key
size_t pub_len; // Length of public key
char *pri_key; // Private key
char *pub_key; // Public key
char msg[KEY_LENGTH/8]; // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
// Generate key pair
printf("Generating RSA (%d bits) keypair...", KEY_LENGTH);
fflush(stdout);
RSA *keypair = RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL);
// To get the C-string PEM form:
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
pri_key = (char *)malloc(pri_len + 1);
pub_key = (char *)malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
#ifdef PRINT_KEYS
printf("\n%s\n%s\n", pri_key, pub_key);
#endif
printf("done.\n");
// Get the message to encrypt
printf("Message to encrypt: ");
fgets(msg, KEY_LENGTH-1, stdin);
msg[strlen(msg)-1] = '\0';
// Encrypt the message
encrypt = (char *)malloc(RSA_size(keypair));
int encrypt_len;
err = (char *)malloc(130);
if((encrypt_len = RSA_public_encrypt(strlen(msg)+1, (unsigned char*)msg, (unsigned char*)encrypt,
keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
return -1;
}
#ifdef WRITE_TO_FILE
// Write the encrypted message to a file
FILE *out = fopen("out.bin", "w");
fwrite(encrypt, sizeof(*encrypt), RSA_size(keypair), out);
fclose(out);
printf("Encrypted message written to file.\n");
free(encrypt);
encrypt = NULL;
// Read it back
printf("Reading back encrypted message and attempting decryption...\n");
encrypt = (char *)malloc(RSA_size(keypair));
out = fopen("out.bin", "r");
fread(encrypt, sizeof(*encrypt), RSA_size(keypair), out);
fclose(out);
#endif
// Decrypt it
decrypt = (char *)malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len, (unsigned char*)encrypt, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error decrypting message: %s\n", err);
return -1;
}
printf("Decrypted message: %s\n", decrypt);
RSA_free(keypair);
BIO_free_all(pub);
BIO_free_all(pri);
free(pri_key);
free(pub_key);
free(encrypt);
free(decrypt);
free(err);
return 0;
}
The problem I have is during compiling with command
$ gcc -I /usr/include/ -L /usr/lib/ ip.cpp -o ip.exe -lcrypto.
Here are the errors I have:
In file included from /usr/include/errno.h:9:0,
from /usr/include/openssl/err.h:140,
from ip.cpp:9:
/usr/include/sys/errno.h:14:0: warning: "errno" redefined
#define errno (*__errno())
^
In file included from /usr/lib/gcc/x86_64-w64-mingw32/4.9.2/include/stddef.h:1:0,
from /usr/include/sys/cdefs.h:45,
from /usr/include/time.h:11,
from /usr/include/openssl/asn1.h:62,
from /usr/include/openssl/rsa.h:62,
from ip.cpp:7:
/usr/x86_64-w64-mingw32/sys-root/mingw/include/stddef.h:19:0: note: this is the location of the previous definition
#define errno (*_errno())
^
In file included from /usr/include/sys/select.h:26:0,
from /usr/include/sys/types.h:85,
from /usr/include/time.h:28,
from /usr/include/openssl/asn1.h:62,
from /usr/include/openssl/rsa.h:62,
from ip.cpp:7:
/usr/include/sys/_timeval.h:40:18: error: conflicting declaration ‘typedef long int time_t’
typedef _TIME_T_ time_t;
^
In file included from /usr/x86_64-w64-mingw32/sys-root/mingw/include/stddef.h:7:0,
from /usr/lib/gcc/x86_64-w64-mingw32/4.9.2/include/stddef.h:1,
from /usr/include/sys/cdefs.h:45,
from /usr/include/time.h:11,
from /usr/include/openssl/asn1.h:62,
from /usr/include/openssl/rsa.h:62,
from ip.cpp:7:
/usr/x86_64-w64-mingw32/sys-root/mingw/include/crtdefs.h:138:20: note: previous declaration as ‘typedef __time64_t time_t’
typedef __time64_t time_t;
As you can see the first error is that errno gots defined twice. I checked and in errno.h there is this code:
#ifndef _REENT_ONLY
#define errno (*__errno())
defining _REENT_ONLY fixes this error, but then in stdio.h there is this:
#ifndef _REENT_ONLY
FILE * _EXFUN(fopen, (const char *__restrict _name, const char *__restrict _type));
so then I have fopen undefined error. Plus I don't think that defining some values without really knowing what it is for is a bad idea.
Then I tried manually commenting out the lines where data gets defined second time to just build it successfully and test the program but then I got:
/tmp/ccC3voSz.o:ip.cpp:(.rdata$.refptr._impure_ptr[.refptr._impure_ptr]+0x0): undefined reference to `_impure_ptr'
So at the end I have two problems (maybe they are even related somehow):
How to get rid of the declaration conflicts?
How to fix undefined reference to _impure_ptr
I am trying to load a rsa object from a generated public key. I used PEM_write_bio_RSAPublicKey to generate the public key string. Then I used PEM_read_bio_RSA_PUBKEY to load the rsa object from the public key string. The problem is the rsa object is null. The generated string looks okay as far as I can tell. Any ideas?
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAxIReUspesPy6a4CPBjt/4Jt+H13q9MekMiutzNKdNO1uuwqcdqDX
pKPeTKXyUH6oCyRdUxkk6IVXGlBlxtW7OsxaYWhpfl9z3CCERCEpFmzN++dvlK2v
mckFL66e9q6Y+HwgyP1LJqrszeqlg2d29TCVKfD/UURVNmc/nPPjs9nO+IDhh7+P
NTQ2OqGBq8ghwVL5ZZyW3yVO5OAbRB6pjKBe9+j4B2TGnD5JO9Nu0jlFANZOKFJu
HDVE3XuTvOkuzL2i8Lwp4Myk42tbIgcCe4G58vKFddL651rWhg4hN3fRSx5YtDnQ
r5cgfNBOAww58S8lwXgU8lvzvEoNV+WMgwIDAQAB
-----END RSA PUBLIC KEY-----
gcc test_public_private_key.c -lcrypto -o test
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
char* get_public_key() {
RSA* rsa = RSA_new();
int kbits = 2048;
BIGNUM* bne = BN_new();
BN_set_word(bne, RSA_F4);
int status = RSA_generate_key_ex(rsa, kbits, bne, NULL);
if(status == 0) {
fprintf(stderr, "rsa key generation failed\n");
}
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPublicKey(bio, rsa);
int length = BIO_pending(bio);
char* pem_key = malloc(length+1);
memset(pem_key, '\0', length+1);
BIO_read(bio, pem_key, length);
return pem_key;
}
int main(int argc, char* argv[]) {
char* public_key = get_public_key();
printf("%s", public_key);
BIO* keybio = BIO_new_mem_buf(public_key, -1);
if (keybio == NULL) {
fprintf(stderr, "failed to create key BIO");
}
printf("keybio: %p\n", keybio);
RSA* rsa = PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL);
printf("rsa result %p\n", rsa);
BIO_free(keybio);
free(public_key);
return 0;
}
I thought it would be good to add that the reason this didn't work is because PEM_read_RSA_PUBKEY expects a SubjectPublicKeyInfo structure, which starts with BEGIN PUBLIC KEY, while PEM_read_RSAPublicKey expects a RSAPublicKey structure, which starts with BEGIN RSA PUBLIC KEY.
PEM_write_bio_RSAPublicKey generated the latter which corresponds to the second function, PEM_read_RSAPublicKey.
For industrial purposes, I want to decrypt an AES-encrypted message with an RSA-encrypted key in C. At first, I thought doing it step-by-step by first, using OpenSSL libcrypto library, by first RSA decoding the key then AES decoding the data.
I have found out that EVP tools were commonly seen as a better way to do this since it actually does what the low-levels functions do but correctly.
Here is what I see the flow of the program :
Initialize OpenSSL;
Read and store the RSA private key;
Initialize the decryption by specifying the decryption algorithm (AES) and the private key;
Update the decryption by giving the key, the data, the key and their length
Finally decrypt the data and return it.
I have been a lot confused by the fact that so far we do not intend to use any IV or ADD (although IV might come up later in the project). I have followed this guide it is not very clear and does not fit the way I use EVP.
So here is my actual code :
#include <openssl/evp.h>
#include <openssl/conf.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include "openssl\applink.c"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
const char PRIVATE_KEY_PATH[] = "C:/Users/Local_user/privateKey.pem";
EVP_PKEY* initializePrivateKey(void)
{
FILE* privateKeyfile;
if ((privateKeyfile = fopen(PRIVATE_KEY_PATH, "r")) == NULL) // Check PEM file opening
{
perror("Error while trying to access to private key.\n");
return NULL;
}
RSA *rsaPrivateKey = RSA_new();
EVP_PKEY *privateKey = EVP_PKEY_new();
if ((rsaPrivateKey = PEM_read_RSAPrivateKey(privateKeyfile, &rsaPrivateKey, NULL, NULL)) == NULL) // Check PEM file reading
{
fprintf(stderr, "Error loading RSA Private Key File.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
if (!EVP_PKEY_assign_RSA(privateKey, rsaPrivateKey))
{
fprintf(stderr, "Error when initializing EVP private key.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
return privateKey;
}
const uint8_t* decodeWrappingKey(uint8_t const* data, const size_t data_len, uint8_t const* wrappingKey, const size_t wrappingKey_len)
{
// Start Decryption
EVP_CIPHER_CTX *ctx;
if (!(ctx = EVP_CIPHER_CTX_new())) // Initialize context
{
fprintf(stderr, "Error when initializing context.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
EVP_PKEY *privateKey = initializePrivateKey();
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, privateKey, NULL)) // Initialize decryption
{
fprintf(stderr, "Error when initializing decryption.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
uint8_t* res;
if ((res = calloc(data_len, sizeof(uint8_t))) == NULL) // Check memory allocating
{
perror("Memory allocating error ");
return NULL;
}
puts("Initialization done. Decoding..\n");
size_t res_len = 0;
if (1 != EVP_DecryptUpdate(ctx, res, &res_len, data, data_len))
{
fprintf(stderr, "Error when preparing decryption.\n");
ERR_print_errors_fp(stderr);
}
if (1 != EVP_DecryptFinal_ex(ctx, res, &res_len))
{
fprintf(stderr, "Error when decrypting.\n");
ERR_print_errors_fp(stderr);
}
return res;
}
void hexToBytes(uint8_t *des, char const *source, const size_t size) {
for (int i = 0; i < size - 1; i += 2)
sscanf(source + i, "%02x", des + (i / 2));
}
int main(void) {
char const *strWrap = "5f82c48f85054ef6a3b2621819dd0e969030c79cc00deb89........";
char const *strData = "ca1518d44716e3a4588af741982f29ad0a3e7a8d67.....";
uint8_t *wrap = calloc(strlen(strWrap), sizeof(uint8_t));
hexToBytes(wrap, strWrap, strlen(strWrap)); // Converts string to raw data
uint8_t *data = calloc(strlen(strData), sizeof(uint8_t));
hexToBytes(data, strData, strlen(strData));
/* Load the human readable error strings for libcrypto */
ERR_load_crypto_strings();
/* Load all digest and cipher algorithms */
OpenSSL_add_all_algorithms();
/* Load config file, and other important initialisation */
OPENSSL_config(NULL);
const uint8_t *res = decodeWrappingKey(data, strlen(strData) / 2, wrap, strlen(strWrap) / 2);
if (res == NULL)
return 1;
return 0;
}
My output is the following one :
Initialization done. Decoding..
Error when preparing decryption.
Error when decrypting.
Obviously it fails when updating and finalising the decryption but I can't figure out why and the ERR_print_errors_fp(stderr); which had always worked for me so far seems to be mute.
Here is a complete working example of how you can encrypt a key using RSA, and encrypt a message using that key using AES, followed by the subsequent decryption of those things. It assumes AES-256-CBC is being used. If you want to use AES-256-GCM instead then you will need to make some changes to get and set the tag (ask me if you need some pointers on how to do this). It also assumes that the RSA encryption is done with PKCS#1 padding (which is all that the EVP_Seal* APIs support). If you need some other kind of padding then you will need to use a different method. Finally it assumes you are using OpenSSL 1.1.0. If you are using 1.0.2 then some changes will probably be necessary (at least you will need to explicitly init and de-init the library - that isn't required in 1.1.0).
The code reads the RSA private and public keys from files called privkey.pem and pubkey.pem which are in the current working directory. I generated these files like this:
openssl genrsa -out privkey.pem 2048
openssl rsa -in privkey.pem -pubout -out pubkey.pem
I've tested this on Linux only. The code is as follows:
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int envelope_seal(EVP_PKEY *pub_key, unsigned char *plaintext,
int plaintext_len, unsigned char **encrypted_key,
int *encrypted_key_len, unsigned char **iv,
int *iv_len, unsigned char **ciphertext,
int *ciphertext_len)
{
EVP_CIPHER_CTX *ctx;
int len, ret = 0;
const EVP_CIPHER *type = EVP_aes_256_cbc();
unsigned char *tmpiv = NULL, *tmpenc_key = NULL, *tmpctxt = NULL;
if((ctx = EVP_CIPHER_CTX_new()) == NULL)
return 0;
*iv_len = EVP_CIPHER_iv_length(type);
if ((tmpiv = malloc(*iv_len)) == NULL)
goto err;
if ((tmpenc_key = malloc(EVP_PKEY_size(pub_key))) == NULL)
goto err;
if ((tmpctxt = malloc(plaintext_len + EVP_CIPHER_block_size(type)))
== NULL)
goto err;
if(EVP_SealInit(ctx, type, &tmpenc_key, encrypted_key_len, tmpiv, &pub_key,
1) != 1)
goto err;
if(EVP_SealUpdate(ctx, tmpctxt, &len, plaintext, plaintext_len) != 1)
goto err;
*ciphertext_len = len;
if(EVP_SealFinal(ctx, tmpctxt + len, &len) != 1)
goto err;
*ciphertext_len += len;
*iv = tmpiv;
*encrypted_key = tmpenc_key;
*ciphertext = tmpctxt;
tmpiv = NULL;
tmpenc_key = NULL;
tmpctxt = NULL;
ret = 1;
err:
EVP_CIPHER_CTX_free(ctx);
free(tmpiv);
free(tmpenc_key);
free(tmpctxt);
return ret;
}
int envelope_open(EVP_PKEY *priv_key, unsigned char *ciphertext,
int ciphertext_len, unsigned char *encrypted_key,
int encrypted_key_len, unsigned char *iv,
unsigned char **plaintext, int *plaintext_len)
{
EVP_CIPHER_CTX *ctx;
int len, ret = 0;
unsigned char *tmpptxt = NULL;
if((ctx = EVP_CIPHER_CTX_new()) == NULL)
return 0;
if ((tmpptxt = malloc(ciphertext_len)) == NULL)
goto err;
if(EVP_OpenInit(ctx, EVP_aes_256_cbc(), encrypted_key, encrypted_key_len,
iv, priv_key) != 1)
return 0;
if(EVP_OpenUpdate(ctx, tmpptxt, &len, ciphertext, ciphertext_len) != 1)
return 0;
*plaintext_len = len;
if(EVP_OpenFinal(ctx, tmpptxt + len, &len) != 1)
return 0;
*plaintext_len += len;
*plaintext = tmpptxt;
tmpptxt = NULL;
ret = 1;
err:
EVP_CIPHER_CTX_free(ctx);
free(tmpptxt);
return ret;
}
int main(void)
{
EVP_PKEY *pubkey = NULL, *privkey = NULL;
FILE *pubkeyfile, *privkeyfile;
int ret = 1;
unsigned char *iv = NULL, *message = "Hello World!\n";
unsigned char *enc_key = NULL, *ciphertext = NULL, *plaintext = NULL;
int iv_len = 0, enc_key_len = 0, ciphertext_len = 0, plaintext_len = 0, i;
if ((pubkeyfile = fopen("pubkey.pem", "r")) == NULL) {
printf("Failed to open public key for reading\n");
goto err;
}
if ((pubkey = PEM_read_PUBKEY(pubkeyfile, &pubkey, NULL, NULL)) == NULL) {
fclose(pubkeyfile);
goto err;
}
fclose(pubkeyfile);
if ((privkeyfile = fopen("privkey.pem", "r")) == NULL) {
printf("Failed to open private key for reading\n");
goto err;
}
if ((privkey = PEM_read_PrivateKey(privkeyfile, &privkey, NULL, NULL))
== NULL) {
fclose(privkeyfile);
goto err;
}
fclose(privkeyfile);
if (!envelope_seal(pubkey, message, strlen(message), &enc_key, &enc_key_len,
&iv, &iv_len, &ciphertext, &ciphertext_len))
goto err;
printf("Ciphertext:\n");
for (i = 0; i < ciphertext_len; i++)
printf("%02x", ciphertext[i]);
printf("\n");
printf("Encrypted Key:\n");
for (i = 0; i < enc_key_len; i++)
printf("%02x", enc_key[i]);
printf("\n");
printf("IV:\n");
for (i = 0; i < iv_len; i++)
printf("%02x", iv[i]);
printf("\n");
if (!envelope_open(privkey, ciphertext, ciphertext_len, enc_key,
enc_key_len, iv, &plaintext, &plaintext_len))
goto err;
plaintext[plaintext_len] = '\0';
printf("Plaintext: %s\n", plaintext);
ret = 0;
err:
if (ret != 0) {
printf("Error\n");
ERR_print_errors_fp(stdout);
}
EVP_PKEY_free(pubkey);
EVP_PKEY_free(privkey);
free(iv);
free(enc_key);
free(ciphertext);
free(plaintext);
return ret;
}
Your key is encrypted with RSA, so you will decrypt it with RSA APIs like RSA_private_decrypt first, not with EVP* APIs.
Once you get key decrypted you need to use it with (EVP*) APIs to decrypt the data with AES.
I use openssl. First off I created private/public keys, then I encrypt a string and keep the result in a file. When I try to decrypt the file my program fails. What's more, the encrypted file is different each time(I use md5sum checked). What have I missed to deal with?
/*
gcc -lssl queation.c -o test_ssl
#openssl genrsa -out test_private.key 1024
#openssl rsa -in test_private.key -pubout -out test_public.key
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<openssl/rsa.h>
#include<openssl/pem.h>
#include<openssl/err.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/netdevice.h>
#include <linux/sockios.h>
#include <linux/if.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if_arp.h>
#include <netinet/if_ether.h>
#include <netinet/ether.h>
#include <fcntl.h>
#include <sys/socket.h>
#define OPENSSLKEY "test_private.key"
#define PUBLICKEY "test_public.key"
#define BUFFSIZE 1024
#define SIZE 1024
#define LIC_FILE "lic.rn"
#define PRTFL printf("fun = %s, line = %d\n", __FUNCTION__,__LINE__)
static char *ptr_en;
static char *p_en;
static RSA *p_rsa_public;
static FILE *fp_public;
static int flen_public, rsa_public_len;
static char *ptr_de;
static char *p_de;
static RSA *p_rsa_private;
static FILE *fp_private;
static int flen_private, rsa_private_len;
void usage( unsigned char * prog_name)
{
printf("usage: %s\n",
prog_name);
exit(1);
}
int main(int argc , char ** argv)
{
int i, ret , len;
unsigned char buf_plain[32];
unsigned char *buf_en;
unsigned char *raw_buffer;
FILE * pf_tmp;
if( argc != 1)
{
usage(argv[0]);
}
snprintf(buf_plain,sizeof(buf_plain),"this is a test line.\n");
if((fp_public=fopen(PUBLICKEY,"r"))==NULL)
{
perror("open public key file error");
ret = -1;
goto error;
}
if((p_rsa_public = PEM_read_RSA_PUBKEY(fp_public,NULL,NULL,NULL))==NULL)
{
ERR_print_errors_fp(stdout);
ret = -1;
goto error;
}
rsa_public_len=RSA_size(p_rsa_public);
p_en=(unsigned char *)malloc(rsa_public_len+1);
memset(p_en,0,rsa_public_len+1);
//printf("%s(%d)p_en = %p,rsa_public_len = %d\n", __FUNCTION__,__LINE__,p_en,rsa_public_len);
len = RSA_public_encrypt(rsa_public_len,buf_plain,p_en,p_rsa_public,RSA_NO_PADDING);
if (len !=rsa_public_len)
{
fprintf(stderr,"Error: len =%d, rsa_public_len = %d,ciphertext should match length of key\n", len,rsa_public_len);
ret = -1;
goto error;
}
pf_tmp = fopen(LIC_FILE,"w");
if( NULL == pf_tmp )
{
printf("open %s failed\n",LIC_FILE);
ret = -1;
goto error;
}
fwrite(p_en,1,128,pf_tmp);
fclose(pf_tmp);
if((fp_private=fopen(OPENSSLKEY,"r"))==NULL)
{
perror("open private key file error");
ret = -1;
goto error;
}
if((p_rsa_private=PEM_read_RSAPrivateKey(fp_private,NULL,NULL,NULL))==NULL)
{
ERR_print_errors_fp(stdout);
ret = -1;
goto error;
}
rsa_private_len = RSA_size(p_rsa_private);
pf_tmp = fopen(LIC_FILE,"r");
if( NULL == pf_tmp )
{
printf("open %s failed\n",LIC_FILE);
ret = -1;
goto error2;
}
raw_buffer = calloc(rsa_private_len,sizeof(char));
if( NULL == raw_buffer )
{
ret = -1;
goto error;
}
len = fread(raw_buffer, sizeof(char),sizeof(raw_buffer), pf_tmp);
if( len <=0 )
{
ret = -1;
goto error;
}
p_de=(unsigned char *)malloc(rsa_private_len+1);
memset(p_de,0,rsa_private_len+1);
//printf("%s(%d)p_en = %p,rsa_public_len = %d\n", __FUNCTION__,__LINE__,p_en,rsa_public_len);
len =RSA_private_decrypt (rsa_private_len,raw_buffer,p_de,p_rsa_private,RSA_NO_PADDING);
printf("%s(%d) p_de = %s\n",__FUNCTION__,__LINE__,p_de);
if ( len != rsa_private_len )
{
fprintf(stderr,"Error: ciphertext should match length of key\n");
exit(1);
}
error2:
fclose(pf_tmp);
error:
free(ptr_en);
free(ptr_de);
fclose(fp_public);
fclose(fp_private);
RSA_free(p_rsa_public);
RSA_free(p_rsa_private);
return ret;
}
It looks like you are not reading the whole file:
len = fread(raw_buffer, sizeof(char),sizeof(raw_buffer), pf_tmp);
Note that sizeof(raw_buffer) is the size of a pointer, but you wrote 128 bytes into the file (1024 bits). So you're only reading back 4 or 8 bytes and trying to decrypt that.
Try reading 128 bytes back.