how to correctly replace bytes with memset? - c

I need to patch first 23 bytes of 32 bytes randomly generated by the rand256 function but it seems memset isn't correctly patching.
0000000000000000000000C90F4094919B9FAE4616149C0FDC61E7C1F318E234
as you can see, memset added only 23 zeroes whereas I am expecting 46 zeroes.
Now I am wondering if there is something like zfill that can correctly fill 23 bytes with zeros.
union uint256_s
{
uint8_t i8[32];
uint16_t i16[16];
uint32_t i32[8];
uint64_t i64[4];
};
typedef union uint256_s uint256_t;
static uint256_t rand256(struct seed *seed)
{
seed->counter++;
return sha256(seed, sizeof(struct seed));
}
static uint256_t rand256_and_mask(struct seed *seed)
{
uint256_t r = rand256(seed);
memset(&r, 0x000, 23);
return r;
}
struct seed {
uint256_t seed;
uint128_t counter;
};
static inline uint256_t sha256(const void *data, size_t len)
{
secp256k1_sha256_t cxt;
secp256k1_sha256_initialize(&cxt);
secp256k1_sha256_write(&cxt, (uint8_t *)data, (int)len);
uint256_t res;
secp256k1_sha256_finalize(&cxt, (uint8_t *)&res);
return res;
}
static void *init_worker(void *arg)
{
struct seed *seed = make_seed();
size_t i = (size_t)arg;
for (size_t j = 0; j < OFFSET_MAX_ROW; j++)
{
int overflow = 0;
do
{
uint256_t x = rand256_and_mask(seed);
secp256k1_scalar_set_b32(&priv_offsets[j][i], x.i8 + 12, &overflow);
}
while (overflow);
secp256k1_gej_t tmp;
secp256k1_ecmult_gen(&cxt->ecmult_gen_ctx, &tmp, &priv_offsets[j][i]);
secp256k1_ge_set_gej(&offsets[j][i], &tmp);
}
free(seed);
putchar('.');
fflush(stdout);
return NULL;
}
how can I correctly patch first 23 bytes?

Long time ago I did C, but I'll try it anyway:
uint256_t r = rand256(seed);
Assuming that the called function returns NOT (!) an uint datatype of any kind but a char array of size 64, as this call sha256(seed, sizeof(struct seed)); can't return an uint because of hash literals, you need to use the correct datatype.
See: SO: 'Will a SHA256 hash always have 64 characters?'
Then change the memset line to this:
memset(&r, '0', 23);
Full code of function in question:
static uint256_t rand256_and_mask(struct seed *seed)
{
char r[] = rand256(seed);
memset(&r, '0', 23);
return r;
}

Related

Dynamically Populate Struct in C

Say you have a struct in C:
typedef struct ID_Info {
uint16_t model_number;
uint16_t serial_number;
uint16_t firmware_version;
} ;
ID_Info id_info;
Now, say I need to set each uint16 variable in this struct to the values of data received byte by byte. So for example, if I received the following bytes: 0x00, 0x11, 0x22, 0x33, 0x44 and 0x55 in some data array data[], I now need to set the values as follows:
id_info.model_number = data[1]*256 + data[0]; // 0x1100
id_info.serial_number = data[3]*256 + data[2]; // 0x3322;
id_info.firmware_version = data[5]*256 + data[4]; // 0x5544;
This is easy enough to hard code as shown above. However, I'd like to be able to do this without hard-coding values and iteratively if possible. Therefore, if I needed to add a variable to the struct, my code and loop would automatically know I need to iterate for two more bytes (assuming a unit16). So this loop would need to iterate foreach member in the struct. Furthermore, is there a way to infer the variable type to know how many bytes I need? Say I needed to add a uint8, and in this case the code could know I only need one byte.
So maybe the pseudo-code would look something like this:
int i = 0;
foreach(member in id_info)
if(member is uint8)
id_info.member = data[i];
i =+ 1;
else if (member is uint16)
id_info.member = data[i] + 256*data[i+1];
i =+ 2;
else
throw error
This way I could easily add and removed struct members without many changes to the code. Thanks in advance for any insight!
If it's not a performance issue (your sample data looks like it isn't), instead of a hard-coded structure with C types, you could define a structure where the type information is encoded, perhaps based on an enum, the name information as a string, and that along with a large enough value type.
The enum type might look like this:
typedef enum {
ui16, ui8
} Type;
One entry could be defined as:
struct entry {
Type type;
char *name;
long value;
};
It is assumed that long is large enough for the largest data type.
A small, self-contained C test program based on your example might then look like the following:
#include <stdio.h>
typedef enum {
ui16, ui8
} Type;
struct entry {
Type type;
char *name;
long value;
};
struct entry id_info[] = {
{ui16, "model_number", 0},
{ui16, "serial_number", 0},
{ui16, "firmware_version", 0}
};
int main(void) {
unsigned char data[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
int x = 0;
for (int i = 0; i < sizeof(id_info) / sizeof(id_info[0]); i++) {
struct entry *current = &id_info[i];
switch (current->type) {
case ui8:
current->value = data[x];
x++;
break;
case ui16:
current->value = data[x] + 256 * data[x + 1];
x += 2;
break;
}
}
//and now print it
for (int i = 0; i < sizeof(id_info) / sizeof(id_info[0]); i++) {
struct entry *current = &id_info[i];
switch (current->type) {
case ui8:
printf("uint8_t %s: %02lx\n", current->name, current->value);
break;
case ui16:
printf("uint16_t %s: %04lx\n", current->name, current->value);
break;
}
}
return 0;
}
The program would produce the following output on the debug console:
uint16_t model_number: 1100
uint16_t serial_number: 3322
uint16_t firmware_version: 5544
One way to do this is with preprocessor macros.
With this method, it is easy to add new elements. And, the import/export functions will be automatically updated.
#ifndef NOINC
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#endif
// define all struct members
#define ALLSTRUCT(_cmd) \
_cmd(uint16_t,"%u",model_number) \
_cmd(uint16_t,"%u",serial_number) \
_cmd(uint16_t,"%u",firmware_version)
// define symbol
#define SYMDEF(_typ,_fmt,_sym) \
_typ _sym;
// define struct
typedef struct ID_Info {
ALLSTRUCT(SYMDEF)
} ID_Info;
ID_Info id_info;
// deserialize
#define SYMIN(_typ,_fmt,_sym) \
do { \
str->_sym = *(_typ *) ptr; \
ptr += sizeof(_typ); \
} while (0);
// serialize
#define SYMOUT(_typ,_fmt,_sym) \
do { \
*(_typ *) ptr = str->_sym; \
ptr += sizeof(_typ); \
} while (0);
// print
#define SYMPRT(_typ,_fmt,_sym) \
printf(" " #_sym "=" _fmt " (%8.8X)\n",str->_sym,str->_sym);
// struct_out -- output struct to byte array
uint8_t *
struct_out(const ID_Info *str,uint8_t *ptr)
{
ALLSTRUCT(SYMOUT)
return ptr;
}
// struct_in -- input struct from byte array
const uint8_t *
struct_in(ID_Info *str,const uint8_t *ptr)
{
ALLSTRUCT(SYMIN)
return ptr;
}
// struct_prt -- print struct to byte array
void
struct_prt(const ID_Info *str)
{
printf("struct_prt:\n");
ALLSTRUCT(SYMPRT)
}
// prtu8 -- print byte array
void
prtu8(const uint8_t *ptr,size_t count,const char *sym)
{
printf("%s:",sym);
for (size_t idx = 0; idx < count; ++idx)
printf(" %2.2X",ptr[idx]);
printf("\n");
}
int
main(void)
{
uint8_t data_in[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
uint8_t data_out[sizeof(data_in)];
// show original byte array
prtu8(data_in,sizeof(data_in),"data_in");
// import data into struct
struct_in(&id_info,data_in);
// show struct values
struct_prt(&id_info);
// export data from struct
struct_out(&id_info,data_out);
// show exported byte array
prtu8(data_out,sizeof(data_out),"data_out");
// reimport the struct data
struct_in(&id_info,data_out);
// show struct data
struct_prt(&id_info);
return 0;
}
Here is the [redacted] preprocessor output:
typedef struct ID_Info {
uint16_t model_number;
uint16_t serial_number;
uint16_t firmware_version;
} ID_Info;
ID_Info id_info;
uint8_t *
struct_out(const ID_Info * str, uint8_t * ptr)
{
do {
*(uint16_t *) ptr = str->model_number;
ptr += sizeof(uint16_t);
} while (0);
do {
*(uint16_t *) ptr = str->serial_number;
ptr += sizeof(uint16_t);
} while (0);
do {
*(uint16_t *) ptr = str->firmware_version;
ptr += sizeof(uint16_t);
} while (0);
return ptr;
}
const uint8_t *
struct_in(ID_Info * str, const uint8_t * ptr)
{
do {
str->model_number = *(uint16_t *) ptr;
ptr += sizeof(uint16_t);
} while (0);
do {
str->serial_number = *(uint16_t *) ptr;
ptr += sizeof(uint16_t);
} while (0);
do {
str->firmware_version = *(uint16_t *) ptr;
ptr += sizeof(uint16_t);
} while (0);
return ptr;
}
void
struct_prt(const ID_Info * str)
{
printf("struct_prt:\n");
printf(" " "model_number" "=" "%u" " (%8.8X)\n", str->model_number, str->model_number);
printf(" " "serial_number" "=" "%u" " (%8.8X)\n", str->serial_number, str->serial_number);
printf(" " "firmware_version" "=" "%u" " (%8.8X)\n", str->firmware_version, str->firmware_version);
}
void
prtu8(const uint8_t * ptr, size_t count, const char *sym)
{
printf("%s:", sym);
for (size_t idx = 0; idx < count; ++idx)
printf(" %2.2X", ptr[idx]);
printf("\n");
}
int
main(void)
{
uint8_t data_in[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
uint8_t data_out[sizeof(data_in)];
prtu8(data_in, sizeof(data_in), "data_in");
struct_in(&id_info, data_in);
struct_prt(&id_info);
struct_out(&id_info, data_out);
prtu8(data_out, sizeof(data_out), "data_out");
struct_in(&id_info, data_out);
struct_prt(&id_info);
return 0;
}
Here is the test program output:
data_in: 00 11 22 33 44 55
struct_prt:
model_number=4352 (00001100)
serial_number=13090 (00003322)
firmware_version=21828 (00005544)
data_out: 00 11 22 33 44 55
struct_prt:
model_number=4352 (00001100)
serial_number=13090 (00003322)
firmware_version=21828 (00005544)

Valgrind memcpy Invalid write of size 8 (uintptr_t *)

I have an issue with memcpy and valgrind, telling me about an Invalid write of size 8.
I got to the point of figuring out where the faulty code is, but I have no clue as to why it is faulty...
I'm aware that there are other questions regarding that, but they don't help me really.
The following is an excerpt of the most important bits of my approach on a somewhat "universal" stack, when my regular value would be of type uintptr_t.
Here are two defines that I used below:
// default stack batch size
#define STACK_BATCH_DEFAULT 8
// size of one value in the stack
#define STACK_SIZEOF_ONE sizeof(uintptr_t)
The structure of the stack is as follows:
typedef struct Stack
{
size_t count; // count of values in the stack
size_t size; // size of one value in bytes
size_t alloced; // allocated count
uintptr_t *value; // the values
int batch; // memory gets allocated in those batches
}
Stack;
I have an initialization function for the stack:
bool stack_init(Stack *stack, size_t size, int batch)
{
if(!stack) return false;
stack->batch = batch ? batch : STACK_BATCH_DEFAULT;
stack->size = size;
stack->count = 0;
stack->value = 0;
stack->alloced = 0;
return true;
}
Then the stack_push function, where valgrind throws the error Invalid write of size 8:
bool stack_push(Stack *stack, uintptr_t *value)
{
if(!stack || !value) return false;
// calculate required amount of elements
size_t required = stack->batch * (stack->count / stack->batch + 1);
// allocate more memory if we need to
if(required > stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
// set the value
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(stack->value + stack->size * stack->count, value, stack->size); // <--- valgrind throws the error here
}
else
{
stack->value[stack->count] = *value;
}
// increment count
stack->count++;
return true;
}
Then in my program I'm calling the functions as follows:
Stack stack = {0};
stack_init(&stack, sizeof(SomeStruct), 0);
/* ... */
SomeStruct push = { // this is a struct that is larger than STACK_SIZEOF_ONE
.int_a = 0,
.int_b = 0,
.int_c = 0,
.id = 0,
.pt = pointer_to_struct, // it is a pointer to some other struct that was allocated beforehand
};
stack_push(&stack, (uintptr_t *)&push);
And with universal I meant that I can also have a regular stack:
Stack stack = {0};
stack_init(&stack, sizeof(uintptr_t), 0);
/* ... */
uintptr_t a = 100;
stack_push(&stack, &a);
Also, I'm open to hear general tips and advices if there are any things that should/could be improved :)
Edit: Below is a runnable code.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
// default stack batch size
#define STACK_BATCH_DEFAULT 8
// size of one value in the stack
#define STACK_SIZEOF_ONE sizeof(uintptr_t)
#define TESTCOUNT 10
#define MAX_BUF 16
typedef struct Stack
{
size_t count; // count of values in the stack
size_t size; // size of one value in bytes
size_t alloced; // allocated count
uintptr_t *value; // the values
int batch; // memory gets allocated in those batches
}
Stack;
typedef struct SomeStruct
{
size_t a;
size_t b;
size_t c;
size_t id;
char *str;
}
SomeStruct;
bool stack_init(Stack *stack, size_t size, int batch)
{
if(!stack) return false;
stack->batch = batch ? batch : STACK_BATCH_DEFAULT;
stack->size = size;
stack->count = 0;
stack->value = 0;
stack->alloced = 0;
return true;
}
bool stack_push(Stack *stack, uintptr_t *value)
{
if(!stack || !value) return false;
// calculate required amount of elements
size_t required = stack->batch * (stack->count / stack->batch + 1);
// allocate more memory if we need to
if(required > stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
// set the value
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(stack->value + stack->size * stack->count, value, stack->size); // <--- valgrind throws the error here
}
else
{
stack->value[stack->count] = *value;
}
// increment count
stack->count++;
return true;
}
bool stack_pop(Stack *stack, uintptr_t *value)
{
if(!stack) return false;
if(!stack->count) return false;
// decrement count of elements
stack->count--;
// return the value if we have an address
if(value)
{
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(value, stack->value + stack->size * stack->count, stack->size);
}
else
{
*value = stack->value[stack->count];
}
}
int required = stack->batch * (stack->count / stack->batch + 1);
if(required < stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
if(!stack->value) return false;
return true;
}
int main(void)
{
// initialize variables
bool valid = false;
Stack default_stack = {0};
Stack some_stack = {0};
// initialize stacks
stack_init(&default_stack, sizeof(uintptr_t), 0);
stack_init(&some_stack, sizeof(SomeStruct), 0);
// test default case - push
printf("Testing the default case, pushing...\n");
for(int i = 0; i < TESTCOUNT; i++)
{
uintptr_t push = i;
valid = stack_push(&default_stack, &push);
if(!valid) return -1;
}
// ...now pop
printf("Testing the default case, popping...\n");
do
{
uintptr_t pop = 0;
valid = stack_pop(&default_stack, &pop);
if(valid) printf("%llu,", pop);
}
while(valid);
printf("\n");
// test some case - push
printf("Testing some case, pushing...\n");
for(int i = 0; i < TESTCOUNT; i++)
{
// generate the push struct
SomeStruct push = {
.a = i * 10,
.b = i * 100,
.c = i * 1000,
.id = i,
.str = 0,
};
// allocate a string
push.str = malloc(MAX_BUF + 1);
snprintf(push.str, MAX_BUF, "%d", i);
// push
valid = stack_push(&some_stack, (uintptr_t *)&push);
if(!valid) return -1;
}
// ...now pop
printf("Testing some case, popping...\n");
do
{
SomeStruct pop = {0};
valid = stack_pop(&some_stack, (uintptr_t *)&pop);
if(valid)
{
printf("a=%d,b=%d,c=%d,id=%d,str=%s\n", pop.a, pop.b, pop.c, pop.id, pop.str);
free(pop.str);
}
}
while(valid);
printf("\n");
/* leave out free functions for this example.... */
return 0;
}
After hours I figured it out :D The mistake happened because I very rarely do pointer arithmetic... In short, I was assuming that it would always calculate with a byte.
Let's take a look at the lines containing:
memcpy(stack->value + stack->size * stack->count, value, stack->size);
...and break it down, so it is more readable. And also, I'll even add a handy dandy comment in it:
size_t offset = stack->size * stack->count; // offset in bytes
void *dest = stack->value + offset;
void *src = value;
memcpy(dest, src, stack->size);
Now the pro C-programmer should instantly spot the problem. It is with the calculation of stack->value + offset, where it should add offset in bytes but it is not, because the stack->value is of type uintptr_t * and not of type uint8_t *.
So to fix it, I replaced it with this line:
void *dest = (uint8_t *)stack->value + offset;
And the code works.

Convert void* from array of shorts (short*) to array of floats (float) in C

I have a struct that contains a void* in this void* is an array of shorts (short*) eg -6,-113, -110,...,n
I would like to convert all of those wonderful shorts to floating point. eg -6 --> -6.0000000
typedef struct datablock
{
int maxRows;
void *data;
} DataBlock;
// imagine *data points to a short* --> { -6, -113, -100, -126 }
static void Read(params here)
{
float *floatData;
data = (float *) DataBlock->data; // obvious fail here
// data will now look like --> { -1.Q#DEN00, -1.Q#ENV00, ..., n}
// i assume the compiler is not handling the conversion for me
// which is why the issue comes up
// **NOTE** Visual Studio 2013 Ultimate is the enviorment (windows 8)
}
typedef struct datablock
{
int maxRows;
void *data;
} DataBlock;
[...]
DataBlock db = ... <some init with shorts>;
DataBlock db_f = {db.maxRows, NULL};
db_f.data = malloc(db_f.maxRows * sizeof(float));
/* Add error checking here. */
for (size_t i = 0; i < db_f.maxRows; ++i)
{
*(((float *) db_f.data) + i) = *(((short *) db.data) + i);
}
/* Use db_f here. */
free(db_d.data); /* Always tidy up before leaving ... */
As proposed by Sylvain Defresne the body of the loop is easiser to read using temporary pointers:
for (
size_t i = 0,
short * src = db.data,
float * dst = db_f.data;
i < db_f.maxRows;
++i)
{
dst[i] = src[i];
}

Memory comparison causes system halt

I am working on a kernel module and I need to compare two buffers to find out if they are equivalent. I am using the memcmp function defined in the Linux kernel to do so. My first buffer is like this:
cache_buffer = (unsigned char *)vmalloc(4097);
cache_buffer[4096] = '/0';
The second buffer is from a page using the page_address() function.
page = bio_page(bio);
kmap(page);
write_buffer = (char *)page_address(page);
kunmap(page);
I have printed the contents of both buffers before hand and not only to they print correctly, but they also have the same content. So next, I do this:
result = memcmp(write_buffer, cache_buffer, 2048); // only comparing up to 2048 positions
This causes the kernel to freeze up and I cannot figure out why. I checked the implementation of memcmp and saw nothing that would cause the freeze. Can anyone suggest a cause?
Here is the memcmp implementation:
int memcmp(const void *cs, const void *ct, size_t count)
{
const unsigned char *su1, *su2;
int res = 0;
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
return res;
}
EDIT: The function causing the freeze is memcmp. When I commented it out, everything worked. Also, when I did I memcmp as follows
memcmp(write_buffer, write_buffer, 2048); //comparing two write_buffers
Everything worked as well. Only when I throw the cache_buffer into the mix is when I get the error. Also, above is a simplification of my actual code. Here is the entire function:
static int compare_data(sector_t location, struct bio * bio, struct cache_c * dmc)
{
struct dm_io_region where;
unsigned long bits;
int segno;
struct bio_vec * bvec;
struct page * page;
unsigned char * cache_data;
char * temp_data;
char * write_data;
int result, length, i;
cache_data = (unsigned char *)vmalloc((dmc->block_size * 512) + 1);
where.bdev = dmc->cache_dev->bdev;
where.count = dmc->block_size;
where.sector = location << dmc->block_shift;
printk(KERN_DEBUG "place: %llu\n", where.sector);
dm_io_sync_vm(1, &where, READ, cache_data, &bits, dmc);
length = 0;
bio_for_each_segment(bvec, bio, segno)
{
if(segno == 0)
{
page = bio_page(bio);
kmap(page);
write_data = (char *)page_address(page);
//kunmap(page);
length += bvec->bv_len;
}
else
{
page = bio_page(bio);
kmap(page);
temp_data = strcat(write_data, (char *)page_address(page));
//kunmap(page);
write_data = temp_data;
length += bvec->bv_len;
}
}
printk(KERN_INFO "length: %u\n", length);
cache_data[dmc->block_size * 512] = '\0';
for(i = 0; i < 2048; i++)
{
printk("%c", write_data[i]);
}
printk("\n");
for(i = 0; i < 2048; i++)
{
printk("%c", cache_data[i]);
}
printk("\n");
result = memcmp(write_data, cache_data, length);
return result;
}
EDIT #2: Sorry guys. The problem was not memcmp. It was the result of memcmp. When ever it returned a positive or negative number, the function that called my function would play with some pointers, one of which was uninitialized. I don't know why I didn't realize it before. Thanks for trying to help though!
I'm no kernel expert, but I would assume you need to keep this memory mapped while doing the comparison? In other words, don't call kunmap until after the memcmp is complete. I would presume that calling it before will result in write_buffer pointing to a page which is no longer mapped.
Taking your code in the other question, here is a rough attempt at incremental. Still needs some cleanup, I'm sure:
static int compare_data(sector_t location, struct bio * bio, struct cache_c * dmc)
{
struct dm_io_region where;
unsigned long bits;
int segno;
struct bio_vec * bvec;
struct page * page;
unsigned char * cache_data;
char * temp_data;
char * write_data;
int length, i;
int result = 0;
size_t position = 0;
size_t max_size = (dmc->block_size * 512) + 1;
cache_data = (unsigned char *)vmalloc(max_size);
where.bdev = dmc->cache_dev->bdev;
where.count = dmc->block_size;
where.sector = location << dmc->block_shift;
printk(KERN_DEBUG "place: %llu\n", where.sector);
dm_io_sync_vm(1, &where, READ, cache_data, &bits, dmc);
bio_for_each_segment(bvec, bio, segno)
{
// Map the page into memory
page = bio_page(bio);
write_data = (char *)kmap(page);
length = bvec->bv_len;
// Make sure we don't go past the end
if(position >= max_size)
break;
if(position + length > max_size)
length = max_size - position;
// Compare the data
result = memcmp(write_data, cache_data + position, length);
position += length;
kunmap(page);
// If the memory is not equal, bail out now and return the result
if(result != 0)
break;
}
cache_data[dmc->block_size * 512] = '\0';
return result;
}

Using MD5 in kernel space of Linux

I am trying to use the kernel space implementation of the md5 algorithm (md5.h and md5.c). It turns out that md5.h does not declare the functions found in md5.c, so I could not simply include md5.h into my c file. I also wanted to avoid altering md5.h to declare the functions, since that could have unintended consequences. Is there any other way to use md5 in kernel space?
Use Crypto API instead of rolling your own.
#include <crypto/hash.h>
bool md5_hash(char *result, char* data, size_t len){
struct shash_desc *desc;
desc = kmalloc(sizeof(*desc), GFP_KERNEL);
desc->tfm = crypto_alloc_shash("md5", 0, CRYPTO_ALG_ASYNC);
if(desc->tfm == NULL)
return false;
crypto_shash_init(desc);
crypto_shash_update(desc, data, len);
crypto_shash_final(desc, result);
crypto_free_shash(desc->tfm);
return true;
}
Beware, the code posted by wande chen will cause kernel heap corruption.
struct shash_desc *desc;
desc = kmalloc(sizeof(*desc), GFP_KERNEL);
desc->tfm = crypto_alloc_shash("md5", 0, CRYPTO_ALG_ASYNC);
This is because md5 engine will use memory past struct shash_desc for storing md5 context.
The correct way to allocate struct shash_desc can be found here.
*shash = crypto_alloc_shash(name, 0, 0);
size = sizeof(struct shash_desc) + crypto_shash_descsize(*shash);
*sdesc = kmalloc(size, GFP_KERNEL);
struct sdesc {
struct shash_desc shash;
char ctx[];
};
static struct sdesc *init_sdesc(struct crypto_shash *alg)
{
struct sdesc *sdesc;
int size;
size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
sdesc = kmalloc(size, GFP_KERNEL);
if (!sdesc)
return ERR_PTR(-ENOMEM);
sdesc->shash.tfm = alg;
return sdesc;
}
static int calc_hash(struct crypto_shash *alg,
const unsigned char *data, unsigned int datalen,
unsigned char *digest)
{
struct sdesc *sdesc;
int ret;
sdesc = init_sdesc(alg);
if (IS_ERR(sdesc)) {
pr_info("can't alloc sdesc\n");
return PTR_ERR(sdesc);
}
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
kfree(sdesc);
return ret;
}
static int do_md5(const unsigned char *data, unsigned char *out_digest)
{
struct crypto_shash *alg;
char *hash_alg_name = "md5";
unsigned int datalen = strlen(data); // remove the null byte
alg = crypto_alloc_shash(hash_alg_name, 0, 0);
if(IS_ERR(alg)){
pr_info("can't alloc alg %s\n", hash_alg_name);
return PTR_ERR(alg);
}
unsigned char hash[32];
calc_hash(alg, data, datalen, hash);
// Very dirty print of 8 first bytes for comparaison with sha256sum
printk(KERN_INFO "HASH(%s, %i): %02x%02x%02x%02x%02x%02x%02x%02x\n",
data, datalen, hash[0] & 0xFFu, hash[1] & 0xFFu, hash[2] & 0xFFu, hash[3] & 0xFFu, hash[4] & 0xFFu,
hash[5] & 0xFFu, hash[6] & 0xFFu, hash[7] & 0xFFu);
char c[3];
for (int i = 0; i < 16; i++)
{
sprintf( c, "%02x", hash[i] & 0xFFu);
memcpy(out_digest+i*2, c, 2);
}
crypto_free_shash(alg);
return 0;
}
tested.

Resources