Initial checkin.
[catacomb-perl] / ciphersaber
CommitLineData
660b443c 1#! /usr/bin/perl -w
2
3use Catacomb;
4
5my $GRIPE = 0;
6my $DEBUG = 0;
7my $QUIS = $0; $QUIS =~ s:^.*/::;
8
9my $MODE = \&encrypt;
10my $OFILE = "-";
11my $TAG = "ciphersaber-%s";
12
13sub usage {
14 my $f = shift;
15 print $f "Usage: $QUIS [-de] [-t TAG] [-o FILE] file...\n";
16}
17sub version {
18 my $f = shift;
19 print $f "$QUIS, catacomb-perl version $Catacomb::VERSION\n";
20}
21sub help {
22 my $f = shift;
23 version($f);
24 print $f "\n";
25 usage($f);
26 print $f <<EOF;
27
28Implements the CipherSaber file encryption system (as described in
29http://ciphersaber.gurus.com/). Options available are:
30
31-h Display this help text.
32-v Show the program's version number.
33-u Show this usage message.
34
35-d Decrypt the input files.
36-e Encrypt the input files. [default]
37-t TAG Use TAG as the passphrase tag.
38-o FILE Write the output to FILE.
39EOF
40#'
41}
42
43sub gripe { print STDERR join(": ", $QUIS, @_), "\n"; $GRIPE = 1; }
44sub barf { gripe(@_); exit(1); }
45sub hexify { unpack("H*", join("", @_)); }
46sub unhexify { my $x = join("", @_); $x =~ tr/\s//d; pack("H*", $x); }
47
48sub debug {
49 return unless $DEBUG;
50 my $what = shift(@_);
51 print STDERR
52 "debug: $what",
53 (@_ ? " = " . join(" ", map { "<" . hexify($_) . ">" } @_) : ""),
54 "\n";
55}
56
57sub encrypt {
58 my $salt = pack("N", time()) . $Catacomb::random->fill(6);
59 debug("salt", $salt);
60 my $tag = sprintf($TAG, hexify($salt));
61 my $pass = Catacomb::Passphrase->verify($tag);
62 barf("passwords don't match") unless defined($pass);
63 open OUT, "> $OFILE" or barf("couldn't write file `$OFILE'", $!);
64 syswrite(OUT, $salt) or barf("error writing `$OFILE'", $!);
65 my $c = $Catacomb::Cipher::rc4->init($pass . $salt);
66 foreach my $f (@ARGV ? @ARGV : "-") {
67 open IN, $f or barf("couldn't read file `$f'", $!);
68 for (;;) {
69 my $buf;
70 my $rc = sysread(IN, $buf, 8192);
71 barf("error reading `$f'", $!) unless defined($rc);
72 last unless $rc;
73 syswrite(OUT, $c->encrypt($buf)) or barf("error writing `$OFILE'", $!);
74 }
75 close(IN);
76 }
77 close(OUT) or barf("error writing `$OFILE'", $!);
78}
79
80sub decrypt {
81 open OUT, "> $OFILE" or barf("couldn't write file `$OFILE'", $!);
82 foreach my $f (@ARGV ? @ARGV : "-") {
83 open IN, $f or barf("couldn't read file `$f'", $!);
84 my ($salt, $buf);
85 my $rc = sysread(IN, $salt, 10);
86 barf("error reading `$f'", $!) unless defined($rc);
87 barf("ciphertext file is too short") unless $rc;
88 debug("salt", $salt);
89 my $tag = sprintf($TAG, hexify($salt));
90 my $pass = Catacomb::Passphrase->read($tag)
91 or barf("couldn't read passphrase", $!);
92 my $c = $Catacomb::Cipher::rc4->init($pass . $salt);
93 for (;;) {
94 my $buf;
95 my $rc = sysread(IN, $buf, 8192);
96 barf("error reading `$f'", $!) unless defined($rc);
97 last unless $rc;
98 syswrite(OUT, $c->decrypt($buf)) or barf("error writing `$OFILE'", $!);
99 }
100 close(IN);
101 }
102 close(OUT) or barf("error writing `$OFILE'", $!);
103}
104
105while (@ARGV) {
106 my $opt = $ARGV[0];
107 last if $opt eq "-" || $opt =~ /^[^-]/;
108 shift(@ARGV);
109 last if $opt eq "--";
110 $opt = substr($opt, 1);
111 while (length($opt)) {
112 my $o = substr($opt, 0, 1);
113 $opt = substr($opt, 1);
114 if ($o eq "o") {
115 $OFILE = length($opt) ? $opt : shift(@ARGV); $opt = "";
116 gripe("option `-o' requires an argument") unless defined($OFILE);
117 } elsif ($o eq "d") {
118 $MODE = \&decrypt;
119 } elsif ($o eq "e") {
120 $MODE = \&encrypt;
121 } elsif ($o eq "t") {
122 $TAG = length($opt) ? $opt : shift(@ARGV); $opt = "";
123 gripe("option `-t' requires an argument") unless defined($TAG);
124 } elsif ($o eq "h") {
125 help(\*STDOUT);
126 exit(0);
127 } elsif ($o eq "v") {
128 version(\*STDOUT);
129 exit(0);
130 } elsif ($o eq "u") {
131 usage(\*STDOUT);
132 exit(0);
133 } elsif ($o eq "D") {
134 $DEBUG = 1;
135 } else {
136 gripe("unknown option `-$o'");
137 }
138 }
139}
140if ($GRIPE) { usage(\*STDERR); exit(1); }
141
142&$MODE();
143exit(0);
144