660b443c |
1 | #! /usr/bin/perl -w |
2 | |
3 | use Catacomb; |
4 | |
5 | my $GRIPE = 0; |
6 | my $DEBUG = 0; |
7 | my $QUIS = $0; $QUIS =~ s:^.*/::; |
8 | |
9 | my $MODE = \&encrypt; |
10 | my $OFILE = "-"; |
11 | my $TAG = "ciphersaber-%s"; |
12 | |
13 | sub usage { |
14 | my $f = shift; |
15 | print $f "Usage: $QUIS [-de] [-t TAG] [-o FILE] file...\n"; |
16 | } |
17 | sub version { |
18 | my $f = shift; |
19 | print $f "$QUIS, catacomb-perl version $Catacomb::VERSION\n"; |
20 | } |
21 | sub help { |
22 | my $f = shift; |
23 | version($f); |
24 | print $f "\n"; |
25 | usage($f); |
26 | print $f <<EOF; |
27 | |
28 | Implements the CipherSaber file encryption system (as described in |
29 | http://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. |
39 | EOF |
40 | #' |
41 | } |
42 | |
43 | sub gripe { print STDERR join(": ", $QUIS, @_), "\n"; $GRIPE = 1; } |
44 | sub barf { gripe(@_); exit(1); } |
45 | sub hexify { unpack("H*", join("", @_)); } |
46 | sub unhexify { my $x = join("", @_); $x =~ tr/\s//d; pack("H*", $x); } |
47 | |
48 | sub debug { |
49 | return unless $DEBUG; |
50 | my $what = shift(@_); |
51 | print STDERR |
52 | "debug: $what", |
53 | (@_ ? " = " . join(" ", map { "<" . hexify($_) . ">" } @_) : ""), |
54 | "\n"; |
55 | } |
56 | |
57 | sub 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 | |
80 | sub 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 | |
105 | while (@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 | } |
140 | if ($GRIPE) { usage(\*STDERR); exit(1); } |
141 | |
142 | &$MODE(); |
143 | exit(0); |
144 | |