#!/usr/bin/perl use strict; use MIME::Base64; use Digest::MD5; my($p_name) = $0 =~ m|/?([^/]+)$|; my $p_version = "20030322.1"; my $p_usage = "Usage: $p_name [--help|--version] | ..."; my $p_cp = <. All rights reserved. This code freely redistributable provided my name and this copyright notice are not removed. Send email to the contact address if you use this program. EOM ext_usage(); my $type = shift || get_input("encryption type: "); if ($type =~ /^plain$/i) { my $user = shift || get_input("username: "); my $pass = shift || get_input("password: ", 1); print "Auth String: ", encode_base64("\0$user\0$pass", ''), "\n"; } elsif ($type =~ /^decode$/i) { my $user = shift || get_input("string: "); print decode_base64($user), "\n"; } elsif ($type =~ /^encode$/i) { my $user = shift || get_input("string: "); print encode_base64($user, ""), "\n"; } elsif ($type =~ /^login$/i) { my $user = shift || get_input("username: "); my $pass = shift || get_input("password: ", 1); print "Username: ", encode_base64($user, ""), "\n", "Password: ", encode_base64($pass, ""), "\n"; } elsif ($type =~ /^cram(-md5)?$/i) { my $user = shift || get_input("username: "); my $pass = shift || get_input("password: ", 1); my $chal = shift || get_input("challenge: "); if ($chal !~ /^; system('stty', 'echo') if ($q); print "\n" if ($q); chomp($r); return($r); } sub get_digest { my $secr = shift; my $chal = shift; my $retr = ''; my $ipad = chr(0x36); my $opad = chr(0x5c); my($isec, $osec) = undef; if (length($secr) > 64) { $secr = Digest::MD5::md5($secr); } else { $secr .= chr(0) x (64 - length($secr)); } foreach my $char (split(//, $secr)) { $isec .= $char ^ $ipad; $osec .= $char ^ $opad; } map { $retr .= sprintf("%02x", ord($_)) } split(//,Digest::MD5::md5($osec . Digest::MD5::md5($isec . $chal))); return($retr); } sub ext_usage { if ($ARGV[0] =~ /^--help$/i) { require Config; $ENV{PATH} .= ":" unless $ENV{PATH} eq ""; $ENV{PATH} = "$ENV{PATH}$Config::Config{'installscript'}"; exec("perldoc", "-F", "-U", $0) || exit 1; # make parser happy %Config::Config = (); } elsif ($ARGV[0] =~ /^--version$/i) { print "$p_name version $p_version\n\n$p_cp\n"; } else { return; } exit(0); } __END__ =head1 NAME gen-auth - Brief description =head1 USAGE gen-auth [--help|--version] | ... =head1 DESCRIPTION gen-auth can generate various authentication strings used for SMTP authentication. The currently supported methods are PLAIN (RFC 2595), LOGIN, and CRAM-MD5 (RFC-2195). The program actions are broken down into types of encoding to generate. each then takes its own specific args. The arguments are expected in a specific order on the command line. Every argument that isn't available on the command line will be prompted for. One benefit to this is arguments corresponding to passwords will not be echoed to the terminal when prompted for. =head1 TYPES The program action is controlled by the first argument. The meaning of the following arguments is specified by this type =over 4 =item PLAIN This type generates a PLAIN authentication string. It accepts two supplemental arguments of username and password. It generates a Base64 encoded string "\0\0". =item LOGIN This method accepts username and password as supplemental args. It simply returns each string Base64 encoded. This provides only minimal advantages over using ENCODE twice. One advantage is hiding the password if you provide it on STDIN =item CRAM-MD5 CRAM-MD5 accepts three supplemental arguments. The first is the username and the second is the password. The third is the challenge string provided by the server. This string can be either Base64 encoded or not. RFC states that all (unencoded) challenge strings must start w/ '<'. This is used to whether the string is Base64 encoded or not. CRAM-MD5 uses the challenge and the supplied password to generate a digest. it then returns the Base64 encoded version of the string " " =item ENCODE Simply Base64 encodes a plaintext string. Provided as a convenience function. =item DECODE Decodes a Base64 encoded string. Provided as a convenience function. =back =head1 OPTIONS =item --help this screen. =item --version version info. =back =head1 EXAMPLES =over 4 =item generate a PLAIN AUTH string for user 'tim', password 'tanstaaftanstaaf' > gen-auth plain tim tanstaaftanstaaf Auth String: AHRpbQB0YW5zdGFhZnRhbnN0YWFm =item generate a CRAM-MD5 string for user 'tim', password 'tanstaaftanstaaf', challenge '<1896.697170952@postoffice.reston.mci.net>', using prompt to hide password > gen-auth cram-md5 username: tim password: challenge: PDE4OTYuNjk3MTcwOTUyQHBvc3RvZmZpY2UucmVzdG9uLm1jaS5uZXQ+ dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw =item use the DECODE method to ensure we provided the correct output in our last example > gen-auth decode dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw tim b913a602c7eda7a495b4e6e7334d3890 =back =head1 REQUIRES MIME::Base64, Digest::MD5 =head1 EXIT CODES =item 0 - no errors occurred =item 1 - unrecognized type specified =head1 CONTACT =item proj-gen-auth@jetmore.net