Tested File Reads as expected but on Complete Code Not Working - c

I have tested the following code to read the tester.txt file and it outputted my expectation, however, when I inserted similar code in my complete code, it just stuck at: "Data from the file:" Why it is not outputting my expectation?
#include <stdio.h>
#include <stdlib.h>
char c[1000];
FILE *fptr;
int fileReader(){
if ((fptr = fopen("tester.txt", "r")) == NULL) {
printf("Error! File cannot be opened.");
// Program exits if the file pointer returns NULL.
exit(1);
}
// reads text until newline is encountered
fscanf(fptr, "%[^\n]", c);
fclose(fptr);
}
int main() {
fileReader();
printf("Data from the file:\n%s", c);
char* anotherone = (char*) c;
printf(anotherone);
return 0;
}
Another code to read file:
int fileReader() {
fp = fopen("tester.txt", "r");
fscanf(fp, "%s", c);
fclose(fp);
}
The complete code is:
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int success = 0;
void handleOpenSSLErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
unsigned char* decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv ){
EVP_CIPHER_CTX *ctx;
unsigned char *plaintexts;
int len;
int plaintext_len;
unsigned char* plaintext = malloc(ciphertext_len);
bzero(plaintext,ciphertext_len);
if(!(ctx = EVP_CIPHER_CTX_new())) handleOpenSSLErrors();
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleOpenSSLErrors();
EVP_CIPHER_CTX_set_key_length(ctx, EVP_MAX_KEY_LENGTH);
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleOpenSSLErrors();
plaintext_len = len;
// return 1 if decryption successful, otherwise 0
if(1 == EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
success = 1;
plaintext_len += len;
/* Add the null terminator */
plaintext[plaintext_len] = 0;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
//delete [] plaintext;
return plaintext;
}
size_t calcDecodeLength(char* b64input) {
size_t len = strlen(b64input), padding = 0;
if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
padding = 2;
else if (b64input[len-1] == '=') //last char is =
padding = 1;
return (len*3)/4 - padding;
}
void Base64Decode( char* b64message, unsigned char** buffer, size_t* length) {
BIO *bio, *b64; // A BIO is an I/O strean abstraction
int decodeLen = calcDecodeLength(b64message);
*buffer = (unsigned char*)malloc(decodeLen + 1);
(*buffer)[decodeLen] = '\0';
bio = BIO_new_mem_buf(b64message, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
//BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
*length = BIO_read(bio, *buffer, strlen(b64message));
BIO_free_all(bio);
}
void initAES(const unsigned char *pass, unsigned char* salt, unsigned char* key, unsigned char* iv )
{
//initialisatio of key and iv with 0
bzero(key,sizeof(key));
bzero(iv,sizeof(iv));
EVP_BytesToKey(EVP_aes_128_cbc(), EVP_sha1(), salt, pass, strlen(pass), 1, key, iv);
}
int checkPlaintext(char* plaintext, char* result){
int length = 10; // we just check the first then characters
return strncmp(plaintext, result, length);
}
char *cas[1000];
FILE *fptr;
int fileReader(){
if ((fptr = fopen("tester.txt", "r")) == NULL) {
printf("Error! File cannot be opened.");
// Program exits if the file pointer returns NULL.
exit(1);
}
// reads text until newline is encountered
fscanf(fptr, "%[^\n]", cas);
fclose(fptr);
}
int main (void)
{
fileReader();
printf("Data from the file:\n%s", cas);
char* ciphertext_base64 = (char*) cas;
char* plaintext = "to be or not to be is the question";
char dict[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int decryptedtext_len, ciphertext_len, dict_len;
// cipher (binary) pointer and length
size_t cipher_len; // size_t is sizeof(type)
unsigned char* ciphertext;
unsigned char salt[8];
ERR_load_crypto_strings();
Base64Decode(ciphertext_base64, &ciphertext, &cipher_len);
unsigned char key[16];
unsigned char iv[16];
unsigned char plainpassword[] = "00000";
unsigned char* password = &plainpassword[0];
// retrive the slater from ciphertext (binary)
if (strncmp((const char*)ciphertext,"Salted__",8) == 0) { // find the keyword "Salted__"
memcpy(salt,&ciphertext[8],8);
ciphertext += 16;
cipher_len -= 16;
}
dict_len = strlen(dict);
time_t begin = time(NULL);
for(int i=0; i<dict_len; i++)
for(int j=0; j<dict_len; j++)
for(int k=0; k<dict_len; k++)
for(int l=0; l<dict_len; l++)
for(int m=0; m<dict_len; m++){
*password = dict[i];
*(password+1) = dict[j];
*(password+2) = dict[k];
*(password+3) = dict[l];
*(password+4) = dict[m];
initAES(password, salt, key, iv);
unsigned char* result = decrypt(ciphertext, cipher_len, key, iv);
if (success == 1){
if(checkPlaintext(plaintext, result)==0){
printf("Password is %s\n", password);
time_t end = time(NULL);
printf("Time elpased is %ld seconds", (end - begin));
return 0;
}
}
free(result);
}
// Clean up
EVP_cleanup();
ERR_free_strings();
return 0;
}

char *cas[1000]; should be char cas[1000];, I would say this is the main issue, you are using an array of pointers as if it was a character array, this is very likely what's causing your program to fail.
Fix bzero, pass the size of the array as argument. When you use sizeof(key) in initAES(), what you are actually getting is the size of the pointer, not the size of the container it points to. More oh this in How to find the 'sizeof' (a pointer pointing to an array)?
You can add size of the array as a global constant with a macro:
#define SIZE 16 // size of the arrays
//...
void initAES(const unsigned char *pass, unsigned char* salt, unsigned char* key, unsigned char* iv )
{
//initialisatio of key and iv with 0
bzero(key, SIZE);
bzero(iv, SIZE);
EVP_BytesToKey(EVP_aes_128_cbc(), EVP_sha1(), salt, pass, strlen(pass), 1, key, iv);
}
You can use it to define the size in main making your code more consistent.
int main (void)
{
//...
unsigned char key[SIZE];
unsigned char iv[SIZE];
//...
}
For good measure make fileReader have void return type if you don't want it to return an int.
I always advise the use of compiler warnings at full blast and preferably to treat warnings as errors.

Related

Automatically Calling The Exit Function Without Performing the Next Task

In reference to my previous question I just have to change most part of the code and use function call. Now the file can read and print as expected, but I noticed that after when it goes to the expected fileReader and prints the file, it automatically exited by calling choiceReader(case: else ) function which is not the expected function to call. My expectation is that algorithm() will be the next call. Please what am I missing here again?
The new code is:
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int success = 0;
char counter[1000];//used to monitor the read file length
int c;
size_t cipher_len; // size_t is sizeof(type)
unsigned char* ciphertext;
unsigned char plainpassword[] = "00000";
unsigned char* password = &plainpassword[0];
unsigned char salt[8];
unsigned char key[16];
unsigned char iv[16];
FILE *fp;
FILE *fptr;
char* plaintext = "To be or not to be is the question.";
char dict[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int decryptedtext_len, ciphertext_len, dict_len;
char* ciphertext_base64;
unsigned char *plaintexts;
int len;
int plaintext_len;
void handleOpenSSLErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
unsigned char* decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv ){
EVP_CIPHER_CTX *ctx;
unsigned char* plaintext = malloc(ciphertext_len);
bzero(plaintext,ciphertext_len);
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleOpenSSLErrors();
/* Initialise the decryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleOpenSSLErrors();
EVP_CIPHER_CTX_set_key_length(ctx, EVP_MAX_KEY_LENGTH);
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleOpenSSLErrors();
plaintext_len = len;
/* Finalise the decryption. Further plaintext bytes may be written at
* this stage.
*/
// return 1 if decryption successful, otherwise 0
if(1 == EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
success = 1;
plaintext_len += len;
/* Add the null terminator */
plaintext[plaintext_len] = 0;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
//delete [] plaintext;
return plaintext;
}
size_t calcDecodeLength(char* b64input) {
size_t len = strlen(b64input), padding = 0;
if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
padding = 2;
else if (b64input[len-1] == '=') //last char is =
padding = 1;
return (len*3)/4 - padding;
}
void Base64Decode( char* b64message, unsigned char** buffer, size_t* length) {
BIO *bio, *b64; // A BIO is an I/O strean abstraction
int decodeLen = calcDecodeLength(b64message);
*buffer = (unsigned char*)malloc(decodeLen + 1);
(*buffer)[decodeLen] = '\0';
bio = BIO_new_mem_buf(b64message, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
//BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
*length = BIO_read(bio, *buffer, strlen(b64message));
BIO_free_all(bio);
}
void initAES(const unsigned char *pass, unsigned char* salt, unsigned char* key, unsigned char* iv )
{
//initialisatio of key and iv with 0
bzero(key,sizeof(key));
bzero(iv,sizeof(iv));
EVP_BytesToKey(EVP_aes_128_cbc(), EVP_sha1(), salt, pass, strlen(pass), 1, key, iv);
}
int checkPlaintext(char* plaintext, char* result){
int length = 10; // we just check the first then characters
return strncmp(plaintext, result, length);
}
//this tries to crack the password.
int algorithm(){
time_t begin = time(NULL);
for(int i=0; i<dict_len; i++)
for(int j=0; j<dict_len; j++)
for(int k=0; k<dict_len; k++)
for(int l=0; l<dict_len; l++)
for(int m=0; m<dict_len; m++){
*password = dict[i];
*(password+1) = dict[j];
*(password+2) = dict[k];
*(password+3) = dict[l];
*(password+4) = dict[m];
initAES(password, salt, key, iv);
unsigned char* result = decrypt(ciphertext, cipher_len, key, iv);
if (success == 1){
if(checkPlaintext(plaintext, result)==0){
printf("Password is %s\n", password);
time_t end = time(NULL);
printf("Time elpased is %ld seconds", (end - begin));
return 0;
}
}
free(result);
}
}
// this given cipher text
int firstReader(){
if ((fp = fopen("givenfile.txt", "r")) == NULL) {
printf("Error! File cannot be opened.");
exit(1);
}
fscanf(fp, "%[^\n]", counter);
printf("Cipher text is:\n%s", counter);
printf("\nCracking cipher text one in progress ....\n");
algorithm();//calls the algorithm function
}
int secondReader(){
if ((fptr = fopen("cipher1.txt", "r")) == NULL) {
printf("Error! File cannot be opened.");
// Program exits if the file pointer returns NULL.
exit(1);
}
fscanf(fptr, "%[^\n]", counter);
printf("Cipher text is:\n%s", counter);
printf("\nCracking cipher text tow in progress ....\n");
algorithm(); // calls the algorithm function
}
// reads user's choice and performs the next operation accordingly
void choiceReader(){
printf("User's application guide.\nIst cipher decryption = 1\nSecond cipher decryption = 2\nQuit = Any other input\n");
scanf("%d", &c);
if(c==1){
firstReader();
}
if(c==2){
secondReader();
}
else{
printf("Application Exited ...");
exit(1);
}
}
int main (void)
{
//the core function that controls the user's action.
choiceReader();
dict_len = strlen(dict);
if (c==1){
ciphertext_base64 = (char*) fp;
}
if (c==2){
ciphertext_base64 = (char*) fptr;
}
printf(ciphertext_base64);
ERR_load_crypto_strings();
Base64Decode(ciphertext_base64, &ciphertext, &cipher_len);
// retrive the slater from ciphertext (binary)
if (strncmp((const char*)ciphertext,"Salted__",8) == 0) { // find the keyword "Salted__"
memcpy(salt,&ciphertext[8],8);
ciphertext += 16;
cipher_len -= 16;
}
// Clean up
fclose(fptr);
EVP_cleanup();
ERR_free_strings();
return 0;
}
The output is screenshot below:
You wrote:
if(c==1){
firstReader();
}
if(c==2){
secondReader();
}
else{
printf("Application Exited ...");
exit(1);
}
which means:
If c is 1, call firstReader.
If c is 2, call secondReader, otherwise exit.
If c is 1, then it calls firstReader, and then exits because c is not 2. The computer is not smart enough to figure out what you actually meant. You probably meant to write else if(c==2) which links the two ifs together so that the final else only runs if neither one is true.
Everything is perfectly working as expected now, the sequential error was simply due to the wrong logical call to the ciphertext_base64
Thanks everyone for your time and guide.

Segmentation fault within do_crypt()

This is my code but when I run it, it gives me a segmentation fault in the function do_crypt(). When I try to print all the keys in the function it will only print out a few and I don't know why because if I print all the keys before calling do_crypt it will print them without any issues.
Any advice in fixing this would be lovely!!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <openssl/evp.h>
#define MAX_LINE_NUM 25143
#define MAX_LINE_LEN 80
#define MAX_WORDS 25143
#define MAX_WORD_LEN 30
char words[MAX_WORDS][MAX_WORD_LEN];
unsigned char output[] = "";
void read_KeyFile(int *line_counter, char *KeyFilename, char arr[MAX_LINE_NUM][MAX_LINE_LEN]){
FILE *fptr;
char read_line[MAX_LINE_LEN];
char buffer[MAX_LINE_NUM];
const char delim[] = " \n";
int buff_line_num = 0;
int word_counter = 0;
char *token;
fptr = fopen(KeyFilename, "r");
while(fgets(read_line, MAX_LINE_LEN, fptr) != NULL){
strncpy(arr[*line_counter], read_line, MAX_LINE_LEN);
*line_counter = *line_counter + 1;
}
fclose(fptr);
for (int i = 0; i<*line_counter; i++){
strncpy(buffer, arr[buff_line_num], MAX_LINE_LEN);
token = strtok(buffer, delim);
while(token != NULL){
strncpy(words[word_counter], token, MAX_WORD_LEN);
word_counter = word_counter + 1;
token = strtok(NULL, delim);
}
buff_line_num++;
}
}
int do_crypt(char plaintext[], char ciphertext[], unsigned char tempKey[], unsigned char output[], int do_encrypt){
unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
EVP_CIPHER_CTX ctx;
unsigned char iv[] = "aabbccddeeff00998877665544332211";
unsigned char key[] = "";
strcpy(key, tempKey);
int len = strlen(key);
if (len < 16){
for (int i=0; i<(16-len)+1; i++){
strcat(key, "#");
}
}
FILE *in;
in = fopen("Input.txt", "r");
FILE *out;
out = fopen("output.txt", "w");
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, NULL, NULL, do_encrypt);
OPENSSL_assert(EVP_CIPHER_CTX_key_length(&ctx) == 16);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(&ctx) == 16);
EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, do_encrypt);
for(;;) {
inlen = fread(inbuf, 1, 1024, in);
if(inlen <= 0) break;
if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen)){
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
strcpy(output, outbuf);
}
if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen)){
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
strcpy(output, outbuf);
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}
void toHexConverter(unsigned char output[], int i, unsigned char tempKey[17]){
char hex[100];
for (int j=0, k=0; j<strlen(output); ++j, k +=2){
sprintf(hex + k, "%02x", output[j] & 0xff);
}
strcpy(output, hex);
}
int main(int argc, char *argv[]){
char plaintext[] = "This is a top secret.";
unsigned char ciphertext[] = "764aa26b55a4da654df6b19e4bce00f4ed05e09346fb0e762583cb7da2ac93a2";
char hexCompare[] = "";
int line_counter = 0;
char *KeyFilename = NULL;
char lines[MAX_LINE_NUM][MAX_LINE_LEN];
unsigned char tempKey[] = "";
int do_encrypt = 1;
KeyFilename = argv[1];
read_KeyFile(&line_counter, KeyFilename, lines);
for (int i=0; i<MAX_WORDS; i++){
// printf("%s\n", words[i]);
strcpy(tempKey, words[i]);
do_crypt(plaintext, ciphertext, tempKey, output, do_encrypt);
}
}

Can't encrypt long string with XOR C crypter

I wrote a C program to perform an XOR encryption,
my problem is that the program is not able to encrypt files with more than 24 characters.
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define BUF_SIZE 2
char* xor(char*, char*);
char* gen_key(size_t);
int main(int argc, char **argv) {
char *buffer = NULL,* encrypted_buffer = NULL;
size_t file_size;
char *key = gen_key(6);
char tmp_buffer[BUF_SIZE];
FILE *finput = NULL, *foutput = NULL;
finput = fopen("file.txt", "rb");
fseek(finput, 0, SEEK_END);
file_size = ftell(finput);
rewind(finput);
printf("File size : %d\n", (int)file_size);
buffer = (char*)malloc((file_size + 1) * sizeof(char));
memset(buffer, 0, sizeof(buffer));
while (!feof(finput)) {
memset(tmp_buffer, 0, sizeof(tmp_buffer));
fgets(tmp_buffer, sizeof(tmp_buffer), finput);
strcat(buffer, tmp_buffer);
}
printf("%s", buffer);
encrypted_buffer = xor(buffer, key);
free(buffer);
buffer = xor(encrypted_buffer, key);
printf("Encrypted : %s\n", encrypted_buffer);
printf("Decrypted : %s\n", buffer);
printf("EOF\n");
free(encrypted_buffer);
fclose(finput);
return 0;
}
char *gen_key(size_t length) {
srand(time(NULL));
const char charset[] = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz012345679";
const size_t charset_size = (sizeof(charset) - 1);
unsigned int i;
char *key = NULL;
key = (char*)malloc((length + 1) * sizeof(char));
memset(key, 0, sizeof(key));
for (i = 0; i < length; i++)
key[i] = charset[rand() % charset_size];
return key;
}
char *xor(char *file, char *key) {
unsigned int i;
char *xor = NULL;
xor = (char*)malloc(sizeof(file));
memset(xor, 0, sizeof(xor));
for (i = 0; i < strlen(file); i++)
*(xor + i) = *(file + i) ^ *(key + (i % strlen(key) - 1));
return xor;
}
And the output is :
File size : 55
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklimnopqrstuvwxyz
Encrypted : A2#G8- M >7S$1!
Decrypted : ABCDEFGHIJKLMNOPQRSTUVWX!:!e!
EOF
There are multiple problems in your code:
The buffer size is very small: #define BUF_SIZE 2. You should use a reasonable size for the line buffer, such as 80 or 100.
in memset(buffer, 0, sizeof(buffer));, buffer is a pointer, so sizeof(buffer) is not the size of the array, just the size of the pointer. Use file_size + 1 in this case.
You make the same mistake in other places in your code: pass the size of the buffers instead of relying on the sizeof() operator.
while (!feof(f)) is always wrong: you could jut use fread to read the file in one step or read line by line with:
while (fgets(tmp_buffer, sizeof(tmp_buffer), finput)) {
...
Note that there is a major problem with your approach: the key is composed of letters and digits and the file is assumed to contain text. If the file contains one of the characters in the key at the appropriate position, xoring this character with the key byte will produce a null byte that will stop the output in printf() and that would also stop the decryption if you were to store it in an output file. You rightfully use binary mode ("rb") for the file stream, but you should also make no assumptions on the file contents and handle null bytes transparently.
Here is a modified version of your program:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
unsigned char *xor(unsigned char *file, size_t size, const char *key);
char *gen_key(size_t length);
void print_buffer(const char *msg, unsigned char *buf, size_t size) {
printf("%s: ", msg);
for (size_t i = 0; i < size; i++) {
switch (buf[i]) {
case '\n':
printf("\\n");
break;
case '\\':
printf("\\\\");
break;
default:
if (buf[i] >= ' ' && buf[i] < 127)
putchar(buf[i]);
else
printf("\\%02x", buf[i]);
break;
}
}
printf("\n");
}
int main(int argc, char **argv) {
long file_size, nread, nwritten;
unsigned char *buffer, *encrypted_buffer, *decrypted_buffer;
char *key = gen_key(6);
FILE *finput = fopen("file.txt", "rb");
if (finput == NULL) {
fprintf(stderr, "cannot open file.txt: %s\n", strerror(errno));
return 1;
}
fseek(finput, 0, SEEK_END);
file_size = ftell(finput);
rewind(finput);
printf("File size: %ld\n", file_size);
buffer = calloc(file_size, sizeof(char));
nread = fread(buffer, 1, file_size, finput);
if (nread != file_size) {
fprintf(stderr, "error reading file.txt: read %ld bytes, expected %ld\n",
nread, file_size);
}
fclose(finput);
FILE *foutput = fopen("output.bin", "wb");
if (foutput == NULL) {
fprintf(stderr, "cannot open output.bin: %s\n", strerror(errno));
return 1;
}
encrypted_buffer = xor(buffer, nread, key);
nwritten = fwrite(encrypted_buffer, 1, nread, foutput);
if (nwritten != nread) {
fprintf(stderr, "error writing output.bin: wrote %ld bytes, expected %ld\n",
nwritten, nread);
}
fclose(foutput);
decrypted_buffer = xor(encrypted_buffer, nread, key);
printf("Key : %s\n", key);
print_buffer("Original ", buffer, nread);
print_buffer("Encrypted", encrypted_buffer, nread);
print_buffer("Decrypted", decrypted_buffer, nread);
if (!memcmp(decrypted_buffer, buffer, nread))
printf("OK\n");
free(decrypted_buffer);
free(encrypted_buffer);
free(buffer);
return 0;
}
char *gen_key(size_t length) {
const char charset[] = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz012345679";
const size_t charset_size = sizeof(charset) - 1;
char *key = (char*)calloc(length + 1, sizeof(char));
size_t i;
srand(time(NULL));
for (i = 0; i < length; i++)
key[i] = charset[rand() % charset_size];
return key;
}
unsigned char *xor(unsigned char *file, size_t size, const char *key) {
size_t i, keylen = strlen(key);
unsigned char *xor = calloc(size, sizeof(char));
for (i = 0; i < size; i++)
xor[i] = file[i] ^ key[i % keylen];
return xor;
}

Error when trying to RSA-decrypt a parameter string with libcrypto

I am a beginner with the libcrypto library. I am trying to give an encrypted string to a function, decrypt it and return it decrypted. The string is encoded with my public key which which is 4096-bit sized.
char* decodeStr(const char* str, const size_t sizeStr)
{
puts("Starting");
FILE* file = fopen(PRIVATE_KEY_PATH, "r");
if (file == NULL)
{
perror("Error while trying to access to Presto's private key.\n");
return NULL;
}
RSA *privateKey = RSA_new();
privateKey = PEM_read_RSAPrivateKey(file, &privateKey, NULL, NULL);
if (privateKey == NULL)
{
fprintf(stderr, "Error loading RSA private key.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
char* res = malloc(sizeStr);
if (res == NULL)
{
perror("Memory allocating error ");
return NULL;
}
const int sizeDecoded = RSA_private_decrypt(sizeStr, str, res, privateKey, RSA_PKCS1_PADDING);
if (sizeDecoded == -1)
{
fprintf(stderr, "Error while decoding RSA-encoded wrapping key.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
if ((res = realloc(res, (size_t)sizeDecoded)) == NULL)
{
perror("Memory allocating error ");
return NULL;
}
return res;
}
The following code outputs :
Starting
Error while decoding RSA-encoded wrapping key.
6928:error;04069506C:lib<4>:func<101>:reason<108>:.\crypto\rsa\rsa_eay.c:518:
Since the error is unknown and I haven't been able to find any information about it on the net, and moreover I am a beginner with libcrypto, does strneed to be in a certain format ?
Obivously it is this which breaks the program but I can't be sure of it, neither do I know how to fix this.
const int sizeDecoded = RSA_private_decrypt(sizeStr, str, res, privateKey, RSA_PKCS1_PADDING);
EDIT : I have been working with a client which provides me those encoded dat for me to decrypt them. I don't know how they are processed exactly. Unfortunately, the encoded strings are even more sensitive than the private key itself, so I can't share it. It looks like 0c79cc00deb89a614db6ebe42be748219089fb5356 but with 1024 characters.
The problem
Your encoded strings
0c79cc00deb89a614db6ebe42be748219089fb5356 but with thousands of characters.
look like hexadecimal representation of the encoded message. I think you really need to convert the message to a raw data, converting hex to bytes.
Your strings are composed by 1024 (hex) chars => 512 bytes (you need two hex digits to represent one byte) => 4096 bits, which is equal to the key length.
Try this simple function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
void hex_2_bytes(uint8_t *des, char *source, size_t size);
int main()
{
char *str = "0c79cc00deb89a614db6ebe42be748219089fb5356";
uint8_t *dest = (uint8_t *) malloc(sizeof(uint8_t) * strlen(str) / 2);
hex_2_bytes(dest, str, strlen(str));
for(int i = 0; i < strlen(str) / 2; i++) {
printf(" %02X ", dest[i]);
}
return 0;
}
void hex_2_bytes(uint8_t *des, char *source, size_t size) {
for(int i = 0; i < size - 1; i+=2) {
sscanf(source+i, "%02x", des + (i/2));
}
}
What is raw data? Your encrypted message is a string, which is an array of characters. I see only digits (from 0 to 9) and the letters from a to f, which make me guess that your original message (which is, originally a binary string, raw data) has been represented as a very long number using hexadecimal digits. You need to convert it back.
If you have a message composed by n bytes, stored as a binary string (raw data), you will have an hexadecimal representation, stored as a text, which is 2*n bytes long.
Example:
uint8_t raw_data_message[] = {0x3c, 0x2f}; // 2 bytes
char hex_representation_as_string_message[] = {'3', 'c', '2', 'f'}; // 4 bytes
Your messages a like hex_representation_as_string_message, but you need them as raw_data_message.
The solution
Here's a fully working example:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#define PRIVATE_KEY_PATH ".ssh/id_rsa"
/*
* Generation of the encrypted message:
* echo "Hello, this is a super secret message" | openssl rsautl -encrypt -pubin -inkey ~/.ssh/id_rsa.pub.pem >message.encrypted
*
* Resulting encrypted message in hex representation:
* 917ab2ebd663bba1dcd0f22aef98b93b039f001e19c997f015d90eaaf35731eb1895c13dfb08250aa28a9dac4f3e1b5fefc53926d3f6422f8055124bb15c24e2b73645dc61f29486deaf278705987738e916a6288531aa923dff15b667dabf4465506e1ee68e6f27a06e3fb4f5040a7775ce69ba10ec337f5bc5ef45969a8fe7c672c9b51243296677385f1b613f4f3edceef620f6ab5dcadec5034c330331bf8e8c3b42554f01c6cf1c0dbc58f23c8f0068e750fc4bb97636b2b3455e7f3932ab9559ff4de5bfc6769bbafefec722441458066ab4a6fdfe99c78bfdd5c1851d411a451925c5ad7ecb0c93618304ae6bc5402193f58af6e6a65208075be35a00
* (converted with: hexdump -ve '1/1 "%.2x"' message.encrypted)
*/
void hex_2_bytes (uint8_t *des, char *source, size_t size);
int decode (uint8_t *dest, const uint8_t *src, const size_t size);
int main (int argc, char **argv) {
// Reading the encrypted message in hex representation
FILE *file = fopen(argv[1], "r");
printf("%s\n", argv[1]);
if (file == NULL) {
perror("Error while trying to access to the encrypted message"
".\n");
return -1;
}
fseek(file, 0, SEEK_END);
long fsize = ftell(file);
fseek(file, 0, SEEK_SET);
char *hex_repr = malloc(fsize);
fread(hex_repr, fsize, 1, file);
fclose(file);
printf("Hexadecimal representation of the encrypted message\n");
for (int i = 0; i < fsize; ++i) {
printf("%c", hex_repr[i]);
}
printf("\nSize: %d\n", fsize);
// Converting to raw data
size_t raw_data_size = fsize / 2;
uint8_t *raw_data = (uint8_t *) malloc(
raw_data_size * sizeof(uint8_t));
hex_2_bytes(raw_data, hex_repr, (size_t) fsize);
printf("Raw encrypted message\n");
for (int i = 0; i < raw_data_size; ++i) {
printf("%02X", raw_data[i]);
}
printf("\nSize: %d\n", raw_data_size);
// Decryption
char *res = malloc(raw_data_size * sizeof(char));
if (res == NULL) {
perror("Memory allocating error ");
return -1;
}
int msg_size = decode(res, raw_data, raw_data_size);
printf("Decrypted message:\n");
for (int j = 0; j < msg_size; ++j) {
printf("%c", res[j]);
}
printf("\nSize: %d\n", msg_size);
return 0;
}
void hex_2_bytes (uint8_t *des, char *source, size_t size) {
for (int i = 0; i < size - 1; i += 2) {
sscanf(source + i, "%02x", des + (i / 2));
}
}
int decode (uint8_t *res, const uint8_t *src, const size_t size) {
puts("Starting");
FILE *file = fopen(PRIVATE_KEY_PATH, "r");
if (file == NULL) {
perror("Error while trying to access to Presto's private key.\n");
return -1;
}
RSA *privateKey = RSA_new();
privateKey = PEM_read_RSAPrivateKey(file, &privateKey, NULL, NULL);
if (privateKey == NULL) {
fprintf(stderr, "Error loading RSA private key.\n");
ERR_print_errors_fp(stderr);
return -1;
}
const int sizeDecoded = RSA_private_decrypt(size, src, res,
privateKey,
RSA_PKCS1_PADDING);
if (sizeDecoded == -1) {
fprintf(stderr,
"Error while decoding RSA-encoded wrapping key.\n");
ERR_print_errors_fp(stderr);
return -1;
}
return sizeDecoded;
}
And the results (as a proof of work):
Note that I'm using 2048 bit rsa keys.
I solved part of the issue. I added :
/* Load the human readable error strings for libcrypto */
ERR_load_crypto_strings();
At the beginning of the function. The output turned into :
Starting
Error while decoding RSA-encoded wrapping key.
1124:errir:0406506C:rsa routines: RSA_EAY_PRIVATE_DECRYPT:data greater than mod len:.\crypto\rsa\rsa_eay.c:518:
Which I guess means that the length of the key is too small for the provided data. Still left to know if the data is wrong, the key is wrong and how to fix it.
Also, to avoid making such mistakes later, I added :
const size_t sizeRSA = RSA_size(prestoPrivateKey);
if (sizeRSA < sizeWrappingKey)
{
fprintf(stderr, "Size of key : %d\n Size of data : %d\n The size of the key should higher than data length.\n", sizeRSA, sizeWrappingKey);
return NULL;
}

Memory allocation for AES_cbc_encrypt

I'm trying to encrypt and decrypt keystore using AES_cbc_encrypt function from openssl library.
I have a problem with memory allocation, it will be nice if someone can give me some advices how to do this in proper way.
For now I can't figure out how to do this so I'm getting Segmentation fault while AES_cbc_encrypt is called.
Another question is how to allocate memory for char tables in C (clean way). I want to do this dynamically. Places in code for this question are marked with QUESTION string.
unsigned char *input;
input = malloc(sizeof(unsigned char)*length);
unsigned char input_question[length];
Output:
[enc_dec_keystore] length: 82
[enc_dec_keystore] QUESTION #1: why sizeof(input) != sizeof(input_question)
[enc_dec_keystore] input size: 8
[enc_dec_keystore] input_question size: 82
Why sizeof(input) is different. Because I'm getting sizeof pointer in this way? I expected to get 82 too because sizeof(unsigned char) should be 1, multiplied by 82 should be 82, right?
Here is a code from my program:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#define DEBUG 1
#define KEYLEN 128
void print_data(const char *tittle, const void* data, int len)
{
printf("%s : ",tittle);
const unsigned char * p = (const unsigned char*)data;
int i = 0;
for (; i<len; ++i)
printf("%02X ", *p++);
printf("\n");
}
void PBKDF2_HMAC_SHA_512(const char *pass, const unsigned char *salt, int32_t iterations, uint32_t outputBytes, unsigned char *result) {
if (DEBUG) {
puts("[PBKDF2_HMAC_SHA_512] in");
}
unsigned char digest[outputBytes];
PKCS5_PBKDF2_HMAC(pass, strlen(pass), salt, strlen(salt), iterations, EVP_sha512(), outputBytes, digest);
for (int i = 0; i < sizeof(digest); i++)
{
result[i] = digest[i];
};
if (DEBUG) {
puts("[PBKDF2_HMAC_SHA_512] out");
}
}
int deriver_key(const char *pass, const char *salt, unsigned char *key) {
if (DEBUG) {
puts("[deriver_key] in");
}
/* allocate 16 bytes of memory for key (128 bits) */
key = (unsigned char *) malloc(sizeof(unsigned char)*16);
/* let's make 10 iteration for now */
PBKDF2_HMAC_SHA_512(pass, salt, 10, KEYLEN/8, key);
if (DEBUG) {
printf("[deriver_key] key(string): %s\n", key);
printf("[deriver_key] key(bytes): ");
for(int i=0; i<KEYLEN/8; i++) {
printf("%02x", key[i]);
}
printf("\n");
puts("[deriver_key] out");
}
return 0;
}
int enc_dec_keystore(char *keystore, char *key) {
/* length of keystore */
int length;
/* if (length % AES_BLOCK_SIZE) !=0 -> fill to 16 bytes block */
int pad_length;
int pad_counter = 0;
FILE *fp;
fp = fopen(keystore, "rb");
fseek(fp, 0L, SEEK_END);
length = ftell(fp);
fseek(fp, 0L, SEEK_SET);
if (DEBUG) {
printf("[enc_dec_keystore] keystore length: %i\n", length);
}
/* check if input fills blocks correctly */
pad_length = length;
while(pad_length % AES_BLOCK_SIZE !=0) {
pad_length++;
pad_counter++;
}
if (DEBUG) {
printf("[enc_dec_keystore] pad_length: %i\n", pad_length);
}
/* IV - fill with 0 for now */
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0x00, AES_BLOCK_SIZE);
unsigned char *input;
input = malloc(sizeof(unsigned char)*length);
unsigned char input_question[length];
if (DEBUG) {
printf("\n[enc_dec_keystore] QUESTION #1: why sizeof(input) != sizeof(input_question)\n");
printf("[enc_dec_keystore] input size: %lu\n", sizeof(input));
printf("[enc_dec_keystore] input_question size: %lu\n\n", sizeof(input_question));
}
/* read data from file */
int ret = 0;
ret = fread(input, 1, length, fp);
if (ret == 0) {
puts("[enc_dec_keystore] file doesn't exist");
}
/* close the file after read */
fclose(fp);
if (DEBUG) {
printf("[enc_dec_keystore] sizeof input: %lu, input length: %lu\n", sizeof(input), strlen(input));
printf("[enc_dec_keystore] input data: \n%s\n", input);
}
/* allocate memory for aes's output */
unsigned char *enc_out;
enc_out = malloc(sizeof(unsigned char)*pad_length);
unsigned char enc_out_question[pad_length];
/* padding with 0 */
memset(enc_out, 0, sizeof(enc_out));
if (DEBUG) {
printf("\n[enc_dec_keystore] QUESTION #2: (again) why sizeof(enc_out) != sizeof(enc_out_question)\n");
printf("[enc_dec_keystore] enc_out size: %lu\n", sizeof(enc_out));
printf("[enc_dec_keystore] enc_out_question size: %lu\n\n", sizeof(enc_out_question));
}
/* AES-128 bit CBC Encryption */
/* set up a key */
/*
unsigned char key_again[KEYLEN/8];
for (int i=0; i<KEYLEN/8; i++) {
key_again[i] = key[i];
}
*/
AES_KEY enc_key;
AES_set_encrypt_key(key, 128, &enc_key);
/* encrypt input data to enc_out */
AES_cbc_encrypt(input, enc_out, sizeof(input), &enc_key, iv, AES_ENCRYPT);
if (DEBUG) {
printf("[enc_dec_keystore] encryption - aes output(string): %s\n", enc_out);
printf("[enc_dec_keystore] encryption - aes output(bytes): ");
for(int i=0; i<pad_length; i++) {
printf("%02x", enc_out[i]);
}
printf("\n");
}
/* AES-128 bit CBC Decryption */
/*
AES_KEY dec_key;
AES_set_encrypt_key(key, 128, &enc_key);
memset(iv, 0x00, AES_BLOCK_SIZE);
unsigned char *enc_out;
enc_out = malloc(sizeof(unsigned char)*pad_length);
AES_cbc_encrypt(enc_out, dec_out, sizeof(enc_out), &enc_key, iv, AES_ENCRYPT);
if (DEBUG) {
printf("[enc_dec_keystore] decryption - aes output(string): %s\n", enc_out);
printf("[enc_dec_keystore] decryption - aes output(bytes): ");
for(int i=0; i<pad_length; i++) {
printf("%02x", enc_out[i]);
}
printf("\n");
puts("[enc_dec_keystore] out");
}
*/
return 0;
}
int main(int argc, char **argv) {
char *user = "user";
char *key_id = "key1";
const char *pass = "temppass";
const char *salt = "tempsalt";
char *keystore = "keystore";
/* Deriver key from password and salt */
unsigned char *key;
if (deriver_key(pass, salt, key) != 0) {
puts("[main] error with key derivery");
}
/* Encrypt and decrypt keystore (for tests) */
if (enc_dec_keystore(keystore, key) != 0) {
puts("[main] error with encrypting/decrypting keystore");
}
return 0;
}
Keystore file contains:
keyid1:01020304050607080900010203040506:
keyid2:06050403020100090807060504030201:
Why sizeof(input) is not 82, because sizeof returns only the size of pointer variable, it does not return the size of dynamically allocated data.
PBKDF2_HMAC_SHA_512 returns a binary key, which may not be delimited by '\0', this could lead to segfault when you print the key

Resources