C: Can not decrypt message Openssl - c

I'm new with cryptography, so I decided to create simple program that would open a file encrypt data, put it in etest.txt, then open this file decrypt it and put it indetest.txt. I know it sounds really weired but its for educational purposes. so here is my code.
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
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 = malloc(256); // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
// Generate key pair
RSA *keypair = RSA_generate_key(2048, 3, NULL, NULL);
FILE *in = fopen("test.txt", "rb");
FILE *out = fopen("etest.txt", "wb");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
encrypt = malloc(RSA_size(keypair));
for(;;)
{
//213 because of padding
memset(msg, '\0', 256);
memset(encrypt, '\0', 256);
fread(msg, 213, 1, in);
if((RSA_public_encrypt(strlen(msg), (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);
}
if(fwrite(encrypt, 256, 1, out) != 1)
{
printf("fwrite Error is %d (%s).\n", errno, strerror(errno));
}
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
in = fopen("etest.txt", "rb");
out = fopen("dtest.txt", "wb");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
decrypt = malloc(RSA_size(keypair));
for(;;)
{
//I use malloc because if i didnt it would from file and if it filled the msg and if this function would execute second time it would not overwrite the whole buffer and would cause problem
memset(decrypt, '\0', 256);
memset(msg, '\0', 256);
fread(msg, 256, 1, in);
if(RSA_private_decrypt(256, (unsigned char*)msg, (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);
}
fwrite(decrypt, 256, 1, out);
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
RSA_free(keypair);
return 0;
}
When I run code it gives me back error saying:Error decrypting message: error:0407A079:rsa routines:RSA_padding_check_PKCS1_OAEP:oaep decoding error but if i delete this codememset(msg, '\0', 256); it shows that everything works fine but it causes problems because msg buffer is overwritten with first few bytes that second fread() function overwrote.
Sorry if my questions sound silly. Hope you can help. thanks.

Your are using fwrite(decrypt, 256, 1, out); which is wrong.size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) Second parameter is the size in bytes of each element to be read And the third one is number of elements, each one with a size of size bytes.

Related

program crashes when encrypting system files

I wrote this code to encrypt and decrypt the contents of folder, both function works well when encrypting normal files but when im changing the folder to system folder, program crashes and when i check the latest file before crashing, im not able to open some of them (File is Open in Another Program), in some of them i just can't make changes.
i'm handling all errors i think, but it still keep crashing when it reachs to opened file by another program, how to solve this problem to ignore these types of files and keep continue instead of crashing?
and the structure is not important to post i think.
char ListFiles(const wchar_t* folder, CIPHER* conf)
{
wchar_t wildcard[MAX_PATH + 1];
swprintf(wildcard, sizeof(wildcard) / sizeof(*wildcard), L"%s\\*", folder);
WIN32_FIND_DATAW fd;
HANDLE handle = FindFirstFileW(wildcard, &fd);
if (handle == INVALID_HANDLE_VALUE) return 1;
do
{
if (wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0)
continue;
wchar_t path[MAX_PATH + 1];
swprintf(path, sizeof(path) / sizeof(*path), L"%s\\%s", folder, fd.cFileName);
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
ListFiles(path, &conf);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
{
wprintf(L"%s\n", path);
FILE* f_dec;
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 1; // encryption
if (AES_L(conf, f_input, f_enc) != 0)
continue;
f_enc = _wfopen(path, L"rb");
f_dec = _wfopen(wcscat(path, L".decrypted"), L"wb");
if (!f_dec || !f_enc) {
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 0; // decryption
if (AES_L(conf, f_enc, f_dec) != 0)
continue;
puts("\n\n");
}
} while (FindNextFileW(handle, &fd));
FindClose(handle);
return 0;
}
char AES_L(CIPHER* params, FILE* ifp, FILE* ofp)
{
unsigned int inlen, outlen;
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX* ctx;
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
if (!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, params->key, params->iv, params->encrypt)) {
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
while (1) {
// Read in data in blocks until EOF. Update the ciphering with each read.
inlen = fread(inbuf, sizeof(*inbuf), params->bufsize, ifp);
if (ferror(ifp)) {
fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (inlen < params->bufsize) /* Reached End of file */
break;
}
/* Now cipher the final block and write it out to file */
if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 0;
}
update:
void cleanup(FILE* ifp, FILE* ofp, unsigned char* inputBuf, unsigned char* outputBuf)
{
free(inputBuf);
free(outputBuf);
fclose(ifp);
fclose(ofp);
}
typedef struct {
unsigned int key_size;
unsigned int block_size;
unsigned int bufsize;
unsigned char* key;
unsigned char* iv;
unsigned int encrypt;
const EVP_CIPHER* cipher_type;
} CIPHER;
I see some problems with your code, although it's hard to know if they can lead to a crash without the rest of the code (for instance, we can't see the cleanup method), or how you create and initialize params.
The first problem is that you may be leaking file handles. When you open the files in ListFiles you open them in pairs, then check if any of them is NULL and if one is, you go on with the loop.
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
What if f_input is opened correctly but f_enc fails? The source file would remain open until the program ends. You should check each of them separately.
A similar problem arises when you allocate memory in AES_L:
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
return 1;
}
If one of the buffers (probably inbuf) is allocated correctly but outbuf fails, you would be leaking memory because you don't free the buffer that was allocated correctly (although, to be honest, I don't think this is directly the problem with the crash because this would happen in situations when you are already very low on memory).
Another problem may appear when you create the path for the encrypted and decrypted files. The path buffer is of size MAX_PATH+1, which is enough for the original file name, but then you perform a couple of wcscat operations that lead additional data to be added to the path. What if the original file name was already almost in the MAX_PATH limit? When you performed the wcscat you would be overflowing a buffer in the stack, which may also lead to a crash.
And finally, ListFiles is recursive, so if there are many nested calls you may be running out of stack, which would also lead to a crash (in fact, from the problems I mention I think it's the main suspect). I would make it iterative.
Anyway, it's very difficult to know if the crash is due to these problems, and your best option is running it in the debugger. The error message from the crash will tell you a lot of information to identify the reason.

openssl EVP_CipherFinal_ex failed

I got this below function file_encrypt_decrypt for encryption and decryption of a file using AES256 CBC from here.
If I'm doing encryption and decryption both from same program, (main function given at the end) encryption and decryption is working properly. Though both the time same function is called and ctx is initiated again.
If I'm commenting the encryption part, passing the above created encrypted_file, decryption is failing with error:
ERROR: EVP_CipherFinal_ex failed. OpenSSL error: error:06065064:lib(6):func(101):reason(100)
[[meaningful]] OpenSSL error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Somewhere people are talking about some padding length issue. But I can't figure it out properly.
Also how the same function is working properly if encryption is done at the same program but separately, it is failing?
Some guidance will be appreciated.
PS: Instead of a common function, I've tried separate functions for encryption and decryption with EVP_DecryptInit_ex(), EVP_DecryptUpdate(), EVP_DecryptFinal_ex() and similar for encryption but of no effect.
Full Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#define ERR_EVP_CIPHER_INIT -1
#define ERR_EVP_CIPHER_UPDATE -2
#define ERR_EVP_CIPHER_FINAL -3
#define ERR_EVP_CTX_NEW -4
#define AES_256_KEY_SIZE 32
#define AES_BLOCK_SIZE 16
#define BUFSIZE 1024
typedef struct _cipher_params_t{
unsigned char *key;
unsigned char *iv;
unsigned int encrypt;
const EVP_CIPHER *cipher_type;
}cipher_params_t;
void cleanup(cipher_params_t *params, FILE *ifp, FILE *ofp, int rc){
free(params);
fclose(ifp);
fclose(ofp);
exit(rc);
}
void file_encrypt_decrypt(cipher_params_t *params, FILE *ifp, FILE *ofp){
// Allow enough space in output buffer for additional block
int cipher_block_size = EVP_CIPHER_block_size(params->cipher_type);
unsigned char in_buf[BUFSIZE], out_buf[BUFSIZE + cipher_block_size];
int num_bytes_read, out_len;
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
if(ctx == NULL){
fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
cleanup(params, ifp, ofp, ERR_EVP_CTX_NEW);
}
// Don't set key or IV right away; we want to check lengths
if(!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, NULL, NULL, params->encrypt)){
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
cleanup(params, ifp, ofp, ERR_EVP_CIPHER_INIT);
}
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == AES_256_KEY_SIZE);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == AES_BLOCK_SIZE);
// Now we can set key and IV
if(!EVP_CipherInit_ex(ctx, NULL, NULL, params->key, params->iv, params->encrypt)){
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, ERR_EVP_CIPHER_INIT);
}
while(1){
// Read in data in blocks until EOF. Update the ciphering with each read.
num_bytes_read = fread(in_buf, sizeof(unsigned char), BUFSIZE, ifp);
if (ferror(ifp)){
fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, errno);
}
if(!EVP_CipherUpdate(ctx, out_buf, &out_len, in_buf, num_bytes_read)){
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, ERR_EVP_CIPHER_UPDATE);
}
fwrite(out_buf, sizeof(unsigned char), out_len, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, errno);
}
if (num_bytes_read < BUFSIZE) {
// Reached End of file
break;
}
}
// Now cipher the final block and write it out to file
if(!EVP_CipherFinal_ex(ctx, out_buf, &out_len)){
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, ERR_EVP_CIPHER_FINAL);
}
fwrite(out_buf, sizeof(unsigned char), out_len, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, errno);
}
EVP_CIPHER_CTX_cleanup(ctx);
}
int main(int argc, char *argv[]) {
FILE *f_input, *f_enc, *f_dec;
// Make sure user provides the input file
if (argc != 2) {
printf("Usage: %s /path/to/file\n", argv[0]);
return -1;
}
cipher_params_t *params = (cipher_params_t *)malloc(sizeof(cipher_params_t));
if (!params) {
// Unable to allocate memory on heap
fprintf(stderr, "ERROR: malloc error: %s\n", strerror(errno));
return errno;
}
// Key to use for encrpytion and decryption
unsigned char key[AES_256_KEY_SIZE];
// Initialization Vector
unsigned char iv[AES_BLOCK_SIZE];
// Generate cryptographically strong pseudo-random bytes for key and IV
if (!RAND_bytes(key, sizeof(key)) || !RAND_bytes(iv, sizeof(iv))) {
// OpenSSL reports a failure, act accordingly
fprintf(stderr, "ERROR: RAND_bytes error: %s\n", strerror(errno));
return errno;
}
params->key = key;
params->iv = iv;
// Indicate that we want to encrypt
params->encrypt = 1;
// Set the cipher type you want for encryption-decryption
params->cipher_type = EVP_aes_256_cbc();
// Open the input file for reading in binary ("rb" mode)
f_input = fopen(argv[1], "rb");
if (!f_input) {
// Unable to open file for reading
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
return errno;
}
// Open and truncate file to zero length or create ciphertext file for writing
f_enc = fopen("encrypted_file", "wb");
if (!f_enc) {
// Unable to open file for writing
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
return errno;
}
// Encrypt the given file
file_encrypt_decrypt(params, f_input, f_enc);
// Encryption done, close the file descriptors
fclose(f_input);
fclose(f_enc);
// Decrypt the file
// Indicate that we want to decrypt
params->encrypt = 0;
// Open the encrypted file for reading in binary ("rb" mode)
f_input = fopen("encrypted_file", "rb");
if (!f_input) {
// Unable to open file for reading
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
return errno;
}
// Open and truncate file to zero length or create decrypted file for writing
f_dec = fopen("decrypted_file", "wb");
if (!f_dec) {
// Unable to open file for writing
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
return errno;
}
// Decrypt the given file
file_encrypt_decrypt(params, f_input, f_dec);
// Close the open file descriptors
fclose(f_input);
fclose(f_dec);
// Free the memory allocated to our structure
free(params);
return 0;
}
The code generates a new key and a new IV with each run. So if only the encryption part is commented out, then two different key / IV pairs are generated and used for encryption and decryption, which leads to the observed error message. If for testing purposes a fixed key / IV pair is used instead of the each time freshly generated pair, the code works as expected.
In general, the key / IV pair used for encryption must also be used for decryption. Regarding the IV, in practice a random IV is usually generated during encryption. After its use, it's simply added in front of the ciphertext (since the IV isn't secret), so that it can be reconstructed and used during decryption.

Encryption using GPGME in C

I am currently working on a project that requires file encryption using GPGME. I have found this sandbox code and am trying to get it going to help understand the subject. I am getting held up on line 46 with the gpgme_get_key() function and it is not allowing the code to continue. I am having a hard time finding documentation on what might be going wrong. I think that the problem is coming from that a key is not properly being generated.
#include <gpgme.h>
#include <gpg-error.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>
//define INSERT_FAILURE
int bang(const gpgme_error_t err)
{
fprintf(stderr, "%s: %s\n", gpgme_strerror(err), gpgme_strsource(err));
return err;
}
int bang_(const char *e)
{
fprintf(stderr, "%s\n", e);
return 1;
}
int main(void)
{
gpgme_check_version(NULL);
gpgme_error_t err;
gpgme_data_t plain, cipher;
gpgme_ctx_t ctx;
gpgme_key_t recp[2] = {NULL, NULL};
gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST;
char *plaintext = "foo bar\0";
char *fp = "845B80B9AD12DB400CE534F6837EED10F97A36A1";
char *result_file = "./result.gpg";
char *verify_file = "./result";
size_t max_buflen = 2048, buflen;
char *buf = malloc(max_buflen * sizeof(char));
FILE *fh = NULL;
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_new(&ctx);
if (err)
return bang(err);
fprintf(stderr, "Got to line: %d\n", __LINE__);
gpgme_set_armor(ctx, 1);
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_get_key(ctx, fp, &recp[0], 0);
if (err)
return bang(err);
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_data_new_from_mem(&plain, plaintext, strlen(plaintext), 0); //look at
if (err)
return bang(err);
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_data_new(&cipher);
if (err)
return bang(err);
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_op_encrypt(ctx, recp, flags, plain, cipher);
if (err)
return bang(err);
gpgme_data_seek(cipher, 0, SEEK_SET);
buflen = gpgme_data_read(cipher, buf, max_buflen);
if (1 > buflen || buflen == max_buflen)
return bang_("Failed to read ciphertext");
fh = fopen(result_file, "w");
if (!fh)
bang_("failed to open result_file");
fwrite(buf, sizeof(char), buflen, fh);
fclose(fh);
fh = NULL;
memset(buf, 0, max_buflen);
snprintf(buf, max_buflen - 1, "gpg --output %s -d %s", verify_file, result_file);
system(buf);
memset(buf, 0, max_buflen);
fh = fopen(verify_file, "rb");
if (!fh)
return bang_("failed to open verify_file");
buflen = fread(buf, sizeof(char), max_buflen, fh);
fclose(fh);
if (buflen < 1 || buflen == max_buflen)
return bang_("Failed to read result file");
#ifdef INSERT_FAILURE
buf[buflen - 1] = '\0';
#endif
if (strncmp(buf, plaintext, strlen(plaintext)) != 0)
return bang_("Decrypted text is different from original plaintext");
return 0;
}

ssh_scp_read returns garbage

I'm trying to download a file from my server; both the client and the server are Linux, yet ssh_scp_read() returns an incorrect integer. According to the documentation the function writes up to 65536 bytes, yet is only reading 16384 when the file is 37980, but that's not my main concern; near the end of this 16384 bytes it starts to fill the buffer with NULL garbage, that will then be written to the file.
The creation of recursive directories works fine; the problem is downloading files larger than 16384 bytes. At this point I'll use sftp instead of scp, but I would like to know what I am doing wrong.
This is the function code:
int get(ssh_session gno_ses,ssh_scp scp)
{
int rc;
int size, permissions;
char *buff, *filename, path[PATH_MAX];
while(1)
{
rc = ssh_scp_pull_request(scp);
switch (rc)
{
// cases [...]
case SSH_SCP_REQUEST_NEWFILE:
size = ssh_scp_request_get_size(scp);
printf("Size is %d\n",size);
filename = strdup(ssh_scp_request_get_filename(scp));
permissions = ssh_scp_request_get_permissions(scp);
FILE *file;
file = fopen(filename, "w+");
if (!file)
{
ssh_scp_deny_request(scp,"Unable to open");
fprintf(stderr, " %s: %s\n", filename, strerror(errno));
fclose(file);
break;
}
buff = malloc(size);
printf("Size of buffer is %d\n", size);
if (!buff)
{
fprintf(stderr, "\nBuff memory allocation error.\n");
return SSH_ERROR;
}
if( ssh_scp_accept_request(scp) != SSH_OK)
{
fprintf(stderr, "Error accepting request: %s\n", ssh_get_error(gno_ses));
break;
}
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR)
{
fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(gno_ses));
break;
}
if (fwrite(buff, 1, size, file) != size)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
} while (rc != 0);
fclose(file);
free(filename);
free(buff);
break;
}
}
return SSH_OK;
}
And this is the output:
Size is 37980
Size of buffer is 37980
ssh_scp_read got 16384
ssh_scp_read got 16384
ssh_scp_read got 5212
Error receiving file data: ssh_scp_read called under invalid state
Any input would be appreciated.
The problem was that I was writing size bytes when indeed scp_scp_read() had reported that it had read less than that:
rc = ssh_scp_read(scp, buff, size);
fwrite(buff, 1, size, file)
The fix is to write only rc bytes:
int len_loop = size;
int len;
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR || rc < 0)
{
fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(gno_ses));
break;
}
else if (!rc)
{
break;
}
len = fwrite(buff, 1, rc, file);
if (len != rc)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
len_loop -= rc;
} while(len_loop);
change your inner loop as
int len = size;
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR)
{
fprintf(stderr, "Error receiving file data: %s\n",
ssh_get_error(gno_ses));
break;
}
if (fwrite(buff, 1, rc, file) != size)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
len-=rc;
} while (len);

C: OpenSSL RSA_private_decrypt() fails with "error:0407A079:rsa routines:RSA_padding_check_PKCS1_OAEP:oaep decoding error”

I'm new with cryptography, so I decided to create simple program that would open a file encrypt data, put it in etest.txt, then open this file decrypt it and put it indetest.txt.I know it sounds really weired but its for educational purposes. so here is my code. I've read many topics about this problem but none of them worked for me.
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
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 = malloc(256); // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
size_t red;
RSA *keypair = RSA_generate_key(2048, 3, NULL, NULL);
FILE *in = fopen("test.txt", "r");
FILE *out = fopen("etest.txt", "w");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
encrypt = malloc(RSA_size(keypair));
for(;;)
{
red = fread(msg, 1, RSA_size(keypair)-42, in);
if((RSA_public_encrypt(RSA_size(keypair)-42, (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);
}
if(fwrite(encrypt, 1, strlen(encrypt), out) == 1)
{
printf("fwrite Error is %d (%s).\n", errno, strerror(errno));
}
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
in = fopen("etest.txt", "r");
out = fopen("dtest.txt", "w");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
decrypt = malloc(RSA_size(keypair));
for(;;)
{
red = fread(msg, 1, 256, in);
if(RSA_private_decrypt(red, (unsigned char*)msg, (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);
}
fwrite(decrypt, 1, strlen(decrypt), out);
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
RSA_free(keypair);
return 0;
}
When I run code it gives me back error saying:Error decrypting message: error:0407A079:rsa routines:RSA_padding_check_PKCS1_OAEP:oaep decoding error Sorry if my question sound silly. Hope you can help. Thanks.
There are a few errors here. First when you're reading and encrypting:
red = fread(msg, 1, RSA_size(keypair)-42, in);
if((RSA_public_encrypt(RSA_size(keypair)-42, (unsigned char*)msg, (unsigned char*)encrypt,
keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
A call to fread won't necessarily read the number of bytes asked for, and could return 0. So when you reach the end of the file, you man be encrypting more bytes than you need. So pass in red for the number of bytes to encrypt. Also, first check if red is 0 and if so break out of the loop:
red = fread(msg, 1, RSA_size(keypair)-42, in);
if (red == 0) break;
if(((red=RSA_public_encrypt(RSA_size(keypair)-42, (unsigned char*)msg, (unsigned char*)encrypt,
keypair, RSA_PKCS1_OAEP_PADDING))) == -1) {
Note that we're saving the return value of RSA_public_encrypt. That comes into play here where you're writing the encrypted data to disk:
if(fwrite(encrypt, 1, strlen(encrypt), out) == 1)
encrypt is an array of characters, not a string. This means it's not NULL terminated, and it might contain NULL bytes. So you can't use strlen. Instead, capture the return value of RSA_public_encrypt and pass that as the size to write:
if(fwrite(encrypt, 1, red, out) == 1)
Because we're checking the return value of fread to break out of the loop, this isn't needed:
if(feof(in))
{
break;
}
See this post regarding the perils of using feof.
Then there's this when you're reading back the encrypted data:
red = fread(msg, 1, 256, in);
if(RSA_private_decrypt(red, (unsigned char*)msg, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
RSA_private_decrypt expects a single encrypted block whose length is RSA_size(keypair). So read in that many bytes from disk and pass in that many bytes to the function. Also, check the return value of fread and break out if you don't get the expected amount, and capture the return value of RSA_private_decrypt:
red = fread(msg, 1, RSA_size(keypair), in);
if (red < RSA_size(keypair)) break;
if((red=RSA_private_decrypt(red, (unsigned char*)msg, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
Later when you write the decrypted data to disk:
fwrite(decrypt, 1, strlen(decrypt), out);
While what was decrypted is probably a string (if your input file was plain text), the returned data is not NULL terminated, so explicitly write than many bytes instead of using strlen:
fwrite(decrypt, 1, red, out);
Finally, as with the encryption loop, this is not needed in the decryption loop:
if(feof(in))
{
break;
}
With these fixes applied, you should get the expected results.

Resources