Hey there. I'm having a very strange problem with creating sha256 hashes. I made a simple C console program that takes a file path as an argument and uses the standalone sha256 code that can be found here. I compiled the program using MinGW 5.1.6 on Windows 7 x64.
When testing the program on a file, the resultant hash is wrong. I made sure of this by using md5deep on the file, and then by using sha256sum on the file under Linux.
I also verified it was not the code by compiling and running the same code on my Linux box with the same file; the hash it produced was identical to the ones produced by md5deep and sha256sum.
I also adapted Aaron Gifford's sha256 implementation into a different version of my simple program and performed the test again on both Windows and Linux and ended up with the same result.
Could it be possible that the issue is being caused by compiler flags that have not been switched on?
My knowledge of C isn't amazing and my knowledge of compiler options is even worse, so any help would be kindly appreciated.
The code for the simple program is below:
#include <stdio.h>
#include "sha256.h"
#define BUFLEN 16384
int main(int argc, char *argv[]) {
sha256_context ctx256;
sha256_starts(&ctx256);
int kl, l, fd;
unsigned char buf[BUFLEN];
FILE *file = (FILE*) 0;
char *filepath;
fd = fileno(stdin);
filepath = argv[1];
file = fopen(filepath, "r");
fd = fileno(file);
while ((l = read(fd, buf, BUFLEN)) > 0) {
kl += l;
sha256_update(&ctx256, buf, l);
}
fclose(file);
uint8 sha256sum[32];
sha256_finish(&ctx256, sha256sum);
int i;
for (i = 0; i < 32; i++) {
printf("%02x", sha256sum[i]);
}
printf("\n");
return 0;
}
Binary mode gets ignored on Linux, but it applies in Windows. For reference on what it does, see http://msdn.microsoft.com/en-us/library/yeby3zcb%28VS.71%29.aspx. In short, \r\n gets translated to \n in non-binary mode.
Related
I wrote an XOR program in C. The purpose of the program is to XOR files, I have tested this program on Linux as it is my main OS and it worked perfectly with an '.exe' (I was using wine to execute exe's on Linux). When the program was tested on Windows however, I noticed that I was losing bytes of data when I XORed the file and I do not know why, if somebody can shed some light on the situation it would be really appreciated. Below I have posted the code to my XOR program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
//XOR key
#define XOR_KEY 0x6F
void XORFile(char *infile, char *outfile)
{
FILE *fp;
FILE *fp2;
int rlen;
char buf[4096];
fp = fopen(infile, "r");
fp2 = fopen(outfile, "w");
while (1) {
rlen = fread(buf,1,sizeof(buf),fp);
if (rlen <= 0)
break;
// XOR read file buffer
for (int i = 0; i < rlen; ++i)
buf[i] ^= XOR_KEY;
fwrite(buf,1,rlen,fp2);
}
fclose(fp);
fclose(fp2);
}
int main (int argc, char *argv[]) {
if(argc <= 3){
fprintf (stderr, "Usage: %s [CRYPT] [IN FILE] [OUTFILE]\n", argv[0]);
exit(1);
}
XORFile (argv[2], argv[3]);
return 0;
}
As pointed out in the comments, you should use the "rb" and "wb" modes in your fopen calls (the added b opens/creates the file in binary mode).
In text mode (the default), Windows does some special processing on certain characters (like converting between a single \n and the \r\n pair).
From cppreference:
Text files are files containing sequences of lines of text. Depending
on the environment where the application runs, some special character
conversion may occur in input/output operations in text mode to adapt
them to a system-specific text file format. Although on some
environments no conversions occur and both text files and binary files
are treated the same way, using the appropriate mode improves
portability.
I was playing with very simple encryption/decryption algorithm like this;
#include <stdio.h>
#include <stdlib.h>
#define BUFFESIZE 1024
int main(int argc, char *argv[]) {
int keylen = 0;
char *key = argv[1];
char *buffer = NULL;
size_t buffersize = 0;
size_t nbytes = 0;
size_t nread;
int i = 0;
while(*key++ != 0) keylen++;
key = argv[1];
do {
buffersize+=BUFFESIZE;
buffer = realloc(buffer, buffersize);
nread = fread(buffer+nbytes, 1, BUFFESIZE, stdin);
nbytes+=nread;
} while (nread > 0);
for(i=0; i<nbytes; i++) {
putchar(buffer[i] ^ key[i % keylen]);
}
return 0;
}
Encyption key is the first command-line argument to the program. I expect that this should get me originial file when encrypted/decrypted with same key. However, I sometimes get only small amount of the file back if I encrypt/decrypt it. My guess is that algorithm adds EOF control character in the middle of file.
How can I get around this problem?
I compiled this using MinGW gcc 4.8.1 on windows XP. If you're interested, you can find a sample input file demonstrating the problem in the edit history of this question.
Well, your code works for me on Linux (compiled with GCC 4.8.2), even using your sample input and key. This suggests that the issue is specific to Windows — most likely, that it's caused by stdin and stdout being in text mode by default. (On Linux and other Unix-ish systems, there's usually no difference between text mode and binary mode, so such issues do not show up there.)
To fix it, you will need to set stdin and stdout to binary mode. The standard way of doing this, as of C99, would be:
freopen(NULL, "rb", stdin);
freopen(NULL, "wb", stdout);
but alas, according to the answers in the thread I linked to above, the Windows C library does not support this C99 feature, so you'll need to fall back on the non-standard _setmode() instead:
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
If you want to remain portable, you could always use some conditional code, e.g. like this (warning: not actually tested on Windows!):
#if __STDC_VERSION__ >= 199901L
#define binmode(fh, w) freopen(NULL, ((w) ? "wb" : "rb"), (fh)) /* C99 */
#elif _MSC_VER >= 1200
#include <io.h>
#include <fcntl.h>
#define binmode(fh, w) _setmode(_fileno(fh), _O_BINARY) /* MSVC 6.0+ */
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#define binmode(fh, w) /* Unix-ish, just do nothing */
#else
#error Not sure how to define binmode() on this platform
#endif
binmode(stdin, 0);
binmode(stdout, 1);
Or, of course, you could just sidestep the whole issue by opening your own input and output files (in binary mode) instead of using stdin and stdout.
I have a program written in Linux in C, and it works well on Linux platform, but it doesn't work in Windows. It compiles successfully in Windows, using Code Blocks(mingw32-gcc), but it doesn't work as expected, it simply throws an error and kills the program. How can I make it to work on Windows, Please help. This is the code:
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i, size, k = 2, ftab, sect = 3;
char buf[512];
char vbuf;
int dev, fil_descr, off=0;
fil_descr = open(argv[2], O_RDONLY);
assert(fil_descr > 0);
read(fil_descr, buf, 512);
close(fil_descr);
printf("Bootsector file: %s\n" ,argv[2]);
dev=open(argv[1], O_RDWR);
assert(dev > 0);
write(dev, buf, 512);
ftab = open("filetable", O_CREAT|O_RDWR);
sprintf(buf, "{");
write(ftab, buf, 1);
for(i = 3; i < argc; i++)
{
off = off + (k * 512);
lseek(dev, off, SEEK_SET);
fil_descr=open(argv[i], O_RDONLY);
assert(fil_descr > 0);
size = 0;
while((read(fil_descr, &vbuf, 1))!=0)
{
size++;
write(dev, &vbuf, 1);
}
k = (size > 512)?2:1;
sprintf(buf, "%s-%d," ,argv[i], sect);
write(ftab, buf, strlen(buf));
printf("Input file \'%s\' written at offset %d\n", argv[i], off);
close(fil_descr);
sect = sect + k;
}
sprintf(buf,"}");
write(ftab, buf, 1);
lseek(ftab, 0, SEEK_SET);
read(ftab, buf, 512);
lseek(dev, 512, SEEK_SET);
write(dev, buf, 512);
close (dev);
close(ftab);
}
This is not a C program not working under Windows (although C is the programming language used).
What isn't woking is trying to compile a program using POSIX API functions (such as open, read, write) using a compiler targetting Win32. This includes the use of several headers that don't exist in this environment (which, if they existed, would declare functions that don't exist on the system).
You will either have to use a Unix compatibility layer (Microsoft used to sell that, not sure if they still do, also Cygwin might work), or use proper C, or use native Win32 API functions.
That said, it will also probably not work in the intended way if you switch to using the C standard library I/O funcitons or the native Win32 functions. The output "Bootsector:" suggests that you are trying something that will not work on the system drive at all, and only work with administrative privilegues on another disk.
In order to debug a problem like this, you should add some lines of code helping you to do so.
I changed the respective part of the program to
printf("Bootsector file: %s\n" ,argv[2]);
fil_descr = open(argv[2], O_RDONLY);
if (fil_descr < 0) {
perror("open");
}
printf("fil_descr: %d\n", fil_descr);
assert(fil_descr > 0);
and became aware of the fact that the 2nd command line argument must be a file name of a file to be read.
If I specify it correctly, it works fine.
The 1st file is being written to, and the remaining arguments are file names to be read as well.
Both the headers are linux specific,
#include <sys/types.h>
#include <unistd.h>
I'm testing tmpfile() with mingw-gcc (CodeBlocks, latest) and program works as expected: opens 10 temp files, write 10 random strings, then read-back those 10 strings and close each *fp.
Like I said, works as expected but reading some articles about temporarily locations on win7, I begun to search where actually the files are stored, before auto-erase. On UNIX, the default location would be /tmp
On windows 7, I'm running out of ideas...
- the program folder
- the user/appdata/local/tmp/
- windows/temp
I cannot find those files and I searched even with total commander from some known strings inside. None. Any idea?
I've had the same question, and after reviewing the thread linked here:
http://sourceforge.net/p/mingw/bugs/666/
... I think the MinGW guys rolled a special version that keeps the temporary file entirely in memory.
I don't know how complete their solution is without combing through MinGW's source and/or asking on the mailing lists. In either case, it is probably a better idea to use some function other than tmpfile() anyway, given its problems.
I used Process Explorer to monitor the open handles on this program:
#include <stdio.h>
int main(int argc, char *argv[]) {
int a;
scanf("%d", &a);
printf("%p", tmpfile());
scanf("%d", &a);
return 0;
}
After printf("%p", tmpfile()); was executed, a new file handle was opened, and the file path was C:\Users\sashoalm\AppData\Local\VirtualStore\t9mc. I ran the program again and this time it was C:\Users\sashoalm\AppData\Local\VirtualStore\t728. So it places them in C:\Users\sashoalm\AppData\Local\VirtualStore\, and the name is some randomly generated string starting with "t".
See Why do files get placed in "C:\Users\<username>AppData\Local\VirtualStore\Program Files(x86)"? about the "Virtual Store" folder.
/ I tested Dev-C++ 5.11 (Mngv) gcc, and dont work. With Borland 5.5 in Code:: Block no problem.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
char filename[L_tmpnam];
char *strs[] = {"Hello\n","Goodbye\n","Cat\n","Dog\n",NULL};
char **mover = strs;
char line[80],command[80];
FILE *fp;
fp = tmpfile();
for(; *mover != NULL; mover++) fputs(*mover,fp);
rewind(fp);
while(fgets(line,80,fp))printf("%s",line);
fclose(fp);
if(tmpnam(filename) == NULL){
printf("Could not get non-conflicting file name\n");
exit(EXIT_FAILURE);
}
printf("\nFilename obtained is: %s\n\n",filename);
fp = fopen(filename, "w+");
for(mover = strs; *mover != NULL; mover++) fputs(*mover, fp);
rewind(fp);
while(fgets(line,80,fp)) printf("%s",line);
putchar('\n');
fclose(fp);
return 0;
}
On Wi32
I am trying to start a executable who redirects to a filename (current date) e.g. the same as:
Someexecutable.exe > 20101220000000.txt
When I do this from windows cmd.exe everything works fine. However when doing this from my program as shown below the system seems ot either drop the redirect even if it creates the file and/or it seems to buffer a large amount of data before flushing to disk.
I can't change the executable that is being run.
The program beeing executed now only writes to stdout, but remember I can't change this at all. (the simplest way woud be to just do stdout = filehandle; but I that is sadly impossible for me right now!)
(Not required: Also the program waits as system() this is not required but what is the simplest way of detaching the program being run via system() )
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
char execstr[512];
char s[30];
size_t i;
struct tm tim;
time_t now;
now = time(NULL);
tim = *(localtime(&now));
i = strftime(s,30,"%Y%m%d%H%M",&tim);
sprintf(execstr,"someexecutable.exe > %s.txt",s);
printf("Executing: \"%s\"\n",execstr);
system(execstr);
exit(0);
return 0;
}
I don't see any reason for this to not work, but if this is the case with you, one of the alternative solution could be to use popen and then read from the pipe for writing in the desired file. Here is some sample code which is printing on the screen. You can write that to file instead of screen/console as per your requirement.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
char execstr[512];
char s[30];
size_t i;
struct tm tim;
time_t now;
char buf[128];
FILE *pipe;
now = time(NULL);
tim = *(localtime(&now));
i = strftime(s,30,"%Y%m%d%H%M",&tim);
#if 0
sprintf(execstr,"a.exe > %s.txt",s);
printf("Executing: \"%s\"\n",execstr);
#endif /* #if 0 */
if( (pipe = _popen("a.exe", "rt")) == NULL )
exit( 1 );
while(!feof(pipe))
{
if (fgets(buf, 128, pipe) != NULL )
printf(buf); /* write to the required file here */
}
_pclose(pipe);
return 0;
}
Your program works fine for me (testing in VS 2010). Some problems you might run into if you're running your tests in the IDE are:
the current directory for the program might not be what you expect it to be (so you might be looking for the output file in the wrong place). By default, the current directory for the program when run in the IDE will be the directory that has the project file (whatever.vcproj or whatever,.vcxproj) - not the directory that has the executable. This can be changed in the project settings.
the IDE's path might not be the same as what you get at a standard command line, so you program might not be finding someexecutable.exe
If you change you program so that the line with the sprintf() call looks like:
sprintf(execstr,"someexecutable.exe",s);
Do you see the output of someexecutable.exe in the console window?