]> git.pld-linux.org Git - packages/gen-auth.git/blame - gen-auth.pl
- drop obsolete and outdated manual inclusion of rpm macros
[packages/gen-auth.git] / gen-auth.pl
CommitLineData
e4f402bc 1#!/usr/bin/perl
2
3use strict;
4use MIME::Base64;
5use Getopt::Std;
6
7my($p_name) = $0 =~ m|/?([^/]+)$|;
8my $p_version = "20060620.0";
9my $p_usage = "Usage: $p_name [--help|--version] | <type> ...";
10my $p_cp = <<EOM;
11 Copyright (c) 2002-2006 John Jetmore <jj33\@pobox.com>
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26EOM
27ext_usage();
28
29my %O = ();
30getopts('s', \%O);
31
32my $type = get_input(\@ARGV, "encryption type: ");
33
34if ($type =~ /^plain$/i) {
35 my $user = get_input(\@ARGV, "username: ", $O{s}||0);
36 my $pass = get_input(\@ARGV, "password: ", $O{s}||1);
37 print "Auth String: ", encode_base64("\0$user\0$pass", ''), "\n";
38
39} elsif ($type =~ /^decode$/i) {
40 my $user = get_input(\@ARGV, "string: ", $O{s}||0);
41 print decode_base64($user), "\n";
42
43} elsif ($type =~ /^encode$/i) {
44 my $user = get_input(\@ARGV, "string: ", $O{s}||0);
45 print encode_base64($user, ""), "\n";
46
47} elsif ($type =~ /^rot13$/i) {
48 my $str = get_input(\@ARGV, "string: ", $O{s}||0);
49 my @c = unpack("c*", $str);
50 foreach my $c (@c) {
51 if ($c <= 123 && $c >= 97) { $c = ((($c - 97 + 13) % 26) + 97); }
52 elsif ($c <= 90 && $c >= 65) { $c = ((($c - 65 + 13) % 26) + 65); }
53 }
54 print pack("c*", @c), "\n";
55
56} elsif ($type =~ /^atbash$/i) {
57 my $str = get_input(\@ARGV, "string: ", $O{s}||0);
58 my @c = unpack("c*", $str);
59 foreach my $c (@c) {
60 if ($c <= 123 && $c >= 97) { $c = (25 - ($c - 97)) + 97; }
61 elsif ($c <= 90 && $c >= 65) { $c = (25 - ($c - 65)) + 65; }
62 }
63 print pack("c*", @c), "\n";
64
65} elsif ($type =~ /^http(-basic)?$/i) {
66 my $user = get_input(\@ARGV, "username: ", $O{s}||0);
67 my $pass = get_input(\@ARGV, "password: ", $O{s}||1);
68 print "Auth String: ", encode_base64("${user}:$pass", ''), "\n";
69
70} elsif ($type =~ /^wcsencode$/i) {
71 try_load("WCS::Encode") || die "WCS::Encode required for rce\n";
72 my $user = get_input(\@ARGV, "string: ", $O{s}||0);
73 chomp($user = WCS::Encode::encode($user));
74 print $user, "\n";
75
76} elsif ($type =~ /^wcsdecode$/i) {
77 try_load("WCS::Encode") || die "WCS::Encode required for rce\n";
78 my $user = get_input(\@ARGV, "string: ", $O{s}||0);
79 print WCS::Encode::decode($user), "\n";
80
81} elsif ($type =~ /^rce$/i) {
82 try_load("WCS::Passwd") || die "WCS::Passwd required for rce\n";
83 my $user = get_input(\@ARGV, "string: ", $O{s}||0);
84 print WCS::Passwd::rce($user), "\n";
85
86} elsif ($type =~ /^rcd$/i) {
87 try_load("WCS::Passwd") || die "WCS::Passwd required for rce\n";
88 my $user = get_input(\@ARGV, "string: ", $O{s}||0);
89 print WCS::Passwd::rcd($user), "\n";
90
91} elsif ($type =~ /^(salt)?encrypt$/i) {
92 my $user = get_input(\@ARGV, "string: ", $O{s}||1);
93 my $salt = join('', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]);
94 $salt = get_input(\@ARGV, "salt: ", $O{s}||0) if ($type =~ /^saltencrypt/i);
95 print crypt($user, $salt), "\n";
96
97} elsif ($type =~ /^login$/i) {
98 my $user = get_input(\@ARGV, "username: ", $O{s}||0);
99 my $pass = get_input(\@ARGV, "password: ", $O{s}||1);
100 print "Username: ", encode_base64($user, ""), "\n",
101 "Password: ", encode_base64($pass, ""), "\n";
102
103} elsif ($type =~ /^md5-(base)?64$/i) {
104 try_load("Digest::MD5") || die "Digest::MD5 required for md5\n";
105 my $string = get_input(\@ARGV, "string: ", $O{s}||0);
106 print Digest::MD5::md5_base64($string), "\n";
107
108} elsif ($type =~ /^md5(-hex)?$/i) {
109 try_load("Digest::MD5") || die "Digest::MD5 required for md5\n";
110 my $string = get_input(\@ARGV, "string: ", $O{s}||0);
111 print Digest::MD5::md5_hex($string), "\n";
112
113} elsif ($type =~ /^cram(-(md5|sha1))?$/i) {
114 my $digest_type = lc($2) || 'md5';
115 if ($digest_type eq 'md5') {
116 try_load("Digest::MD5") || die "Digest::MD5 required for CRAM-MD5\n";
117 } elsif ($digest_type eq 'sha1') {
118 try_load("Digest::SHA1") || die "Digest::SHA1 required for CRAM-SHA1\n";
119 }
120 my $user = get_input(\@ARGV, "username: ", $O{s}||0);
121 my $pass = get_input(\@ARGV, "password: ", $O{s}||1);
122 my $chal = get_input(\@ARGV, "challenge: ", $O{s}||0);
123 if ($chal !~ /^</) {
124 chomp($chal = decode_base64($chal));
125 }
126 my $digest = get_digest($pass, $chal, $digest_type);
127 print encode_base64("$user $digest", ""), "\n";
128
129} elsif ($type =~ /^(ntlm|spa|msn)$/i) {
130 try_load("Authen::NTLM") || die "Authen::NTLM required for $type\n";
131 my $user = get_input(\@ARGV, "username: ", $O{s}||0);
132 my $pass = get_input(\@ARGV, "password: ", $O{s}||1);
133 my $domn = get_input(\@ARGV, "domain: ", $O{s}||0);
134 print "Auth Request: ", Authen::NTLM::ntlm(), "\n";
135 Authen::NTLM::ntlm_user($user);
136 Authen::NTLM::ntlm_password($pass);
137 Authen::NTLM::ntlm_domain($domn);
138 my $chal = get_input(\@ARGV, "challenge: ", $O{s}||0);
139 print "Auth Response: ", Authen::NTLM::ntlm($chal), "\n";
140
141} elsif ($type =~ /^apop$/i) {
142 try_load("Digest::MD5") || die "Digest::MD5 required for APOP\n";
143 my $chal = get_input(\@ARGV, "challenge: ");
144 my $pass = get_input(\@ARGV, "password: ", 1);
145 my $ctx = Digest::MD5->new;
146 $ctx->add($chal . $pass);
147 print $ctx->hexdigest, "\n";
148
149} else {
150 print STDERR "I don't speak $type\n";
151 exit 1;
152}
153
154exit 0;
155
156sub get_input {
157 my $a = shift; # command line array
158 my $s = shift; # prompt string
159 my $q = shift; # quiet
160 my $r; # response
161
162 if (scalar(@$a) > 0) {
163 $r = shift(@$a);
164 } else {
165 print $s;
166 system('stty', '-echo') if ($q);
167 $r = <>;
168 system('stty', 'echo') if ($q);
169 print "\n" if ($q);
170 chomp($r);
171 }
172
173 $r = '' if ($r eq '<>');
174 return($r);
175}
176
177sub get_digest {
178 my $secr = shift;
179 my $chal = shift;
180 my $type = shift;
181 my $ipad = chr(0x36) x 64;
182 my $opad = chr(0x5c) x 64;
183
184 if (length($secr) > 64) {
185 if ($type eq 'md5') {
186 $secr = Digest::MD5::md5($secr);
187 } elsif ($type eq 'sha1') {
188 $secr = Digest::SHA1::sha1($secr);
189 } else {
190 # unknown digest type
191 return;
192 }
193 } else {
194 $secr .= chr(0) x (64 - length($secr));
195 }
196
197 my $digest = $type eq 'md5'
198 ? Digest::MD5::md5_hex(($secr ^ $opad),
199 Digest::MD5::md5(($secr ^ $ipad), $chal))
200 : Digest::SHA1::sha1_hex(($secr ^ $opad),
201 Digest::SHA1::sha1(($secr ^ $ipad), $chal));
202 return($digest);
203}
204
205sub try_load {
206 my $mod = shift;
207
208 eval("use $mod");
209 return $@ ? 0 : 1;
210}
211
212sub ext_usage {
213 if ($ARGV[0] =~ /^--help$/i) {
214 require Config;
215 $ENV{PATH} .= ":" unless $ENV{PATH} eq "";
216 $ENV{PATH} = "$ENV{PATH}$Config::Config{'installscript'}";
217 exec("perldoc", "-F", "-U", $0) || exit 1;
218 # make parser happy
219 %Config::Config = ();
220 } elsif ($ARGV[0] =~ /^--version$/i) {
221 print "$p_name version $p_version\n\n$p_cp\n";
222 } else {
223 return;
224 }
225
226 exit(0);
227}
228
229__END__
230
231=head1 NAME
232
233gen-auth - generate various authentication strings
234
235=head1 USAGE
236
237gen-auth [--help|--version] | <type> ...
238
239=head1 DESCRIPTION
240
241gen-auth is tool to assist in all kinds of authentication / encoding / decoding / encrypting tasks. It began life as an smtp-specific tool, but has drifted in functionality over time.
242
243The program actions are broken down into types of encoding to generate.
244Each <type> then takes its own specific args. The arguments are expected
245in a specific order on the command line. Every argument that isn't
246available on the command line will be prompted for. One benefit to this is
247arguments corresponding to passwords will not be echoed to the terminal when
248prompted for.
249
250=head1 TYPES
251
252The program action is controlled by the first argument. The meaning of the
253following arguments is specified by this type
254
255=over 4
256
257=item PLAIN <username> <password>
258
259This type generates a PLAIN (RFC 2595) authentication string. It accepts
260supplemental arguments of username and password. It generates a Base64
261encoded string "\0<username>\0<password>".
262
263=item LOGIN <username> <password>
264
265This method accepts username and password as supplemental args. It simply
266returns each string Base64 encoded. This provides only minimal advantages
267over using ENCODE twice. One advantage is hiding the password if you
268provide it on STDIN
269
270=item CRAM-MD5 <username> <password> <challenge>
271
272CRAM-MD5 (RFC 2195) accepts three supplemental arguments. The first is the username and
273the second is the password. The third is the challenge string provided
274by the server. This string can be either Base64 encoded or not. The RFC states
275that all (unencoded) challenge strings must start w/ '<'. This is used to
276whether the string is Base64 encoded or not.
277
278CRAM-MD5 uses the challenge and the supplied password to generate a digest.
279it then returns the Base64 encoded version of the string md5("<username> <challenge>")
280
281This authentication method requires the Digest::MD5 perl module to be installed.
282
283=item CRAM-SHA1 <username> <password> <challenge>
284
285This behaves the same as CRAM-MD5 but uses SHA1 digesting rather than MD5.
286
287This authentication method requires the Digest::SHA1 perl module to be installed.
288
289=item NTLM/SPA/MSN <username> <password> <domain> <challenge>
290
291Although it may be advertised as one of the above types, this method of authentication if refered to singularly as NTLM. This is a multi-step authentication type. The first 3 arguments must be supplied up front. They are username, password, and domain, in that order. These three strings are used to generate an "Auth Request" string. This string should be passed verbatim to the server. The server will then respond with a challenge. This challenge is the fourth argument. After receiving the server challenge, gen-auth will produce an "Auth Response". Posting this response to the server completes the NTLM authentication transaction.
292
293This authentication method requires the Authen::NTLM perl module to be installed. See EXAMPLES for an example of this transaction. Note also that 'domain' is often blank from client or ignored by server.
294
295=item HTTP-BASIC <username> <password>
296
297Returns the value base64("<username>:<password>"). Used for HTTP Basic authentication (RFC 2617). Used by adding a header "Authorization: Basic <string>" to a HTTP request where <string> is the output of this command.
298
299=item APOP <challenge> <password>
300
301This implements the APOP authentication for the POP3 protocol as described in RFC 1939. <challenge> is the challenge string presented by the POP3 server in the greeting banner. <password> is the "secret" (usually a password) used to authenticate the user. This method returns a digest md5("<challenge><password>"). This can be used to authenticate to a POP3 server in a string like "APOP <user> <digest>" where <digest> is the string generated by this command.
302
303APOP required the Digest::MD5 perl module.
304
305=item ENCODE <string>
306
307Simply Base64 encodes a plaintext string. Provided as a convenience function.
308
309=item DECODE <string>
310
311Decodes a Base64 encoded string. Provided as a convenience function.
312
313=item MD5/MD5-HEX <string>
314
315Provides an MD5 digest of the supplied string in hex.
316
317=item MD5-BASE64 <string>
318
319Provides an MD5 digest of the supplied string in Base64.
320
321=item ENCRYPT <string>
322
323Returns a crypt(3) string generated from the input string.
324
325=item SALTENCRYPT <string> <salt>
326
327Same as ENCRYPT but you provide the salt as the second argument. See crypt(3) man page for details.
328
329=item ROT13 <string>
330
331This performs a rot13 action on <string>. This implementation only performs the action on ASCII 65-90,97-123. Any other character value is left untouched. Therefore this method is primarily for LOCALE=C, ASCII only. Feel free to send patches if you care to have it work in another setting.
332
333=item ATBASH <string>
334
335This performs an atbash action on <string>. Atbash mirrors a string such that 'a'=='z', 'b'=='y', etc. See the comments on locale and character set under ROT13.
336
337=back
338
339=head1 OPTIONS
340
13a0f5e2 341=over 4
342
e4f402bc 343=item -s
344
345Supresses echo on all input fields read from standard input. If this option is not used, echo is suppressed on fields which are known to be password fields but this may not be secure enough.
346
347=item --help
348
349this screen.
350
351=item --version
352
353version info.
354
13a0f5e2 355=back
356
e4f402bc 357=head1 EXAMPLES
358
359=over 4
360
361=item generate a PLAIN AUTH string for user 'tim', password 'tanstaaftanstaaf'
362
363 > gen-auth plain tim tanstaaftanstaaf
364 Auth String: AHRpbQB0YW5zdGFhZnRhbnN0YWFm
365
366=item generate a CRAM-MD5 string for user 'tim', password 'tanstaaftanstaaf',
367challenge '<1896.697170952@postoffice.reston.mci.net>', using prompt to
368hide password
369
370 > gen-auth cram-md5
371 username: tim
372 password:
373 challenge: PDE4OTYuNjk3MTcwOTUyQHBvc3RvZmZpY2UucmVzdG9uLm1jaS5uZXQ+
374 dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw
375
376=item use the DECODE method to ensure we provided the correct output in our last
377example
378
379 > gen-auth decode dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw
380 tim b913a602c7eda7a495b4e6e7334d3890
381
382=item use the NTLM (MSN) method to authenticate to a mail server using user 'tim', password 'tanstaaftanstaaf', and domain MAIL. Both the gen-auth transaction and SMTP transaction are shown to demonstrate the interaction between the two.
383
384 AUTH MSN
385 334 NTLM supported
386 TlRMTVNTUAABAAAAB7IAAAMAAwAgAAAABAAEACMAAAB0aW1NQUlM
387 334 TlRMTVNTUAACAAAAAAAAAAAoAAABggAA9RH5KZlXvygAAACAAAAAZL//4sQAAAAC
388 TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAAAwAAAABgAGAHAAAAAGAAYAdgAAAAAAAAA8AAAAAYIAAK3lcO8PldNxIrkbvgKGJRR5owQePUtYaTtLVgfQiVQBywW2yZKyp+VFGqYfgDtdEHQAaQBtAHQAaQBtAA==
389 235 Authentication succeeded
390
391 > gen-auth spa
392 username: tim
393 password:
394 domain: MAIL
395 Auth Request: TlRMTVNTUAABAAAAB7IAAAMAAwAgAAAABAAEACMAAAB0aW1NQUlM
396 challenge: TlRMTVNTUAACAAAAAAAAAAAoAAABggAA9RH5KZlXvygAAACAAAAAZL//4sQAAAAC
397 Auth Response: TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAAAwAAAABgAGAHAAAAAGAAYAdgAAAAAAAAA8AAAAAYIAAK3lcO8PldNxIrkbvgKGJRR5owQePUtYaTtLVgfQiVQBywW2yZKyp+VFGqYfgDtdEHQAaQBtAHQAaQBtAA==
398
399=back
400
401=head1 REQUIRES
402
13a0f5e2 403=over 4
404
e4f402bc 405=item MIME::Base64
406
407Required for all functionality
408
409=item Digest::MD5
410
411Required for MD5, MD5-BASE64, CRAM-MD5, APOP
412
413=item Digest::SHA1
414
415Required for CRAM-SHA1
416
417=item Authen::NTLM
418
419Required for NTLM/MSN/SPA
420
13a0f5e2 421=back
422
e4f402bc 423=head1 EXIT CODES
424
13a0f5e2 425=over 4
426
e4f402bc 427=item 0 - no errors occurred
428
429=item 1 - unrecognized type specified
430
13a0f5e2 431=back
432
e4f402bc 433=head1 CONTACT
434
13a0f5e2 435=over 4
436
e4f402bc 437=item proj-gen-auth@jetmore.net
This page took 0.128545 seconds and 4 git commands to generate.