#!/usr/bin/perl

# gen-auth 20030310

# gen-auth <type> <type specific data...>
#
# gen-auth plain <user> <pass>
# gen-auth login <user> <pass>
# gen-auth cram-md5 <user> <pass> <challenge>
# gen-auth encode <string>
# gen-auth decode <string>
#
# any missing arguments will be prompted for.

# Copyright (c) 2003
#	John Jetmore <jj33@pobox.com>.  All rights reserved.
# This code freely redistributable provided my name and this copyright notice
# are not removed

use strict;
use MIME::Base64;
use Digest::MD5;

my $type = shift || get_input("encryption type: ");

if ($type eq 'plain') {
  my $user = shift || get_input("username: ");
  my $pass = shift || get_input("password: ", 1);
  print "Auth String: ", encode_base64("\0$user\0$pass");
} elsif ($type eq 'decode') {
  my $user = shift || get_input("string: ");
  print decode_base64($user), "\n";
} elsif ($type eq 'encode') {
  my $user = shift || get_input("string: ");
  print encode_base64($user);
} elsif ($type eq 'login') {
  my $user = shift || get_input("username: ");
  my $pass = shift || get_input("password: ", 1);
  print "Username: ", encode_base64($user), "Password: ", encode_base64($pass);
} elsif ($type =~ /^cram/i) {
  my $user = shift || get_input("username: ");
  my $pass = shift || get_input("password: ", 1);
  my $chal = shift || get_input("challenge: ");
  if ($chal !~ /^</) {
    chomp($chal = decode_base64($chal));
    print "Challenge is $chal\n";
  }
  my $digest = get_digest($pass, $chal);
  print "Digest: $digest\n";
  #print "Auth String: ", encode_base64("$user $digest");
  print encode_base64("$user $digest");
} else {
  print STDERR "I don't speak $type\n";
}

exit;

sub get_input {
  my $s = shift;
  my $q = shift;
  print $s;

  system('stty', '-echo') if ($q);
  my $r = <>;
  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);
}
