7 my($p_name) = $0 =~ m|/?([^/]+)$|;
8 my $p_version = "20060620.0";
9 my $p_usage = "Usage: $p_name [--help|--version] | <type> ...";
11 Copyright (c) 2002-2006 John Jetmore <jj33\@pobox.com>
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.
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.
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
32 my $type = get_input(\@ARGV, "encryption type: ");
34 if ($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";
39 } elsif ($type =~ /^decode$/i) {
40 my $user = get_input(\@ARGV, "string: ", $O{s}||0);
41 print decode_base64($user), "\n";
43 } elsif ($type =~ /^encode$/i) {
44 my $user = get_input(\@ARGV, "string: ", $O{s}||0);
45 print encode_base64($user, ""), "\n";
47 } elsif ($type =~ /^rot13$/i) {
48 my $str = get_input(\@ARGV, "string: ", $O{s}||0);
49 my @c = unpack("c*", $str);
51 if ($c <= 123 && $c >= 97) { $c = ((($c - 97 + 13) % 26) + 97); }
52 elsif ($c <= 90 && $c >= 65) { $c = ((($c - 65 + 13) % 26) + 65); }
54 print pack("c*", @c), "\n";
56 } elsif ($type =~ /^atbash$/i) {
57 my $str = get_input(\@ARGV, "string: ", $O{s}||0);
58 my @c = unpack("c*", $str);
60 if ($c <= 123 && $c >= 97) { $c = (25 - ($c - 97)) + 97; }
61 elsif ($c <= 90 && $c >= 65) { $c = (25 - ($c - 65)) + 65; }
63 print pack("c*", @c), "\n";
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";
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));
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";
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";
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";
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";
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";
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";
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";
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";
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);
124 chomp($chal = decode_base64($chal));
126 my $digest = get_digest($pass, $chal, $digest_type);
127 print encode_base64("$user $digest", ""), "\n";
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";
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";
150 print STDERR "I don't speak $type\n";
157 my $a = shift; # command line array
158 my $s = shift; # prompt string
159 my $q = shift; # quiet
162 if (scalar(@$a) > 0) {
166 system('stty', '-echo') if ($q);
168 system('stty', 'echo') if ($q);
173 $r = '' if ($r eq '<>');
181 my $ipad = chr(0x36) x 64;
182 my $opad = chr(0x5c) x 64;
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);
190 # unknown digest type
194 $secr .= chr(0) x (64 - length($secr));
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));
213 if ($ARGV[0] =~ /^--help$/i) {
215 $ENV{PATH} .= ":" unless $ENV{PATH} eq "";
216 $ENV{PATH} = "$ENV{PATH}$Config::Config{'installscript'}";
217 exec("perldoc", "-F", "-U", $0) || exit 1;
219 %Config::Config = ();
220 } elsif ($ARGV[0] =~ /^--version$/i) {
221 print "$p_name version $p_version\n\n$p_cp\n";
233 gen-auth - generate various authentication strings
237 gen-auth [--help|--version] | <type> ...
241 gen-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.
243 The program actions are broken down into types of encoding to generate.
244 Each <type> then takes its own specific args. The arguments are expected
245 in a specific order on the command line. Every argument that isn't
246 available on the command line will be prompted for. One benefit to this is
247 arguments corresponding to passwords will not be echoed to the terminal when
252 The program action is controlled by the first argument. The meaning of the
253 following arguments is specified by this type
257 =item PLAIN <username> <password>
259 This type generates a PLAIN (RFC 2595) authentication string. It accepts
260 supplemental arguments of username and password. It generates a Base64
261 encoded string "\0<username>\0<password>".
263 =item LOGIN <username> <password>
265 This method accepts username and password as supplemental args. It simply
266 returns each string Base64 encoded. This provides only minimal advantages
267 over using ENCODE twice. One advantage is hiding the password if you
270 =item CRAM-MD5 <username> <password> <challenge>
272 CRAM-MD5 (RFC 2195) accepts three supplemental arguments. The first is the username and
273 the second is the password. The third is the challenge string provided
274 by the server. This string can be either Base64 encoded or not. The RFC states
275 that all (unencoded) challenge strings must start w/ '<'. This is used to
276 whether the string is Base64 encoded or not.
278 CRAM-MD5 uses the challenge and the supplied password to generate a digest.
279 it then returns the Base64 encoded version of the string md5("<username> <challenge>")
281 This authentication method requires the Digest::MD5 perl module to be installed.
283 =item CRAM-SHA1 <username> <password> <challenge>
285 This behaves the same as CRAM-MD5 but uses SHA1 digesting rather than MD5.
287 This authentication method requires the Digest::SHA1 perl module to be installed.
289 =item NTLM/SPA/MSN <username> <password> <domain> <challenge>
291 Although 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.
293 This 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.
295 =item HTTP-BASIC <username> <password>
297 Returns 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.
299 =item APOP <challenge> <password>
301 This 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.
303 APOP required the Digest::MD5 perl module.
305 =item ENCODE <string>
307 Simply Base64 encodes a plaintext string. Provided as a convenience function.
309 =item DECODE <string>
311 Decodes a Base64 encoded string. Provided as a convenience function.
313 =item MD5/MD5-HEX <string>
315 Provides an MD5 digest of the supplied string in hex.
317 =item MD5-BASE64 <string>
319 Provides an MD5 digest of the supplied string in Base64.
321 =item ENCRYPT <string>
323 Returns a crypt(3) string generated from the input string.
325 =item SALTENCRYPT <string> <salt>
327 Same as ENCRYPT but you provide the salt as the second argument. See crypt(3) man page for details.
331 This 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.
333 =item ATBASH <string>
335 This 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.
345 Supresses 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.
361 =item generate a PLAIN AUTH string for user 'tim', password 'tanstaaftanstaaf'
363 > gen-auth plain tim tanstaaftanstaaf
364 Auth String: AHRpbQB0YW5zdGFhZnRhbnN0YWFm
366 =item generate a CRAM-MD5 string for user 'tim', password 'tanstaaftanstaaf',
367 challenge '<1896.697170952@postoffice.reston.mci.net>', using prompt to
373 challenge: PDE4OTYuNjk3MTcwOTUyQHBvc3RvZmZpY2UucmVzdG9uLm1jaS5uZXQ+
374 dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw
376 =item use the DECODE method to ensure we provided the correct output in our last
379 > gen-auth decode dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw
380 tim b913a602c7eda7a495b4e6e7334d3890
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.
386 TlRMTVNTUAABAAAAB7IAAAMAAwAgAAAABAAEACMAAAB0aW1NQUlM
387 334 TlRMTVNTUAACAAAAAAAAAAAoAAABggAA9RH5KZlXvygAAACAAAAAZL//4sQAAAAC
388 TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAAAwAAAABgAGAHAAAAAGAAYAdgAAAAAAAAA8AAAAAYIAAK3lcO8PldNxIrkbvgKGJRR5owQePUtYaTtLVgfQiVQBywW2yZKyp+VFGqYfgDtdEHQAaQBtAHQAaQBtAA==
389 235 Authentication succeeded
395 Auth Request: TlRMTVNTUAABAAAAB7IAAAMAAwAgAAAABAAEACMAAAB0aW1NQUlM
396 challenge: TlRMTVNTUAACAAAAAAAAAAAoAAABggAA9RH5KZlXvygAAACAAAAAZL//4sQAAAAC
397 Auth Response: TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAAAwAAAABgAGAHAAAAAGAAYAdgAAAAAAAAA8AAAAAYIAAK3lcO8PldNxIrkbvgKGJRR5owQePUtYaTtLVgfQiVQBywW2yZKyp+VFGqYfgDtdEHQAaQBtAHQAaQBtAA==
407 Required for all functionality
411 Required for MD5, MD5-BASE64, CRAM-MD5, APOP
415 Required for CRAM-SHA1
419 Required for NTLM/MSN/SPA
427 =item 0 - no errors occurred
429 =item 1 - unrecognized type specified
437 =item proj-gen-auth@jetmore.net