Saggy Posted January 19, 2008 Share Posted January 19, 2008 (edited) I'm trying to figure out how to use XOR bitwise operation to create a simple encryption method that allows a user to input a key that is needed to encrypt and decrypt with. #include <stdio.h>#include <stdlib.h>int main(int argc, char** argv){FILE *in=stdin,*out=stdout;if(argc>1)in=(argv[1][0]!='-')?fopen(argv[1],"rb"):stdin;if(argc>2)out=(argv[2][0]!='-')?fopen(argv[2],"wb"):stdout;char msg;while((msg = fgetc(in)) != EOF) { msg = msg ^ argv[3][0] ^ argv[3][1] ^ argv[3][2] ^ argv[3][3] ^ argv[3][4] ^ argv[3][5] ^ argv[3][6] ^ argv[3][7] ^ argv[3][8] ^ argv[3][9] ^ argv[3][10] ^ argv[3][11] ^ argv[3][12] ^ argv[3][13] ^ argv[3][14] ^ argv[3][15] ^ argv[3][16] ^ argv[3][17] ^ argv[3][18] ^ argv[3][19] ^ argv[3][20] ^ argv[3][21] ^ argv[3][22] ^ argv[3][23] ^ argv[3][24] ^ argv[3][25] ^ argv[3][26] ^ argv[3][27] ^ argv[3][28] ^ argv[3][29] ^ argv [3][30] ^ argv[3][31] ^ argv[3][32]; fprintf(out, "%c", msg);} fclose(in);fclose(out);return 0;} Usage programname filein[-] fileout[-] key Use '-' for stdin or stdout What I'm trying to do here is use each character in the supplied key within the bitwise operation, so that if any of them were different, it wouldn't decode correctly. While it sounds somewhat good in theory, and in practice it was even more misleading with many results that made it seem spot on, I've found out that it just doesn't operate in the way I want it to. If I use "passwordpassword" as a key, just for kicks, I can then decode it perfectly fine with "mdsswordmdssword". While there are not many more instances where it will decode perfectly, if I change each digit to either plus or minus one space on the ASCII chart, then more and more parts of the text will begin to show themselves. I don't have much of an understanding of why this is happening, but I have a good hunch it's because of the way the XOR operator is changing the bits around. Apparently "md" is the same as "pa" in bits after XOR, and I'm wondering just how many instances of this there are. Is there a better direction I could be going to do this? Someone suggested that I try using XOR to do it because they knew of a good few programs that used user-supplied keys and XOR, but I just can't seem to come to a good enough understanding of how it works in order to even begin to understand why I'm having this issue. Of the few programs I've found that use the XOR and user-supplied key combination, they use MD5 somehow in the operation, but I haven't found any details on how. Here is a good example: http://www.myersdaily.org/joseph/javascript/alphac.html As a side note, I'm getting more into the area of cryptography and it seems to be a good area to practice C with. It seems to be hard to find vary many cryptography program examples though, anyone know of any specialty programming sites heard around cryptography? I know there's google, but I just wonder if anyone knows personally of any really good ones. It doesn't exactly seem to be a popular subject. Edit As a side note, I think I discovered another problem. Using it like this, the order of the characters does not matter. So if you use a keyword like "sucks" you can then decode with "sckus" without any problem. I've tested this on some pretty long strings, and it seems to hold true on strings of any lenth. For example, "rbf)R{sXviUO$MIvrisOdXgc<hQV7koL" will be decoded by "rbf)R{sXviUO$<IvrisOdXgcMhQV7koL" even with the 'M' and '<" switched. I think the reason for this is because with XOR the position of the character must have no effect on the resulting bit value, but I'm not sure if that's what it is or how to rectify that. Edited January 19, 2008 by SagaciousKJB QUOTE (K^2) ...not only is it legal for you to go around with a concealed penis, it requires absolutely no registration! Link to comment Share on other sites More sharing options...
K^2 Posted January 20, 2008 Share Posted January 20, 2008 (edited) Use a different character of the key with different characters of the message. Also, I'd use feof(FILE*) function to check for file end. Otherwise, you might get early termination because of the \0 character in file. Here is how I would do it. #include <stdio.h>#include <strings.h>int main(int argc, char **argv){FILE *in=stdin,*out=stdout;char msg;int l,i;if(argc>1)in=(argv[1][0]!='-')?fopen(argv[1],"rb"):stdin;if(argc>2)in=(argv[2][0]!='-')?fopen(argv[2],"wb"):stdout;if(argc<4){ printf("No key suplied.\n"); return 0;}i=0;l=strlen(argv[3]); //Length of the key.while(!feof(in)){ msg=fgetc(in); msg^=argv[3][i]; fprintf(out,"%c",msg); i++; if(i>=l)i=0;}fclose(in);fclose(out);return 0;} Edit: The XOR operator gives 1 if input bits are 1,0 or 0,1. If both are 0 or both are 1, it gives you 0. Because of that, anything^anything = 0, and something ^ 0 = something. So ((msg^key)^key) = msg^(key^key) = msg ^ 0 = msg. That means that if you run the same key twice, you get original file back. There is a slight problem with this encryption. It's really easy to break if you know something about the file you want to crack. So don't use it on files you want to hide from FBI. Other than that, it's pretty nifty. Hope that helps. Edited January 20, 2008 by K^2 Prior to filing a bug against any of my code, please consider this response to common concerns. Link to comment Share on other sites More sharing options...
Saggy Posted January 20, 2008 Author Share Posted January 20, 2008 Use a different character of the key with different characters of the message. Also, I'd use feof(FILE*) function to check for file end. Otherwise, you might get early termination because of the \0 character in file. Here is how I would do it. #include <stdio.h>#include <strings.h>int main(int argc, char **argv){FILE *in=stdin,*out=stdout;char msg;int l,i;if(argc>1)in=(argv[1][0]!='-')?fopen(argv[1],"rb"):stdin;if(argc>2)in=(argv[2][0]!='-')?fopen(argv[2],"wb"):stdout;if(argc<4){ printf("No key suplied.\n"); return 0;}i=0;l=strlen(argv[3]); //Length of the key.while(!feof(in)){ msg=fgetc(in); msg^=argv[3][i]; fprintf(out,"%c",msg); i++; if(i>=l)i=0;}fclose(in);fclose(out);return 0;} Edit: The XOR operator gives 1 if input bits are 1,0 or 0,1. If both are 0 or both are 1, it gives you 0. Because of that, anything^anything = 0, and something ^ 0 = something. So ((msg^key)^key) = msg^(key^key) = msg ^ 0 = msg. That means that if you run the same key twice, you get original file back. There is a slight problem with this encryption. It's really easy to break if you know something about the file you want to crack. So don't use it on files you want to hide from FBI. Other than that, it's pretty nifty. Hope that helps. Yeah, I've been reading up on it, you can XOR the plaintext bits with the ciphertext bits and the result will be the key bits you used to encrypt with, but like you said it's pretty nifty, and I was just trying my hand at writing a program for it. I had a few more days to work on my code, and wound up with this #include <stdio.h>#include <stdlib.h>#include <string.h>int main(int argc, char** argv){FILE *in=stdin,*out=stdout;/*File handling scheme, if the first letters are - use stdin or stdout, if not use the stringe as filename*/if(argc>1)in=(argv[1][0]!='-')?fopen(argv[1],"rb"):stdin;if(argc>2)out=(argv[2][0]!='-')?fopen(argv[2],"wb"):stdout;int msg;unsigned int strl = strlen(argv[3]);unsigned int i = 0;while((msg = fgetc(in)) != EOF) { msg = msg ^ argv[3][i]; fprintf(out, "%c", msg); if(i < strl) { i++; } else if(i == strl) { i = 0; }} fclose(in);fclose(out);return 0;} It looks pretty similar to yours, aside from the usage of feof(). I have noticed a couple of occurrences of the text being cut short, so I think I will use feof(). The only thing is that with the loop like while(!feof(in)) { msg = fgetc(in); msg = msg ^ argv[3][i]; fprintf(out, "%c", msg); if(i < strl) { i++; } else if(i == strl) { i = 0; } } It spits out an extra character at the end ( on a new line usually ), so I haven't been able to figure out where that's coming from yet, but even though using EOF has only cut it short once or twice, I'd still rather use feof. Guess I've got more tracking down to do. QUOTE (K^2) ...not only is it legal for you to go around with a concealed penis, it requires absolutely no registration! Link to comment Share on other sites More sharing options...
K^2 Posted January 21, 2008 Share Posted January 21, 2008 Hmm... It might not throw feof until it tries reading past the end of file. If that really is the cause, try make the following change. if(!feof(in))fprintf(out, "%c", msg); Just check to make sure this doesn't cut off the last byte of your cypher. Prior to filing a bug against any of my code, please consider this response to common concerns. Link to comment Share on other sites More sharing options...
Saggy Posted January 21, 2008 Author Share Posted January 21, 2008 (edited) Well, that seems to work perfectly, every bit and byte seems to be where it should be, that is it deciphers and enciphers correctly without loss of any characters. Thanks for the help on that, it seems to be working perfectly now. The only thing I might want to do is figure out a way to fill in the rest of the key with a random sequence to match the length of the message, that way the key won't be repeated all throughout the message and will be less susceptible to frequency analysis. I was thinking about learning another algorithm like RC4 that uses XOR in its operations, but all of the practical C examples I can find don't actually use "^", but "%". Like this excerpt example: // Key Scheduling Algorithm// Input: state - the state used to generate the keystream// key - Key to use to initialize the state// len - length of key in bytes void ksa(unsigned char state[], unsigned char key[], int len){ int i,j=0,t; for (i=0; i < 256; ++i) state[i] = i; for (i=0; i < 256; ++i) { j = (j + state[i] + key[i % len]) % 256; t = state[i]; state[i] = state[j]; state[j] = t; } } http://bradconte.com/code/rc4_c I haven't actually tested it out, just referencing it as some of the only C code I can find that demonstrates various algorithims. The person that coded it also coded AES, DES, 3DES, and some hashing algorithims too, but right now I can't really even figure out how the simple RC4 one works. Even though the practicality of it all is useless ( text encryption, wooo), it's still nifty to fool around with this stuff. One of the reasons I started learning about XOR was to try to use it in my own algorithm because from what I've heard most algorithims use it. I've learned from various sources how easy it is to crack simple XOR encryption, so I doubt I'll be able to think of a way to use it in strong encryption until I understand how its used in those other algorithims. Edit About that completely useless remark, I hadn't realized until just now that I could actually use this program to encrypt or decrypt data. I never stopped to think that my own custom program didn't encrypt or decrypt data because it didn't handle all data, but this does. I wonder if it's a good or bad sign that I just wrote a program that can encrypt data by accident. There is a problem though, the program will segment fault on Linux when trying to encrypt a file larger than around 2.5 GB ( from what I've tested so far). I'm not sure if this is a result of the Linux kernel itself. This is the strace result execve("/usr/bin/xor", ["xor", "./gtasa.iso", "-", "doesnotmattertest"], [/* 37 vars */]) = 0brk(0) = 0x804a000access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f34000access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.cache", O_RDONLY) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=61789, ...}) = 0mmap2(NULL, 61789, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f24000close(3) = 0access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260a\1"..., 512) = 512fstat64(3, {st_mode=S_IFREG|0644, st_size=1339816, ...}) = 0mmap2(NULL, 1349136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7dda000mmap2(0xb7f1e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x143) = 0xb7f1e000mmap2(0xb7f21000, 9744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7f21000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7dd9000set_thread_area({entry_number:-1 -> 6, base_addr:0xb7dd96b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0mprotect(0xb7f1e000, 4096, PROT_READ) = 0munmap(0xb7f24000, 61789) = 0brk(0) = 0x804a000brk(0x806b000) = 0x806b000open("./gtasa.iso", O_RDONLY) = -1 EFBIG (File too large)--- SIGSEGV (Segmentation fault) @ 0 (0) ---+++ killed by SIGSEGV (core dumped) +++Process 3066 detached This part and the fact that I can encode and decode files that large on Windows makes me think it's some limitation with Linux, but I wouldn't know what or how to rectify it. I don't really ever forsee encrypting anything with this, let alone a file over 2 gigs, but it would be nice to know what the limitation here is. Obviously, "open("./gtasa.iso", O_RDONLY) = -1 EFBIG (File too large)" is what clues me in on the file being to large, but what is the limit, is there a way to change it, etc. Edited January 21, 2008 by SagaciousKJB QUOTE (K^2) ...not only is it legal for you to go around with a concealed penis, it requires absolutely no registration! Link to comment Share on other sites More sharing options...
TwoZero Posted January 22, 2008 Share Posted January 22, 2008 Are you reading it from a network mount? I know that smbfs has a 2gb file size limit, the newer alternative cifs does a better job. If it's on a local filesystem such as EXT3 or ReiserFS then it's odd, they should be able to handle large files just fine. Link to comment Share on other sites More sharing options...
K^2 Posted January 23, 2008 Share Posted January 23, 2008 Are you reading it from a network mount? I know that smbfs has a 2gb file size limit, the newer alternative cifs does a better job. If it's on a local filesystem such as EXT3 or ReiserFS then it's odd, they should be able to handle large files just fine. It's a problem in the C library. He already found a fix. Prior to filing a bug against any of my code, please consider this response to common concerns. Link to comment Share on other sites More sharing options...
Saggy Posted January 23, 2008 Author Share Posted January 23, 2008 (edited) Yeah, here's the link explaining the fix, in case anyone else wants to reference it. Edit Wow, I guess that did no one any good after a few months of not being there... Whoops. Here's the link: http://mail.nl.linux.org/kernelnewbies/2001-12/msg00186.html Edited February 12, 2008 by SagaciousKJB QUOTE (K^2) ...not only is it legal for you to go around with a concealed penis, it requires absolutely no registration! Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now