--- /dev/null
+#!/usr/bin/perl -w
+use strict;
+use Getopt::Long qw(:config no_ignore_case);
+use Pod::Usage;
+use Crypt::PBKDF2;
+use Time::HiRes;
+use Math::Random::Secure qw(irand);
+
+my %opts;
+GetOptions(\%opts,
+ qw[ help|?! man! a|algorithm=s i|iterations=i l|len=i s|salt=s S|Salt=s t|time! z|saltlen=i ]
+) or pod2usage(2);
+pod2usage(1) if $opts{help};
+pod2usage(-verbose => 2) if $opts{man};
+
+my $algo = 'HMACSHA2';
+if (exists $opts{a}) {
+ my %algorithm = ('1' => 'HMACSHA1', 'sha1' => 'HMACSHA1',
+ '2' => 'HMACSHA2', 'sha2' => 'HMACSHA2',
+ '3' => 'HMACSHA3', 'sha3' => 'HMACSHA3');
+ $algo = $algorithm{$opts{a}};
+ if (!defined $algo) {
+ print "Bad algorithm\n";
+ exit(1);
+ }
+}
+
+my $iter;
+my %hargs;
+my $ssiz;
+if ($algo eq 'HMACSHA1') {
+ $iter = 1000;
+ %hargs = ( output_len => 20 );
+ $ssiz = 8;
+} elsif ($algo eq 'HMACSHA2' or $algo eq 'HMACSHA3') {
+ $iter = 10000;
+ my $len = 256;
+ if (exists $opts{l}) {
+ my @length = (224, 256, 384, 512);
+ if (grep {$_ eq $opts{l}} @length) {
+ $len = $opts{l};
+ } else {
+ print "Bad length\n";
+ exit(1);
+ }
+ }
+ %hargs = ( hash_args => {
+ sha_size => $len,
+ } );
+ $ssiz = 16;
+}
+
+if (exists $opts{i}) {
+ $iter = $opts{i};
+ if ($iter < 1 || $iter > 0xffffffff) {
+ print "Bad iterations\n";
+ exit(1);
+ }
+}
+
+my $password = $ARGV[0];
+if (!defined $password) {
+ print "Missing password\n";
+ exit(1);
+}
+
+my $salt = $opts{s};
+if (exists $opts{S}) {
+ if (defined $salt) {
+ print "Redundant salt\n";
+ exit(1);
+ }
+ $salt = pack('H*', $opts{S});
+}
+if (!defined $salt) {
+ $ssiz = $opts{z} if (exists $opts{z});
+ if ($ssiz < 0) {
+ print "Bad salt length\n";
+ exit(1);
+ }
+ while ($ssiz >= 4) {
+ $salt .= pack('N', irand());
+ $ssiz -= 4;
+ }
+ $salt .= substr(pack('N', irand()), 1, $ssiz) if ($ssiz > 0);
+}
+
+my $pbkdf2;
+$pbkdf2 = Crypt::PBKDF2->new(
+ hash_class => $algo,
+ %hargs,
+ iterations => $iter,
+ salt_len => $ssiz, # Seems to use non-cryptographic rand
+);
+
+my $t0 = [Time::HiRes::gettimeofday];
+my $hash = $pbkdf2->generate($password, $salt);
+my $t1 = Time::HiRes::tv_interval($t0);
+print substr($hash, 10)."\n";
+print "Time:".$t1."\n" if (exists $opts{t});
+
+__END__
+
+=head1 NAME
+
+Pbkdf2Passwd - Generate a PBKDF2 hashed password
+
+=head1 DESCRIPTION
+
+Generate a Password Based Key Derivation Functiong version 2 using given
+password, a hashing algorithm, the number of iterations, and optional salt.
+
+=head1 SYNOPSIS
+
+ Pbkdf2Passwd [options] <password>
+
+=head1 OPTIONS
+
+=over
+
+=item B<-a> or B<-algorithm> <algorithm>
+
+Format options:
+
+=over
+
+=item B<1> or B<sha1> : SHA-1
+
+=item B<2> or B<sha2> : SHA-2 (default)
+
+=item B<3> or B<sha3> : SHA-3
+
+=back
+
+=item B<-i> or B<-iterations> <count>
+
+Count of algorithm iterations (1 to 4294967295 | SHA-1 default: 1000,
+SHA-2 / SHA-3 default: 10000).
+
+=item B<-l> or B<-length> <length>
+
+For SHA-2 / SHA-3 algorithm bit length (224, 256, 384, or 512 | default: 256).
+
+=item B<-s> or B<-salt> <string>
+
+=item B<-S> or B<-Salt> <hexadecimal string>
+
+Salt string appended to password and hashed.
+
+=item B<-z> or B<-saltlen> <length>
+
+Byte length of random salt appended to password and hashed, if no salt string
+is explicitly given (SHA-1 default:8, SHA-2 / SHA-3 default: 16).
+
+=item B<-t> or B<-time>
+
+Approximate time to generate password (in seconds).
+
+=item B<-?> or B<-help>
+
+Print a brief help message.
+
+=item B<-man>
+
+Print the manual page.
+
+=back
+=cut
ATTRIBUTE SSHA2-256-Password 1181 octets
ATTRIBUTE SSHA2-384-Password 1182 octets
ATTRIBUTE SSHA2-512-Password 1183 octets
+ATTRIBUTE PBKDF2-Password 1184 octets
ATTRIBUTE Exec-Export 1190 string
{ "{ssha256}", FR_SSHA2_256_PASSWORD },
{ "{ssha384}", FR_SSHA2_384_PASSWORD },
{ "{ssha512}", FR_SSHA2_512_PASSWORD },
+ { "{x-pbkdf2}", FR_PBKDF2_PASSWORD },
#endif
{ "{sha}", FR_SHA_PASSWORD },
{ "{ssha}", FR_SSHA_PASSWORD },
{ NULL, 0 }
};
+#ifdef HAVE_OPENSSL_EVP_H
+static const FR_NAME_NUMBER pbkdf2_names[] = {
+ { "HMACSHA1", FR_SSHA_PASSWORD },
+ { "HMACSHA2+224", FR_SSHA2_224_PASSWORD },
+ { "HMACSHA2+256", FR_SSHA2_256_PASSWORD },
+ { "HMACSHA2+384", FR_SSHA2_384_PASSWORD },
+ { "HMACSHA2+512", FR_SSHA2_512_PASSWORD },
+ { NULL, 0 }
+};
+#endif
+
static int mod_instantiate(void *instance, CONF_SECTION *conf)
{
rlm_pap_t *inst = instance;
}
found_pw = true;
break;
+
+ case FR_PBKDF2_PASSWORD:
+ found_pw = true; /* Already base64 standardized */
+ break;
#endif
case FR_SHA_PASSWORD:
return RLM_MODULE_OK;
}
+
+#define B64_DIM(siz) FR_BASE64_DEC_LENGTH(FR_BASE64_ENC_LENGTH(siz))
+
+static inline rlm_rcode_t CC_HINT(nonnull) pap_auth_pbkdf2_ldap(REQUEST *request, const uint8_t *str, size_t len)
+{
+ rlm_rcode_t rcode = RLM_MODULE_INVALID;
+
+ uint8_t const *p, *q, *end;
+ ssize_t slen;
+
+ EVP_MD const *evp_md;
+ int digest_type;
+ size_t digest_len;
+
+ uint32_t iterations;
+
+ uint8_t *salt = NULL;
+ size_t salt_len;
+ uint8_t hash[EVP_MAX_MD_SIZE];
+ uint8_t digest[EVP_MAX_MD_SIZE];
+
+ RDEBUG("Comparing with \"known-good\" PBKDF2-Password (ldap format)");
+
+ /*
+ * Parse PBKDF string = {hash_algorithm}:base64(interations):base64(salt):base64(hash)
+ */
+ p = str;
+ end = p + len;
+
+ q = memchr(p, ':', end - p);
+ if (!q) {
+ REDEBUG("PBKDF2-Password has no component separators");
+ goto finish;
+ }
+
+ digest_type = fr_substr2int(pbkdf2_names, (char const *)p, -1, q - p);
+ switch (digest_type) {
+ case FR_SSHA_PASSWORD:
+ evp_md = EVP_sha1();
+ digest_len = 20;
+ break;
+
+ case FR_SSHA2_224_PASSWORD:
+ evp_md = EVP_sha224();
+ digest_len = 28;
+ break;
+
+ case FR_SSHA2_256_PASSWORD:
+ evp_md = EVP_sha256();
+ digest_len = 32;
+ break;
+
+ case FR_SSHA2_384_PASSWORD:
+ evp_md = EVP_sha384();
+ digest_len = 48;
+ break;
+
+ case FR_SSHA2_512_PASSWORD:
+ evp_md = EVP_sha512();
+ digest_len = 64;
+ break;
+
+ default:
+ REDEBUG("Unknown PBKDF2 hash method \"%.*s\"", (int)(q - p), p);
+ goto finish;
+ }
+
+ p = q + 1;
+
+ if (((end - p) < 1) || !(q = memchr(p, ':', end - p))) {
+ REDEBUG("PBKDF2-Password missing iterations component");
+ goto finish;
+ }
+
+ if ((q - p) == 0) {
+ REDEBUG("PBKDF2-Password iterations component too short");
+ goto finish;
+ }
+
+ (void)fr_strerror();
+ slen = fr_base64_decode((uint8_t *)&iterations, sizeof(iterations), (char const *)p, q - p);
+ if (slen < 0) {
+ REDEBUG("Failed decoding PBKDF2-Password iterations component (%.*s): %s", (int)(q - p), p,
+ fr_strerror());
+ goto finish;
+ }
+ if (slen != sizeof(iterations)) {
+ REDEBUG("Decoded PBKDF2-Password iterations component is wrong size");
+ }
+
+ iterations = ntohl(iterations);
+
+ p = q + 1;
+
+ if (((end - p) < 1) || !(q = memchr(p, ':', end - p))) {
+ REDEBUG("PBKDF2-Password missing salt component");
+ goto finish;
+ }
+
+ if ((q - p) == 0) {
+ REDEBUG("PBKDF2-Password salt component too short");
+ goto finish;
+ }
+
+ MEM(salt = talloc_array(request, uint8_t, FR_BASE64_DEC_LENGTH(q - p)));
+ slen = fr_base64_decode(salt, talloc_array_length(salt), (char const *) p, q - p);
+ if (slen < 0) {
+ REDEBUG("Failed decoding PBKDF2-Password salt component: %s", fr_strerror());
+ goto finish;
+ }
+ salt_len = (size_t)slen;
+
+ p = q + 1;
+
+ if ((q - p) == 0) {
+ REDEBUG("PBKDF2-Password hash component too short");
+ goto finish;
+ }
+
+ slen = fr_base64_decode(hash, sizeof(hash), (char const *)p, end - p);
+ if (slen < 0) {
+ REDEBUG("Failed decoding PBKDF2-Password hash component: %s", fr_strerror());
+ goto finish;
+ }
+
+ if ((size_t)slen != digest_len) {
+ REDEBUG("PBKDF2-Password hash component length is incorrect for hash type, expected %zu, got %zd",
+ digest_len, slen);
+
+ RHEXDUMP(L_DBG_LVL_2, hash, slen, "hash component");
+
+ goto finish;
+ }
+
+ RDEBUG2("PBKDF2 %s: Iterations %u, salt length %zu, hash length %zd",
+ fr_int2str(pbkdf2_names, digest_type, "<UNKNOWN>"),
+ iterations, salt_len, slen);
+
+ /*
+ * Hash and compare
+ */
+ if (PKCS5_PBKDF2_HMAC((char const *)request->password->vp_octets, (int)request->password->vp_length,
+ (unsigned char const *)salt, (int)salt_len,
+ (int)iterations,
+ evp_md,
+ (int)digest_len, (unsigned char *)digest) == 0) {
+ REDEBUG("PBKDF2 digest failure");
+ goto finish;
+ }
+
+ if (fr_digest_cmp(digest, hash, (size_t)digest_len) != 0) {
+ REDEBUG("PBKDF2 digest does not match \"known good\" digest");
+ rcode = RLM_MODULE_REJECT;
+ RHEXDUMP(L_DBG_LVL_3, salt, salt_len, "salt");
+ RHEXDUMP(L_DBG_LVL_3, hash, slen, "\"known good\" digest");
+ RHEXDUMP(L_DBG_LVL_3, digest, digest_len, "computed digest");
+ } else {
+ rcode = RLM_MODULE_OK;
+ }
+
+finish:
+ talloc_free(salt);
+
+ return rcode;
+}
+
+static inline rlm_rcode_t CC_HINT(nonnull) pap_auth_pbkdf2(UNUSED rlm_pap_t const *inst,
+ REQUEST *request, VALUE_PAIR *vp)
+{
+ if (vp->vp_length < 2) {
+ REDEBUG("PBKDF2-Password too short");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (vp->vp_octets[0] == '$') {
+ ERROR("Crypt PBKDF2 is currently unsupported");
+ return RLM_MODULE_FAIL;
+ } else {
+ return pap_auth_pbkdf2_ldap(request, vp->vp_octets, vp->vp_length);
+ }
+
+ REDEBUG("Can't determine format of PBKDF2-Password");
+ return RLM_MODULE_INVALID;
+}
#endif
static rlm_rcode_t CC_HINT(nonnull) pap_auth_nt(rlm_pap_t const *inst, REQUEST *request, VALUE_PAIR *vp)
case FR_SSHA2_512_PASSWORD:
auth_func = &pap_auth_ssha2;
break;
+
+ case FR_PBKDF2_PASSWORD:
+ auth_func = &pap_auth_pbkdf2;
+ break;
#endif
case FR_SHA_PASSWORD:
--- /dev/null
+#
+# Test the "pap" module
+#
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_dig_big'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
--- /dev/null
+if (&User-Name == 'pbkdf2_dig_big') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_dig_small'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
--- /dev/null
+if (&User-Name == 'pbkdf2_dig_small') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI'
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter0'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
--- /dev/null
+if (&User-Name == 'pbkdf2_iter0') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAAAP:CuNDJ9NimZoP5ljnPNCBUA==:f09zV7dReGg5SIv/EXY9tCL4XQRr5guhL0Q6UXSKI3c='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter1'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
--- /dev/null
+if (&User-Name == 'pbkdf2_iter1') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:OErtptMl2hOxhQqvNw7sNw==:4KkrgL+3Q9j8KlHPivtApBKRZAjyWjtDWmZEz2UjNko='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter1000'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
--- /dev/null
+if (&User-Name == 'pbkdf2_iter1000') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAD6A:yhmqoKrtPLY2KYK6cNjnfw==:Y6gkSZEo4TRtlsryHqnGYZhoe2qn5tJ4IUyyVHb/3WU='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter100000'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_iter100000') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AA9CQA:fCfnJGMVC1QLtTOPiaSICA==:KCmjMpQ+lokMvyFTl4f4pPJNc0xJq4iHZPdtHa0OEXM='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter_big'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
--- /dev/null
+if (&User-Name == 'pbkdf2_iter_big') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAAAQ==:E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter_miss'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
--- /dev/null
+if (&User-Name == 'pbkdf2_iter_miss') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256::E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate {
+ invalid = 1
+ }
+ if (invalid) {
+ test_pass
+ } else {
+ test_fail
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter_small'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
--- /dev/null
+if (&User-Name == 'pbkdf2_iter_small') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAAA:E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate {
+ invalid = 1
+ }
+ if (invalid) {
+ test_pass
+ } else {
+ test_fail
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt0'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_salt0') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAnEA::4RJEKVFQ5nE8126aURI0cJO9tqy/DIAhq64piBEwshA='
+ }
+ pap.authorize
+ pap.authenticate {
+ invalid = 1
+ }
+ if (invalid) {
+ test_pass
+ } else {
+ test_fail
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt1'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_salt1') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAnEA:qg==:KQzCdedgOZYFwx+mQp1TKA8VM4fwf02pqSdJEh2ekwM='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt1024'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_salt1024') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAnEA:/IUrkJKe+1kzJNBw7aAMbnQuSFZpjbCqPeKso3cbuSUzWinxngxjK8yyZLiWwF+WE/0Gplfx25zZEQNTdRTvjZZNefoxQBR8Hht0FpdU9YiEBaeErwVo63EDEu83+ycvB18uH0IXpJKGSSkIPRfGpHT3BkwJDGo5SqjRJadDsyQzkc/WJCMrrfJ0igaWMxb5eR5J8qfXIjBFepRrOOU6acZGtANW8qvDYLJwN+TMd9Jb1wDDY14eoAlKglTF21S3kewNMkDDyeP+oDYv29t1S/soFUnnB+Pb5IdR6pDy2VDGx4jFZMQGshSHWTYQFqgulavS/tGEF8TvzcorrJZKuksAjKdTSmfZ6j4aBY3U+oMSQ+2lO131pkNfNQuMsDfr72r9wUA2xRgUiL/J7CgKn7mamL2OCaksl0Rw2PGqqIaHvAYS6Q1EoIzsmLNrWBYYqTRLyCGZw6+hUOahYRon2lglGmnuWHPfowU+LgcaR5gF1QjvTXhXQ8I39mB3ePgdi+7TUn644Z1FB+JTqGJbue92x4V40Zyyy+Qdt52QsR49iYokbKAwQRiqfVJ7J8NzCY/kIQnqT9RE0NCxZoMBRzboZxVPchxdpmWGQ9dXP06PqIuDCFFiJlVQUfyPMgOAxIlVJ/9NAmj5MWFdWMrmlBNDx9ihEV1FdTv23iFZH5Ejg+x4D3qN5oOyCDL2i9lobzFXh5z4EDpbbogQaFkUzqKEaxRGPBrfYVOi6XXYujVUnxHJaRxbs2UqjpJNsXMg8f7P78aRvOKCIbW70CHWlt7nF0pA5+kFUQRLXKuq7bW+ivoXKeDW5o4FVP3+Pcr67+DOsUXuehALLj9Mu2ICWlMIV/AWcM2szaqk1bwSo7bAeG4RtDKmNjGA7gpnT+w2x+/qS1eWbc832Sumqc1IA8aY6HNVDPsJZf99To4BR+N0rCoQQ/KIZybI31mQagR3+FR9yNzqWzKIl+qf69RTc1CbUCkKVF8pxWZ0ocP+CAdoKadgpdF8evQIiGcUD73HiJ0RsDWo21y0tN0P5jfzWo3WMhCk9e2wl6o1JAfKw54uHzWJnNlGLBK1LXF+R2m+WvNGBgvUhh4PtYV9gPSudumFdk614oak/Aqcn6xi+YZqOMPkW4WYaiczhHyS7qAyefqKaQkRVYS0Af+79CSjlxZJq57HrD7/1E+d/i0gKmSAbPe80uGHs2a13V3VxztFMBi4xD7zj9Mq7+0goVPD4MNXcR651MZ7vxDRGbvPPmclddZe/nkTEn1YB/909b9mC5P/XzximZYW8gEhBReZouukADRTAjuH8zgSIv6/uyTURnmSVoOumVLBpL7veJIzDm4dZ38BWiasiBnzgMuG9A==:RUoCF5O11OgwLFMTqnKY/yRJy6DYh+yNq4xHZC7COGM='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt64'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_salt64') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAnEA:msGxE1XuC+wlgRr+H4+ioyxZuiN3KYLUSky2FINDTq7KJylKt4XnqloV+FuHGXUbOu1EWcsFp51u2z8wdXVnQQ==:rAV9BeEJH5kt9uZ6pJt0o5pYpN5LQRe4MAYyk2jvjpU='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt_big'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_salt_big') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:E+VXOSsE8RwyYGdygQoW9QA==:pF23EcxNBhJLQ+9JRtd9wQ1Gz+k4i6YjeNZq+7DRBX8='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt_small'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_salt_small') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:E+VXOSsE8RwyYGdygQoW9Q=:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha1'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_sha1') {
+ update control {
+ PBKDF2-Password := 'HMACSHA1:AAAD6A:Xw1P133xrwk=:dtQBXQRiR/No5A8Ip3JFGF/qUC0='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha2_224'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_sha2_224') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+224:AAAnEA:UHScBrg/ZWOyBKqQdAh7bw==:tcFp6CDrkIYdhwa60g24U4ko+mBxzAiFxlpPnA=='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha2_256'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_sha2_256') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+256:AAAnEA:a/8HbYW2HWsMthN27JI+Ew==:3nPlXYOlOuDCFOfethUomHxTXkG9JCivOdvh6FDNdGw='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha2_384'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_sha2_384') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+384:AAAnEA:pyHRsYLfNZdjszRcu6eHrA==:ktGfNmZ6PyD8FNEgPzFK1fypKERZ13pgvFl+PQdyKouaMXsXIiWPuTMXHqDUCWsx'
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
--- /dev/null
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha2_512'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
--- /dev/null
+if (&User-Name == 'pbkdf2_sha2_512') {
+ update control {
+ PBKDF2-Password := 'HMACSHA2+512:AAAnEA:TG8Mb94NEmfPLaePwi5CFA==:SYSFeRf9jr4Uo5DB4NvNUEuc1gmEiLjTac5J4WgyKa7mO58KHKWop9xWmcFeuLtUN/iexLTNSgcubOugAyZcog=='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}