0: #!/usr/bin/perl -w
1: #
2: # Chaffing/winowing utility
3: # (Achieving privacy without encryption)
4: # (Or 'textual steganography')
5: #
6: # See my Node [Privacy without Encryption]
7: # for more info about the used scheme
8: #
9: # TODO : _ Handle the packet size thru command line (or/and auto adapt size)
10: # packet size handling isn't coherent yet !!!
11: # _ Implement my 'modified' variant (without the sequence number)
12: # _ Find/correct bugs
13: # _ Find a way to handle LARGE files
14:
15: use strict; # Let's pretend we're doing it right ;-)
16:
17: use Compress::LZV1;
18: use Digest::MD5 qw(md5_base64);
19: use MIME::Base64;
20: use Getopt::Long;
21:
22: my $BSIZE = 32; # Block size
23: my $VERSION = '0.03'; # Did I mention pre-alpha ? ;-)
24:
25: #
26: # Command line options variable
27: #
28:
29: my $O_infile;
30: my $O_afile;
31: my $O_fake;
32: my $O_outfile;
33: my $O_encrypt;
34: my $O_decrypt;
35: my $O_key;
36: my $O_akey;
37: my $O_mpackets=4;
38:
39: GetOptions (
40: 'key=s' => \$O_key,
41: 'akey=s' => \$O_akey,
42: 'afile=s' => \$O_afile,
43: 'encrypt' => \$O_encrypt,
44: 'decrypt' => \$O_decrypt,
45: 'infile=s' => \$O_infile,
46: 'outfile=s', => \$O_outfile,
47: 'maxpackets=s', => \$O_mpackets,
48: '<>' => \&unknown
49: );
50: ############################################################
51: # Command line option handling
52: ############################################################
53: sub usage {
54: print "\n\t$0 - chaffing/winowing utility $VERSION\n\n";
55: print "\tUsage $0 (--encrypt | --decrypt) --infile=<file1> --outfile=<file2> --key=<key> [--afile=<file> --akey=<key>] [--maxpackets=<number>]\n\n";
56: print "\t\t--encrypt\t\tAsk for encryption&\n";
57: print "\t\t--decrypt\t\tAsk for decryption\n";
58: print "\t\t--infile=<file>\t\tInput file to be processed\n";
59: print "\t\t--afile=<file>\t\tAlternate input file to be processed\n";
60: print "\t\t--outfile=<file>\tOutput file to be produced\n\n";
61: print "\t\t--key=<key>\tKey used to authenticate\n\n";
62: print "\t\t--akey=<key>\tAlternate key used to authenticate\n\n";
63: print "\t\t--maxpackets=<number>\tMaximum number of packets generated for a part of the message\n\n";
64: }
65:
66: sub unknown {
67: print "Unknown option : ",shift,"\n" && usage();
68: }
69:
70: ############################################################
71: # Encryption subs
72: ############################################################
73:
74: ##############################
75: # pre encryption process to handle all-or-nothing encoding
76: #
77: sub preencrypt {
78: my $file = shift;
79: open (INFILE,"<$file") or die "Can't open $file ($!)\n";
80: my @content=<INFILE>;
81: close (INFILE);
82:
83: # May be I should do it step by step ?
84: my $temp = encode_base64(compress(join('',@content)),'');
85:
86: return reverse $temp;
87: }
88:
89: sub encrypt {
90: my $pos = 0;
91: my $length = 0;
92: my ($plaintext,$fake,$fprocessed);
93: my $processed=preencrypt($O_infile);
94:
95: if ($O_afile) { $fprocessed=preencrypt($O_afile) }
96:
97: $length=length($processed);
98:
99: if ($fprocessed && $length<length($fprocessed)) { $length=length($fprocessed) }
100:
101: open (OUTFILE,">$O_outfile") or die "Can't open $O_outfile ($!)\n";
102:
103: for(my $i=0;$pos<$length;$i++) {
104: if ($O_afile && ($pos<length($fprocessed))) {
105: $fake=substr($fprocessed,$pos,$BSIZE)
106: } else {
107: $fake= undef;
108: }
109: if ($pos<length($processed)) {
110: $plaintext=substr($processed,$pos,$BSIZE)
111: } else {
112: $plaintext=undef
113: }
114: my @packets=real_packets($i,$plaintext,$fake);
115: shuffle_packets(\@packets);
116: emit_packets(*OUTFILE,@packets);
117: $pos=$i*$BSIZE;
118: }
119: }
120:
121: ############################################################
122: # Decryption subs
123: ############################################################
124:
125: ##############################
126: # post decryption process to handle all-or-nothing encoding
127: #
128: sub postdecrypt {
129: my $temp2 = decode_base64(reverse(shift));
130: my $temp;
131: eval { $temp = decompress $temp2;}; # Don't trust the documentation
132: if ($@) { die "ERREUR=($@)()\n"}
133: return $temp;
134: }
135:
136: sub decrypt {
137: my @content;
138:
139: open (INFILE,"<$O_infile") or die "Can't open $O_outfile ($!)\n";
140: while (<INFILE>) {
141: my ($pos,$bloc,$mac)=split ',';
142: chomp $mac;
143: if (md5_base64($bloc.$O_key) eq $mac) { $content[$pos]=$bloc }
144: }
145: close(INFILE);
146: my $content=join '',@content;
147:
148:
149: open (OUTFILE,">$O_outfile") or die "Can't open $O_outfile ($!) \n";
150: my $processed=postdecrypt($content);
151: print OUTFILE $processed;
152: close(OUTFILE);
153: }
154:
155: ############################################################
156: # Packet building/manipulation subs
157: ############################################################
158:
159: ##############################
160: # Shuffle packets
161: #
162: sub shuffle_packets { # Fisher-Yates shuffling algo 'stolen' from a snowcrash's post.
163: my $t = shift;
164: my $x;
165: for ($x = @$t; --$x; ) {
166: my $y = int rand ($x+1);
167: next if $x == $y;
168: @$t[$x,$y] = @$t[$y,$x];
169: }
170: }
171:
172: ##############################
173: # Print the packets to the output file
174: #
175: sub emit_packets {
176: my $FH = shift;
177: my @pkt = @_;
178: foreach (@pkt) { print $FH $_ }
179: }
180:
181: ##############################
182: # Return a real packetS
183: #
184: sub real_packets {
185: my $step = shift;
186: my $plaintext = shift;
187: my $fake = shift;
188: my $mpackets = $O_mpackets;
189: my @packets;
190:
191: while ($mpackets--) {
192: if (!$mpackets) {
193: if ($plaintext) {
194: push @packets,real_packet($step,$plaintext,$O_key)
195: } else {
196: push @packets,fake_packet($step);
197: }
198: }
199: if (($O_afile)&&($mpackets==1)) {
200: if ($fake) {
201: push @packets,real_packet($step,$fake,$O_akey)
202: } else {
203: push @packets,fake_packet($step);
204: }
205: }
206: push @packets,fake_packet($step);
207: }
208: return @packets;
209: }
210:
211: ##############################
212: # Return a valid packet (wheat)
213: #
214: sub real_packet {
215: my $step = shift;
216: my $plaintext = shift;
217: my $key = shift;
218:
219: if ($plaintext) {
220: return "$step,$plaintext,".md5_base64($plaintext.$key)."\n";
221: } else {
222: return fake_packet($step)
223: }
224: }
225:
226: ##############################
227: # Return a fake packet (chaff)
228: #
229: sub fake_packet {
230: my $step = shift;
231:
232: return "$step,".rand_data().",".md5_base64(rand_data())."\n";
233: }
234:
235: ##############################
236: # Return random data
237: #
238: sub rand_data {
239: my $random =join '', map { chr(rand 255) } (1..24); #UGLY ! I'm not supposed to obfuscate
240: return encode_base64($random,'');
241: }
242:
243: ###################################################################
244: # Main program #
245: ###################################################################
246:
247: #
248: # Check for correct command line parameters
249: #
250: if ( ($O_encrypt && $O_decrypt) || (!$O_infile) ||
251: (!($O_encrypt || $O_decrypt)) || (!$O_outfile) || (!$O_key) ||
252: ($O_afile && !$O_akey) || (!$O_afile && $O_akey)) {
253: usage();
254: die
255: }
256:
257: #
258: # All is here ;-) guess what it does...
259: #
260: if ( $O_encrypt ) {
261: encrypt();
262: } elsif ( $O_decrypt ) {
263: decrypt();
264: }
265: #
266: # Following a 'chaffed' text
267: # try to decipher it using 'noilluminati' password
268: # (without quotes) after pasting it in a file and removing the #
269: #
270: #0,k5VXbo7skZ0eBw273YYuO0Z5ElzWK81p,++6IKesuyf71P1bd8fB+vQ
271: #0,==vCukGdh5WatVHbslEIlhGVKogLztmb,ZP6XzVcLHgfqXB+i9p7pVg
272: #0,Ngtvqm6sHXa9cakc578fugLZ6z7VCqFS,KquicDZSCPTwmIWCJQj2lw
273: #0,=ogIhASa0Fmbp1WdsxWSgwmclBFIv5GI,iaN8T9QW40NXzyMO3Ufr0g
274: #0,dXQbmi7tRep0RHSP2S5jL28foyXx4xc2,D13ZO25QvJmc5jj6Vs3Peg
275: #0,O/XXJoxtfLP7QejNSNhZXPeJEcY7EOgk,CDYs03Z42dMzAqgvt4NLOQ
276: #1,h0cBb46gj4e22g5BRN3EAQ7B/Ic444JJ,bKf3RiWEKW6AtG7gHek5YA
277: #1,Gc0LTGrpMBzsH1GYio6sqYc3jwSNguPM,2+NCOWj9rZ4Rl+VGBaa+bQ
278: #1,==vCukGdh5WatVHbslEIlhGVKogLztmb,ZP6XzVcLHgfqXB+i9p7pVg
279: #1,vOk9JaQWC3VGWgcuOrWhHCQv3ng1kbOp,XePqzBtcyTeOB7oYQROP1w
280: #1,WESG/Up8i9y1zLrplglsrXmQeDeC97n9,GkCJoaPkG0GsQwqxusvErQ
281: #1,=ogIhASa0Fmbp1WdsxWSgwmclBFIv5GI,iaN8T9QW40NXzyMO3Ufr0g
282: #2,v1GIlhGdgY2bgQ3cv1GIvRHI0VmcjV2c,3bQ70TJ8LprFvXmm027QKQ
283: #2,e6t59MmADzczzOxQUZPeuafSAHlsZzw6,87CMpxoNZ5V+ZXH16/xnog
284: #2,v27ZovnIWHa4RTIs0OZOqvrMoOQJsguw,HaYIHPDNKw01KTAZwDoz8A
285: #2,zlGIlJXZoRlIKogOggGd1JHdgkHbu9GI,YtuomVRssOL5H3O93FwLKQ
286: #2,o6F57TE1qgOCIZDu6dOS1JUS2K+Ma1pL,aWyekOAavnP30J1LjMyabQ
287: #2,134KqWcow3Gotvo7vQRB7GuIsZuHkNlK,PQXtcFybDCWJjmZzNsmNBg
288: #3,XZjtMRzywQ132+o1fIBM7lEhgHMIBcun,QwHh8axfX9b3O1aZVtnppQ
289: #3,za805qiDVRNqRk7pHaSjkQYQcy3eY/6e,v6hp+yOzem9Iyyv7mD1A0w
290: #3,g4Wah1WZyBCZsV3boNHIltWYoNHZuFGa,vqTDULwuwilPcCeJ8PBu4w
291: #3,9ZFJA5b39uYB9w4wUGxnaiv2UBPQc+uV,RXT3oNiFzHBEvBPJL7WNIQ
292: #3,RmfrKeyA+KNIYszgKcBpVp5bnhDJLrIu,jDooJK6UNABjEqTAazbCPw
293: #3,lhGdgMXagUmclhUV,ztNOKDCwtiLGZR2Syly+oA
294: #4,CYtEcUP40pZ/PkSDKBcNkWp8siY8RpPa,Pivu98789IuyHas9x7dEaw
295: #4,gvvHE5ICpgrPj4Lw7ttD0Lir4fFN2+id,PVw4bA+9zzT8qHg1sIDJ2w
296: #4,gQXZyNWZzBSZoRVV,sObdXXLTzTrB3ZhcJ56Hkw
297: #4,2o5ydT4GTQfJqcCihKPRV+9vVa2cmvf9,hFNeDq6OtjzCGpbmgY3SXQ
298: #4,oR53Eye8qP5MOdXuzKwGhrcsrkOMnAbQ,sX2i+IeO3ocE5ksZaxE/Vg
299: #4,0VUxgoJB1ISiRw7RfmVFIVp0uDV1BTjV,RVVgPI1yY5LwAXNXDG/qBw
300:
In reply to chaffwinnow.pl (Privacy without Encryption) by arhuman
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |