I've had this question a lot recently and there don't seem to be any Perl examples
easily found online, so here we go: A lot of people have been asking how to generate
the salt, server key and the stored key for the Salted Challenge Response Authentication
Mechanism or SCRAM in Perl. The actual formula for generating the salted password is
fairly simple: PBKDF2 ( HMAC, p, s, i ) where p is the cleartext password encoded as a
UTF8 string, s is the salt and i is the number of times to apply the HMAC function to
the given password using the given salt. This will give us a derived key that will be
used to compute the server key and the stored key, two of the essentials that will be
used as proofs that both client and server have the same authentication variable.
Required Perl modules:
Encode
MIME::Base64
Bytes::Random::Secure
PBKDF2::Tiny
Digest::SHA1
Digest::HMAC_SHA1
Authen::SASL::SASLprep
#!/usr/bin/perl
################################################################################
# #
# scram_gen #
# #
# Fraser Gutteridge, blue@udel.edu 2018-09-12 #
# University of Delaware IT-NSS Systems Group #
# #
# Example Perl implementation of SCRAM. #
# #
################################################################################
use strict;
use warnings;
use Encode qw ( encode_utf8 );
use MIME::Base64 qw ( encode_base64 );
use Bytes::Random::Secure qw ( random_bytes );
use PBKDF2::Tiny qw ( derive );
use Digest::SHA1 qw ( sha1 );
use Digest::HMAC_SHA1 qw ( hmac_sha1 );
use Authen::SASL::SASLprep;
# the pseudorandom cryptographic hash function that will be used in our
# PBKDF2 to derive our key
my $hmac = "SHA-256";
# number of times to apply the pseudorandom function to our password string
# using the given salt; 4096 iterations was recommended by Kerberos in 2005,
# increase as necessary (as an example in 2011 LastPass was using *100000*
# iterations for server-side hashing!) as long as the number is a big endian
# 32-bit integer
my $rounds = 4096;
# generate some random bytes for our salt - using 16 bytes here, but it can
# of course be larger
my $salt = random_bytes ( 16 );
# a cleartext test password
my $pw = "test123";
# derive our hashed password using PBKDF2
my $pw_hash = derive ( $hmac, encode_utf8 ( $pw ), $salt, $rounds );
# generate our proofs
my $server_key = hmac_sha1 ( "Server Key", $pw_hash );
my $client_key = hmac_sha1 ( "Client Key", $pw_hash );
my $stored_key = sha1 ( $client_key );
# save them in base64 for storage in a database, for example
$salt = encode_base64 ( $salt );
$server_key = encode_base64 ( $server_key );
$stored_key = encode_base64 ( $stored_key );
chomp ( $salt );
chomp ( $server_key );
chomp ( $stored_key );
print "SALT: $salt\nSERVER KEY: $server_key\nSTORED KEY: $stored_key\n";
exit;
|
|
|