Related
I have a C program to match a particular regex in a string and perform some substitution. I want to match all patterns of string concatenation and convert it to another form.
For Example for the input string
This "is" + "an" + "example" + "string" to be matched and replaced
The Matched regex should be
"is" + "an" + "example" + "string"
So I want to convert this matched regex to
CONCAT("is", "an", "example", "string")
I am using C PCRE2 Library and my code is below. Can anyone help me fix the substitution part?
#define PCRE2_CODE_UNIT_WIDTH 8
#define BUFFERSIZE 100
#include <my_global.h>
#include <mysql.h>
#include <stdio.h>
#include <string.h>
#include <pcre2.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
pcre2_code *re;
PCRE2_SPTR pattern;
PCRE2_SPTR subject;
int errornumber;
int i;
int rc;
PCRE2_SIZE erroroffset;
PCRE2_SIZE *ovector;
size_t subject_length;
pcre2_match_data *match_data;
char buffer[BUFFERSIZE];
MYSQL *con = mysql_init(NULL);
/* Read Query String from standard input here*/
printf("Enter a Query to be substituted: \n");
while(fgets(buffer, BUFFERSIZE , stdin) != NULL)
{
printf("%s\n", buffer);
break;
}
pattern = (PCRE2_SPTR)'"[^"]*"(?: *\\+ *"[^"]*")+'; // Regex for string concatenation
subject = (PCRE2_SPTR)buffer;
subject_length = strlen((char *)subject);
/* Compile regex and perform matching here by wrapping match within CONCAT() and replace + with , */
re = pcre2_compile(
pattern,
PCRE2_ZERO_TERMINATED,
0,
&errornumber,
&erroroffset,
NULL);
if (re == NULL)
{
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
printf("PCRE2 compilation failed at offset %d: %s\n", (int)erroroffset,
buffer);
return 1;
}
match_data = pcre2_match_data_create_from_pattern(re, NULL);
rc = pcre2_match(
re,
subject,
subject_length,
0,
0,
match_data,
NULL);
if (rc < 0)
{
switch(rc)
{
case PCRE2_ERROR_NOMATCH: printf("No match\n"); break;
default: printf("Matching error %d\n", rc); break;
}
pcre2_match_data_free(match_data);
pcre2_code_free(re);
// return 1;
goto server;
}
ovector = pcre2_get_ovector_pointer(match_data);
printf("\nMatch succeeded at offset %d\n", (int)ovector[0]);
/* Do Substitution for matches found here. by wrapping match within CONCAT() and replace + with ,. For now only one match is handled*/
/* Use Connector C here to forward query that is rewritten to MariaDB/MySQL server */
server:
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
if (mysql_real_connect(con, "localhost", "root", "root",
NULL, 0, NULL, 0) == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
printf("Connected to Database\n");
if (mysql_query(con, subject))
{
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
int num_fields = mysql_num_fields(result);
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\n");
}
mysql_free_result(result);
mysql_close(con);
printf("\n");
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return 0;
}
I was trying to fetch Mac addrs of all the devices present in WiFi environment(whole subnet).
Initially when i ran the code approx it took 10 mins to get the result for whole subnet so in order to reduce the time i used multithreaded concept in windows machine but this method is not at all working.
I am pasting the code snippet below.
Even i tried different logic like running 255, 100, 50 ,2 threads at a time but still it failed.
I suspect synchronization issue in this but i don't have any idea to resolve this, so please help me in this getting done.
DWORD WINAPI GetMacAddrOfSubNet(LPVOID lpParam)
{
DWORD dwRetVal;
IPAddr DestIp = 0;
IPAddr SrcIp = 0; /* default for src ip */
ULONG MacAddr[2]; /* for 6-byte hardware addresses */
ULONG PhysAddrLen = 6; /* default to length of six bytes */
char look[100];
strcpy(look ,(char *)lpParam);
DestIp = inet_addr(look);
memset(&MacAddr, 0xff, sizeof (MacAddr));
/*Pinging particular ip and retrning mac addrs if response is thr*/
dwRetVal = SendARP(DestIp, SrcIp, &MacAddr, &PhysAddrLen);
if (dwRetVal == NO_ERROR)
{
/**/
}
return 0;
}
extern "C" __declspec(dllexport) int __cdecl PopulateARPTable(char *IpSubNetMask)
{
char ipn[100];
char buffer[10];
unsigned int k;
DWORD dwThreadIdArray[260];
HANDLE hThreadArray[260];
/*Run 255 threads at once*/
for (k=1; k<255; k++)
{
itoa(k, buffer, 10);
strcpy(ipn, IpSubNetMask);
strcat(ipn, ".");
strcat(ipn, buffer);
/*Thread creation */
hThreadArray[k] = CreateThread( NULL, 0, GetMacAddrOfSubNet, ipn, 0, &dwThreadIdArray[k]);
if (hThreadArray[k] == NULL)
{
//ExitProcess(3);
}
}
WaitForMultipleObjects(255, hThreadArray, TRUE, INFINITE);
return 0;
}
The ipn buffer only exists once. You are using and modifying it as parameter for your (up to) 255 threads. And you expect that the statement strcpy(look ,(char *)lpParam) in the thread will be performed before the main thread modifies ipnagain for calling the next thread. But this is not the case, at least it's not guaranteed. So your threads may use wrong parameters.
Either use different buffers for each thread, or implement a synchronization, that ensures that the parameter has been copied by the thread before main thread modifies the buffer again.
I've done this already for Excel, wrote a multi-threaded DLL that in addition to getting MAC addresses, will do DNS reverse hostname and ICMP ping RT.
Lemme know if you want the VBA code that goes with it. The source for the C-based DLL (which you may be happy with as a template) is:
/*
ExcelNet library: Provide threaded networking functions
NOTE: Serially doing these on the network involves serially waiting for timeouts, much ouchies!
Written by: Danny Holstein
*/
#if 1 // header stuff
#include <windows.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define MSEXPORT __declspec(dllexport)
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define BUFSZ 256
typedef struct {
char ip[BUFSZ]; // IP addresses in dotted notation.
int ipSize; // size of IP address buffer
char data[BUFSZ]; // general network data (MAC, hostname, etc)
int dataSize; // size of data buffer ^
int err_no; // WinAPI error number
int (*func)(LPCSTR Addr, char* buf, int BufSz); // function address, &GetNameInfos, &GetARP or &GetICMP
} NET_DATA;
int GetARP(LPCSTR Addr, char* Buf, int BufSz);
int GetNameInfos(LPCSTR Addr, char* Buf, int BufSz);
int GetICMP(LPCSTR Addr, char* Buf, int BufSz);
char msg_dbg[BUFSZ], dan[BUFSZ];
#define DEBUG_PRT() {snprintf(msg_dbg, BUFSZ, "lineno = %d\tfunc = %s", __LINE__ , __func__); MessageBox(0, msg_dbg, "debug", 0);}
#define DEBUG_MSG(msg) {snprintf(msg_dbg, BUFSZ, "msg=\"%s\"\tlineno = %d\tfunc = %s", msg, __LINE__ , __func__); MessageBox(0, msg_dbg, "debug", 0);}
#if 0 // documentation indicates malloc/realloc/free shouldn't be used in DLLs
#define malloc(A) malloc(A)
#define realloc(A, B) realloc(A, B)
#define free(A) free(A)
// #define NOMEMLEAK // dudint work
#else // kinda works, when NOT allocating all the NET_DATA structure elements
#define malloc(A) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, A)
#define realloc(A, B) HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, A, B)
#define free(A) (void) HeapFree(A, HEAP_GENERATE_EXCEPTIONS, NULL)
#define NOMEMLEAK
#endif
#endif
MSEXPORT void __stdcall ArrayDGH(SAFEARRAY **IntArr, SAFEARRAY **StrArr)
{
SAFEARRAY *A = (SAFEARRAY*) (*IntArr);
SAFEARRAY *S = (SAFEARRAY*) (*StrArr);
int n = (*A).rgsabound[0].cElements;
snprintf(dan, BUFSZ, "a num elems = %d, str num elems = %d", n, (*S).rgsabound[0].cElements); DEBUG_MSG(dan);
// for (int i=0; i<n; i++) {snprintf(dan, BUFSZ, "elem[%d] = %d", i, ((int*) (*A).pvData)[i]); DEBUG_MSG(dan);}
OLECHAR* str[] = {L"Da",L"Fuk",L"Waz",L"Dat?",L"dot",L"dot"};
for (int i=0; i<n; i++) {SysReAllocString(&(((BSTR*) (*S).pvData)[i]), str[i]);}
}
DWORD dwMilliseconds = 10000;
MSEXPORT void __stdcall SetTIMO(DWORD Timo) {dwMilliseconds = Timo;}
MSEXPORT bool __stdcall ExcelSendARP(LPCSTR Addr, BSTR* MAC)
{
char buf[BUFSZ];
int err = GetARP(Addr, buf, BUFSZ);
*MAC = SysAllocStringByteLen(buf, strlen(buf)); // avoid WIDE to ANSI stuff
return !err;
}
MSEXPORT bool __stdcall ExcelICMPRT(LPCSTR Addr, BSTR* RoundTrip)
{
char buf[BUFSZ];
int err = GetICMP(Addr, buf, BUFSZ);
*RoundTrip = SysAllocStringByteLen(buf, strlen(buf)); // avoid WIDE to ANSI stuff
return !err;
}
MSEXPORT bool __stdcall ExcelGetNameInfo(LPCSTR Addr, BSTR* NameInfo)
{
char buf[BUFSZ];
#ifdef TEST_FUNC_PTR
int (*FunAddr[2])(LPCSTR Addr, char** buf, int BufSz);
FunAddr[0] = &GetARP; FunAddr[1] = &GetNameInfos; // DRY code hooks
int err = (*(FunAddr[1]))(Addr, buf, BUFSZ);
#else
int err = GetNameInfos(Addr, buf, BUFSZ);
#endif
*NameInfo = SysAllocStringByteLen(buf, strlen(buf)); // avoid WIDE to ANSI stuff
return !err;
}
int GetNameInfos(LPCSTR Addr, char* buf, int BufSz)
{
ULONG inet; DWORD resp = 0; HOSTENT *tHI;
struct in_addr addr = { 0 };
if ((inet = inet_addr(Addr)) == INADDR_NONE) {
if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
return inet;
}
addr.s_addr = inet; tHI = gethostbyaddr((char *) &addr, 4, AF_INET);
if (tHI == NULL) { // no reponse for this IP condition, decode condition and place in PCHAR buf
resp = WSAGetLastError();
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
return resp;
}
_snprintf_s(buf, BufSz-1, _TRUNCATE, "%s", tHI->h_name); // place hostname in PCHAR buf
return resp; // <- resp = 0, we have a hostname associated with this IP, SUCCESS!
}
int GetARP(LPCSTR Addr, char* buf, int BufSz)
{
#define BUFLEN 6
ULONG pMacAddr[BUFLEN], inet, BufLen = BUFLEN; DWORD resp = 0;
if ((inet = inet_addr(Addr)) == INADDR_NONE) {
if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
return inet;
}
resp = SendARP(inet, 0, pMacAddr, &BufLen);
if (resp) { // no reponse for this IP condition, decode condition and place in PCHAR buf
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
return resp;
}
UCHAR *pMacAddrBytes = (UCHAR *) pMacAddr;
_snprintf_s(buf, BufSz, _TRUNCATE, "%02x:%02x:%02x:%02x:%02x:%02x", pMacAddrBytes[0], pMacAddrBytes[1], pMacAddrBytes[2],
pMacAddrBytes[3], pMacAddrBytes[4], pMacAddrBytes[5]); // place MAC in PCHAR buf
return resp; // <- resp = 0, we have a MAC associated with this IP, SUCCESS!
}
int GetICMP(LPCSTR Addr, char* buf, int BufSz)
{
HANDLE hIcmpFile;
ULONG inet; DWORD resp = 0;
char SendData[] = "Data Buffer";
LPVOID ReplyBuffer = NULL;
DWORD ReplySize = 0;
if ((inet = inet_addr(Addr)) == INADDR_NONE) {
if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
return inet;
}
hIcmpFile = IcmpCreateFile();
if (hIcmpFile == INVALID_HANDLE_VALUE) {
resp = GetLastError();
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
return resp;
}
// Allocate space for at a single reply
ReplySize = sizeof (ICMP_ECHO_REPLY) + sizeof (SendData) + 8;
ReplyBuffer = (VOID *) malloc(ReplySize);
resp = IcmpSendEcho2(hIcmpFile, NULL, NULL, NULL,
inet, SendData, sizeof (SendData), NULL,
ReplyBuffer, ReplySize, dwMilliseconds);
PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY) ReplyBuffer;
if (resp == 0) { // no reponse for this IP condition, decode condition and place in PCHAR buf
resp = pEchoReply->Status; // WSAGetLastError();
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
return resp;
}
_snprintf_s(buf, BufSz-1, _TRUNCATE, "%d", ((PICMP_ECHO_REPLY) ReplyBuffer)->RoundTripTime); // place roundtrip time in PCHAR buf (ASCII representation)
IcmpCloseHandle(hIcmpFile);
return 0; // we have a RT time in milliseconds associated with this IP, SUCCESS!
}
NET_DATA *NetData;
DWORD WINAPI tGetDATA(LPVOID NetData)
{
char buf[BUFSZ];
NET_DATA *m = NetData; // stupid me, I had allocated the space, instead of address of, not thinking it all disappears on exit
m->err_no = (*(m->func))(m->ip, buf, BUFSZ); // GetARP, GetNameInfos or GetICMP
if (_snprintf_s(m->data, m->dataSize-1, _TRUNCATE, "%s", buf) == -1) DEBUG_MSG("_snprintf_s error!");
// A resources error may have hit AFTER the calling function has returned, including having the thread/memory deallocated in the calling function
return 0;
}
MSEXPORT BSTR __stdcall ExcelRngNetData(UCHAR *list, ULONG *ErrNos, BSTR *DataArry, DWORD dwMilliseconds, char sep, char FunctType)
{ // take list of IP addresses (newline-separated), create thread for each to get network data. Return results in (sep-separated) BSTR.
int i=0, j, NumIPs=0, k = strlen(list), l=0;
#define NMSZ 100
char nm[NMSZ];
void* FuncAddr[3]; // DRY code hooks
FuncAddr[0] = &GetARP; FuncAddr[1] = &GetNameInfos; FuncAddr[2] = &GetICMP;
while (i<k && sscanf_s(list+i, "%[^\n]\n", nm, NMSZ)){i += strnlen_s(nm, NMSZ) + 1; NumIPs++;} // count newline-separated items before doing malloc(), because realloc() is REALLY resource intensive
NetData = malloc(NumIPs * sizeof(NET_DATA)); i = 0;
while (i<k && sscanf_s(list+i, "%[^\n]\n", nm, NMSZ)){ // load calling routines list into structures
j = strnlen_s(nm, NMSZ) + 1; i += j;
NetData[l].err_no = WAIT_TIMEOUT; // easy way to preset the error to a TIMEOUT, if the thread successfully completes before the timeout, this will be set to reflect its timeout
NetData[l].dataSize = BUFSZ;
NetData[l].func = FuncAddr[FunctType]; // DRY (Don't Repeat Yourself) code hook
if (strncpy_s(NetData[l].ip, (NetData[l].ipSize = BUFSZ), nm, j)) DEBUG_MSG("strcpy_s error!");
l++;
}
HANDLE *tHandles = malloc(NumIPs * sizeof(HANDLE)); DWORD ThreadId;
for (i=0; i<NumIPs; i++){
tHandles[i] = CreateThread(NULL, 0, tGetDATA, &(NetData[i]), 0, &ThreadId);
if (tHandles[i] == NULL) {DEBUG_MSG("Could not create threads!\nExiting now"); ExitProcess(3);}
}
if(WaitForMultipleObjects(NumIPs, tHandles, TRUE, dwMilliseconds) == WAIT_FAILED) {
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, GetLastError(), 0, dan, BUFSZ, 0); DEBUG_MSG(dan);
// Prolly means too many threads, kicked in when I exceeded 64; ERROR_INVALID_PARAMETER = "The parameter is incorrect"
}
#define CHUNK 1024
#define DATASZ 256 // tested with intentionally small size to check "safe" string functions
wchar_t wcs[DATASZ]; char MacChunk[DATASZ];
char *ans = malloc(CHUNK); int anslen = 0, anssz = CHUNK;
char separator[2]; separator[0] = sep; separator[1] = 0;
for(i=0; i<NumIPs; i++) { // build return BSTR and load array with data
CloseHandle(tHandles[i]); ErrNos[i] = NetData[i].err_no;
if (strncpy_s(MacChunk, DATASZ-1, NetData[i].err_no == 0 ? NetData[i].data : "", NetData[i].dataSize-1)) DEBUG_MSG("strcpy_s error!");
if (i<NumIPs-1 && sep != 0) if (strncat_s(MacChunk, DATASZ-1, separator, 1)) DEBUG_MSG("strcpy_s error!");
while (strnlen_s(MacChunk, DATASZ) > anssz - anslen -1) ans = realloc(ans, (anssz += CHUNK)); // choose CHUNK size to avoid constant realloc(), because realloc() is REALLY resource intensive
if (strncpy_s(&(ans[anslen]), DATASZ-1, MacChunk, DATASZ-1)) DEBUG_MSG("strcpy_s error!"); anslen += strnlen_s(MacChunk, DATASZ); // return data in returned BSTR
MultiByteToWideChar(CP_UTF8, 0,
ErrNos[i] == WAIT_TIMEOUT ? "The wait operation timed out." : NetData[i].data,
-1, wcs, DATASZ-1); // return data in supplied array
SysReAllocString(&DataArry[i], wcs);
}
BSTR r = SysAllocStringByteLen(ans, strlen(ans));
#ifdef NOMEMLEAK
free(NetData); free(tHandles); free(ans);
#endif
return r;
}
#include <stdio.h>
#include <string.h>
#include <pcre.h>
#define OVECCOUNT 30
#define SRCBUFFER 1024*1024
int main(int argc, char **argv){
pcre *re;
const char *error;
int erroffset;
int ovector[OVECCOUNT];
int rc, i;
if (argc != 2){
fprintf(stderr, "Usage : %s PATTERN\n", argv[0]);
return 1;
}
char *src=malloc(SRCBUFFER);
int srclen = fread(src, sizeof(char), SRCBUFFER, stdin);
re = pcre_compile(argv[1], 0, &error, &erroffset, NULL);
if (re == NULL){
fprintf(stderr, "PCRE compilation failed at offset %d: %s\n", erroffset, error);
return 1;
}
rc = pcre_exec(re, NULL, src, srclen, 0, 0, ovector, OVECCOUNT);
if (rc < 0){
if (rc == PCRE_ERROR_NOMATCH) fprintf(stderr, "Sorry, no match...\n");
else fprintf(stderr, "Matching error %d\n", rc);
return 1;
}
for (i = 0; i < rc; i++){
char *substring_start = src + ovector[2 * i];
int substring_length = ovector[2 * i + 1] - ovector[2 * i];
fprintf(stdout, "%2d: %.*s\n", i, substring_length, substring_start);
}
return 0;
}
run it
echo "apple banana africa" | ./program '\ba\w+\b'
and it print
0: apple
I've tried to use the PCRE_MULTILINE option,but no use.How to make it print all matchs?
It sounds like what you're looking for is the equivalent of the Perl /g regex flag to repeat the match as many times as possible and return the results of all the matches. I don't believe PCRE has anything like that.
Instead, you will need to add a loop around pcre_exec. Each time you call it, it will return the byte offset of the start and end of the match. You want to then run pcre_exec again on the string starting at the end of the match. Repeat until pcre_exec doesn't match.
I am trying to read a file(.txt) in this case and encrypting/decrypting it with AES256CBC using EVP api of openssl.(read(plain.txt)->create(encrypt.txt)->create(decrypt.txt))
# include <stdio.h>
# include <stdlib.h>
# include <openssl/evp.h>
# include <openssl/aes.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <assert.h>
# include <error.h>
# include "debug.h"
# define SIZE 32
char buf[SIZE];
int aes_init(unsigned char* pwd, unsigned int pwd_len, unsigned char * salt, EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx)
{
int i, rounds =5; /* rounds */
unsigned char key[32], iv[32];
i = EVP_BytesToKey(EVP_aes_256_cbc(),EVP_sha1(),salt,pwd,pwd_len,rounds,key,iv);
if(i != 32)
{
printf("\n Error,Incorrect key size generated:%d:\n",i);
return -1;
}
EVP_CIPHER_CTX_init(e_ctx);
EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
EVP_CIPHER_CTX_init(d_ctx);
EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv);
return 0;
}
unsigned char* aes_encrypt(EVP_CIPHER_CTX *e,unsigned char * plain_text, unsigned int * len ) /* this function encryptes the file:fd is passed as parameter */
{
int ci_len = (*len) + AES_BLOCK_SIZE;
int flen =0;
unsigned char * cipher_text = malloc(ci_len);
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); /* allows reusing of e for multiple cipher cycles */
EVP_EncryptUpdate(e, cipher_text, &ci_len, plain_text, *len); /* Update cipher text */
EVP_EncryptFinal_ex(e, cipher_text+ci_len, &flen); /* updates the remaining bytes */
*len = ci_len + flen;
return cipher_text;
}
unsigned char* aes_decrypt(EVP_CIPHER_CTX *e, unsigned char * c_text, unsigned int * len)
{
int pi_len = (*len);
int flen = 0;
unsigned char * plain_text = malloc(pi_len);
EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);
EVP_DecryptUpdate(e, plain_text, &pi_len, c_text, *len);
EVP_DecryptFinal_ex(e, plain_text+pi_len, &flen);
(*len) = pi_len + flen;
return plain_text;
}
int main(int argc,char **argv)
{
if(argc != 2)
{
perror("\n Error:\nCorrect Usage: Enter Password to be used");
exit(-1);
}
EVP_CIPHER_CTX en,de; /* The EVP structure which keeps track of all crypt operations see evp.h for details */
int in, out, fd, dec,i =0; /* fd for input and output files and random dev*/
unsigned int pwd_len = strlen((const char *)argv[1]); /* Length of the pwd supplied by the user */
unsigned char *pwd =(unsigned char*) argv[1]; /* Pointer to the pwd supplied by the user */
unsigned int rd= 0;
unsigned char salt[8];
unsigned char * encry = NULL, *decry = NULL;
i =0;
if((in = open("plain.txt",O_RDONLY)) == -1) /* Opening a plain text file for encryption */
{
perror("\n Error,Opening file for reading::");
exit(-1);
}
if((fd = open("/dev/random", O_RDONLY)) == -1)
{
perror("\n Error,Opening /dev/random::");
exit(-1);
}
else
{
if(read(fd,salt,8) == -1)
{
perror("\n Error,reading from /dev/random::");
exit(-1);
}
}
if(aes_init(pwd,pwd_len,(unsigned char*) salt,&en,&de)) /* Generating Key and IV and initializing the EVP struct */
{
perror("\n Error, Cant initialize key and IV:");
return -1;
}
if((out = open("encrypt.txt",O_RDWR|O_CREAT,0400 | 0200)) == -1)
{
dbug_p("ENC%d",out);
perror("\n Error,Opening the file to be written::");
exit(-1);
}
rd =0;
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::%d*\n",buf,rd);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
if((write(out,encry,rd)) != rd)
{
perror("\n Error,Required encrypted bytes not written::");
exit(-1);
}
free(encry);
}
rd =0;
if((dec = open("dec22.txt",O_RDWR|O_CREAT,0400 | 0200)) == -1)
{
dbug_p("dec%d",dec);
perror("\n Error,Opening the decrypting o/p file::");
exit(-1);
}
if((lseek(out,0,SEEK_SET)) != 0) perror("\n Error:setting lseek::");
for(i=0;i<SIZE;i++) buf[i] =0;
while((rd = read(out,dbuf,SIZE)) >0)
{
decry = aes_decrypt(&de,(unsigned char*) dbuf, &rd);
if((write(dec,decry,rd)) != rd)
{
perror("\n Error,Required decrypted bytes not written::");
exit(-1);
}
free(decry);
}
close(in);
close(fd);
EVP_CIPHER_CTX_cleanup(&en);
EVP_CIPHER_CTX_cleanup(&de);
return 0;
}
My problem was that my when i decrypt an encrypted file i get a file which is not properly decrypted (e.g. correct stringgarbagecorrect stringgarbage ...)
abhi#ubuntu:~/mpro/EFF$ cat plain.txt
Today is tuesday
tomorrow is wednesday
then thursday and friday and saturday
finally sunday
Decrypted file
cat dec22.txt
Today is tuesdayw)Q������O-%�A�8���R��.�O���and saturday
finally sunday
What can be the reason for this. Is it reading something else also or i am making any foolish error somewhere.
EDIT: If I just encrypt an array (tried with 36char long) it correctly encrypted and decrypted without printing any garbage.
I guess i am missing(not handling) some *nix file structure details ..??
Or is there any better way to do this encryption on a file.?
Many thanks
I think your analysis is wrong. This loop is problematic:
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::\n",buf);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
dbug_p("\n EN::%s::\n",encry);
decry = aes_decrypt(&de,(unsigned char*) encry,&rd);
dbug_p("\n DE::%s::\n",decry);
free(encry);
free(decry);
}
Firstly because you print using %s which expects a zero terminator. However, the encrypted/decrypted data is not zero terminated. Instead, you should print rd characters using a loop like for (i = 0; i < rd; i++) printf("%02x "); - this is why your analysis of the problem is likely flawed.
Secondly, I assume that in your real problem, you are reading SIZE bytes at a time and sending them to aes_decrypt() separately. This will fail because EVP_DecryptFinal_ex() is getting called too early (before all the encrypted blocks were read). You have two options. Either you send the read bytes through EVP_DecryptUpdate() in each loop iteration, and call EVP_DecryptFinal() after completing the loop (and init accordingly before the loop), or you read the whole file into a buffer first, and then send it through aes_decrypt() in one go.
Or in other words, you need to send the whole data block resulting from aes_encrypt() later to aes_decrypt(). You cannot send them in different chunks, unless you split the functions up and use the EVP "update" functions on the separate chunks.
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::%d*\n",buf,rd);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
and,
unsigned char* aes_encrypt(EVP_CIPHER_CTX *e,unsigned char * plain_text, unsigned int * len ) /* this function encryptes the file:fd is passed as parameter */
{
int ci_len = (*len) + AES_BLOCK_SIZE;
int flen =0;
unsigned char * cipher_text = malloc(ci_len);
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); /* allows reusing of e for multiple cipher cycles */
EVP_EncryptUpdate(e, cipher_text, &ci_len, plain_text, *len); /* Update cipher text */
EVP_EncryptFinal_ex(e, cipher_text+ci_len, &flen); /* updates the remaining bytes */
You are calling EVP_EncryptFinal_ex multiple times. It is supposed to be called only once at the end.
Same is true for how you are doing decryption.
Here is a simple example from the man page on how to do encrypt.
Have a similar function for decryption and it should work.
int do_crypt(char *outfile)
{
unsigned char outbuf[1024];
int outlen, tmplen;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
unsigned char iv[] = {1,2,3,4,5,6,7,8};
char intext[] = "Some Crypto Text";
EVP_CIPHER_CTX ctx;
FILE *out;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_bf_cbc(), NULL, key, iv);
if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, intext, strlen(intext)))
{
/* Error */
return 0;
}
/* Buffer passed to EVP_EncryptFinal() must be after data just
* encrypted to avoid overwriting it.
*/
if(!EVP_EncryptFinal_ex(&ctx, outbuf + outlen, &tmplen))
{
/* Error */
return 0;
}
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
/* Need binary mode for fopen because encrypted data is
* binary data. Also cannot use strlen() on it because
* it wont be null terminated and may contain embedded
* nulls.
*/
out = fopen(outfile, "wb");
fwrite(outbuf, 1, outlen, out);
fclose(out);
return 1;
}
the following example is reading a file as your case. See how Update (called multiple times) and Final (once at the end) routines are used.
int do_crypt(FILE *in, FILE *out, int do_encrypt)
{
/* Allow enough space in output buffer for additional block */
inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = "0123456789";
unsigned char iv[] = "12345678";
/* Don't set key or IV because we will modify the parameters */
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit_ex(&ctx, EVP_rc2(), NULL, NULL, NULL, do_encrypt);
EVP_CIPHER_CTX_set_key_length(&ctx, 10);
/* We finished modifying parameters so now we can set key and IV */
EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, do_encrypt);
for(;;)
{
inlen = fread(inbuf, 1, 1024, in);
if(inlen <= 0) break;
if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen))
{
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
}
if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))
{
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}
a kind user here gave me some code to work with for a command line shell, but I want it to output to stdout and stderr instead of using a screen or whatever it is doing right now. I am new to C so I don't know anything about converting it. I also need its ability to detect arrow keys preserved... I'm trying to make a simplistic bash clone. This is what I have right now, it's about 50% my code and 50% others'... yes, it is buggy. There are large sections commented out because they were no longer being used or because they were broken. Ignore them. :)
The particular difficulty is in the use of draw_frame() in main().
#include "os1shell.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h> /* standard unix functions, like getpid() */
#include <sys/types.h> /* various type definitions, like pid_t */
#include <signal.h> /* signal name macros, and the kill() prototype */
#include <ncurses/curses.h> /* a library for cursor-based programs */
#include <poll.h>
#include <termios.h>
#include <time.h>
/** VT100 command to clear the screen. Use puts(VT100_CLEAR_SCREEN) to clear
* the screen. */
#define VT100_CLEAR_SCREEN "\033[2J"
/** VT100 command to reset the cursor to the top left hand corner of the
* screen. */
#define VT100_CURSOR_TO_ORIGIN "\033[H"
struct frame_s {
int x;
int y;
char *data;
};
char* inputBuffer; /* the command input buffer, will be length 65 and null
* terminated. */
char** cmdHistory; /* the command history, will be no longer than 20
* elements and null terminated. */
int historySize = 0;
void addToHistory(char* newItem) {
char** h;
int historySize = 0;
for (historySize; historySize < 21; ++historySize) {
if (cmdHistory[historySize] == NULL) break;
}
if (historySize == 20) {
char** newPtr = cmdHistory + sizeof(char *);
free(cmdHistory[0]);
cmdHistory = newPtr;
h = (char**)realloc(cmdHistory,21*sizeof(char *));
cmdHistory = h;
cmdHistory[19] = newItem;
cmdHistory[20] = NULL;
} else {
h = (char**)realloc(cmdHistory,(historySize+2)*sizeof(char *));
cmdHistory = h;
cmdHistory[historySize] = newItem;
cmdHistory[historySize+1] = NULL;
}
}
/* Some help from http://stackoverflow.com/users/1491/judge-maygarden*/
char** getArguments(char* input) {
char** arguments;
int k = 0;
char* tokenized;
arguments = calloc(1, sizeof (char *));
tokenized = strtok(input, " &");
while (tokenized != NULL) {
arguments[k] = tokenized;
++k;
arguments = realloc(arguments, sizeof (char *) * (k + 1));
tokenized = strtok(NULL, " &");
}
// an extra NULL is required to terminate the array for execvp()
arguments[k] = NULL;
return arguments;
}
void printHistory(struct frame_s *frame) {
snprintf(frame->data, frame->x, "\n\n");
char** currCmd = cmdHistory;
while (*currCmd != NULL) {
snprintf(frame->data[(2*frame->x)], frame->x, "%s\n", *currCmd);
currCmd++;
}
snprintf(frame->data, frame->x, "\n\n");
}
/* Some help from http://stackoverflow.com/users/659981/ben*/
static int draw_frame(struct frame_s *frame) {
int row;
char *data;
int attrib;
puts(VT100_CLEAR_SCREEN);
puts(VT100_CURSOR_TO_ORIGIN);
for ( row = 0, data = frame->data;
row < frame->y;
row++, data += frame->x ) {
// 0 for normal, 1 for bold, 7 for reverse.
attrib = 0;
// The VT100 commands to move the cursor, set the attribute,
// and the actual frame line.
fprintf( stdout,
"\033[%d;%dH\033[0m\033[%dm%.*s",
row + 1,
0,
attrib, frame->x, data);
fflush(stdout);
}
return (0);
}
/* Some help from http://stackoverflow.com/users/659981/ben*/
int main(void) {
const struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 };
struct frame_s frame;
struct termios tty_old;
struct termios tty_new;
unsigned char line[65]; // the input buffer
unsigned int count = 0; // the count of characters in the buff
int ret;
struct pollfd fds[1];
sigset_t sigmask;
struct tm *tp;
time_t current_time;
cmdHistory = (char**)calloc(21,sizeof(char *)); // initialize the
// command history
cmdHistory[20] = NULL; // null terminate the history
int histInd = 0; // an index for the history for arrows
int t;
int r;
char** downTemp;
char** enterTemp;
// Set up a little frame.
frame.x = 80;
frame.y = 32;
frame.data = malloc(frame.x * frame.y);
if (frame.data == NULL) {
fprintf(stderr, "No memory\n");
exit (1);
}
memset(frame.data, ' ', frame.x * frame.y);
// Get the terminal state.
tcgetattr(STDIN_FILENO, &tty_old);
tty_new = tty_old;
// Turn off "cooked" mode (line buffering) and set minimum characters
// to zero (i.e. non-blocking).
tty_new.c_lflag &= ~ICANON;
tty_new.c_cc[VMIN] = 0;
// Set the terminal attributes.
tcsetattr(STDIN_FILENO, TCSANOW, &tty_new);
// Un-mask all signals while in ppoll() so any signal will cause
// ppoll() to return prematurely.
sigemptyset(&sigmask);
fds[0].events = POLLIN;
fds[0].fd = STDIN_FILENO;
// Loop forever waiting for key presses. Update the output on every key
// press and every 1.0s (when ppoll() times out).
do {
fd_set rdset;
int nfds = STDIN_FILENO + 1;
FD_ZERO(&rdset);
FD_SET(STDIN_FILENO, &rdset);
ret = pselect(nfds, &rdset, NULL, NULL, &timeout, &sigmask);
if (ret < 0) { // check for pselect() error.
if (errno == EINTR) {
continue;
} else {
break;
}
}
if (FD_ISSET(STDIN_FILENO, &rdset)) {
ret = read(STDIN_FILENO,&line[count],sizeof(line)-count);
// do {
// fds[0].revents = 0;
// ret = poll(fds, sizeof(fds) / sizeof(struct pollfd), 1000);
//
// if (fds[0].revents & POLLIN) {
// ret = read(STDIN_FILENO,&line[count],sizeof(line)-count);
if (ret > 0) {
line[count + ret] = '\0';
if (strcmp(&line[count], "\033[A") == 0) {
if (histInd > 0) {
--histInd;
}
count = 0;
if(cmdHistory[histInd]!=NULL) {
snprintf(&frame.data[(2*frame.x)],
frame.x,
"hist: %s",
cmdHistory[histInd]);
strcpy(line, cmdHistory[histInd]);
}
} else if (strcmp(&line[count],"\033[B")==0) {
char** downTemp = cmdHistory;
r = 0;
while (*downTemp != NULL) {
++downTemp;
++r;
}
if (histInd < r-1 && r!= 0) {
++histInd;
}
count = 0;
if(cmdHistory[histInd]!=NULL) {
snprintf(&frame.data[(2*frame.x)],
frame.x,
"hist: %s",
cmdHistory[histInd]);
strcpy(line, cmdHistory[histInd]);
}
} else if (line[count] == 127) {
if (count != 0) {
line[count] = '\0';
count -= ret;
}
snprintf(&frame.data[(2*frame.x)], frame.x, "backspace");
} else if (line[count] == '\n') {
char** arguments = getArguments(line);
snprintf( &frame.data[(2*frame.x)],
frame.x,
"entered: %s",
line);
if (count > 0) {
int hasAmpersand = 0;
char* cmd = (char*)
malloc(65*sizeof(char));
strcpy(cmd, line);
addToHistory(cmd);
/*
char* temp = cmd;
while (*temp != '\0') {
if (*temp == '&') {
hasAmpersand = 1;
}
++temp;
}
pid_t pid;
pid = fork();
if (pid == 0) {
int exeret;
exeret = execvp(*arguments,
arguments);
if (exeret < 0) {
snprintf(
&frame.data[
(2*frame.x)],
frame.x,
"Exec failed.\n\n");
exit(1);
}
} else if (pid < 0) {
snprintf(
&frame.data[
(2*frame.x)],
frame.x,
"Fork failed.\n\n");
exit(1);
} else if (pid > 0) {
if (!hasAmpersand) {
wait(NULL);
}
free(arguments);
snprintf(frame.data,
frame.x,
"\n\n");
}*/
} else {
free(arguments);
}
enterTemp = cmdHistory;
t = 0;
while (*enterTemp != NULL) {
++enterTemp;
++t;
}
if (t > histInd) histInd = t;
count = 0;
} else {
//snprintf( frame.data,
// frame.x,
// "char: %c",
// line[count]);
count += ret;
}
}
}
// Print the current time to the output buffer.
//current_time = time(NULL);
//tp = localtime(¤t_time);
//strftime( &frame.data[1 * frame.x],
// frame.x,
// "%Y/%m/%d %H:%M:%S",
// tp);
// Print the command line.
line[count] = '\0';
snprintf( frame.data,
frame.x,
"OS1Shell -> %s",
line);
draw_frame(&frame);
} while (1);
// Restore terminal and free resources.
tcsetattr(STDIN_FILENO, TCSANOW, &tty_old);
free(frame.data);
int n = 0;
while (n < 21) {
free(cmdHistory[n]);
++n;
}
free(cmdHistory);
return (0);
}
Any help getting it to act more like bash would be highly appreciated! Part of the credit is for using stderr correctly anyways, so it would definitely help to take the stdin/stdout/stderr approach.
It looks to me it already is going to STDOUT
fprintf( stdout,
"\033[%d;%dH\033[0m\033[%dm%.*s",
row + 1,
0,
attrib, frame->x, data);
fflush(stdout);