Reading char array containing Hex values in C - c

This is part of a program that I use to decrypt AES in C. The program is supposed to take in an IV from an external file, read it then set as the IV. Unfortunately the IV is declared as a char array in the code (which I cannot change) so what I tried to do is to read the external file as byte[], then convert it to char[].
One of the issues I am currently facing is regarding the AES_IV variable as seen below:
#define AES_BLOCK_SIZE 0x10
char AES_IV[AES_BLOCK_SIZE] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
When I try to print out the AES_IV using the code
printf("\nAES_IV: ");
for (i3 = 0; i3 < AES_BLOCK_SIZE; i3++) {
printf("%02x", AES_IV[i3]);
}
printf("\n");
The output is:
AES_IV: 0c0a513398f1eda13ed2fc7213b50b10
Which is different from the AES_IV I declared.
I changed the for loop to
for (i3 = 0; i3 < 50; i3++) {
and the resultant output is much longer
AES_IV: 0c0a513398f1eda13ed2fc7213b50b105369a...(100 chars in total)
I checked the length of AES_IV and it is still 16, but why does my for loop returns such a long result? Also why did the value of AES_IV change? I have checked and there are no reference to AES_IV anywhere before this part.
Your help is much appreciated.
Source code for reference:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <dlfcn.h>
#include "SmartSDLib.h"
#define SDCARD_PATH "/boot"
#define P1_INDEX 2
#define P2_INDEX 3
#define P3_INDEX 4
#define AES_BLOCK_SIZE 0x10
#define APDU_HEADER_SIZE 5
#define FILELEN 32 // For reading IV from file
void To_Hex(char s8Data[],char hexBuffer[], int offset, int nlen)
{
int j;
int nSize = (nlen - offset);
char finalhash[8192];
char hexval [] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
for(j=0 ; j < nSize; j++)
{
finalhash[j*2] = hexval[(s8Data[j] >> 4) & 0xF];
finalhash[(j*2) + 1] = hexval[s8Data[j] & 0x0F];
}
memset(hexBuffer,0x00,8192);
memcpy(hexBuffer, finalhash, nSize*2);
}
char * AccessAPDU(char command[], int size)
{
unsigned char u8Ret;
int s32Len[1];
char s8Buffer[512], hexBuffer[8192];
To_Hex(command, hexBuffer, 0, size);
//printf ("%s\n%s%s\n", "AccessAPDUCommand:","CMD:" , hexBuffer);
u8Ret = OT_SmartSDCard_AccessAPDUCommand(size, command, s32Len, s8Buffer, 0);
if(u8Ret == 0x00)
{
printResult(s32Len, s8Buffer);
}
else
{
printf ("%s%x\n\n", "Error 0x", u8Ret);
}
return s8Buffer;
}
void printResult (int s32Len[], char s8Buffer[])
{
char hexBuffer[8192];
if(s32Len[0] >= 2)
{
To_Hex(s8Buffer, hexBuffer, 0, s32Len[0]);
// printf ("%s%s\n", "Ret:", hexBuffer);
// printf ("%s%d\n\n", "Len: ", s32Len[0]);
}
else
{
printf ("%s%d\n", "Len: ", s32Len[0]);
}
}
void CopyBuffer(char Dest[], char Source[], unsigned int length){
while(length){
Dest[length - 1] = Source[length - 1];
length--;
}
}
int ascii_to_hex(char c) // For reading IV from file
{
int num = (int) c;
if(num < 58 && num > 47) // Handle numbers (0-9)
{
return num - 48;
}
if(num < 103 && num > 96) // Handle lowercase alphabets (a-f)
{
return num - 87;
}
if(num < 71 && num > 64) // Handle uppercase alphabets (A-F)
{
return num - 55;
}
return num;
}
int main()
{
unsigned char u8Ret;
char SDCard_Path[64];
char line[64];
int s32Len[1];
char s8Buffer[512], hexBuffer[8192];
int exit = 1;
int iChoice;
char * response;
int test;
char testchar[32];
bool flag = true;
char fileName[100];
char encrypted[100];
char decrypted[100];
int i;
int j;
int blockCounter = 0;
int commandCounter = 0;
char imageBuffer[1];
/* APDU commands */
char AES_encrypt_cmd[APDU_HEADER_SIZE + AES_BLOCK_SIZE] = {0x80, 0x2A, 0x01,0x00, AES_BLOCK_SIZE}; //encryption APDU
char AES_decrypt_cmd[APDU_HEADER_SIZE + AES_BLOCK_SIZE] = {0x80, 0x2A, 0x02,0x00, AES_BLOCK_SIZE}; //decryption APDU
char GetResponse_cmd[] = {0x00, 0xC0, 0x00,0x00, 0x00}; //Le to be changed before use
char SelectAESapplet_cmd[] = {0x00, 0xA4, 0x04,0x00, 0x10, 0xA0, 0x00, 0x00, 0x00, 0x77, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x04};
//char PutKeyAES_cmd[] = {0x80, 0xD8, 0x00,0xF8, 0x20, 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11,0x00};
char PutKeyAES_cmd[] = {0x80, 0xD8, 0x00,0xF8, 0x20, 0xCF,0x10,0xF9,0xBD,0xF6,0xAA,0x15,0xC5,0x0E,0xCD,0x79,0xE6,0x28,0x3D,0xA8,0x0A,0x79,0x7A,0x2D,0x27,0x03,0xAE,0x07,0xD5,0x2F,0x5D,0x8F,0x60,0x1F,0x1E,0xF2,0x6F};
/* AES variables */
int AES_keyIndex = 0;
char AES_IV[AES_BLOCK_SIZE] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
//char AES_IV[AES_BLOCK_SIZE] = {0x12,0xFB,0x87,0x11,0x62,0x7E,0xBB,0x55,0x71,0x7B,0x2F,0x70,0xA4,0x97,0x55,0x7B};
//char AES_IV[AES_BLOCK_SIZE];
char AES_CBC_vector[AES_BLOCK_SIZE];
char AES_cmdBuffer[APDU_HEADER_SIZE + AES_BLOCK_SIZE];
FILE * rFile;
FILE * wFile;
FILE *fileptr;char *buffer;long filelen;int i2,i3,i4;char IV_temp[AES_BLOCK_SIZE]; // This line for the file --> byte --> Hex
printf ("%s\n", "This program will run 1, 2 followed by 6");
// case 1 :
printf ("%s\n", "Initializing: ");
u8Ret = OT_SmartSDCard_Initialization(SDCARD_PATH);
if(u8Ret == 0x00)
printf ("%s\n\n", "Initialization OK");
else
printf ("%s%x\n\n", "Initialization: Error 0x",u8Ret);
// printf ("%s\n\n", "-------------------------------------");
/* ATR */
u8Ret = OT_SmartSDCard_Reset(s32Len, s8Buffer);
if(u8Ret == 0x00)
{
To_Hex(s8Buffer,hexBuffer, 0, s32Len[0]);
// printf ("%s%s\n", "ATR : ", hexBuffer);
// printf ("%s%d\n\n", "Len : ", s32Len[0]);
}
else
printf ("%s%x\n\n", "Reset: Error 0x",u8Ret);
// printf ("%s\n\n", "-------------------------------------");
/* Select AES applet */
printf("%s\n", "Selecting AES applet...");
response = AccessAPDU(SelectAESapplet_cmd, sizeof(SelectAESapplet_cmd));
if(response[0] == 0x61){
GetResponse_cmd[P3_INDEX] = response[1];
AccessAPDU(GetResponse_cmd, sizeof(GetResponse_cmd));
}
// printf ("%s\n\n", "-------------------------------------");
// case 2 :
printf("Putting key...");
AES_keyIndex = 0;
memset(line, 0x00, sizeof(line));
PutKeyAES_cmd[2] = AES_keyIndex;
printf("putting key on index %d\n", AES_keyIndex);
response = AccessAPDU(PutKeyAES_cmd, sizeof(PutKeyAES_cmd));
AES_encrypt_cmd[P2_INDEX] = AES_keyIndex;
AES_decrypt_cmd[P2_INDEX] = AES_keyIndex;
// printf ("%s\n\n", "-------------------------------------");
// case 6 :
printf ("Decrypting in CBC...");
// printf ("File Name: /home/pi/test_encrypted\n");
// printf ("Encrypted File Name: /home/pi/test_decrypted\n");
rFile = fopen("/home/pi/test_encrypted","rb");
wFile = fopen("/home/pi/test_decrypted","wb");
////////////////////////////////////////////////////////////////
// This part to read rFile and store as a byte [WORKING!]
fseek(rFile, 0, SEEK_END); // Jump to the end of the file
filelen = ftell(rFile); // Get the current byte offset in the file
rewind(rFile); // Jump back to the beginning of the file
buffer = (char *)malloc((filelen+1)*sizeof(char)); // Enough memory for file + \0
fread(buffer, filelen, 1, rFile); // Read in the entire file
// This part to convert buffer to hex value [WORKING!]
for (i2 = 0; i2 < 100; i2++)
{
if (i2 > 0) printf(" ");
printf("%02X", buffer[i2]);
IV_temp[i2] = buffer[i2];
}
// This part to print stuff [AES_IV not printing out correctly]
printf("\nAES_IV: ");
//fwrite(AES_IV, 1, sizeof(AES_IV), stdout);
for (i3 = 0; i3 < 50; i3++) {
printf("%02x", AES_IV[i3]);
}
printf("\n");
/*
printf("IV_temp: ");
for (i4 = 0; i4 < AES_BLOCK_SIZE; i4++) {
printf("%02x", IV_temp[i4]);
}
printf("\n");
*/
for (i3 = 0; i3 < AES_BLOCK_SIZE; i3++) {
AES_IV[i3] = IV_temp[i3];
}
printf("\nLength of AES_IV = %d\n", sizeof(AES_IV));
printf("\nAES_IV: ");
for (i3 = 0; i3 < 50; i3++) {
printf("%02x", AES_IV[i3]);
}
printf("\n");
// Return the file pointer to start of file
rewind(rFile);
////////////////////////////////////////////////////////////////
if (rFile == NULL || wFile == NULL)
perror("Error opening File");
else{
int IsEOF = false;
// Initialize the CBC block with IV
CopyBuffer(AES_CBC_vector, AES_IV, AES_BLOCK_SIZE);
while (IsEOF == false) {
i = 0;
while(i < AES_BLOCK_SIZE){ // i run from 0 to (AES_BLOCK_SIZE - 1)
AES_cmdBuffer[APDU_HEADER_SIZE + i] = fgetc(rFile);
if(feof(rFile)) {
IsEOF = true;
if(i == 0) { // break out of while loop if a new block is not yet in progress
break;
} else { // continue to finish the block and pad with zeros
AES_cmdBuffer[APDU_HEADER_SIZE + i] = 0x00; //padding
}
}
i++;
}
if(i == 0) break; //break out of while loop, nothing to send to card
// Fill in the APDU header
CopyBuffer(AES_cmdBuffer, AES_decrypt_cmd, APDU_HEADER_SIZE);
response = AccessAPDU(AES_cmdBuffer, sizeof(AES_cmdBuffer));
if(response[0] == 0x61){
if(response[1] != AES_BLOCK_SIZE) {
perror("Card returning wrong block size");
}
GetResponse_cmd[P3_INDEX] = AES_BLOCK_SIZE;
response = AccessAPDU(GetResponse_cmd, sizeof(GetResponse_cmd));
/* CBC mode */
for(i = 0; i < AES_BLOCK_SIZE; i++){
response[i] ^= AES_CBC_vector[i];
}
fwrite(response, sizeof(char), AES_BLOCK_SIZE, wFile);
// Take the ciphertext to perform XOR next time
CopyBuffer(AES_CBC_vector, &AES_cmdBuffer[APDU_HEADER_SIZE], AES_BLOCK_SIZE);
} else {
perror("Error decrypting file using the smart card");
}
}
}
fclose (rFile);
fclose (wFile);
// printf ("%s\n\n", "-------------------------------------");
return 0;
}

As one comment already stated you should use unsigned char otherwise each element is treated as a signed char by default. Better yet you might want to use fixed-width uint8_t from #include <stdint.h> instead.
Here is a minimal example that works as expected:
#include <stdint.h>
#include <stdio.h>
#define AES_BLOCK_SIZE 0x10
uint8_t AES_IV[AES_BLOCK_SIZE] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
int
main( void )
{
int i;
for ( i = 0; i < sizeof(AES_IV); i++ ) {
printf( "%02x", AES_IV[i] );
}
return 0;
}

Related

Cast uint8_t to hex string (2 digits)

I'm currently using the following to print uint8_t to hex:
for(int j = 0; j < len; j++) {
printf("%02X ", bytes[j]);
}
Is it possible to do this without a for-loop and simply assign the result to a variable?
Here's one simple way:
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
bool to_hex(char* dest, size_t dest_len, const uint8_t* values, size_t val_len) {
if(dest_len < (val_len*2+1)) /* check that dest is large enough */
return false;
*dest = '\0'; /* in case val_len==0 */
while(val_len--) {
/* sprintf directly to where dest points */
sprintf(dest, "%02X", *values);
dest += 2;
++values;
}
return true;
}
int main() {
uint8_t values[256];
char buf[sizeof(values)*2+1]; /* one extra for \0 */
for(size_t i=0; i<256; ++i)
values[i] = i;
if(to_hex(buf, sizeof(buf), values, sizeof(values)))
printf("%s\n", buf);
}
Output:
000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
For completeness, here's a self contained version using a lookup table instead of sprintf:
bool to_hex(char* dest, size_t dest_len, const uint8_t* values, size_t val_len) {
static const char hex_table[] = "0123456789ABCDEF";
if(dest_len < (val_len*2+1)) /* check that dest is large enough */
return false;
while(val_len--) {
/* shift down the top nibble and pick a char from the hex_table */
*dest++ = hex_table[*values >> 4];
/* extract the bottom nibble and pick a char from the hex_table */
*dest++ = hex_table[*values++ & 0xF];
}
*dest = 0;
return true;
}
Personally, I'd go for the sprintf approach, but if you badly do not want to use one of the library api, you could use something like this:
char HexLookUp[] = "0123456789abcdef";
void bytes2hex (unsigned char *src, char *out, int len)
{
while(len--)
{
*out++ = HexLookUp[*src >> 4];
*out++ = HexLookUp[*src & 0x0F];
src++;
}
*out = 0;
}
Test code:
int main(void)
{
unsigned char bytes[] = {0x00, 0x01, 0x02, 0x03, 0xDE, 0xAD, 0xBE, 0xEF, 0xCC};
char buffer[sizeof(bytes)*2 + 1];
bytes2hex(bytes, buffer, sizeof(bytes));
printf("%s\n",buffer);
return 0;
}
Output:
00010203deadbeefcc

How to convert LSB extracted data to text or binary to text

UPDATE***********************
For reference I included the program I made for opening a PPM image - embedding a message into the image and then saving out a new image with the embedded text. With the function below I'm hoping to extra that message, (hidden in the LSB) and then converting it to text to display it. Thanks for the replies so far - I'm going to start testing them out and see if anything works.
I'm trying to write a function that extracts the LSB of an unsigned char value - puts them bits together to form an extracted message. I have the length of how many LSBs I need to extract from the file, but I'm having trouble with how to convert this into a message.
At first I extracted the first 8 bits into an int array - giving me something such as 00110000. Now I have an INT array with that value, and I need to convert it to a single char for the letter representation. However, I think I should be taking in all of the LSBs into an array that is messageLength * 7 and somehow converting that int array into the text. It would be giving me the binary represenation of the text before converting. Maybe theirs a way to convert a long string of 1's and 0's to text?
unsigned char * extBits(PPMImage *img, int messageLen, unsigned char * decMsg)
{
//int count = 2;
int embCount = 0;
int deM = messageLen * 7;
int count = 0;
unsigned char byte;
// int mask;
// unsigned char update;
// unsigned char flipOne = 0x01; //0x01
// unsigned char flipZero = 0xFE; //0x00
unsigned char dMsg[deM];
int byteArray[7];
int takeByte = 0;
unsigned char *extMsg;
char c;
for(int j = 0; j < 7; j++)
{
if(takeByte == 8)
{
//first letter extracted
takeByte = 0;
}
//byte = msgOne[j];
// byte = img->pixel[j];
//encMsg[j] = byte;
byte = img->pixel[j];
//printf("byte: %c\n", byte);
// printf("byte: %x\n", byte);
byte &= 1;
//printf("byte after: %x\n", byte);
dMsg[j] = byte;
byteArray[j] = byte;
data[j] = byteArray[j];
printf("dMsg:%x ", dMsg[j]);
// printf("pixel:%c \n", img->pixel[j]);
embCount++;
takeByte++;
}
/*
for(int r=0;r<7;r++)
{
printf("\n%d\n", byteArray[r]);
}
printf("count: %d", embCount);
printf("%s ", dMsg);
*/
return decMsg = dMsg;
}
embedding program*******
//////////////////////////////////////////////////////////////
/*
execute as ./emb -i <img2embed> -i <text file> -o <embedIMG>
*/
//////////////////////////////////////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct {
int x, y;
unsigned char *pixel;
} PPMImage;
#define RGB_COMPONENT_COLOR 255
static PPMImage *readPPM(const char *filename)
{
FILE * fp;
PPMImage *img;
int rgb_comp_color;
int size = 0;
fp = fopen(filename, "a+");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char *buff;
unsigned char stuff[16];
int c;
int x,y;
buff = (unsigned char*) malloc(sizeof(unsigned char)*size +1);
memset(buff, '\0', sizeof(unsigned char)*size+1);
fgets(stuff, sizeof(stuff), fp);
if (stuff[0] != 'P' || stuff[1] != '3') {
fprintf(stderr, "Invalid image format (must be 'P3')\n");
exit(1);
}
//alloc memory form image
img = (PPMImage*)malloc(sizeof(PPMImage));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
c = getc(fp);
while (c == '#') {
while (getc(fp) != '\n') ;
c = getc(fp);
}
ungetc(c, fp);
if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);
}
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}
if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
fprintf(stderr, "'%s' does not have 8-bits components\n",filename);
exit(1);
}
//printf("x: %d y: %d\n", img->x, img->y);
unsigned char buffer[1024];
memset(buffer,0,1024);
fgets(buffer,1024,fp);
fread(buff, 1, size, fp);
img->pixel = buff;
/*
for(int h = 0; h < 20; h++)
{
printf("%c", buff2[h]);
}
printf("%s", buff2);
*/
fclose(fp);
return img;
}
void writePPM(const char *filename, unsigned char * img, int x, int y)
{
FILE *fp;
//open file for output
fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
//write the header file
//image format
fprintf(fp, "P3\n");
//comments
// fprintf(fp, "# Created by %s\n",CREATOR);
//image size
fprintf(fp, "%d %d\n",x,y);
// rgb component depth
fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);
// pixel pixel
fwrite(img,1, strlen(img), fp);
fclose(fp);
}
//unsigned char * embBits(PPMImage *img, int messageLen, unsigned char*msgOne, unsigned char *encMsg)
int embBits(PPMImage *img, int messageLen, unsigned char*msgOne, int embLen)
{
//int count = 2;
int embCount = 0;
int count = 0;
unsigned char *eMsg;
unsigned char byte;
int mask;
unsigned char update;
unsigned char flipOne = 0x01; //0x01
unsigned char flipZero = 0xFE; //0x00
for(int j = 0; j < messageLen; j++)
{
byte = msgOne[j];
//encMsg[j] = byte;
for(int k=7; 0 < k; k--)
{
update = byte;
update = update & (1<<k);
//printf("pixel:%c\n", img->pixel[count]);
//printf("pixel+1:%c\n", img->pixel[count+1]);
// printf("pixel+2:%c\n", img->pixel[count+2]);
if(update == 0)
{
// if i see 1 |=
// if i see a 0 &=
//img->pixel[count] = img->pixel[count] &= flipZero;
img->pixel[count+2] &= flipZero;
}
else
{
//flip bit
//red
//check LSB and FLIP
// img->pixel[count] = img->pixel[count] |= flipOne;
img->pixel[count+2] |= flipOne;
}
//mask--;
//eMsg[count] = img->pixel[count];
//printf("count: %d\n", count);
count = count + 3;
}
// eMsg[j] = byte;
}
//return encMsg = eMsg;
//unsigned char *yes = "sucess";
/*
for(int a = 0; a < messageLen; a++)
{
printf("pixel: %c", img->pixel[a]);
printf("msg: %c\n", eMsg[a]);
// eMsg[a] = img->pixel[a];
}
*/
embCount = count;
return embLen = embCount;
}
int main(int argc, char **argv){
int messageLen;
int i = 0;
PPMImage *img;
int size = 0;
FILE * fp;
int testSize;
fp = fopen(argv[4], "a+");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char *buff;
buff = (unsigned char*) malloc(sizeof(unsigned char)*size +1);
memset(buff, '\0', sizeof(unsigned char)*size+1);
fread(buff, 1, size, fp);
fclose(fp);
// printf("text encryption: %s\n", buff);
testSize = strlen(buff);
// printf("Size of text %d\n", testSize);
messageLen = strlen(buff);
img = readPPM(argv[2]);
/*
int testing = strlen(img->pixel);
for (int f=0;f<6;f++)
{
//f2 = 1
//f3 = 6
printf("%c", img->pixel[f]);
}
*/
// printf("%c \n", img->pixel[2]);
// printf("%c \n", img->pixel[5]);
printf("\n");
// unsigned char * encMsg;
int encMsg = 0;
encMsg = embBits(img, messageLen, buff, encMsg);
// printf("cipher msg:%s\n", img->pixel);
printf("message length: %d\n", messageLen);
// printf("cipher msg length: %d\n", encMsg);
writePPM(argv[6], img->pixel, img->x, img->y);
printf("Please press enter to complete\n");
getchar();
}
I don't know what you are doing specifically with your file and assigning each bit to a position in an array but you can print binary sequences stored in a unsigned int. Try using something like this...
#include <stdio.h>
int main() {
unsigned int arr[] = {00110110, 00111100, 10111011};
int i = sizeof(arr)/sizeof(arr[0]);
while(i-->0) {
printf("%c, ", arr[i]);
}
printf("\n");
}
You can use bit operations to gather these bits into a byte.
#include <stdio.h>
#define BYTE_LENGTH 8
#if 1
/* MSB is in data[0], LSB is in data[BYTE_LENGTH - 1] */
int arrayToChar(const int data[]) {
int c = 0;
int i;
for (i = 0; i < BYTE_LENGTH; i++) {
if (data[i]) c |= (1 << (BYTE_LENGTH - 1 - i));
}
return c;
}
#else
/* LSB is in data[0], MSB is in data[BYTE_LENGTH - 1] */
int arrayToChar(const int data[]) {
int c = 0;
int i;
for (i = 0; i < BYTE_LENGTH; i++) {
if (data[i]) c |= (1 << i);
}
return c;
}
#endif
int main(void) {
int data[8] = {0, 0, 1, 1, 0, 0, 0, 0};
int c = arrayToChar(data);
printf("%d %c\n", c, c);
return 0;
}
If you want to produce one byte from 7 bits, change BYTE_LENGTH to 7.
If you want to deal with long sequence of bits, apply arrayToChar repeatedly with changing the (address of) first element to be passed.

How to convert ascii string to binary?

I'm trying to convert an ascii string to a binary string in C. I found this example Converting Ascii to binary in C but I rather not use a recursive function. I tried to write an iterative function as opposed to a recursive function, but the binary string is missing the leading digit. I'm using itoa to convert the string, however itoa is a non standard function so I used the implementation from What is the proper way of implementing a good "itoa()" function? , the one provided by Minh Nguyen.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int32_t ascii_to_binary(char *input, char **out, uint64_t len)
{
uint32_t i;
uint32_t str_len = len * 8;
if(len == 0)
{
printf("Length argument is zero\n");
return (-1);
}
(*out) = malloc(str_len + 1);
if((*out) == NULL)
{
printf("Can't allocate binary string: %s\n", strerror(errno));
return (-1);
}
if(memset((*out), 0, (str_len)) == NULL)
{
printf("Can't initialize memory to zero: %s\n", strerror(errno));
return (-1);
}
for(i = 0; i < len; i++)
itoa((int32_t)input[i], &(*out)[(i * 8)], 2);
(*out)[str_len] = '\0';
return (str_len);
}
int main(void)
{
int32_t rtrn = 0;
char *buffer = NULL;
rtrn = ascii_to_binary("a", &buffer, 1);
if(rtrn < 0)
{
printf("Can't convert string\n");
return (-1);
}
printf("str: %s\n", buffer);
return (0);
}
I get 1100001 for ascii character a, but I should get 01100001, so how do I convert the ascii string to the whole binary string?
You could change the for loop to something like this:
for(i = 0; i < len; i++) {
unsigned char ch = input[i];
char *o = *out + 8 * i;
int b;
for (b = 7; b >= 0; b--)
*o++ = (ch & (1 << b)) ? '1' : '0';
}
or similar:
for(i = 0; i < len; i++) {
unsigned char ch = input[i];
char *o = &(*out)[8 * i];
unsigned char b;
for (b = 0x80; b; b >>= 1)
*o++ = ch & b ? '1' : '0';
}
This program gets and integer ( which contains 32 bits ) and converts it to binary, Work on it to get it work for ascii strings :
#include <stdio.h>
int main()
{
int n, c, k;
printf("Enter an integer in decimal number system\n");
scanf("%d", &n);
printf("%d in binary number system is:\n", n);
for (c = 31; c >= 0; c--)
{
k = n >> c;
if (k & 1)
printf("1");
else
printf("0");
}
printf("\n");
return 0;
}
Best just write a simple function to do this using bitwise operators...
#define ON_BIT = 0x01
char *strToBin(char c) {
static char strOutput[10];
int bit;
/*Shifting bits to the right, but don't want the output to be in reverse
* so indexing bytes with this...
*/
int byte;
/* Add a nul at byte 9 to terminate. */
strOutput[8] = '\0';
for (bit = 0, byte = 7; bit < 8; bit++, byte--) {
/* Shifting the bits in c to the right, each time and'ing it with
* 0x01 (00000001).
*/
if ((c >> bit) & BIT_ON)
/* We know this is a 1. */
strOutput[byte] = '1';
else
strOutput[byte] = '0';
}
return strOutput;
}
Something like that should work, there's loads of ways you can do it. Hope this helps.

Bit shifting results in negative number

I'm working on an assignment that deals with compression and decompression. More specifically, a variation of run-length encoding (9-bit blocks). The issue I am having deals with the sign of the "type" bit. I am able to acquire the desired bit, however, in the cases that the bit should be a 1, my printf returns -1. This would lead me to believe that I am not doing something correct in my bit shifting, but I am unaware as to what that might be.
void bitShift(char * mostFreq, unsigned char * byteBuf, int byteCount) {
char type;
int typels = 0;
int typers = 7;
int i = 0;
for(i = 0; i < byteCount - 1; i++) {
type = byteBuf[i];
printf("type before = %d\t", (unsigned int)type);
type = type << typels;
type = type >> typers;
typels++;
printf("type after = %d\n", (unsigned int)type);
}/*End for i*/
for(i = 0; i < byteCount; i++)
byteBuf[i] = 0;
}/*End bitShift*/
void decompressFile(char * mostFreq) {
unsigned char byteBuf[9] = { 0 };
int num, byteCount, i;
num = 0; byteCount = 0; i = 0;
unsigned char buf;
while((num = read(0,&buf, 1)) > 0) {
byteBuf[byteCount] = buf;
byteCount++;
if(byteCount == 9) {/*Flush bytes if buffer is full*/
bitShift(mostFreq, byteBuf, byteCount);
for(i = 0; i < 9; i++) {
byteBuf[i] = 0;
}/*End for i*/
byteCount = 0;
}/*End if*/
}/*End while*/
if(num == 0) {/*If EOF*/
if(byteCount != 0) {/*Bits have not been flushed*/
bitShift(mostFreq, byteBuf, byteCount);
}/*End if*/
} else if(num < 0) {
perror("Read error");
exit(1);
}/*End else if*/
}/*End decompressFile*/
You problem is that you declared type as a plain char that, in your system seems to be a signed type.
So when you have for example 0x80, it is actually -128, a negative number, and when it is shifted to the right the sign bit is extended: 1 bit: 0xC0 (-64), 2 bits: 0xE0 (-32), ... 7 bits: 0xFF (-1).
Change it to unsigned char and done!

Parsing command line input string into char array

I am trying to write a C program where the input from command line argument is in the form 0x1234aabb.
This definitely comes in the program as a char *[].
Now, I want to store this input in the form of char a[]={0x12, 0x34, 0xaa, 0xbb}.
Please help.
If you know the string is always a fixed length (e.g. 10 characters as in your example), then you can split the string into four equal parts each three characters long (two for the digits and one for the terminator), and then use strtoul on each part. If the argument is less than ten characters, only fill in the relevant parts and keep the other as "00".
What I would firstly do is use strtoul with the base argument of 16 (hex) to parse the string as an integer. unsigned long is guaranteed to be at least 32-bits in size, so if all your numbers have 8 hexadecimal digits (4 bytes) it should be a suitable type.
Once you have your number, bit shift and bit-wise AND the number 4 times to extract each of the 4 bytes that make up the number. Here's an example:
#include <stdlib.h>
#include <stdio.h>
#define NUM_BYTES 4
int main(void)
{
char *input = "0x1234aabb";
unsigned long num = strtoul(input, NULL /* TODO: error checking */, 16);
unsigned char bytes[NUM_BYTES];
unsigned i;
printf("The number is: 0x%lx\n", num);
/* bytes[0] = LSB, bytes[NUM_BYTES - 1] = MSB */
for (i = 0; i < NUM_BYTES; i++) {
bytes[i] = (num >> 8*i) & 0xFF; /* byte = 8 bits, 0xFF = max byte value */
printf("Byte %u: 0x%x\n", i+1, bytes[i]);
}
return 0;
}
Output:
The number is: 0x1234aabb
Byte 1: 0xbb
Byte 2: 0xaa
Byte 3: 0x34
Byte 4: 0x12
Try something like this to parse input of an arbitrary length:
#include <stdio.h>
int main(int argc, char** argv)
{
char *input;
int len;
int num;
char *a;
int i;
int tmp;
if (argv < 2)
{
printf("No input specified!\n");
return 0;
}
input = argv[1]; // "0x1234aabb"
if (strncmpi(input, "0x", 2) != 0)
{
printf("Bad input!\n");
return 0;
}
printf("Input: %s\n", input);
input += 2;
len = strlen(input);
num = (len / 2) + (len % 2);
if (num < 1)
{
printf("Bad input!\n");
return 0;
}
printf("Number of bytes: %d\n", num);
a = (char*) calloc(num, sizeof(char));
if (a == NULL)
{
printf("Cannot allocate memory for bytes!\n");
return 0;
}
for (i = 0; i < num; ++i)
{
if (sscanf(input, "%2x", &tmp) != 1)
{
printf("Byte %d: Illegal byte value '%02s'\n", i+1, input);
break;
}
a[i] = (char) tmp;
printf("Byte %d: 0x%02x\n", i+1, a[i]);
input += 2;
}
free(a);
return 0;
}

Resources