Write Error: bad address on writing encrypted data to wrapper filesystem - encryption

I am implementing a simple caeser cipher on WrapFS to store encrypted data and decrypt while reading. For that purpose I made minor changes to wrapfs_read() and wrapfs_write() functions provided in the source code to encrypt and decypt the data. My decryption is working fine, but due to my encryption code I am getting an error on write as follows bash: echo: write error: bad address. Any help regarding handling it would be really appreciated.
void caeser_encrypt(char __user *encrypted, size_t count)
{
int i;
for(i=0;i<(unsigned int)count;i++)
encrypted[i]=encrypted[i]+3;
printk(KERN_INFO "%s",encrypted);
return;
}
static ssize_t wrapfs_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int err = 0;
struct file *lower_file;
struct dentry *dentry = file->f_path.dentry;
char *encrypted = NULL;
lower_file = wrapfs_lower_file(file);
/*Added by me*/
encrypted=kmalloc(sizeof(buf),GFP_USER);
memcpy(encrypted,buf,count);
printk(KERN_INFO "%d %d",(int)sizeof(buf), (int)count);
caeser_encrypt(encrypted,count);
err = vfs_write(lower_file, encrypted, count, ppos);
/*Added by me*/
//err = vfs_write(lower_file, buf, count, ppos);
/* update our inode times+sizes upon a successful lower write */
if (err >= 0) {
fsstack_copy_inode_size(dentry->d_inode,
lower_file->f_path.dentry->d_inode);
fsstack_copy_attr_times(dentry->d_inode,
lower_file->f_path.dentry->d_inode);
}
/*Added by me*/
kfree(encrypted);
return err;
}

I would say that "const char __user *buf" is user space address and vfs_write expects user space address and you are passing kernel space address to it. Also you cannot directly copy user space address to kernel space address. You can try using copy_from_user and copy_to_user functions. I hope you are aware that caeser cipher is insecure.

Related

How to use read() to get the adress of a pointer?

I have 2 programs communicating with each other through a fifo, one's the writer the other's the reader.
The writer sends a pointer to a struct containing information.
The reader should receive the pointer and be able to see the information inside the struct.
Header file:
typedef struct req{
int _code;
char _client_pipe[PIPENAME];
char _box_name[BOXNAME];
} request;
/*writes to pipe tx a pointer with information*/
void send_request(int tx, request *r1) {
ssize_t ret = write(tx, &r1, sizeof(r1));
if (ret < 0) {
fprintf(stdout, "ERROR: %s\n", ERROR_WRITING_PIPE);
exit(EXIT_FAILURE);
}
}
/*Returns a pointer to a struct containing the request*/
request *serialize(int code, char* client_pipe, char* box_name){
request *r1 = (request*) malloc(sizeof(request));
r1->_code = code;
strcpy(r1->_client_pipe, client_pipe);
strcpy(r1->_box_name, box_name);
return r1;
}
Program writer:
int main(int argc, char **argv){
(void *) argc; // in my program i used argc, but for this problem it's not important hence why the //typecast to void
char register_pipe[PIPENAME];
char personal_pipe[PIPENAME];
char box_name[BOXNAME];
strcpy(register_pipe, argv[1]);
strcpy(personal_pipe, argv[2]);
strcpy(box_name, argv[3]);
int reg_pipe = open(register_pipe, O_WRONLY);
if (reg_pipe == -1) {
fprintf(stdout, "ERROR: %s\n", UNEXISTENT_PIPE);
return -1;
}
send_request(reg_pipe, serialize(1, personal_pipe, box_name));
}
Program reader:
char register_pipe[PIPENAME];
strcpy(register_pipe, argv[1]);
if(mkfifo(register_pipe, 0644) < 0)
exit(EXIT_FAILURE);
if ((reg_pipe = open(register_pipe, O_RDONLY)) < 0){
exit(EXIT_FAILURE);
}
if ((reg_pipe = open(register_pipe, O_RDONLY)) < 0){
exit(EXIT_FAILURE);
}
request* buffer = (request*) malloc(sizeof(request)); //this might be the issue but not sure
ssize_t broker_read= read(reg_pipe, buffer, 256); //is not reading correctly
printf("%d, %s, %s\n", buffer->_code, buffer->_client_pipe, buffer->_box_name);
So if i start program reader and set register pipe as "reg", this will create the register pipe and wait for someone to join it.
Then if i start the program writer like ./writer reg personal box
this will open the reg pipe correctly, create a struct of type request and then sent it to the reader.
The reader should receive a pointer to a struct req set like:
_code = 1;
_client_pipe[PIPENAME] = "personal";
_box_name[BOXNAME] = "box";
The reader is in fact receiving but for some reason it's not receiving correctly.
If i try to print like in the last line, it will output some random numbers and letters.
How can i fix this?
You would need to have that structure exist inside a shared memory region that you have arranged to be mapped into both processes at the same address.
Without some such arrangement, each process has a private address space, so an address known to process A is meaningless to process B.
How to make such an arrangement is very much dependent upon you operating system, and perhaps even variant of said operating system.
You will likely find it easier to just copy the structure, as opposed to its address, via the fifo.

AsyncTCP on ESP32 and Odd Heap/Socket Issues w/SOFTAP

I'm struggling with an issue where an ESP32 is running as a AP with AsyncTCP connecting multiple ESP32 clients. The AP receives some JSON data and replies with some JSON data. Without the handleData() function, the code runs 100% fine with no issues. Heap is static when no clients connect and issues only occur when clients start connecting.
Can anyone see anything with my code that could be causing heap corruption or other memory weirdness?
static void handleData(void* arg, AsyncClient* client, void *data, size_t len) {
int i = 0, j = 0;
char clientData[CLIENT_DATA_MAX];
char packetData[len];
char *packetBuf;
packetBuf = (char *)data;
clientData[0] = '\0';
for (i=0;i <= len;i++) {
packetData[j] = packetBuf[i]; //packetBuf[i];
if ((packetData[j] == '\n') || (i == len)) {
packetData[j] = '\0';
if ((j > 0) && (packetData[0] != '\n') && (packetData[0] != '\r')) {
// See sensorData() below...
parseData.function(packetData, clientData);
if (clientData != NULL) {
// TCP reply to client
if (client->space() > 32 && client->canSend()) {
client->write(clientData);
}
}
}
j = 0;
} else
j++;
}
}
void sensorData(void *data, void *retData) {
StaticJsonDocument<CLIENT_DATA_MAX> fields;
StaticJsonDocument<CLIENT_DATA_MAX> output;
char sensor[15] = "\0";
char MAC[18] = "\0";
char value[20] = "\0";
bool sendOK = false;
memcpy((char *)retData, "\0", 1);
DeserializationError error = deserializeJson(fields, (char *)data, CLIENT_DATA_MAX);
if (error) {
DEBUG_PRINTLN(F("deserializeJson() failed"));
return;
}
if (fields["type"])
strcpy(sensor, fields["type"]);
switch (sensor[0]) {
case 'C':
if (fields["value"])
strcpy(value, fields["value"]);
sendOK = true;
break;
case 'T': //DEBUG_PRINT(F("Temp "));
setExtTempSensor(fields["value"]);
sendOK = true;
break;
case 'N':
output["IT"] = intTempC; //Internal temp
output["B1"] = battLevels[0];
serializeJson(output, (char *)retData, CLIENT_DATA_MAX-1);
break;
}
if (sendOK) {
output["Resp"] = "Ok";
serializeJson(output, (char *)retData, CLIENT_DATA_MAX-1);
}
strcat((char *)retData, "\n");
}
static void handleNewClient(void* arg, AsyncClient* client) {
client->setRxTimeout(1000);
client->setAckTimeout(500);
client->onData(&handleData, NULL);
client->onError(&handleError, NULL);
client->onDisconnect(&handleDisconnect, NULL);
client->onTimeout(&handleTimeOut, NULL);
}
void startServer() {
server = new AsyncServer(WIFI_SERVER_PORT);
server->onClient(&handleNewClient, &server)
}
Using AsyncTCP on the ESP32 was having multiple issues. Heap issues, socket issues, assert issues, ACK timeouts, connection timeouts, etc. Swapping to AsyncUDP using the exact same code as shown above with romkey's changes, resolved all of my issues. (Just using romkey's fixes did not fix the errors I was having with AsyncTCP.) I don't believe the issue is with AsyncTCP but with ESP32 libraries.
Either you should declare packetData to be of length len + 1 or your for loop should iterate until i < len. Because the index starts at 0, packetData[len] is actually byte len + 1, so you'll overwrite something random when you store something in packetData[len] if the array is only len chars long.That something random may be the pointer stored in packetBuf, which could easily cause heap corruption.
You should always use strncpy() and never strcpy(). Likewise use strncat() rather than strcat(). Don't depend on having done the math correctly or on sizes not changing as your code evolves. strncpy() and strncat() will guard against overflows. You'll need to pass a length into sensorData() to do that, but sensorData() shouldn't be making assumptions about the available length of retData.
Your test
if (clientData != NULL) {
will never fail because clientData is the address of array and cannot change. I'm not sure what you're trying to test for here but this if will always succeed.
You can just write:
char sensor[15] = "";
you don't need to explicitly assign a string with a null byte in it.
And
memcpy((char *)retData, "\0", 1);
is equivalent to
((char *)retData)[0] = '\0';
What's the point of declaring retData to be void * in the arguments to sensorData()? Your code starts out with it being a char* before calling sensorData() and uses it as a char* inside sensorData(). void * is meant to be an escape hatch for passing around pointers without worrying about their type. You don't need that here and end up needing to extra casts back to char* because of it. Just declare the argument to be char* and don't worry about casting it again.
You didn't share the code that calls handleData() so there may well be issues outside of these functions.

Proper implementation for mbed TLS AES-CTR?

I'm using this library: https://tls.mbed.org/download with an Espressif ESP32. The goal is to encrypt some data using AES-CTR then decrypt the cypher-text back to the original plain-text. I am getting incorrect result after I've decrypted.
Since we're using CTR mode, we don't need to have a separate "decrypt" function; We can just call the encrypt function once to encrypt then call the same function one more time and it should decrypt. At least, that's what most sources say and that was the case with this other implementation: https://github.com/kokke/tiny-AES-c
I tried using the same nonce, same stream-block, different nonces, different stream-blocks, set the key before each of the function calls, etc.
mbedtls_aes_context aes;
unsigned char key[16];
size_t plainText_len = 64;
unsigned int nc_off = 0;
unsigned char nonce_counter[16] = {0};
unsigned char stream_block[16] = {0};
unsigned char plainText[64] = {0x48, 0x45, 0x4c, 0x4c, 0x4f};
unsigned char encryptText[64];
unsigned char decryptText[64];
memcpy(key, key_128, 16); //key_128 comes from a different file
//Print Key
printf("aes Key: \n");
for(int i = 0; i < 16; i++){
printf("%x",key[i]);
}
printf("\n");
//Print plain-text
printf("aes plainText: \n");
for(int i = 0; i < 5; i++){
printf("%x",plainText[i]);
}
printf("\n");
esp_aes_init(&aes); //context is initialized
esp_aes_setkey(&aes, key, 128); //key is associated to context
esp_aes_crypt_ctr(&aes, plainText_len, &nc_off, nonce_counter, stream_block, plainText, encryptText); //encrypt
//Print encrypt-text
printf("aes encryptText: \n");
for(int i = 0; i < 5; i++){
printf("%x",encryptText[i]);
}
printf("\n");
esp_aes_crypt_ctr(&aes, plainText_len, &nc_off, nonce_counter, stream_block, encryptText, decryptText); //decrypt
//Print decrypt-text
printf("aes decrypt: \n");
for(int i = 0; i < 5; i++){
printf("%x",decryptText[i]);
}
printf("\n");
After the encrypt function is called a second time the resulting decryptText should be the same as the original plain-text, however, at the moment plainText =/= decryptText.
This is what my monitor is printing:
aes key: 7d3043fb95355e6ccd850ad8debc279
aes plainText: 48454c4c4f
aes encryptText: 852b97da59
aes decryptText: 814268329f
As you can see, I'm missing something that'll properly decrypt the encryptText!
Since we're using CTR mode, we don't need to have a separate "decrypt" function; We can just call the encrypt function...
I think you are conflating topics. CTR mode does operate the cipher in the forward direction for both encryption and decryption. However, the same sort of symmetry may not exist in the higher level mbedTLS objects.
esp_aes_init(&aes); //context is initialized
esp_aes_setkey(&aes, key, 128); //key is associated to context
esp_aes_crypt_ctr(&aes, plainText_len, &nc_off, nonce_counter, stream_block, plainText, encryptText); //encrypt
// ...
esp_aes_crypt_ctr(&aes, plainText_len, &nc_off, nonce_counter, stream_block, encryptText, decryptText); //decrypt
// ...
esp_aes_crypt_ctr is a define for mbedtls_aes_crypt_ctr. mbedtls_aes_crypt_ctr docs say the function updates both nonce_counter and stream_block. I believe you need to restart both when you want to perform decryption.
Here is one of the mentions of stream_block in the docs. You are not contiuing encryption. You need to restart the parameter.
stream_block - The saved stream block for resuming. This is overwritten by the function. It must be a readable-writeable buffer of
16 Bytes.
But in the bigger picture as was commented by #James... You should probably use mbedTLS the way it was designed to be used rather than trying to take shortcuts.

GCM-AEAD support for ubuntu system running linux kernel-3.10

I am trying to implement a AEAD sample code for encryption Using GCM encryption. But I always get invalid argument error while setting the key
static int init_aead(void)
{
printk("Starting encryption\n");
struct crypto_aead *tfm = NULL;
struct aead_request *req;
struct tcrypt_result tresult;
struct scatterlist plaintext[1] ;
struct scatterlist ciphertext[1];
struct scatterlist gmactext[1];
unsigned char *plaindata = NULL;
unsigned char *cipherdata = NULL;
unsigned char *gmacdata = NULL;
const u8 *key = kmalloc(16, GFP_KERNEL);
char *algo = "rfc4106(gcm(aes))";
unsigned char *ivp = NULL;
int ret, i, d;
unsigned int iv_len;
unsigned int keylen = 16;
/* Allocating a cipher handle for AEAD */
tfm = crypto_alloc_aead(algo, 0, 0);
init_completion(&tresult.completion);
if(IS_ERR(tfm)) {
pr_err("alg: aead: Failed to load transform for %s: %ld\n", algo,
PTR_ERR(tfm));
return PTR_ERR(tfm);
}
/* Allocating request data structure to be used with AEAD data structure */
req = aead_request_alloc(tfm, GFP_KERNEL);
if(IS_ERR(req)) {
pr_err("Couldn't allocate request handle for %s:\n", algo);
return PTR_ERR(req);
}
/* Allocting a callback function to be used , when the request completes */
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, aead_work_done,&tresult);
crypto_aead_clear_flags(tfm, ~0);
/* Set key */
get_random_bytes((void*)key, keylen);
if((ret = crypto_aead_setkey(tfm, key, 16) != 0)) {
pr_err("Return value for setkey is %d\n", ret);
pr_info("key could not be set\n");
ret = -EAGAIN;
return ret;
}
/* Set authentication tag length */
if(crypto_aead_setauthsize(tfm, 16)) {
pr_info("Tag size could not be authenticated\n");
ret = -EAGAIN;
return ret;
}
/* Set IV size */
iv_len = crypto_aead_ivsize(tfm);
if (!(iv_len)){
pr_info("IV size could not be authenticated\n");
ret = -EAGAIN;
return ret;
}
plaindata = kmalloc(16, GFP_KERNEL);
cipherdata = kmalloc(16, GFP_KERNEL);
gmacdata = kmalloc(16, GFP_KERNEL);
ivp = kmalloc(iv_len, GFP_KERNEL);
if(!plaindata || !cipherdata || !gmacdata || !ivp) {
printk("Memory not availaible\n");
ret = -ENOMEM;
return ret;
}
for (i = 0, d = 0; i < 16; i++, d++)
plaindata[i] = d;
memset(cipherdata, 0, 16);
memset(gmacdata, 0, 16);
for (i = 0,d=0xa8; i < 16; i++, d++)
ivp[i] = d;
sg_init_one(&plaintext[0], plaindata, 16);
sg_init_one(&ciphertext[0], cipherdata, 16);
sg_init_one(&gmactext[0], gmacdata, 128);
aead_request_set_crypt(req, plaintext, ciphertext, 16, ivp);
aead_request_set_assoc(req, gmactext, 16);
ret = crypto_aead_encrypt(req);
if (ret)
printk("cipher call returns %d \n", ret);
else
printk("Failure \n");
return 0;
}
module_init(init_aead);
module_exit(exit_aead);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("My code for aead encryption test");
}
On inserting the module I get following output
Starting encryption
Return value for setkey is -22
key could not be set
According to AEAD specification aead uses aes-128 for encryption hence the block size should be 128 bit .
But my system shows only 1 Byte block size support for AEAD
name : rfc4106(gcm(aes))
driver : rfc4106-gcm-aesni
module : aesni_intel
priority : 400
refcnt : 1
selftest : passed
type : nivaead
async : yes
blocksize : 1
ivsize : 8
maxauthsize : 16
geniv : seqiv
Does the invalid argument error is thrown becuase of the block size. If so , what shall I do to make it work ?
The block size of AES is indeed always 128 bit. The block size of GCM is a different matter though. GCM (Galois-Counter Mode) is - as the name suggests - build on top of the CTR (Counter) mode of operation, sometimes also called the SIC (Segmented Integer Counter) mode of operation. This turns AES into a stream cipher. Stream ciphers - by definition - have a block size of one byte (or, more precisely, one bit, but bit level operations are usually not supported by API's).
Block size however has little to do with the key size displayed in the call, and the argument does seem to require bytes instead of bits (in which key lengths are usually defined).
The size of the IV should be 12 bytes (the default). Otherwise additional calculations may be needed by the GCM implementation (if those exist at all).
For Aes GCM RFC 4106 the key must be 20 bytes. I don't known yet why. I've looked into ipsec source code to see how the encryption is made there.

How can I use memfrob() to encrypt an entire file?

#include <Windows.h>
void memfrob(void * s, size_t n)
{
char *p = (char *) s;
while (n-- > 0)
*p++ ^= 42;
}
int main()
{
memfrob("C:\\Program Files\\***\***\\***\***\\***", 30344);
}
There's my code. If you can't tell, I'm not sure what I'm doing. I've Googled for about an hour and I haven't seen an example of how to use memfrob(), which is probably why I'm so lost. I'm trying to pass it the name of the file and then the size of the file in bytes, but my program just crashes.
Alright, this is what I have right now:
#include <Windows.h>
#include <stdio.h>
int count = 0;
FILE* pFile = 0;
long Size = 0;
void *memfrob(void * s, size_t n)
{
char *p = (char *) s;
while (n-- > 0)
*p++ ^= 42;
return s;
}
int main()
{
fopen_s(&pFile, "C:\\Program Files\\CCP\\EVE\\lib\\corelib\\nasty.pyj", "r+");
fseek(pFile, 0, SEEK_END);
Size = ftell(pFile);
char *buffer = (char*)malloc(Size);
memset(buffer, 0, Size);
fread(buffer, Size, 1, pFile);
fclose(pFile);
memfrob(buffer, Size);
fopen_s(&pFile, "C:\\Program Files\\CCP\\EVE\\lib\\corelib\\nasty.pyj", "w+");
fwrite(buffer, Size, 1, pFile);
fclose(pFile);
}
In my debugger, it seems that fread is not writing anything to buffer, and my ending file is just 2A over and over, which is 00 xor'd with 42. So can I get another hint?
You need to pass memfrob a piece of memory containing the contents of the file, rather than the name of the file. It's crashing because you're passing in a buffer of read-only memory, and then trying to modify it.
Investigate the open and read I/O functions, or alternatively fopen and fread. Your mainline should look something like:
int main() {
// open file
// find size of file
// allocate buffer of that size
// read contents of file into the buffer
// close the file
// call memfrob on the buffer
// do what you want with the file
// free the buffer
}
Well, several things are wrong here.
The minor problem is that you're passing it the location of the file and not the file itself. Read up on how to do file I/O in C (this being a pretty good link).
The real problem is that you seem to think this is encryption. This doesn't really encrypt your file from anything but the most trivial security issues (such as someone randomly opening your file).

Resources