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;
}
Related
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.
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.
Requirements
I'm a developer but with near-zero experience with C until a week ago. For a project, I need to encrypt/decrypt source-code/text files and need to use C for that.
What I did till now?
I'm using Kokke/tony-AES-c library for it and implementing it with pkcs7 padding as explained in this Gist.
In my code (given below), I have a function my_encrypt, which is encrypting contents and returning uint8_t array (which contains hex). I need to save it and read it later from a file for decryption. I know how to save a string into a file but how can I save uint8_t in a file.
For this, I need to convert uint8_t to string but after trying multiple solution, I am unable to do it.
Question
How can I convert uint8_t array (which contains hex) to string in C.
My code
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <stdlib.h>
#define CBC 1
#define DECRYPT 0;
#define ENCRYPT 1;
#include "aes.h"
#include "pkcs7_padding.h"
const uint8_t * my_encrypt(char *report) {
//Initialization Vector
uint8_t iv[] = { 0x75, 0x52, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x21, 0x21 };
uint8_t i;
// char* report = "my super secret thing that needs to remain that way!";
char* key = "thisIstheKey";
int dlen = strlen(report);
int klen = strlen(key);
printf("THE PLAIN TEXT STRING = ");
for (i=0; i<dlen;i++){
printf("%c", report[i]);
}
printf("\n");
//Proper Length of report
int dlenu = dlen;
if (dlen % 16) {
dlenu += 16 - (dlen % 16);
printf("The original length of the STRING = %d and the length of the padded STRING = %d\n", dlen, dlenu);
}
//Proper length of key
int klenu = klen;
if (klen % 16) {
klenu += 16 - (klen % 16);
printf("The original length of the KEY = %d and the length of the padded KEY = %d\n", klen, klenu);
}
// Make the uint8_t arrays
uint8_t hexarray[dlenu];
uint8_t kexarray[klenu];
// Initialize them with zeros
memset( hexarray, 0, dlenu );
memset( kexarray, 0, klenu );
// Fill the uint8_t arrays
for (int i=0;i<dlen;i++) {
hexarray[i] = (uint8_t)report[i];
}
for (int i=0;i<klen;i++) {
kexarray[i] = (uint8_t)key[i];
}
int reportPad = pkcs7_padding_pad_buffer( hexarray, dlen, sizeof(hexarray), 16 );
int keyPad = pkcs7_padding_pad_buffer( kexarray, klen, sizeof(kexarray), 16 );
printf("The padded STRING in hex is = ");
for (i=0; i<dlenu;i++){
printf("%02x",hexarray[i]);
}
printf("\n");
printf("The padded key in hex is = ");
for (i=0; i<klenu;i++){
printf("%02x",kexarray[i]);
}
printf("\n");
// In case you want to check if the padding is valid
int valid = pkcs7_padding_valid( hexarray, dlen, sizeof(hexarray), 16 );
int valid2 = pkcs7_padding_valid( kexarray, klen, sizeof(kexarray), 16 );
printf("Is the pkcs7 padding valid report = %d | key = %d\n", valid, valid2);
//start the encryption
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, kexarray, iv);
// encrypt
AES_CBC_encrypt_buffer(&ctx, hexarray, dlenu);
printf("the encrypted STRING = ");
for (i=0; i<dlenu;i++){
printf("%02x",hexarray[i]);
}
printf("\n");
return hexarray;
}
int main(int argc, char *argv[]) {
// File pointer
FILE *input_file;
int operation;
char * input_file_buffer = 0;
long input_file_length;
// ////////////////////////////////////////////////////////
// Read command line arguments
// ////////////////////////////////////////////////////////
// Make sure proper command params are supplied
if (argc != 3) {
printf("Usage: %s encrypt/decrypt filename\n", argv[0]);
return -1;
}
// Define operation type
if (strcmp(argv[1], "encrypt") == 0) {
operation = ENCRYPT;
} else if (strcmp(argv[1], "decrypt") == 0) {
operation = DECRYPT;
}
// ////////////////////////////////////////////////////////
// Open File contents
// ////////////////////////////////////////////////////////
// Open input_file to encrypt/decrypt.
input_file = fopen(argv[2], "rb");
if (!input_file) {
fprintf(stderr, "ERROR: '%s' file fopen error: %s\n", argv[2], strerror(errno));
return errno;
}
// Read contents of file in buffer
fseek(input_file, 0, SEEK_END);
input_file_length = ftell (input_file);
fseek(input_file, 0, SEEK_SET);
input_file_buffer = malloc (input_file_length);
if (input_file_buffer)
{
fread(input_file_buffer, 1, input_file_length, input_file);
}
// Close input_file
fclose(input_file);
// We have contents of file in input_file_buffer, let's print them.
printf("File contents:\n-------\n%s\n", input_file_buffer);
// Let's encrypt input_file_buffer
uint8_t result = 0;
result = my_encrypt(input_file_buffer);
// Convery result to string.
printf("main: Encrypted File contents:\n-------\n%d\n", result);
return 0;
}
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;
}
How do I read the bytes from a bmp file using C?
Here's a general-purpose skeleton to just load a binary file, and return a pointer to the first byte. This boils down to "fopen() followed by fread()", but is a ... bit more verbose. There's no error-handling, although errors are checked for and I believe this code to be correct. This code will reject empty files (which, by definition, don't contain any data to load anyway).
#include <stdio.h>
#include <stdlib.h>
static int file_size(FILE *in, size_t *size)
{
if(fseek(in, 0, SEEK_END) == 0)
{
long len = ftell(in);
if(len > 0)
{
if(fseek(in, 0, SEEK_SET) == 0)
{
*size = (size_t) len;
return 1;
}
}
}
return 0;
}
static void * load_binary(const char *filename, size_t *size)
{
FILE *in;
void *data = NULL;
size_t len;
if((in = fopen(filename, "rb")) != NULL)
{
if(file_size(in, &len))
{
if((data = malloc(len)) != NULL)
{
if(fread(data, 1, len, in) == len)
*size = len;
else
{
free(data);
data = NULL;
}
}
}
fclose(in);
}
return data;
}
int main(int argc, char *argv[])
{
int i;
for(i = 1; argv[i] != NULL; i++)
{
void *image;
size_t size;
if((image = load_binary(argv[i], &size)) != NULL)
{
printf("Loaded BMP from '%s', size is %u bytes\n", argv[i], (unsigned int) size);
free(image);
}
}
}
You can easily add the code to parse the BMP header to this, using links provided in other answers.
Use fopen and fread as suggested by others. For the format of the bmp header take a look here
fopen followed by fread
ImageMagick supports BMP. You can use either of two C APIs, the low-level MagickCore or the more high level Magick Wand.
make sure this file is not compressed using RLE method. otherwise, you'll have to read from the file and dump into a buffer to reconstruct the image, after reading the header file and knowing it's dimensions.