Mini Shell
#!/usr/bin/perl
#
# Program information.
#
$Program = 'makepasswd';
$Version = '1.10';
$Author = 'Rob Levin <levin@openproject.net>';
$Date = "Monday, 7 April 1999 at 22:56 (UCT)";
$Copyright = '1997-1999';
$Description = 'This program is extracted from the author\'s GPL\'ed mkircconf program. '.
'It is used to create and/or encrypt true-random-seeded password strings.';
#
# Setup.
#
use Getopt::Long;
use FileHandle;
use integer;
use bytes;
use Crypt::OpenSSL::Random;
#
# Set default values for options ("" to indicate not-specified).
#
$Chars = "";
$Clear = "";
$Count = "";
$Crypt = 0;
$CryptMd5 = 0;
$CryptSalt = "";
$MaxChars = "";
$MinChars = "";
$RandomSeed = "";
$RepeatPass = "";
$Rerandom = "";
$ShowHelp = 0;
$String = "";
$Verbose = 0;
#
# Limit and current value variables for execution.
#
$Error = 0;
$CharMin = 8;
$CharMax = 10;
$CharFormat = $CharMax + 3;
$CountUsed = 1;
$PasswordRepeat = 1;
$CurrentChar=$CharMin;
$Password = "";
$Randomize = 1;
$RandSeed = 0;
$RerandomCount = -1;
$RerandomNow = 1;
$SeedValue = 0;
#
# Crypt() mode set on the basis of options interpreted:
#
# 0 No related options yet interpreted.
# 1 Password generation will be done.
# 2 Password generation w/o encryption will be done.
# 3 Password generation and encryption will be done.
# 4 Encryption w/o password generation will be done.
#
$CryptMode = 0;
#
# Default characters for passwords include all lowercase
# and uppercase alphabetics, plus numerics 0-9. Uppercase
# O and Z and lowercase k and l are omitted to improve
# hand-transcription clarity.
#
$StringUsed = "ABCDEFGHIJKLMNPQRSTUVWXYabcdefghijmnopqrstuvwxyz0123456789";
$ValString = length($StringUsed) - 1;
#
# Characters for salt construction.
#
$SaltList="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
#
# Process the options.
#
&GetOptions
(
'chars=i' => \$Chars,
'clear=s' => \$OldClear,
'clearfrom=s' => \$Clear,
'count=i' => \$Count,
'crypt!' => \$Crypt,
'crypt-md5!' => \$CryptMd5,
'cryptsalt=i' => \$CryptSalt,
'help' => \$ShowHelp,
'maxchars=i' => \$MaxChars,
'minchars=i' => \$MinChars,
'randomseed=i' => \$RandomSeed,
'repeatpass=i' => \$RepeatPass,
'rerandom=i' => \$Rerandom,
'string=s' => \$String,
'verbose!' => \$Verbose,
) or do
{
$Error = 1;
};
$#ARGV != -1 and do
{
print STDERR "$Program: Non-argument options specified: @ARGV\n";
$Error = 1;
};
#
# If password generation option was specified with the old --clear,
# warn the user and exit
#
$OldClear ne "" and do
{
print STDERR "$Program: Option --clear is no longer present \n".
"please use --clearfrom and supply a file for it.\n";
$Error = 1;
};
#
# If password generation option was specified with --clearfrom, flag it.
#
$Clear ne "" and do
{
(
$Chars ne "" or
$MaxChars ne "" or
$MinChars ne "" or
$Count ne "" or
$String ne ""
) and do
{
print STDERR "$Program: Option --clearfrom may not be specified ".
"with a password generation option.\n";
print STDERR "$Program: Password generation options are ".
"--chars --minchars --maxchars --count --string.\n";
$Error = 1;
};
$Crypt or $CryptMd5 or do
{
print STDERR "$Program: Option --clearfrom may not be specified ".
"without option --crypt or --crypt-md5.\n";
$Error = 1;
};
open CLEARFROM, "$Clear" or do
{
print STDERR "$Program: Could not read $Clear, error: $!\n";
$Error = 1;
};
$Clear = <CLEARFROM>;
$Clear =~ s/[\n]*$//;
close CLEARFROM;
$CryptMode = 4;
};
#
# If --chars was specified, process it.
#
$Chars ne "" and do
{
($MinChars ne "" or $MaxChars ne "") and do
{
print STDERR "$Program: May not specify --chars with --minchars or --maxchars.\n";
$Error = 1;
};
$CryptMode == 0 and $CryptMode = 1;
$CharMin = $Chars;
$CharMax = $Chars;
$CharFormat = $CharMax + 3;
};
#
# If --minchars was specified, process it.
#
$MinChars ne "" and do
{
$Chars eq "" or do
{
print STDERR "$Program: May not specify --minchars with --chars.\n";
$Error = 1;
};
$CryptMode == 0 and $CryptMode = 1;
$CharMin = $MinChars;
};
#
# If --maxchars was specified, process it.
#
$MaxChars ne "" and do
{
$Chars eq "" or do
{
print STDERR "$Program: May not specify --maxchars with --chars.\n";
$Error = 1;
};
$CryptMode == 0 and $CryptMode = 1;
$CharMax = $MaxChars;
$CharFormat = $CharMax + 3;
};
#
# Make sure minimum character length is less than or equal to maximum.
#
$CharMin > $CharMax and do
{
print STDERR "$Program: Illegal value --minchars=$CharMin is larger than --maxchars=$CharMax.\n";
$Error = 1;
};
#
# If --count was specified, process it.
#
$Count ne "" and do
{
#
# Make sure the password count is a positive number.
#
$Count > 0 or do
{
print STDERR "$Program: Number of passwords to be made must be positive\n";
$Error = 1;
};
#
# If so, finish processing it.
#
$CryptMode == 0 and $CryptMode = 1;
$CountUsed = $Count;
};
#
# If --string was specified, process it.
#
$String ne "" and do
{
$CryptMode == 0 and $CryptMode = 1;
$StringUsed = $String;
$ValString = length($String) - 1;
};
#
# If --repeatpass was specified, process it.
#
$RepeatPass ne "" and do
{
#
# If --crypt is not set or --cryptsalt is set, disallow this parameter.
#
$Crypt or $CryptMd5 or do
{
print STDERR "$Program: To use --repeatpass, --crypt or --crypt-md5 must also be set.\n";
$Error = 1;
};
$CryptSalt and do
{
print STDERR "$Program: To use --repeatpass, --cryptsalt may not be set.\n";
$Error = 1;
};
#
# Make sure the password repeat count is a positive number.
#
($RepeatPass > 0 and $RepeatPass < 4097) or do
{
print STDERR "$Program: Password repeat count must be positive and less than 4097.\n";
$Error = 1;
};
$CryptMode == 0 and $CryptMode = 1;
$PasswordRepeat = $RepeatPass;
};
#
# If crypt mode is set to `password generation will be done, not yet known if
# encryption will be done,' fill in the blanks. If crypt mode is not yet set,
# it's going to be `password generation will be done, encryption will not.'
#
$CryptMode == 1 and do
{
$CryptMode += ($Crypt + 1);
};
$CryptMode == 0 and do
{
$CryptMode = 2;
};
#
# If a cryptographic seed value was specified, process it.
#
$CryptSalt ne "" and do
{
#
# If --crypt wasn't specified, signal the error.
#
$Crypt or do
{
print STDERR "$Program: Option --cryptsalt may not be ".
"specified without option --crypt.\n";
$Error = 1;
};
#
# Make sure the seed value is between 0 and 4095, inclusive.
#
($CryptSalt > -1 and $CryptSalt <= 4096) or do
{
print STDERR "$Program: Crypt() seed value must be zero thru 4096\n";
$Error = 1;
};
#
# If so, save the value.
#
$SeedValue = $CryptSalt;
};
#
# If we're not in a password generation mode and --cryptsalt was set to a
# nonzero value, then we shouldn't have any randomization options. If we
# do in that case, signal error and quit.
#
$CryptMode == 4 and $SeedValue and do
{
$Randomize = 0;
($RandomSeed ne "" or $Rerandom ne "") and do
{
print STDERR "$Program: Options --randomseed and --rerandom may not be ".
"specified unless password generation or random seed encryption ".
"is performed.\n";
$Error = 1;
};
};
#
# If a random number seed was specified, check for a valid number and process it.
#
$RandomSeed ne "" and do
{
($RandomSeed > -1 and $RandomSeed <= 2^32) or do
{
print STDERR "$Program: Random number seed must be zero thru 2^32\n";
$Error = 1;
};
$RandSeed = $RandomSeed;
};
#
# If a rerandomize character count was specified, check for a non-negative
# number and process it.
#
$Rerandom ne "" and do
{
($ReRandom > -1) or do
{
print STDERR "$Program: Rerandomize parameter must be zero or positive\n";
$Error = 1;
};
$RerandomCount = $Rerandom;
$RerandomCount or $RerandomCount--;
};
#
# If --help was specified, display the message and terminate with the exit
# code in $Error, which will be nonzero if a syntax error occurred.
#
$ShowHelp and do
{
$Error and print STDERR "\n";
Help();
exit $Error;
};
#
# If an error occurred, display help message on STDERR and quit with the
# exit code in $Error.
#
$Error and do
{
$Error and
print STDERR "$Program: For more information, type: $Program --help\n";
exit $Error;
};
#
# If verbose mode was selected, display the output header.
#
$PassLabel = $CryptLabel = "";
$Verbose and print "
$Program v$Version (c) $Copyright by $Author,
last modified $Date
All rights reserved by the author, licensed under GPL version 2.
";
#
# Process the number of passwords specified. Terminate normally.
#
for ($ctr=0; $ctr < $CountUsed; $ctr++)
{
ProcessPassword();
}
exit(0);
#
# sub Help: Display help information on STDERR.
#
sub Help
{
print STDERR
"$Program v$Version, a utility to generate and/or encrypt passwords.
Copyright (c) $Copyright by $Author. All rights are reserved by
the author. This program may be used under the terms of version 2 of the
GNU Public License.
Last modified on $Date.
Format: $Program [option...]
Options are:
--chars=N Generate passwords with exactly N characters (do not use with
options --minchars and --maxchars).
--clearfrom=FILE Use a clear password from FILE instead of generating passwords.
Requires the --crypt or --crypt-md5 option; may not be
used with options --chars, --maxchars, --minchars,
--count, --string, --nocrypt. Trailing newlines are
ignored, other whitespace is not.
--count=N Produce a total of N passwords (the default is one).
--crypt Produce encrypted passwords.
--crypt-md5 Produce encrypted passwords using the MD5 digest (hash)
algorithm.
--cryptsalt=N Use crypt() salt N, a positive number <= 4096. If random
seeds are desired, specify a zero value (the default).
--help Ignore other operands and produce only this help display.
--maxchars=N Generate passwords with at most N characters (default=10).
--minchars=N Generate passwords with at least N characters (default=8).
--nocrypt Do not encrypt the generated password(s) (the default).
--noverbose Display no labels on output (the default).
--randomseed=N Use random number seed N, between 0 and 2^32 inclusive. A zero
value results in a real-random seed. This option
generates predictable passwords, and should normally
be avoided.
--rerandom=N Set the random seed value every N values used. Specify zero
to use a single seed value (the default). Specify
one to get true-random passwords, but plan on hitting
the CONTROL key a lot while it's running. ;)
--repeatpass=N Use each password N times (4096 maximum, --crypt or
--crypt-md5 must be set and --cryptsalt may not be set).
--string=STRING Use the characters in STRING to generate random passwords.
--verbose Display labelling information on output.
";
}
#
# sub NumBits(N): Number of significant bits in N.
#
sub NumBits
{
return length(sprintf('%b', $_[0]));
}
#
# sub Random(A, B): Produce a random integer from A to B, inclusive.
#
sub Random
{
$RerandomNow--;
$RerandomNow == 0 and do
{
SeedRandom();
$RerandomNow = $RerandomCount;
};
$RerandomCount == -1 and do
{
$RerandomNow = $RerandomCount;
};
my $RandomOutputVal;
if ($RandSeed)
{
$RandomOutputVal = rand($_[1]-$_[0]+1);
}
else
{
# Annoyingly, there's no Perl binding for
# BN_pseudo_rand_range, so we have to emulate it. We
# repeatedly generate n-bit pseudo-random byte sequences
# (with n = number of significant bits in range) until we
# get something less than range.
my $range = $_[1]-$_[0]+1;
my $bits = NumBits($range);
my $bytes = ($bits - 1) / 8 + 1;
my $max = 1 << ($bytes * 8);
$max -= $max % $range;
while (1)
{
my $buf = Crypt::OpenSSL::Random::random_pseudo_bytes($bytes);
my $val = 0;
for my $byte (unpack('C*', $buf))
{
$val = ($val << 8) + $byte;
}
if ($val < $max)
{
# Using the modulus is OK here; we're
# working with a byte stream, so the
# low-order bits are no worse than any of
# the others.
$RandomOutputVal = $val % $range;
last;
}
}
}
$RandomOutputVal=$RandomOutputVal+$_[0];
$RandomOutputVal =~ s/\..*$//;
$RandomOutputVal;
}
#
# sub SeedRandom: Seed the random number function.
#
sub SeedRandom
{
my $i;
my $SeedOutput = $RandSeed;
if ($SeedOutput)
{
srand $SeedOutput;
}
else
{
open(RANDOMSEED, "<:unix", "/dev/urandom") or die "Could not access a seed value.\n";
$SeedOutput='';
my $i=0;
while ($i < 32)
{
my $r = read(RANDOMSEED, $SeedOutput, 32 - $i, $i);
die "read /dev/urandom failed: $!\n" unless defined $r;
$i += $r;
}
close(RANDOMSEED);
Crypt::OpenSSL::Random::random_seed($SeedOutput);
Crypt::OpenSSL::Random::random_status() or die "OpenSSL PRNG could not be sufficiently seeded.\n";
};
}
#
# sub MakePassword(A, B): Generate a password from A to B bytes in length.
#
sub MakePassword
{
my $i;
my $Password;
if ($Clear)
{
$Password = $Clear;
}
else
{
my $Total = Random($CharMin, $CharMax);
$Password = "";
for (my $i=0; $i < $Total; $i++)
{
$Password .= substr($StringUsed, Random(0, $ValString), 1);
}
}
$Password;
}
#
# sub MakeSalt(A): Generate a crypt salt string from a number from 0 through 4095.
#
sub MakeSalt
{
my $i = $_[0] >> 6;
my $j = $_[0] % 64;
my $SaltOut = substr($SaltList, $i, 1).substr($SaltList, $j, 1);
$SaltOut;
}
#
# sub CryptPassword(A, B): Encrypt the password provided; keep a running
# list of codes used as long as B is true.
#
sub CryptPassword
{
my $ThisSeed = $SeedValue;
if ($ThisSeed)
{
$ThisSeed--;
}
else
{
$_[1] or do
{
%UsedSeed = ();
};
$ThisSeed = Random(0, 4095);
do
{
$ThisSeed = Random(0, 4095);
}
until not exists $UsedSeed{$ThisSeed};
$UsedSeed{$ThisSeed} = $ThisSeed;
}
crypt($_[0], MakeSalt($ThisSeed));
}
#
# sub Md5Base64Char(A): Base-64-encode a character from an MD5 digest.
#
sub Md5Base64Char
{
my $map64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
my $char = shift;
$char = 0 if $char < 0;
$char = 63 if $char > 63;
substr($map64, $char, 1);
}
#
# sub MakeMd5Salt(A, B): Generate a crypt salt string from a number from 0
# through 4095.
#
sub MakeMd5Salt
{
my $md5 = Digest::MD5->new();
$md5->add(time);
$md5->add($$);
$md5->add($_[0]);
$md5->add($_[1]);
my $digest = $md5->digest;
$digest = substr($digest, 0, 8);
my $salt;
for my $char (map { ord($_) & 077 } split //, $digest)
{
$salt .= Md5Base64Char($char);
}
$salt;
}
#
# sub CryptMd5Password(A, B): Encrypt the password provided using the
# MD5 digest algorithm; keep a running list of codes used as long as B is
# true.
#
sub CryptMd5Password
{
my $password = $_[0];
eval "use Crypt::PasswdMD5";
if ($@)
{
print STDERR "$Program: Could not load the Crypt::PasswdMD5 library, cannot use --crypt-md5\n".
"This may be due to an invalid or incomplete Perl installation\n.";
exit 1;
};
my $ThisSeed = $SeedValue;
if ($ThisSeed)
{
$ThisSeed--;
}
else
{
$_[1] or do
{
%UsedSeed = ();
};
$ThisSeed = Random(0, 4095);
do
{
$ThisSeed = Random(0, 4095);
}
until not exists $UsedSeed{$ThisSeed};
$UsedSeed{$ThisSeed} = $ThisSeed;
}
my $salt = MakeMd5Salt($password, $ThisSeed);
unix_md5_crypt($password, $salt);
}
#
# sub ProcessPassword(A): Process the password provided.
#
sub ProcessPassword
{
my $i;
my $Password = "";
my $CryptedPass = "";
my $PaddedPass = "";
$Password = MakePassword();
$Crypt and $PaddedPass = sprintf "%-$CharFormat"."s", $Password;
$CryptMd5 and $PaddedPass = sprintf "%-$CharFormat"."s", $Password;
$Verbose and do
{
$PassLabel="Password=";
$CryptLabel="Encrypted String=";
$EmptyPassword=sprintf "%-$CharFormat"."s", "";
$ctr and $Verbose and print "\n";
};
for ($i = 0; $i < $PasswordRepeat; $i++)
{
if ($Crypt)
{
$CryptedPass = CryptPassword($Password, $i);
print "$PassLabel"."$PaddedPass"."$CryptLabel"."$CryptedPass\n";
$Verbose and $PaddedPass = $EmptyPassword;
}
elsif ($CryptMd5)
{
$CryptedPass = CryptMd5Password($Password);
print "$PassLabel"."$PaddedPass"."$CryptLabel"."$CryptedPass\n";
$Verbose and $PaddedPass = $EmptyPassword;
}
else
{
print "$PassLabel"."$Password\n";
}
$Verbose and do
{
$PassLabel=" ";
$CryptLabel=" ";
};
}
}
Zerion Mini Shell 1.0