#!/usr/bin/perl use strict; use warnings; use MIME::Base64; use Digest::SHA1 qw(sha1); # echo "our \$secret = decode_base64('"`dd 2>/dev/null if=/dev/random bs=20 count=1 | base64`"');" # Keep your secret somewhere else, not in your config file with the password. # Perhaps in another config file! or only in memory. our $secret = decode_base64('nVTgNfKcP+SbcgetHdux+o8SeGI='); # With this system it's important not to use the same salt for two different # passwords, that could reveal part of the secret. sub encode_password { my ($passwd, $salt) = @_; if (length($passwd) > 20) { die "encode_password: sorry, max passwd length is 20"; } if ($passwd =~ /\0/) { die "encode_password: sorry, passwd may not contain \\0"; } if ($salt =~ /\0/) { die "encode_password: sorry, salt may not contain \\0"; } my $salted_secret = sha1("$salt$secret"); my $encoded_passwd = "$passwd\0" ^ $salted_secret; my $salt_encoded_passwd = encode_base64("$salt\0$encoded_passwd"); chomp $salt_encoded_passwd; return $salt_encoded_passwd; } sub decode_password { my ($salt_encoded_passwd) = @_; my ($salt, $encoded_passwd) = split /\0/, decode_base64($salt_encoded_passwd), 2; my $salted_secret = sha1("$salt$secret"); my ($passwd) = split /\0/, ($encoded_passwd ^ $salted_secret); return $passwd; } my $passwd = 'broccoli'; my $salt = encode_base64(sha1(time.".".rand)); my $enc = encode_password($passwd, $salt); my $decoded = decode_password($enc); print "password $passwd was encoded as $enc\n\n"; print "$enc decoded to $decoded\n\n"; if ($decoded ne $passwd) { die "bork! it doesn't work"; }