📄 2c.c
字号:
/* 2c.c - main entry point ----------------------- Copyright (C) 2003 by Michal Zalewski <lcamtuf@coredump.cx> */#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <termios.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/fcntl.h>#include <openssl/md5.h>#include <assert.h>#include <string.h>#include <errno.h>#include <getopt.h>#include "types.h"#include "config.h"#include "lzf.h"#include "macros.h"#define STR_CNT 5struct bitstream { _u8 buf[KEYSIZE]; // I/O or key buffer _s32 buftop; // Upper usable buffer size limit _u32 bitoff; // Bit offset selector _u32 fd,len; // file descriptor, file length _u32 kID; // key generation stuff _u64 kCARRY; // key generation stuff _u8* pass; // passphrase} bs[STR_CNT];_u32 random_d;void volatile wipe_memory(void* volatile ptr,_u32 cnt) { if (!ptr) return; cnt = (cnt + 3)/4; asm volatile( "movl $0xdeadbeef,%%eax ; rep stosl" : "=D" (ptr), "=c" (cnt) : "D" (ptr), "c" (cnt) : "memory", "eax");}void register_stream(_u8 id,_u32 fd,_u32 kID,_u8* pass,_u32 len) { if (id >= STR_CNT) fatal("register_stream id >= %u\n",STR_CNT); bs[id].fd=fd; bs[id].bitoff=0; bs[id].buftop=0; bs[id].kID=kID; bs[id].len=len; bs[id].kCARRY=0; bs[id].pass=pass;}_u8 get_bit(_u8 sid) { _u8 ret; if ((bs[sid].bitoff >> 3) >= bs[sid].buftop) { bs[sid].buftop = read(bs[sid].fd,bs[sid].buf,KEYSIZE); if (bs[sid].buftop <= 0) return 255; bs[sid].bitoff = 0; } ret = (bs[sid].buf[bs[sid].bitoff>>3] & (1<<(bs[sid].bitoff % 8))) != 0; bs[sid].bitoff++; return ret;}void get_basekey(_u8 sid);_u8 get_keybit(_u8 sid) { _u8 ret; if ((bs[sid].bitoff >> 3) >= bs[sid].buftop) { get_basekey(sid); bs[sid].buftop = KEYSIZE; bs[sid].bitoff = 0; } ret = (bs[sid].buf[bs[sid].bitoff>>3] & (1<<(bs[sid].bitoff % 8))) != 0; bs[sid].bitoff++; return ret;}void put_bit(_u8 sid,_u8 val) { if (val==255) { if (bs[sid].bitoff) { if (bs[sid].bitoff & 8) bs[sid].bitoff += 8; ckwrite(bs[sid].fd,bs[sid].buf,bs[sid].bitoff >> 3); bs[sid].bitoff = 0; } return; } if ((bs[sid].bitoff >> 3) == KEYSIZE) { ckwrite(bs[sid].fd,bs[sid].buf,KEYSIZE); bs[sid].bitoff = 0; } if (val) bs[sid].buf[bs[sid].bitoff>>3] |= (1<<(bs[sid].bitoff % 8)); else bs[sid].buf[bs[sid].bitoff>>3] &= ~(1<<(bs[sid].bitoff % 8)); bs[sid].bitoff++; return;}void get_basekey(_u8 sid) { _u32 i; MD5_CTX k; assert(!(KEYSIZE % 8)); for (i=0;i< KEYSIZE>>3;i++) { MD5_Init(&k); MD5_Update(&k,bs[sid].pass,strlen(bs[sid].pass)); MD5_Update(&k,&bs[sid].kCARRY,8); MD5_Update(&k,&bs[sid].kID,4); MD5_Final(bs[sid].buf+(i<<3),&k); bs[sid].kCARRY = *(_u64*)(bs[sid].buf+(i<<3)); }}void term_echo(_u8 state) { struct termios tios; ioctl(0,TCGETS,&tios); if (state) tios.c_lflag |= ECHO; else tios.c_lflag &= ~ECHO; ioctl(0,TCSETS,&tios);}_u8* get_password(_u8* what) { static _u8 pass_buf[MAX_PASS+1]; _u8* p;retry: term_echo(0); debug("[+] Enter %s password: ",what); fgets(pass_buf,MAX_PASS,stdin); term_echo(1); debug("\n"); if ((p=strrchr(pass_buf,'\n'))) *p=0; else fatal("[-] Password incomplete or too long.\n"); if (!pass_buf[0]) fatal("[-] Password empty.\n"); if (strlen(pass_buf) < MIN_PASS) { debug("Password too short, use at least %u characters.\n",MIN_PASS); goto retry; } return strdup(pass_buf);}void compress_file(_u32 infd,_u32 outfd,_u32 total) { struct secthdr s; _u8 buf[CMP_BLK],cbuf[CMP_BLK]; _u32 i,c,sofar=0,tlen=0; while ((i=read(infd,buf,CMP_BLK))>0) { if (sofar >= total) break; if (sofar + i >= total) i = total - sofar; sofar += i; c=lzf(buf,i,cbuf,i); if (!c) { s.type=BLK_UNCOMP; s.len =i; ckwrite(outfd,&s,sizeof(struct secthdr)); ckwrite(outfd,buf,i); tlen += i + sizeof(struct secthdr); } else { s.type=BLK_COMP; s.len =c; ckwrite(outfd,&s,sizeof(struct secthdr)); ckwrite(outfd,cbuf,c); tlen += c + sizeof(struct secthdr); } debug("\rProgress: ["); for (i=0;i<sofar * 40 / total;i++) debug("*"); for (;i<40;i++) debug(" "); debug("]"); } debug("\r%70s\r",""); wipe_memory(buf,CMP_BLK); wipe_memory(cbuf,CMP_BLK); // Remove last ) to crash gcc with sig11. Yeah! debug("[*] Compressed size: %0.02f%%\n",(tlen*100.0)/((float)sofar));}void uncompress_file(_u32 infd,_u32 outfd) { struct secthdr s; _u8 buf[CMP_BLK],ubuf[CMP_BLK]; _u32 i,c; while ((i=read(infd,&s,sizeof(struct secthdr)))>0) { if (s.len > CMP_BLK || !s.len) fatal("[-] Compression header corrupted 1 (bad password?).\n"); if (read(infd,buf,s.len) != s.len) fatal("[-] Compressed data corrupted 2 (bad password?).\n"); if (s.type == BLK_COMP) { c=unlzf(buf,s.len,ubuf,CMP_BLK); ckwrite(outfd,ubuf,c); } else if (s.type == BLK_UNCOMP) { ckwrite(outfd,buf,s.len); } else fatal("[-] Compression header corrupted 3 (bad password?).\n"); }}void encrypt_file(_u8 sid,_u32 of) { _u8 ibuf[KEYSIZE]; _u32 c,i; _u32 sT=4; _u32 total=0; *(_u32*)ibuf = bs[sid].len; while (total < bs[sid].len + 4) { c=read(bs[sid].fd,ibuf+sT,KEYSIZE-sT); if (c<=0) fatal("\n[-] Whoops, unexpected EOF in encrypt() - %d/%d\n", total,bs[sid].len+4); c+=sT; sT=0; get_basekey(sid); if (total + c >= bs[sid].len + 4) c = bs[sid].len + 4 - total; for (i=0;i<c;i++) ibuf[i] ^= bs[sid].buf[i]; ckwrite(of,ibuf,c); total += c; debug("\rProgress: ["); for (i=0;i<total * 40 / bs[sid].len;i++) debug("*"); for (;i<40;i++) debug(" "); debug("]"); } debug("\r%70s\r",""); wipe_memory(ibuf,CMP_BLK);}_u32 decrypt_file(_u8 sid,_u32 of) { _u8 ibuf[KEYSIZE]; _u32 c,i,cT=0; _u32 total=0; while (total < bs[sid].len) { c=read(bs[sid].fd,ibuf,KEYSIZE); if (c<=0) fatal("\n[-] Whoops, unexpected EOF in decrypt() - %d/%d.\n", total,bs[sid].len); get_basekey(sid); for (i=0;i<c;i++) ibuf[i] ^= bs[sid].buf[i]; if (!total) { cT=*(_u32*)ibuf; ckwrite(of,ibuf+4,c-4); } else ckwrite(of,ibuf,c); total += c; debug("\rProgress: ["); for (i=0;i<total * 40 / bs[sid].len;i++) debug("*"); for (;i<40;i++) debug(" "); debug("]"); } debug("\r%70s\r",""); return cT;}void wipe_file(_u32 fd) { _u8 zerobuf[4096]; _u8 pass; debug("[+] Wiping temporary file: "); for (pass=0;pass<8;pass++) { _s32 siz = getlen(fd); debug("%d ",pass); fsync(fd); if (read(random_d,zerobuf,4096)!=4096) debug("*OOOPS!* "); while (siz > 0) { write(fd,zerobuf,(siz>4096)?4096:siz); siz -= 4096; } fsync(fd); } debug("(done)\n");}// Slow, but we can afford it._u32 get_random(void) { _u32 ret; ckread(random_d,&ret,4); return ret;}void usage(_u8* name) { debug("Usage: %s -o ofile -e file1 file2 - combine and encrypt files\n" " %s -o ofile -e file1 - encrypt and pad with random\n" " %s -o ofile -d file1 - decrypt one component\n\n", name,name,name); exit(2);}int main(int argc,char* argv[]) { _u8 encrypt=2; _s8 opt,clin; _u32 bit_count=0; _u32 i; _u8 *outfile=0,*pass1,*pass2,*infile1,*infile2; _u32 flen1,flen2=0; _u32 data_s1,data_s2; // Working descriptors: _s32 out_d,in1_d,in2_d,tmp1_d,tmp2_d,cmp_d; debug("2c by <lcamtuf@coredump.cx>\n"); if (argc<2) usage(argv[0]); while ((opt=getopt(argc,(void*)argv, "+edo:"))!=EOF) switch(opt) { case 'e': encrypt=1; break; case 'o': outfile=optarg; break; case 'd': encrypt=0; break; default: usage(argv[0]); } if (encrypt == 2) usage(argv[0]); if (!outfile) usage(argv[0]); if (!(argc-optind)) usage(argv[0]); if (argc-optind > 2) usage(argv[0]); unlink(outfile); out_d=ckopen(outfile,O_RDWR|O_EXCL|O_CREAT,0600); infile1=argv[optind]; infile2=argv[optind+1]; if (mlockall(MCL_FUTURE|MCL_CURRENT)) debug("[!] Warning: can't lock physical memory.\n"); random_d = ckopen(RND_SOURCE,O_RDONLY); debug("[*] Using %s for random pad data...\n",RND_SOURCE); if (get_random() == get_random()) debug("[-] Faulty randomness source or a really bad day.\n"); if (encrypt) { in1_d = ckopen(infile1,O_RDONLY); flen1 = getlen(in1_d); if (!infile2) { _u32 bogus[4] = { get_random(), get_random(), get_random(), 0 }; // We use /dev/urandom because we hardly need fresh entropy for this. in2_d = dup(random_d); if (in2_d < 0) fatal("[-] dup() failed: %s\n",strerror(errno)); flen2 = flen1; debug("[*] Source 1: %s (%u bytes)\n" " Source 2: <random pad>\n",infile1,flen1); pass1 = get_password(infile1); pass2 = strdup((_u8*)bogus); } else { in2_d = ckopen(infile2,O_RDONLY); flen2 = getlen(in2_d); debug("[*] Source 1: %s (%u bytes)\n" " Source 2: %s (%u bytes)\n",infile1,flen1,infile2,flen2); if (flen1 < flen2) fatal("[-] Second file is larger. Data hiding would be evident.\n"); pass1 = get_password(infile1); pass2 = get_password(infile2); } if (flen1 >= 0x10000000) fatal("[-] Input file too big.\n"); debug("[+] Compressing input data source 1...\n"); cmp_d=cktemp(); compress_file(in1_d,cmp_d,flen1); flen1 = getlen(cmp_d); close(in1_d); in1_d=cmp_d; debug("[+] Encrypting input data source 1...\n"); register_stream(0,in1_d,CFILE1_ID,pass1,flen1); tmp1_d=cktemp(); encrypt_file(0,tmp1_d); wipe_file(cmp_d); flen1 += 4; close(in1_d); lseek(tmp1_d,0,SEEK_SET); register_stream(0,tmp1_d,0,0,0); // 0 - encrypted file1 // If using random, spoof the compression ratio of the original // file. if (!infile2) flen2=flen1; debug("[+] Compressing input data source 2...\n"); cmp_d=cktemp(); compress_file(in2_d,cmp_d,flen2); if (infile2) { flen2 = getlen(cmp_d); if (flen2 > flen1) { debug("[-] Second file compressed well and is larger than " "the first one.\n Second file cannot be larger, data hiding" " would be evident.\n"); wipe_file(cmp_d); exit(3); } } else { ftruncate(cmp_d,flen1); lseek(cmp_d,0,SEEK_SET); } close(in2_d); in2_d=cmp_d; debug("[+] Encrypting input data source 2...\n"); register_stream(1,in2_d,CFILE2_ID,pass2,flen2); tmp2_d=cktemp(); encrypt_file(1,tmp2_d); wipe_file(cmp_d); flen2 += 4; close(in2_d); lseek(tmp2_d,0,SEEK_SET); register_stream(1,tmp2_d,0,0,0); // 1 - encrypted file2 // 2 - selector bitstream generated with pass1 register_stream(2,0,CSTREAM_ID,pass1,0); // 3 - oputput file register_stream(3,out_d,0,0,0); // 4 - /dev/urandom for stuffing in1_d=ckdup(random_d); register_stream(4,in1_d,0,0,0); // Calculate bit sizes data_s1 = flen1 * 8; data_s2 = flen2 * 8; debug("[+] Data scrambling in progress...\n"); clin=0; debug(".------------------------------------------.\n| "); while (data_s1 || data_s2) { i=get_keybit(2); if (i) { if (data_s1) { put_bit(3,get_bit(0)); data_s1--; } else put_bit(3,get_bit(4)); } else { if (data_s2) { put_bit(3,get_bit(1)); data_s2--; } else put_bit(3,get_bit(4)); } bit_count++; // Sometimes, we might want to display some stuff... if (!((bit_count / 800) % 50)) { if (i) debug("O"); else debug(" "); if (!(bit_count % 40)) { if (!(bit_count % 400)) { debug(" |\n`------------------------------------------'" "\r\033[A\033[A\033[A\033[A\033[A" "\033[A\033[A\033[A\033[A\033[A| "); clin=0; } else { debug(" |\n| "); clin++; } } } } for (i=0;i<11-clin;i++) debug("\n"); flen1 = get_random() % RANDOM_PAD; // Add some more non-key, non-filesize random padding. for (i=0;i<flen1;i++) put_bit(3,get_bit(4)); put_bit(3,255); debug("[+] Mixed %u stream bits, %d trailing.\n",bit_count,flen1); close(out_d); } else { in1_d = ckopen(infile1,O_RDONLY); flen1 = getlen(in1_d); debug("[*] File %s opened successfully, credentials please.\n",infile1); pass1 = get_password("main"); // 0 - original scrambled file register_stream(0,in1_d,0,0,0); // 1 - selector bitstream generated with pass1 register_stream(1,0,CSTREAM_ID,pass1,0); // 2 - temporary output file 1 tmp1_d = cktemp(); register_stream(2,tmp1_d,0,0,0); // 3 - temporary output file 2 tmp2_d = cktemp(); register_stream(3,tmp2_d,0,0,0); debug("[+] Splitting data stream...\n"); flen1 = 0; flen2 = 0; while ((i=get_bit(0))!=255) { if (get_keybit(1)) { flen1++; put_bit(2,i); } else { flen2++; put_bit(3,i); } if ((flen1 % 1717)==1) debug("\rBins: %u / %u bits...",flen1,flen2); } put_bit(2,255); put_bit(3,255); close(in1_d); debug("\r%40s\r",""); cmp_d=cktemp(); // 0 - primary chunk lseek(tmp1_d,0,SEEK_SET); flen1 >>= 3; register_stream(0,tmp1_d,CFILE1_ID,pass1,flen1); i=decrypt_file(0,cmp_d); if (i > flen1 || i < MIN_SIZE) { debug("[-] The output file appears to be corrupted (bad password?).\n"); unlink(outfile); exit(3); } close(tmp1_d); ftruncate(cmp_d,i); lseek(cmp_d,0,SEEK_SET); uncompress_file(cmp_d,out_d); close(cmp_d); close(out_d); debug("[+] Main chunk deciphered. Any secondary file? Hit RETURN for none.\n"); pass2 = get_password("secondary"); infile2 = malloc(strlen(outfile)+4); sprintf(infile2,"%s-2",outfile); outfile = infile2; unlink(outfile); out_d=ckopen(outfile,O_RDWR|O_EXCL|O_CREAT,0600); debug("[*] Saving secondary data to %s...\n",outfile); // 0 - secondary chunk cmp_d = cktemp(); lseek(tmp2_d,0,SEEK_SET); flen2 >>= 3; register_stream(0,tmp2_d,CFILE2_ID,pass2,flen2); i=decrypt_file(0,cmp_d); if (i > flen2 || i < MIN_SIZE) { debug("[-] The output file appears to be corrupted (no file at all?).\n"); unlink(outfile); exit(3); } close(tmp2_d); ftruncate(cmp_d,i); lseek(cmp_d,0,SEEK_SET); uncompress_file(cmp_d,out_d); close(cmp_d); close(out_d); } debug("[*] Done, have a nice day, and remember to wipe the data.\n"); for (i=0;i<STR_CNT;i++) wipe_memory(bs[i].buf,KEYSIZE); for (i=0;i<STR_CNT;i++) if (bs[i].pass) wipe_memory(bs[i].pass,strlen(bs[i].pass)); exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -