I would like to optimize my code and avoid errors, I have this function that does the "work" but I think I can improve and avoid memory problems.
void function(char* message)
{
char * pointer;
unsigned char buffer[2048] = {0};
int buffer_len = 0;
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, message);
buffer_len = strlen(buffer);
memset(buffer, 0, sizeof(&buffer));
for(int i = 0, pointer = message; i < (buffer_len / 2); i++, pointer += 2)
{
sscanf(pointer, "%02hhX", &buffer[i]);
}
}
The idea of the function is to receive a string of this style "0123456789" and pass it to 0x01, 0x23, 0x45, ... in an unsigned char array. Any tip, good practice or improvement would be very useful.
The ussage is something like this:
function("0123456789");
In the function buffer ends like:
buffer[0] = 0x01
buffer[1] = 0x23
...
There are a few optimizations possible.
The biggest optimization comes from avoiding doing
2x memset and strcpy,
No need to:
// memset(buffer, 0, sizeof(buffer));
// strcpy(buffer, message);
// memset(buffer, 0, sizeof(&buffer));
which drastically simplifies the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(char* message)
{
unsigned char * pointer;
unsigned char buffer[2048]; // not needed = {0};
int buffer_half_len; // not needed = 0;
buffer_half_len = strlen(message)/2; // avoiding division in the for loop;
pointer = message;
for(int i = 0; i < buffer_half_len; i++, pointer += 2)
{
sscanf(pointer, "%02hhX", &buffer[i]);
printf("%02hhX\n", buffer[i] );
}
}
OUTPUT:
01
23
45
67
89
char * a= -80; // let supposed you get returned value( i represented in int) from whatever source.
unsigned char b = * a; // now b equal the complemntry of -80 which will be 176
std::cout << b ;
Related
I am seeing a potential overflow: streamBuffer is a struct object (part of the FreeRTOS lib) and upon executing the following line in OutputToSerial(), I see streamBuffer.xHead's value is set to an extremely large value even though it's not being modified at the time.
LONG_TO_STR(strData, txStr);
Note that I didn't have any issues when I called nRF24_ReadReg() multiple times before.
Also, often times I see that printf doesn't print the entire text that's being printed (prior to calling the time when I see a potential overflow) - instead misses on some chars.
Any way to get a better understanding of the cause? I don't see any hardfaults or anything to look in the registers...
For a reference, the following is the struct's definition:
typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
{
volatile size_t xTail; /* Index to the next item to read within the buffer. */
volatile size_t xHead; /* Index to the next item to write within the buffer. */
size_t xLength; /* The length of the buffer pointed to by pucBuffer. */
size_t xTriggerLevelBytes; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */
volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */
volatile TaskHandle_t xTaskWaitingToSend; /* Holds the handle of a task waiting to send data to a message buffer that is full. */
uint8_t *pucBuffer; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */
uint8_t ucFlags;
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */
#endif
} StreamBuffer_t;
// file.c
#define PRI_UINT64_C_Val(value) ((unsigned long) (value>>32)), ((unsigned long)value)
#define LONG_TO_STR(STR, LONG_VAL) (sprintf(STR, "%lx%lx", PRI_UINT64_C_Val(LONG_VAL)))
unsigned long long concatData(uint8_t *arr, uint8_t size)
{
long long unsigned value = 0;
for (uint8_t i = 0; i < size; i++)
{
value <<= 8;
value |= arr[i];
}
return value;
}
void nRF24_ReadReg(nrfl2401 *nrf, uint8_t reg, const uint8_t rxSize, uint8_t *rxBuffer, char *text)
{
uint8_t txBuffer[1] = {0};
uint8_t spiRxSize = rxSize;
if (reg <= nRF24_CMD_W_REG)
{
txBuffer[0] = nRF24_CMD_R_REG | (reg & nRF24_R_W_MASK);
spiRxSize++;
}
else
{
txBuffer[0] = reg;
}
nRF24_SendCommand(nrf, txBuffer, rxBuffer, spiRxSize);
OutputToSerial(txBuffer, rxBuffer, spiRxSize, text);
}
void OutputToSerial(uint8_t *writeBuffer, uint8_t *readBuffer, uint8_t size, char *text)
{
char strData[100] = {0}, rxStrData[100] = {0};
long long unsigned txStr = concatData(writeBuffer, size);
long long unsigned rxStr = concatData(readBuffer, size);
LONG_TO_STR(strData, txStr); // POTENTIAL ERROR.....!
LONG_TO_STR(rxStrData, rxStr);
char outputMsg[60] = {0};
strcpy(outputMsg, text);
strcat(outputMsg, ": 0x%s ----------- 0x%s\n");
printf (outputMsg, strData, rxStrData);
}
// main.c
StreamBufferHandle_t streamBuffer;
Perhaps other issues, yet the LONG_TO_STR(x) is simply a mess.
Consider the value 0x123400005678 would print as "12345678". That ref code is broken.
Yes its too bad code has long long yet no "%llx". Easy enough to re-write it all into a clean function.
//#define PRI_UINT64_C_Val(value) ((unsigned long) (value>>32)), ((unsigned long)value)
//#define LONG_TO_STR(STR, LONG_VAL) (sprintf(STR, "%lx%lx", PRI_UINT64_C_Val(LONG_VAL)))
#include <stdio.h>
#include <string.h>
#include <limits.h>
// Good for base [2...16]
void ullong_to_string(char *dest, unsigned long long x, int base) {
char buf[sizeof x * CHAR_BIT + 1]; // Worst case size
char *p = &buf[sizeof buf - 1]; // set to last element
*p = '\0';
do {
p--;
*p = "0123456789ABCDEF"[x % (unsigned) base];
x /= (unsigned) base;
} while (x);
strcpy(dest, p);
}
int main(void) {
char buf[100];
ullong_to_string(buf, 0x123400005678, 16); puts(buf);
ullong_to_string(buf, 0, 16); puts(buf);
ullong_to_string(buf, ULLONG_MAX, 16); puts(buf);
ullong_to_string(buf, ULLONG_MAX, 10); puts(buf);
return 0;
}
Output
123400005678
0
FFFFFFFFFFFFFFFF
18446744073709551615
I have wrote a c code which takes the input value of key and message makes call to openssl hmac functions and generate result of mac code.
Input values are collected from NIST Test Vectors
#define KEY_SIZE 11 // in bytes
#define MSG_SIZE 129 // in bytes
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
void str2hex(char *, char*, int);
int main() {
char *key, *msg;
unsigned char keyy[KEY_SIZE], msgt[MSG_SIZE], temp[4];
unsigned char* result;
unsigned int i, len = 20,Tlen = 10;
key = "";//values specified below
msg ="";//values specified below
/*CONVERT STRING TO HEX DIGITS - KEY*/
str2hex(key, keyy, KEY_SIZE);
//CONVERT STRING TO HEX DIGITS - MSG*//
str2hex(msg, msgt, MSG_SIZE);
result = (unsigned char*)malloc(sizeof(char) * len);
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, keyy, strlen(keyy), EVP_sha1(), NULL);
HMAC_Update(&ctx, (unsigned char*)&msgt, strlen(msgt));
HMAC_Final(&ctx, result, &len);
HMAC_CTX_cleanup(&ctx);
printf("HMAC digest: ");
for (i = 0; i < Tlen; i++)
printf("%02x", result[i]);
printf("\n");
free(result);
return 0;
}
//===================== string to hex conversion
================================//
void str2hex(char *str, char *hex, int len) {
int tt, ss;
unsigned char temp[4];
for (tt = 0, ss = 0; tt < len, ss < 2 * len; tt++, ss += 2) {
temp[0] = '0';
temp[1] = 'x';
temp[2] = str[ss];
temp[3] = str[ss + 1];
hex[tt] = (int) strtol(temp, NULL, 0);
}
}
//---------------------------------------------------------------------------------//
The first input given:
Key = 82f3b69a1bff4de15c33
Msg = fcd6d98bef45ed6850806e96f255fa0c8114b72873abe8f43c10bea7c1df706f10458e6d4e1c9201f057b8492fa10fe4b541d0fc9d41ef839acff1bc76e3fdfebf2235b5bd0347a9a6303e83152f9f8db941b1b94a8a1ce5c273b55dc94d99a171377969234134e7dad1ab4c8e46d18df4dc016764cf95a11ac4b491a2646be1
Output generated:
HMAC digest: 1ba0e66cf72efc349207
Nist_Mac = 1ba0e66cf72efc349207
It matches so success
But for the Second input
Key = 4766e6fe5dffc98a5c50
Msg = d68b828a153f5198c005ee36c0af2ff92e84907517f01d9b7c7993469df5c21078fa356a8c9715ece2414be94e10e547f32cbb8d0582523ed3bb0066046e51722094aa44533d2c876e82db402fbb00a6c2f2cc3487973dfc1674463e81e42a39d9402941f39b5e126bafe864ea1648c0a5be0a912697a87e4f8eabf79cbf130e
Output generated:
HMAC digest: ca96f112a79882074b63
Nist_Mac = 007e4504041a12f9e345
Its failing.If any one could check my code and kindly let me know what am i doing wrong it will be really helpfull.
You have two issues here.
The first is that you're using strlen on an array of characters that may contain a null byte. Since this function counts the number of bytes until it find a null byte, you won't get what you expect if your array contains a null byte (as is the case for your second example).
Instead of using strlen on the byte array to determine the length, use the actual length of the data. Since you're converting a string containing hex digits to bytes, the length of the byte array is half the length of the input string.
HMAC_Init_ex(&ctx, keyy, strlen(key)/2, EVP_sha1(), NULL);
HMAC_Update(&ctx, msgt, strlen(msg)/2);
Note also that you should pass msgt to HMAC_Update, not &msgt, as the latter is a pointer to an array.
The second issue is in your str2hex function. When you construct temp, you don't have enough space for a terminating null byte. This causes strtol, which expects a null-terminated string, to read past the end of the array. This invokes undefined behavior.
In this particular case you're "lucky" that it works, as the byte in memory that follows temp happens to contain either a null byte or a non-digit. You can't however depend on this behavior. Fix this by making temp one byte longer and explicitly setting that byte to 0. And while you're at it, you should also fix the signed / unsigned mismatch in your function arguments and change the type of temp to an unsigned char array.
void str2hex(char *, unsigned char*, int);
...
void str2hex(char *str, unsigned char *hex, int len) {
int tt, ss;
char temp[5];
for (tt = 0, ss = 0; tt < len, ss < 2 * len; tt++, ss += 2) {
temp[0] = '0';
temp[1] = 'x';
temp[2] = str[ss];
temp[3] = str[ss + 1];
temp[4] = 0;
hex[tt] = strtol(temp, NULL, 0);
}
}
At byte position 58 in the message, you have a 0x00 byte (null). Since you're doing an strlen(msgt), this results in 58 instead of 128. Excerpt from the documentation (emphasis mine):
The C library function size_t strlen(const char *str) computes the length of the string str up to, but not including the terminating null character.
Just use the proper length of the message and don't use string operations on char arrays that do not contain printable bytes.
I am trying to print out byte array as one byte at the time in hexadecimal format within for loop like this:
int my_function(void *data)
{
obuf = (str*)data;
int i;
for (i = 0; i < obuf->len; i++)
{
printf("%02X:", obuf->s[i]);
}
return 0;
}
str in this case is structure from Kamailio - review at http://www.asipto.com/pub/kamailio-devel-guide/#c05str
The expected output:
80:70:0F:80:00:00:96:00:1D:54:7D:7C:36:9D:1B:9A:20:BF:F9:68:E8:E8:E8:F8:68:98:E8:EE:E8:B4:7C:3C:34:74:74:64:74:69:2C:5A:3A:3A:3A:3A:3A:3A:32:24:43:AD:19:1D:1D:1D:1D:13:1D:1B:3B:60:AB:AB:AB:AB:AB:0A:BA:BA:BA:BA:B0:AB:AB:AB:AB:AB:0A:BA:BA:BA:BA:B9:3B:61:88:43:
What I am getting:
FFFFFF80:70:0F:FFFFFF80:00:00:FFFFFF96:00:1D:54:7D:7C:36:FFFFFF9D:1B:FFFFFF9A:20:FFFFFFBF:FFFFFFF9:68:FFFFFFE8:FFFFFFE8:FFFFFFE8:FFFFFFF8:68:FFFFFF98:FFFFFFE8:FFFFFFEE:FFFFFFE8:FFFFFFB4:7C:3C:34:74:74:64:74:69:2C:5A:3A:3A:3A:3A:3A:3A:32:24:43:FFFFFFAD:19:1D:1D:1D:1D:13:1D:1B:3B:60:FFFFFFAB:FFFFFFAB:FFFFFFAB:FFFFFFAB:FFFFFFAB:0A:FFFFFFBA:FFFFFFBA:FFFFFFBA:FFFFFFBA:FFFFFFB0:FFFFFFAB:FFFFFFAB:FFFFFFAB:FFFFFFAB:FFFFFFAB:0A:FFFFFFBA:FFFFFFBA:FFFFFFBA:FFFFFFBA:FFFFFFB9:3B:61:FFFFFF88:43:
Could someone please help me understand why there are some of bytes prefixed with FFFFFF and other aren't?
Thanks in advance
Looks like obuf->s[i] returns a signed value
You would need to cast it to a unsigned value to get rid of the FFF.. at start.
printf("%02X:", (unsigned char)(obuf->s[i]));
The problem appears with chars that have the most significant bit set (which are out of the proper pure ASCII set range 0-127). The key point is to consider chars as unsigned.
printf("%02X:", (unsigned char)(obuf->s[i]));
See this simple compilable repro C code:
#include <stdio.h>
#include <string.h>
struct _str {
char* s; /* pointer to the beginning of string (char array) */
int len; /* string length */
};
typedef struct _str str;
int my_function(void *data)
{
str* obuf;
int i;
obuf = (str*)data;
for (i = 0; i < obuf->len; i++) {
printf("%02X:", (unsigned char)(obuf->s[i]));
}
return 0;
}
int main(void)
{
char buf[2];
str s;
/* Test with ordinary ASCII string */
s.s = "Hello";
s.len = strlen(s.s);
my_function(&s);
printf("\n");
/* Test with char values with most significant bit set */
buf[0] = 0xF1;
buf[1] = 0x00;
s.s = buf;
s.len = 1;
my_function(&s);
return 0;
}
With MSVC, I get this output:
48:65:6C:6C:6F:
F1:
How do I work with msgpack_pack_raw and msgpack_pack_raw_body to send an unsigned char array to more importantly, how to retrieve (unpack) it?
What I have done is as follows:
msgpack_sbuffer* buffer = msgpack_sbuffer_new();
msgpack_packer* pk = msgpack_packer_new(buffer, msgpack_sbuffer_write);
msgpack_sbuffer_clear(buffer);
msgpack_pack_array(pk, 10);
unsigned char a[10] = "0123456789";
msgpack_pack_raw(pk, 10);
msgpack_pack_raw_body(pk,a,10);
and in the receiver part I have:
msgpack_unpacked msg;
msgpack_unpacked_init(&msg);
msgpack_unpack_next(&msg, buffer->data, buffer->size, NULL);
msgpack_object obj = msg.data;
msgpack_object* p = obj.via.array.ptr;
int length = (*p).via.raw.size;
IDPRINT(length);
unsigned char* b = (unsigned char*) malloc(length);
memcpy(b,(*p).via.raw.ptr,length);
But it throws seg fault when executing "int length = (*p).via.raw.size;".
Any idea why?
Any idea why?
This is because msgpack_pack_array(pk, 10); is not required here, since you pack your data as a raw buffer of a given size. In other words msgpack_pack_raw and msgpack_pack_raw_body are sufficient.
At unpack time, you must access its fields as follow:
length: obj.via.raw.size
data: obj.via.raw.ptr
see: msgpack_object_raw in object.h.
Here's a recap of how to proceed:
#include <stdio.h>
#include <assert.h>
#include <msgpack.h>
int main(void) {
unsigned char a[10] = "0123456789";
char *buf = NULL;
int size;
/* -- PACK -- */
msgpack_sbuffer sbuf;
msgpack_sbuffer_init(&sbuf);
msgpack_packer pck;
msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write);
msgpack_pack_raw(&pck, 10);
msgpack_pack_raw_body(&pck, a, 10);
size = sbuf.size;
buf = malloc(sbuf.size);
memcpy(buf, sbuf.data, sbuf.size);
msgpack_sbuffer_destroy(&sbuf);
/* -- UNPACK -- */
unsigned char *b = NULL;
int bsize = -1;
msgpack_unpacked msg;
msgpack_unpacked_init(&msg);
if (msgpack_unpack_next(&msg, buf, size, NULL)) {
msgpack_object root = msg.data;
if (root.type == MSGPACK_OBJECT_RAW) {
bsize = root.via.raw.size;
b = malloc(bsize);
memcpy(b, root.via.raw.ptr, bsize);
}
}
/* -- CHECK -- */
assert(bsize == 10);
assert(b != NULL);
for (int i = 0; i < bsize; i++)
assert(b[i] == a[i]);
printf("ok\n");
free(buf);
free(b);
return 0;
}
This is my code (the errors checking were deliberately omitted for code readability):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gcrypt.h>
#define GCRYPT_VERSION "1.5.0"
#define GCRY_CIPHER GCRY_CIPHER_AES128
int main(void){
if(!gcry_check_version(GCRYPT_VERSION)){
fputs("libgcrypt version mismatch\n", stderr);
exit(2);
}
gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN);
gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0);
gcry_control(GCRYCTL_RESUME_SECMEM_WARN);
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
int algo = -1;
size_t i;
const char *name = "aes128";
char plain_text[16] = {0x80};
char key[16] = {0};
char iniVector[16] = {0};
size_t txtLenght = strlen(plain_text);
char *encBuffer = malloc(txtLenght);
gcry_cipher_hd_t hd;
algo = gcry_cipher_map_name(name);
size_t blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER);
size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER);
gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_setkey(hd, key, keyLength);
gcry_cipher_setiv(hd, iniVector, blkLength);
gcry_cipher_encrypt(hd, encBuffer, txtLenght, plain_text, txtLenght);
printf("encBuffer = ");
for(i = 0; i < txtLenght; i++){
printf("%02x", (unsigned char) encBuffer[i]);
}
printf("\n");
gcry_cipher_close(hd);
free(encBuffer);
return 0;
}
Expected result:
KEY = 00000000000000000000000000000000
IV = 00000000000000000000000000000000
PLAINTEXT = 80000000000000000000000000000000
CIPHERTEXT = 3ad78e726c1ec02b7ebfe92b23d9ec34
My result:
KEY = 00000000000000000000000000000000
IV = 00000000000000000000000000000000
PLAINTEXT = 80000000000000000000000000000000
CIPHERTEXT = 42
Why i got this output? What am I doing wrong?
You are using ASCII values but the AES test vectors are given as hexadecimal values.
Try with hex values instead (the remaining values of the array are initialized by 0 in C):
char plain_text[16] = {0x80};
char key[16] = {0};
char iniVector[16] = {0};
size_t txtLenght = sizeof plain_text;