Encrypt/decrypt single octet with no padding using RSA_public_encrypt - c

I am trying to encrypt the decimal number 1 with no padding using RSA_public_encrypt. Of course the result of this encryption should be 1 again. But in fact it is
Cipher:
5228673350895653896383201058815462877426144378065091716669226352446563314310753759122681282019606231774744798481087922688401463790373072832646006963123849664906627085625735903412727878929921552918090336305565457632762612646244666075746315455854479912774071351362988587769873374454538153517081634942043196173525640004822126101409481060928041484882764412543090155480476597339865942466034635200613687987398189458867055031285752787781897557950334515480742629110423562374837915117562936777536259795189526199285672603820591631423849227226304977053415509662563290672486408474162339095049681422645956742727171481170704
What am I doing wrong?
I am aware that there are high level routines in OpenSSL and also that using RSA without padding is insecure. This is just an experiment.
I am also aware that OpenSSL uses the Big Endian format. So I also tried to change the order of the input bytes to the encryption - then 1 was encrypted to 1. But implementing the decryption, taking into account the reverse byte order in both encryption and decryption, some numbers, like 2, were encrypted-decrypted correctly and others were not...very strange!
Here is my code for the encryption:
#include <stdio.h>
#include "rsa.h"
#include "pem.h"
#define LENGTH 1000
int main(void)
{
//Variables for message and cipher
//BIGNUM format
BIGNUM message_bignum, cipher_bignum;
BIGNUM *ptr_message_bignum=&message_bignum;
BIGNUM *ptr_cipher_bignum=&cipher_bignum;
//Formatted as decimal string
unsigned char message_decimal[]="1";
//binary format for input to RSA encryption
unsigned char message[LENGTH]={0},cipher[LENGTH]={0};
//Initialise RSA structure
RSA *rsa=RSA_new();
//Get public key
BIO *publickey_handle=BIO_new_file("rsa_publickey.txt","rb");
if(publickey_handle==NULL)
{
fprintf(stderr,"Could not open key file!\n");
return -1;
}
PEM_read_bio_RSA_PUBKEY(publickey_handle,&rsa,NULL,NULL);
if(BIO_free(publickey_handle)==0)
{
fprintf(stderr,"Error closing key file!\n");
return -1;
}
//Convert message to BIGNUM format
BN_init(ptr_message_bignum);
BN_dec2bn(&ptr_message_bignum,(const char *)message_decimal);
//Convert message as BIGNUM to binary format
BN_bn2bin(ptr_message_bignum,message);
//Encrypt message in binary format
if(RSA_public_encrypt(RSA_size(rsa),(const unsigned char*)message,cipher,rsa,RSA_NO_PADDING)==-1)
{
fprintf(stderr,"Error during encryption!\n");
return -1;
}
//Convert cipher to BIGNUM format
BN_init(ptr_cipher_bignum);
BN_bin2bn((const unsigned char*)cipher,RSA_size(rsa),ptr_cipher_bignum);
//Convert cipher from BIGNUM format to decimal format and print it to stdout
printf("Cipher:\n%s",BN_bn2dec(ptr_cipher_bignum));
printf("\nDone!\n");
return 0;
}

As documented:
BN_bn2bin() converts the absolute value of a into big-endian form and stores it at to. to must point to BN_num_bytes(a) bytes of memory.
But it doesn't. It first contains a single 00 because of message[LENGTH]={0}. Then it contains, well, whatever is in LENGTH amount of bytes.
In RSA_public_encrypt you use RSA_size(rsa) as first parameter, flen. flen however should be the result of BN_num_bytes(&ptr_message_bignum), i.e. 1 byte. The output location cipher on the other hand must be able to store RSA_size(rsa) bytes.
Possibly the confusion comes from the fact that BN_bn2bin will store the value as the shortest Big Endian encoding (in bytes). For the value 1 that will of course be one byte, not RSA_size(rsa) bytes.
Edit: I found the RSA_padding_add_none method that could be able to resize.

Related

EVP_KEY get raw private key in C

Good day,
I have been trying to do a simple exercise where I could generate the public and the private key using RSA with Openssl and print them both. My code looks something like this:
size_t private_key_len = KEY_LENGTH;
EVP_PKEY *pkey = EVP_RSA_gen(KEY_LENGTH);
if (pkey == NULL)
{
fprintf(stderr, "error: rsa gen\n");
ERR_print_errors_fp(stderr);
return NULL;
}
unsigned char *private_key = calloc((KEY_LENGTH + 1),sizeof(unsigned char));
EVP_PKEY_get_raw_private_key(pkey, private_key, &private_key_len);
printf("%s\n",private_key);
So normally it should print the private key, given that KEY_LENGTH is 1024, however it just prints nothing (The zeros initialized by calloc). I have tried with malloc too, the result is similar the only difference being that it prints 0xBE.
So basically the array private_key is never filled, and I have no idea why.
What am I missing to make this work?
Thanks in advance!
Quoting the man page with emphasis changed:
EVP_PKEY_get_raw_private_key() fills the buffer provided by priv with raw private key data. The size of the priv buffer should be in *len on entry to the function, and on exit *len is updated with the number of bytes actually written. If the buffer priv is NULL then *len is populated with the number of bytes required to hold the key. The calling application is responsible for ensuring that the buffer is large enough to receive the private key data. This function only works for algorithms that support raw private keys. Currently this is: EVP_PKEY_HMAC, EVP_PKEY_POLY1305, EVP_PKEY_SIPHASH, EVP_PKEY_X25519, EVP_PKEY_ED25519, EVP_PKEY_X448 or EVP_PKEY_ED448.
Notice that RSA is not one of the supported algorithms.
You can "print" an RSA key either by converting each of its components (n,e,d,p,q,dp,dp,qinv) to printable form, which EVP_PKEY_print_private does for you, or getting the encoding of the whole key in PEM which is 'printable' in the sense of being printable and typable characters, but not the sense of being easily understood (or copied or created) by people, with PEM_write_PrivateKey or PEM_write_RSAPrivateKey.
Also, the value you pass to EVP_RSA_gen is in bits, but the size of displayed components of an RSA key (other than e, which is small) will be in hex or decimal digits or (mostly) base64 characters.

C: unsigned short stored into buffer after fread from a binary file doesn't match original pattern

I have a binary file filled with 2-byte words following this pattern(in HEX): 0XY0. this is the part of the code where I execute fread and fopen.
unsigned short buffer[bufferSize];
FILE *ptr; //
ptr = fopen(fileIn,"rb"); //
if(ptr == NULL)
{
fprintf(stderr,"Unable to read from file %s because of %s",fileIn,strerror(errno));
exit(20);
}
size_t readed = fread(buffer,(size_t)sizeof(unsigned short),bufferSize,ptr);
if(readed!=bufferSize)
{
printf("readed and buffersize are not the same\n");
exit(100);
}
//---------------------------
If I look at any content of the buffer, for example buffer[0], instead of being a short with pattern 0XY0, it is a short with pattern Y00X
Where is my error? is it something regarding endianess?
of course i checked every element inside buffer. the program execute with no errors.
EDIT: If i read from file with size char instead of short, the content of buffer(obviously changed to char buffer[bufferSize*2];) match the pattern OXYO. So I have that (for example) buffer[0] is 0X and buffer[1] is Y0
Your problem seems to be exactly typical of an endianness mismatch between the program that stored the data into the file and the one that reads it. Remember that mobile phone processors tend to use big-endian representations and laptop little-endian.
Another potential explanation is your file might have been written in text mode by a windows based program that converted the 0x0A bytes into pairs of 0x0D / 0x0A, causing the contents to shift and cause a similar pattern as what you observe.
Instead of reading the file with fread, you should read it byte by byte and compute the values according the endianness specified for the file format.

Transmit integer value serially using AT89S51

I have written a program to transmit char value serially for AT89S51. Its is working perfectly.
Program is given below:-
#include<reg51.h>
void main()
{
TMOD=0x20;
TH1=0xFD;
SCON=0x50;
TR1=1;
while(1)
{
SBUF='A';
while(TI==0);
TI=0;
}
}
In above code char 'A' is transmitted.
Now I want to transmit an integer value and I have written a program for it.
Program is given below:-
#include<reg51.h>
void main()
{
int i=61;
TMOD=0x20;
TH1=0xFD;
SCON=0x50;
TR1=1;
while(1)
{
SBUF=i;
while(TI==0);
TI=0;
}
}
Above program is transmitting ' = ' (i.e decimal 61 corresponds to ' = ' character in ASCII).
I want to know how I can transmit an integer value.
Please guide me in this regard.
SBUF contains a single byte (i.e. char) to be transmitted. If you put 'A' there, that's what will be transmitted (in fact 0x41 will be transmitted, which corresponds to ASCII value of 'A'). When assigning a value of i into SBUF, it will be interpreted as byte regardless of type of i. This byte can be interpreted in any way the receiving party desires - it can treat it as integer or as ASCII value, it's the same as far as transmission goes; the difference is in the way the data is treated.
Icepack is right if you only wanted to transmit a char or unsigned char, but if you really wanted to transmit more than 8 bits you will have to do it byte by byte. What you are trying to do requires putting bytes into the array, and sending them over line one byte at a time (SBUF in 8051 can only hold single TX and single RX value at a time). Than you have another issue, do you transmit most significant byte first, or last? Then you should ask yourself if you wanted to transmit binary data (just spit the bytes over the wire) assuming the other party knew your data format? Or do you want to work with strings, so that number '34567' will take for example five bytes (five ASCII codes) or more if you wanted some kind of terminator, line feed, or other non printable characters, while binary it would really be an integer taking two bytes on the 8051. As you can see, your question opens to many other questions.

Conversion from binary file to hex in C

I am trying to write some simple program to uploading files to my server. I' d like to convert binary files to hex. I have written something, but it does not work properly.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static int bufferSize = 1024;
FILE *source;
FILE *dest;
int n;
int counter;
int main() {
unsigned char buffer[bufferSize];
source = fopen("server.pdf", "rb");
if (source) {
dest = fopen("file_test", "wb");
while (!feof(source)) {
n = fread(buffer, 1, bufferSize, source);
counter += n;
strtol(buffer, NULL, 2);
fwrite(buffer, 1, n, dest);
}
}
else {
printf("Error");
}
fclose(source);
fclose(dest);
}
I use strtol to convert binary do hex. After invoking this code I have still strange characters in my file_test file.
I' d like to upload a file on server, for example a PDF file. But firstly I have to write a program, that will convert this file to a hex file. I'd like that the length of a line in hex file would be equal 1024. After that, I will upload this file line by line with PL/SQL.
EDIT: I completely misunderstood what the OP was aiming for. He wants to convert his pdf file to its hex representation, as I see now, because he wants to put that file in a text blob field in some database table. I still claim the exercise is a complete waste of time,since blobs can contain binary data: that's what blobs were invented for. Blob means binary large object.
You said: "I' d like to upload file on server, for example pdf file. But firstly I have to write a program, that will convert this file to hex file."
You don't have to, and must not, write any such conversion program.
You have to first understand and internalize the idea that hex notation is only an easy-to-read representation of binary. If you think, as you seem to, that you have to "convert" a pdf file to hex, then you are mistaken. A pdf file is a binary file is a binary file. You don't "convert" anything, not unless you want to change the binary!
You must abandon, delete, discard, defenestrate, forget about, and expunge your notion of "converting" any binary file to anything else. See, hex exists only as a human-readable presentation format for binary, each hex digit representing four contiguous binary digits.
To put it another way: hex representation is for human consumption only, unsuitable (almost always) for program use.
For an example: suppose your pdf file holds a four-bit string "1100," whose human-readable hex representation can be 'C'. When you "convert" that 1100 to hex the way you want to do it, you replace it by the ASCII character 'C', whose decimal value is 67. You can see right away that's not what you want to do and you immediately see also that it's not even possible: the decimal value 67 needs seven bits and won't fit in your four bits of "1100".
HTH
Your code is fantastically confused.
It's reading in the data, then doing a strtol() call on it, with a base of 2, and then ignoring the return value. What's the point in that?
To convert the first loaded byte of data to hexadecimal string, you should probably use something like:
char hex[8];
sprintf(hex, "%02x", (unsigned int) buffer[0] & 0xff);
Then write hex to the output file. You need to do this for all bytes loaded, of course, not just buffer[0].
Also, as a minor point, you can't call feof() before you've tried reading the file. It's better to not use feof() and instead check the return value of fread() to detect when it fails.
strtol converts a string containing a decimal representation of a number to the binary number if i am not mistaken. You probably want to convert something like a binary OK to 4F 4B... To do that you can use for example sprintf(aString, "%x", aChar).

Read a binary file C programming

I'm doing a program to manage a clinic, but I'm having a problem. I need to read a binary file with the information from the Doctors. The information is name, code and telephone. They are inserted by the user.
How can I printf that info separately. For example:
Name: John Cruz
Code: JC
Telephone: 90832324
I'm trying to use
typedef struct {
char code[10];
char name[100];
int telephone;
} DOCTOR;
int newDoctor() {//This is the function that create the binary file
DOCTOR d;
FILE *fp;
fp = fopen("Doctors.dat","wb");
if(fp==NULL) {
printf("Error!");
return -1;
}
printf("Code\n");
fflush(stdin);
gets(d.code);
printf("Name\n");
gets(d.name);
printf("Telephone\n");
scanf("%d",&d.telephone);
fprintf(fp,"%s;%s;%d",d.code,d.name, d.telephone);
fclose(fp);
}
//And to open
FILE* fp;
fp=fopen("Doctors.dat","rb");
while(!EOF(fp)) {
fgets(line, 100, fp);
printf("%s",line);
}
Just to see the line but it's not working, and how i can separate the info?
Regards
fgets assumes that the data is ascii strings. For binary data you need to know the binary format and read the data into the appropriate data structures.
You must know the format the binary is in, such as if you serialized a previous struct then you can read it into a struct of the same type:
typedef struct
{
int stuff;
double things;
} myStruct;
myStruct writeMe = {5, 20.5};
FILE* fp;
fp = fopen("Doctores.dat","wb");
if (fp == NULL) { fputs ("File error", stderr); exit(EXIT_ERROR); }
fwrite(writeMe, 1, sizeof(writeMe), fp);
fclose(fp);
Then later to read:
myStruct readMe;
FILE* fp2;
fp2 = fopen("Doctores.dat","rb");
if (fp2 == NULL) { fputs ("File error", stderr); exit(EXIT_ERROR); }
fread(readMe, 1, sizeof(readMe), fp2);
fclose(fp2);
printf("my int: %i\nmy double: %f", readMe.stuff, readMe.things);
Hope this helps
There are at least two issues here: file & data format and reading a binary file. File format is how the information is organized within the file. Binary reading involves reading the file without any translations.
File and Data Format
For text fields, you need to know the following:
Fixed or variable length field.
Maximum field width.
Representation (null terminated,
fixed length, padded, preceded by
length of string, etc.)
You can't assume anything. Get the format in writing. If you don't understand the writing, have the original author rewrite the documentation or explain it to you.
For integral numeric fields you need to know the following:
Size of number, in bytes.
Endianness: Is first byte the Most
Significant (MSB) or Least
significant (LSB)?
Signed or Unsigned
One's complement or two's complement
Numbers can range from 1 "byte" to at least 8 bytes, depending on the platform. If your platform has a native 32-bit integer but the format is 16-bit, your program will read 16 extra bits from the next field. Not good; bad, very bad.
For floating point: you need to know the representation.
The are many ways to represent a floating point number. Floating point numbers can very in size also. Some platforms use 32-bits, while others use 80 bits or more. Again, assume nothing.
Binary Reading
There are no magic methods in the C and C++ libraries to read your structure correctly in one function call; you will have to assemble the fields yourself. One thorn or bump is the fact that compilers may insert "padding" bytes between fields. This is compiler dependent and the quantity of padding bytes is not standard. It is also known as alignment.
Binary reading involves using fread or std::istream::read. The common method is to allocate a buffer, read a block of data into the buffer, then compose the structures from that buffer based on the file format specification.
Summary
Before reading a binary stream of data, you will need a format specification. There are various ways to represent data and internal data representation varies by platform. Binary data is best read into a buffer, then program structures and variables can be built from the buffer.
Textual representations are simpler to input. If possible, request that the creator of the data file use textual representations of the data. Field separators are useful too. A language like XML helps organize the textual data and provides the format in the data file (but may be too verbose for some applications).

Resources