Related
Here is a working example of a simple HTTP server written in C (working well for it's purpose)
But what I try to achieve/understand is how to implement directory listening!!
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<signal.h>
#include<fcntl.h>
#include <dirent.h>
#define CONNMAX 100
#define BYTES 1024
char* directory;
struct dirent *dirst;
DIR *dir;
char *ROOT;
int listenfd, clients[CONNMAX];
void error(char *);
void startServer(char *);
void respond(int);
int main(int argc, char* argv[])
{
struct sockaddr_in clientaddr;
socklen_t addrlen;
char c;
//Default Values PATH = ~/ and PORT=10000
char PORT[6];
ROOT = getenv("PWD");
strcpy(PORT,"10000");
int slot=0;
//Parsing the command line arguments
while ((c = getopt (argc, argv, "p:r:")) != -1)
switch (c)
{
case 'r':
ROOT = malloc(strlen(optarg));
strcpy(ROOT,optarg);
break;
case 'p':
strcpy(PORT,optarg);
break;
case '?':
fprintf(stderr,"Wrong arguments given!!!\n");
exit(1);
default:
exit(1);
}
printf("Server started at port no. %s%s%s with root directory as %s%s%s\n","\033[92m",PORT,"\033[0m","\033[92m",ROOT,"\033[0m");
// Setting all elements to -1: signifies there is no client connected
int i;
for (i=0; i<CONNMAX; i++)
clients[i]=-1;
startServer(PORT);
// ACCEPT connections
while (1)
{
addrlen = sizeof(clientaddr);
clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen);
if (clients[slot]<0)
error ("accept() error");
else
{
if ( fork()==0 )
{
respond(slot);
exit(0);
}
}
while (clients[slot]!=-1) slot = (slot+1)%CONNMAX;
}
return 0;
}
//start server
void startServer(char *port)
{
struct addrinfo hints, *res, *p;
// getaddrinfo for host
memset (&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo( NULL, port, &hints, &res) != 0)
{
perror ("getaddrinfo() error");
exit(1);
}
// socket and bind
for (p = res; p!=NULL; p=p->ai_next)
{
listenfd = socket (p->ai_family, p->ai_socktype, 0);
if (listenfd == -1) continue;
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) break;
}
if (p==NULL)
{
perror ("socket() or bind()");
exit(1);
}
freeaddrinfo(res);
// listen for incoming connections
if ( listen (listenfd, 1000000) != 0 )
{
perror("listen() error");
exit(1);
}
}
//client connection
void respond(int n)
{
char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
int rcvd, fd, bytes_read;
memset( (void*)mesg, (int)'\0', 99999 );
rcvd=recv(clients[n], mesg, 99999, 0);
if (rcvd<0) // receive error
fprintf(stderr,("recv() error\n"));
else if (rcvd==0) // receive socket closed
fprintf(stderr,"Client disconnected unexpectedly.\n");
else // message received
{
// printf("%s", mesg);
reqline[0] = strtok (mesg, " \t\n");
if ( strncmp(reqline[0], "GET\0", 4)==0 )
{
reqline[1] = strtok (NULL, " \t");
reqline[2] = strtok (NULL, " \t\n");
if ( strncmp( reqline[2], "HTTP/1.0", 8)!=0 && strncmp( reqline[2], "HTTP/1.1", 8)!=0 )
{
write(clients[n], "HTTP/1.0 400 Bad Request\n", 25);
}
else
{
if ( strncmp(reqline[1], "/\0", 2)==0 )
reqline[1] = "/index.html"; //Because if no file is specified, index.html will be opened by default (like it happens in APACHE...
strcpy(path, ROOT);
strcpy(&path[strlen(ROOT)], reqline[1]);
printf("Serving: %s\n", path);
if ( (fd=open(path, O_RDONLY))!=-1 ) //FILE FOUND
{
send(clients[n], "HTTP/1.0 200 OK\n\n", 17, 0);
while ( (bytes_read=read(fd, data_to_send, BYTES))>0 )
write (clients[n], data_to_send, bytes_read);
}
else write(clients[n], "HTTP/1.0 404 Not Found\n", 23); //FILE NOT FOUND
}
}
}
//Closing SOCKET
shutdown (clients[n], SHUT_RDWR); //All further send and recieve operations are DISABLED...
close(clients[n]);
clients[n]=-1;
}
gcc -Wall -Wextra -Werror simplehttp.c -o http
./http -p 9090 -r /home/configs
Now, in browser if i type address http://localhost:9090 => got error( because index,html is missing)
As I'm still rusty in C(trying to get back in shape), i try to modify the code to allow also dir listen :)
Any help is much appreciate :)
I have created a simple webserver, but I am unable to re-fetch the page twice. In server code my intention was to fetch as many times as the user prefers. I am fetching the page in Firefox browser. I am not saying there is anything wrong with the browser, but there may be problems with my code. So can anyone please tell me what could be the reason that my server is unable to render the page and css again. Is there any mistake in the response header? Why is browser unable to fetch the page?
This is the code:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
//aaa
#define PORT 5000
#define BUF_SIZE 20000
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
int min(int a, int b)
{
return a>b?b:a;
}
int process(int size,char buffer[size],char status)
{
int i=0;
int line_len=0;
char *line=malloc(sizeof(char) *150);
while(i<size)
{
if(strncmp((void *)&buffer[i],"style9.css",strlen("style9.css"))==0)
return 3;
if(strncmp((void *)&buffer[i],"GET / HTTP/1.1",14)==0)
{
while(buffer[i]!='\n')
{
line[line_len]=buffer[i];
line_len++;
i++;
}
//line[line_len]='\0';
//printf("%s\n",line);
memset(line,0,line_len);
line_len=0;
return 2;
}
i++;
line_len++;
}
return 2;
}
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
{
off_t orig;
if (offset != NULL) {
/* Save current file offset and set offset to value in '*offset' */
orig = lseek(in_fd, 0, SEEK_CUR);
if (orig == -1)
return -1;
if (lseek(in_fd, *offset, SEEK_SET) == -1)
return -1;
}
size_t totSent = 0;
while (count > 0) {
size_t toRead = min(BUF_SIZE, count);
char buf[BUF_SIZE];
ssize_t numRead = read(in_fd, buf, toRead);
if (numRead == -1)
return -1;
if (numRead == 0)
break; /* EOF */
ssize_t numSent = write(out_fd, buf, numRead);
if (numSent == -1)
return -1;
if (numSent == 0) /* Should never happen */
printf("fatal: should never happen");
//fatal("sendfile: write() transferred 0 bytes");
count -= numSent;
totSent += numSent;
}
if (offset != NULL) {
/* Return updated file offset in '*offset', and reset the file offset
to the value it had when we were called. */
*offset = lseek(in_fd, 0, SEEK_CUR);
if (*offset == -1)
return -1;
if (lseek(in_fd, orig, SEEK_SET) == -1)
return -1;
}
return totSent;
}
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1000] = {0};
int get_return321;
//GET /css/style.css HTTP/1.1
char *hello = "HTTP/1.1 200 Okay\r\nContent-Type: text/html; charset=ISO-8859-4 \r\n\r\n";
//"HTTP/1.1 200 OK\\r\\n" \
"Content-Length: 55\r\n\n Content-Type: application/json\r\n '{\"name\":\"fawad\"}'";
//struct stat sb;
char *hello1 = "HTTP/1.1 200 Okay\r\nContent-Type: text/css\r\n\r\n";
struct stat sb_html;
struct stat sb_css;
int fd_in_html=open("/home/fawad/Desktop/C-work/html9.html",O_RDONLY);
const char* filename_html="/home/fawad/Desktop/C-work/html9.html";
int fd_in_css=open("/home/fawad/Desktop/C-work/css/style9.css",O_RDONLY);
const char* filename_css="/home/fawad/Desktop/C-work/css/style9.css";
if (stat(filename_html, &sb_html) == -1)
{
printf("%d\n",errno);
//exit(EXIT_FAILURE);
}
if (stat(filename_css, &sb_css) == -1)
{
printf("%d\n",errno);
//exit(EXIT_FAILURE);
}
printf("%lu\n",sb_css.st_size);
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
//exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt, sizeof(opt)))
{
perror("setsockopt");
//exit(EXIT_FAILURE);
}
/*if( setsockopt(server_fd, SOL_SOCKET, SO_SNDBUF, &sb.st_size, sizeof(sb.st_size)))
{
printf("sockopt\n");
}*/
/*int state = 1;
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &state, sizeof(state)))
{
printf("sockopt\n");
}*/
int state = 1;
if(setsockopt(server_fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)))
{
printf("TCP CORK\n");
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address,sizeof(address))<0)
{
perror("bind failed");
//exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
//exit(EXIT_FAILURE);
}
while(1)
{
printf("in loop\n");
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
// exit(EXIT_FAILURE);
}
printf("request came\n");
valread = read( new_socket , buffer, (1000));
//printf("%s\n",buffer );
printf("_________________________________\n");
get_return321=process(900,buffer,'r');
buffer[499]='\0';
printf("\n");
printf("\n");
if(get_return321==2)
{
send(new_socket , hello , strlen(hello) , 0 );
//send(new_socket , buffer_html , sb_html.st_size , 0 );
sendfile(new_socket,fd_in_html,0,sb_html.st_size);
printf("html sent\n");
}
if(get_return321==3)
{
send(new_socket , hello1 , sb_css.st_size , 0 );
sendfile(new_socket,fd_in_css,0,sb_css.st_size);
printf("3 reached\n");
}
close(new_socket);
state = 0;
setsockopt(server_fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
//close(new_socket);
state = 1;
setsockopt(server_fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
}
//close(fd_in);
close(fd_in_html);
}
This is the output of running the program and sending a few requests from browser
user#fawad:Desktop/C-work# ./a.out
22926
in loop
request came
_________________________________
html sent
in loop
request came
_________________________________
3 reached
in loop
request came
_________________________________
html sent
in loop
request came
_________________________________
html sent
in loop
Killed
I have fixed it. I was not closing file descriptors so my current positions always stayed at the end of files in re-fetch attempts from firefox. Now working this is the full working code
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
//aaa
#define PORT 80
#define BUF_SIZE 20000
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
int min(int a, int b)
{
return a>b?b:a;
}
int process(int size,char buffer[size],char status)
{
int i=0;
int line_len=0;
char *line=malloc(sizeof(char) *150);
while(i<size)
{
if(strncmp((void *)&buffer[i],"style9.css",strlen("style9.css"))==0)
return 3;
if(strncmp((void *)&buffer[i],"GET / HTTP/1.1",14)==0)
{
while(buffer[i]!='\n')
{
line[line_len]=buffer[i];
line_len++;
i++;
}
//line[line_len]='\0';
//printf("%s\n",line);
memset(line,0,line_len);
line_len=0;
return 2;
}
i++;
line_len++;
}
return 2;
}
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
{
off_t orig;
if (offset != NULL) {
/* Save current file offset and set offset to value in '*offset' */
orig = lseek(in_fd, 0, SEEK_CUR);
if (orig == -1)
return -1;
if (lseek(in_fd, *offset, SEEK_SET) == -1)
return -1;
}
size_t totSent = 0;
while (count > 0) {
size_t toRead = min(BUF_SIZE, count);
char buf[BUF_SIZE];
ssize_t numRead = read(in_fd, buf, toRead);
if (numRead == -1)
return -1;
if (numRead == 0)
break; /* EOF */
ssize_t numSent = write(out_fd, buf, numRead);
if (numSent == -1)
return -1;
if (numSent == 0) /* Should never happen */
printf("fatal: should never happen");
//fatal("sendfile: write() transferred 0 bytes");
count -= numSent;
totSent += numSent;
}
if (offset != NULL) {
/* Return updated file offset in '*offset', and reset the file offset
to the value it had when we were called. */
*offset = lseek(in_fd, 0, SEEK_CUR);
if (*offset == -1)
return -1;
if (lseek(in_fd, orig, SEEK_SET) == -1)
return -1;
}
return totSent;
}
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1000] = {0};
int get_return321;
//GET /css/style.css HTTP/1.1
char *hello = "HTTP/1.1 200 Okay\r\nContent-Type: text/html; charset=ISO-8859-4 \r\n\r\n";
//"HTTP/1.1 200 OK\\r\\n" \
"Content-Length: 55\r\n\n Content-Type: application/json\r\n '{\"name\":\"fawad\"}'";
//struct stat sb;
char *hello1 = "HTTP/1.1 200 Okay\r\nContent-Type: text/css\r\n\r\n";
struct stat sb_html;
struct stat sb_css;
int fd_in_html;//=open("/home/fawad/Desktop/C-work/html9.html",O_RDONLY);
const char* filename_html="/home/fawad/Desktop/C-work/html9.html";
int fd_in_css;//=open("/home/fawad/Desktop/C-work/css/style9.css",O_RDONLY);
const char* filename_css="/home/fawad/Desktop/C-work/css/style9.css";
//printf("%lu\n",sb_css.st_size);
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
//exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt, sizeof(opt)))
{
perror("setsockopt");
//exit(EXIT_FAILURE);
}
/*if( setsockopt(server_fd, SOL_SOCKET, SO_SNDBUF, &sb.st_size, sizeof(sb.st_size)))
{
printf("sockopt\n");
}*/
/*int state = 1;
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &state, sizeof(state)))
{
printf("sockopt\n");
}*/
int state = 1;
if(setsockopt(server_fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)))
{
printf("TCP CORK\n");
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address,sizeof(address))<0)
{
perror("bind failed");
//exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
//exit(EXIT_FAILURE);
}
while(1)
{
printf("in loop\n");
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
// exit(EXIT_FAILURE);
}
printf("request came\n");
valread = read( new_socket , buffer, (1000));
//printf("%s\n",buffer );
printf("_________________________________\n");
get_return321=process(900,buffer,'r');
buffer[499]='\0';
printf("\n");
printf("\n");
if(get_return321==2)
{
send(new_socket , hello , strlen(hello) , 0 );
//send(new_socket , buffer_html , sb_html.st_size , 0 );
fd_in_html=open("/home/fawad/Desktop/C-work/html9.html",O_RDONLY);
if (stat(filename_html, &sb_html) == -1)
{
printf("%d\n",errno);
//exit(EXIT_FAILURE);
}
sendfile(new_socket,fd_in_html,0,sb_html.st_size);
close(fd_in_html);
printf("html sent\n");
}
if(get_return321==3)
{
send(new_socket , hello1 , sb_css.st_size , 0 );
fd_in_css=open("/home/fawad/Desktop/C-work/css/style9.css",O_RDONLY);
if (stat(filename_css, &sb_css) == -1)
{
printf("%d\n",errno);
//exit(EXIT_FAILURE);
}
sendfile(new_socket,fd_in_css,0,sb_css.st_size);
printf("3 reached\n");
close(fd_in_css);
}
close(new_socket);
state = 0;
setsockopt(server_fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
//close(new_socket);
state = 1;
setsockopt(server_fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
}
//close(fd_in);
close(fd_in_html);
}
I wrote those two codes. server and client.
//***Server***
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#define BUF_SIZE 1024
#define OPSZ 4
void ErrorHandling(char *message);
int calculate(int opnum, int opnds[], char op);
int main(int argc, char *argv)
{
WSADATA wsaData;
SOCKET hServSock, hClntSock;
char opinfo[BUF_SIZE];
int result, opndCnt, i;
int recvCnt, recvLen;
SOCKADDR_IN servAdr, clntAdr;
int clntAdrSize;
if(argc != 2)
{
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHandling("WSAStartup() error!");
hServSock = socket(PF_INET, SOCK_STREAM, 0);
if(hServSock == INVALID_SOCKET)
ErrorHandling("socket() error");
memset(&servAdr, 0, sizeof(servAdr));
servAdr.sin_family = AF_INET;
servAdr.sin_addr.s_addr = htonl(INADDR_ANY);
servAdr.sin_port = htons(atoi((char*)argv[1]));
if(bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
ErrorHandling("bind() error");
if(listen(hServSock, 5) == SOCKET_ERROR)
ErrorHandling("listen() error");
clntAdrSize = sizeof(clntAdr);
for(i=0; i<5; i++)
{
opndCnt = 0;
hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &clntAdrSize);
recv(hClntSock, (char*)&opndCnt, 1, 0);
recvLen = 0;
while((opndCnt*OPSZ+1) > recvLen)
{
recvCnt = recv(hClntSock, &opinfo[recvLen], BUF_SIZE-1, 0);
recvLen += recvCnt;
}
result = calculate(opndCnt, (int*)opinfo, opinfo[recvLen-1]);
send(hClntSock, (char*)&result, sizeof(result), 0);
closesocket(hClntSock);
}
closesocket(hServSock);
WSACleanup();
return 0;
}
int calculate(int opnum, int opnds[], char op)
{
int result = opnds[0], i;
switch(op)
{
case '+':
for(i=1; i<opnum; i++) result += opnds[i];
break;
case '-':
for(i=1; i<opnum; i++) result -= opnds[i];
break;
case '*':
for(i=1; i<opnum; i++) result *= opnds[i];
break;
}
return result;
}
void ErrorHandling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
//***client***
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#define BUF_SIZE 1024
#define RLT_SIZE 4
#define OPSZ 4
void ErrorHandling(char *message);
int main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET hSocket;
char opmsg[BUF_SIZE];
int result, opndCnt, i;
SOCKADDR_IN servAdr;
if(argc != 3)
{
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHandling("WSAStartup() error!");
hSocket = socket(PF_INET, SOCK_STREAM, 0);
if(hSocket == INVALID_SOCKET)
ErrorHandling("socket() error");
memset(&servAdr, 0, sizeof(servAdr));
servAdr.sin_family = AF_INET;
servAdr.sin_addr.s_addr = inet_addr(argv[1]);
servAdr.sin_port = htons(atoi(argv[2]));
if(connect(hSocket, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
ErrorHandling("connect() error!");
else
puts("Connected..........");
fputs("Operand count: ", stdout);
scanf("%d", &opndCnt);
opmsg[0] = (char)opndCnt;
for(i=0; i<opndCnt; i++)
{
printf("Operand %d: ", i+1);
scanf("%d", (int*)&opmsg[i*OPSZ+1]);
}
fgetc(stdin);
fputs("Operator: ", stdout);
scanf("%c", &opmsg[opndCnt*OPSZ+1]);
send(hSocket, opmsg, opndCnt*OPSZ+2, 0);
recv(hSocket, (char*)&result, RLT_SIZE, 0);
printf("Operation result: %d \n", result);
closesocket(hSocket);
WSACleanup();
return 0;
}
void ErrorHandling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
I compiled those two codes (that means 2 projects separately) and that made Debug folder.
I saved those 2 project folders to Desktop.
I started cmd and then wrote
cd Desktop-> cd server -> cd Debug -> server 9190
but the error happens (I first coded server to turn the server on, and then I was planning to make the connection between the server and client.)
int main(int argc, char *argv) should read int main(int argc, char **argv)
char *argv[] would also work.
What does int argc, char *argv[] mean? might be worth a read.
Here is a link to a tutorial that will help you get started with winsock programming.
who can tell me ? I use directshow and wia but don't find the method
Why don't you use the OpenCV?
main.cpp
int main(int argc, char** argv) {
CvCapture* capture = cvCaptureFromCAM(0);
int index = 0;
while(cvGrabFrame(capture)) {
/*Get webcam image!*/
IplImage *camImg = cvRetrieveFrame(capture);
/*Save the image to the disk!*/
string fileName = "tmp/" + int2str(index) + ".jpg";
cvSaveImage(fileName.c_str(), screenShotImg);
index++;
int key = cvWaitKey(10);
if(key == 27) {
break;
}
}
cvReleaseCapture(&capture);
return 0;
}
TypeConvert.cpp
#include "TypeConvert.h"
#include <iostream>
#include <sstream>
string int2str(int &num) {
string emptyStr;
stringstream ss(emptyStr);
ss << num;
return ss.str();
}
I am trying to port my program from Windows to Linux. The windows program uses Window CryptoAPI and linux is using libmcrypt.
Here is the Windows code:
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <exception>
using namespace std;
class CryptError:public exception{
public:
CryptError(){}
};
#define CHECK_RET(x) if(x == FALSE) {retval = GetLastError(); throw CryptError();};
LONG Decrypt(const string &key, std::vector<BYTE> &data){
LONG retval = 0;
try{
HCRYPTPROV hCrypt;
HCRYPTHASH hHash;
HCRYPTKEY hKey;
CHECK_RET(CryptAcquireContext(&hCrypt, NULL, NULL, PROV_RSA_FULL, 0));
CHECK_RET(CryptCreateHash(hCrypt, CALG_MD5, 0, 0, &hHash));
CHECK_RET(CryptHashData(hHash, reinterpret_cast<const BYTE *>(key.c_str()), key.size(), 0));
CHECK_RET(CryptDeriveKey(hCrypt, CALG_RC2, hHash, MAKELPARAM(CRYPT_EXPORTABLE, 80), &hKey));
BYTE tempVal[200];
DWORD len = 200;
CryptGetKeyParam(hKey, KP_EFFECTIVE_KEYLEN, tempVal, &len, 0);
len = 200;
CryptGetKeyParam(hKey, KP_MODE, tempVal, &len, 0);
len = 200;
CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB, 0, tempVal, &len);
len = 200;
CryptGetKeyParam(hKey, KP_IV, tempVal, &len, 0);
DWORD count = data.size();
CHECK_RET(CryptDecrypt(hKey, 0, TRUE, 0, &(data[0]), &count));
data.resize(count);
}catch(CryptError &e){
}
return retval;
}
int main(void){
BYTE data[9] = {0xdc,0x3d,0x96,0x23,0x29,0xdd,0x1b,0x2f, 0};
vector<BYTE> vData(data, data + 8);
Decrypt("PNEMAIL", vData);
cerr << "vData: ";
int len = vData.size();
for(int i = 0; i < len; i++){
if(i > 0)
cerr << ',';
cerr << hex << setw(2) << setfill('0') << (int)(vData[i]);
}
cerr << endl;
return 0;
}
When the program is run, it returns:
vData: 42,46,30,41,43,34,31
The Q&D linux version looks like this:
#include <mcrypt.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <openssl/md5.h>
#include <stdint.h>
#include <stdexcept>
#include <vector>
#include <valarray>
#include <memory.h>
using namespace std;
class MCrypt{
private:
MCRYPT mcrypt;
public:
MCrypt(char *algorithm, char* algorithm_directory, char *mode, char* mode_directory){
mcrypt = mcrypt_module_open(algorithm, algorithm_directory, mode, mode_directory);
if(mcrypt == MCRYPT_FAILED)
throw runtime_error("MCrypt init failed");
}
int init(void *key, int lenofkey, void *IV){
return mcrypt_generic_init(mcrypt, key, lenofkey, IV);
}
int enc_get_iv_size(){
return mcrypt_enc_get_iv_size(mcrypt);
}
int deinit(){
return mcrypt_generic_deinit(mcrypt);
}
int decrypt(void *data, int len){
mdecrypt_generic(mcrypt, data, len);
}
~MCrypt(){
deinit();
mcrypt_module_close(mcrypt);
}
};
#ifdef DEBUG
void inline printArrayFunc(const char *start, const uint8_t *data, int len){
// DEBUG: print value of $key1
cerr << start;
for(int i = 0; i < len; i++){
if(i > 0)
cerr << ',';
cerr << hex << setw(2) << setfill('0') << (int)(data[i]);
}
cerr << endl;
}
#define printArray(start, data, len) printArrayFunc(start, data, len)
#else
#define printArray(start, data, len)
#endif
int main(void){
uint8_t data[8] = {0xdc,0x3d,0x96,0x23,0x29,0xdd,0x1b,0x2f};
const char *sKey1 = "PNEMAIL";
const int key1Len = 7;
uint8_t *dataPtr = &(data[0]);
uint8_t key1[17];
key1[16] = 0;
// Hash sKey1
MD5(reinterpret_cast<const unsigned char *>(sKey1), key1Len, key1);
MCrypt mcrypt(MCRYPT_RC2, NULL, MCRYPT_CBC, NULL);
vector<uint8_t> iv(mcrypt.enc_get_iv_size(), 0);
// Use the first 80-bits of key1
mcrypt.init(key1, 10, &(iv[0]));
mcrypt.decrypt(dataPtr, 8);
printArray("vData: ", dataPtr, 8);
return 0;
}
When the program is run, it returns:
vData: 4d,3d,82,71,88,d2,d5,4b
I've check that both programs are using the same data.
CryptDeriveKey creates a key 07,f1,e2,ea,d4,c8,79,74,03,a6 (according to CryptExportKey), the same as the first 10 bytes of the md5 generated in Linux (which I shorten to match the requested 80-bit key).
Neither are using a salt on the algorithm (or at least are not reporting as such)
They are both using an 8-byte IV of {0,0,0,0,0,0,0,0}
They are both using the RC2 algorithm
They are both using CBC mode
I cannot figure out why they are returning different data. Any assistance would be greatly appreciated.