unixpass
Version:
Native implementation of Unix compatible DES/MD5/SHA256/SHA512 password hashing.
178 lines (171 loc) • 6.76 kB
JavaScript
'use strict';
const up = require('../unixpass.js');
const crypto = require('crypto');
const test = function() {
const t = [
// The following test vectors are from reference implementation.
{ p: "Hello world!",
s: "$1$saltstring",
r: "$1$saltstri$YMyguxXMBpd2TEZ.vS/3q1" },
{ p: "Hello world!",
s: "$5$saltstring",
r: "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5" },
{ p: "Hello world!",
s: "$5$rounds=10000$saltstringsaltstring",
r: "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2.opqey6IcA" },
{ p: "This is just a test",
s: "$5$rounds=5000$toolongsaltstring",
r: "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8mGRcvxa5" },
{ p: "a very much longer text to encrypt. This one even stretches over morethan one line.",
s: "$5$rounds=1400$anotherlongsaltstring",
r: "$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12oP84Bnq1" },
{ p: "we have a short salt string but not a short password",
s: "$5$rounds=77777$short",
r: "$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/" },
{ p: "a short string",
s: "$5$rounds=123456$asaltof16chars..",
r: "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/cZKmF/wJvD" },
{ p: "the minimum number is still observed",
s: "$5$rounds=10$roundstoolow",
r: "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL972bIC" },
{ p: "Hello world!",
s: "$6$saltstring",
r: "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1" },
{ p: "Hello world!",
s: "$6$rounds=10000$saltstringsaltstring",
r: "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sbHbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." },
{ p: "This is just a test",
s: "$6$rounds=5000$toolongsaltstring",
r: "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQzQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0" },
{ p: "a very much longer text to encrypt. This one even stretches over morethan one line.",
s: "$6$rounds=1400$anotherlongsaltstring",
r: "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wPvMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1" },
{ p: "we have a short salt string but not a short password",
s: "$6$rounds=77777$short",
r: "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0gge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0" },
{ p: "a short string",
s: "$6$rounds=123456$asaltof16chars..",
r: "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1" },
{ p: "the minimum number is still observed",
s: "$6$rounds=10$roundstoolow",
r: "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1xhLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." },
// The rest are not official test vectors but are generated
// using GNU libc implementation, because there was only one
// test for MD5 based password hash.
{ p: "Hello world!",
s: "$1$toolongsaltistruncated",
r: "$1$toolongs$EVlrXgIzSyVBiscgwJ6jL0" },
{ p: "a very much longer text to encrypt. This one even stretches over morethan one line.",
s: "$1$anotherlongsaltstring",
r: "$1$anotherl$K6Vw1g4o5xCrk48TD5civ." },
// Ad-hoc tests for legacy DES password encryption created
// with glibc and verified to match with various other
// implementations.
{ p: 'foobar',
s: '..',
r: '..Tgnr41TuFZA' },
{ p: 'foobar',
s: 'Az',
r: 'Az/bPFC5oIitA' },
{ p: 'FooBar',
s: 'Az',
r: 'AzOxUVFhcFncc' },
{ p: '01234567',
s: 'zz',
r: 'zznQBYYSwOYps' },
{ p: '0123456789',
s: 'zz',
r: 'zznQBYYSwOYps' },
{ p: '%/,;.~"!',
s: 'zz',
r: 'zzKc2XDgEi/Yo' },
{ p: '%/,;.~"!',
s: 'h5',
r: 'h5nMUGD6YY9i.' },
{ p: '$$$$',
s: 'XX',
r: 'XXvI/jEG6AEWk' },
{ p: 'Kukkuu?',
s: 'tr',
r: 'trthmtW0sP6Ik' },
{ p: 'foobar',
s: '_N...Az..',
r: '_N...Az../bPFC5oIitA' },
{ p: 'foobar',
s: '_N...Az..',
r: '_N...Az../bPFC5oIitA' },
{ p: 'foobar',
s: '_N...Az..',
r: '_N...Az../bPFC5oIitA' },
{ p: 'foobar01234567890',
s: '_N...Az..',
r: '_N...Az../JG7CJ871dQ' },
{ p: 'foobar01234567890',
s: '_zZ9/Az..',
r: '_zZ9/Az..1dMpKVztK6Y' },
{ p: 'foobar01234567890',
s: '_zZ9/Az.0',
r: '_zZ9/Az.0Ka1310aiq6Q' },
{ p: 'FooBar01234567890',
s: '_zZ9/Az.0',
r: '_zZ9/Az.0Bp65KHBw6Ys' },
{ p: 'FooBar01234567890€',
s: '_zZ9/Az.0',
r: '_zZ9/Az.0qd4iljFxBa6' },
// Following "rasmus" password tests have been picked
// up from PHP manual page for crypt
// (https://www.php.net/manual/en/function.crypt.php)
{ p: 'rasmuslerdorf',
s: 'rl',
r: 'rl.3StKT.4T8M' },
{ p: 'rasmuslerdorf',
s: '_J9..rasm',
r: '_J9..rasmBYk8r9AiWNc' },
{ p: 'rasmuslerdorf',
s: '$1$rasmusle$',
r: '$1$rasmusle$rISCgZzpwk3UhDidwXvin0' },
{ p: 'rasmuslerdorf',
s: '$2a$07$usesomesillystringforsalt$',
r: '$2a$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi' },
{ p: 'rasmuslerdorf',
s: '$5$rounds=5000$usesomesillystringforsalt$',
r: '$5$rounds=5000$usesomesillystri$KqJWpanXZHKq2BOB43TSaYhEWsQ1Lr5QNyPCDH/Tp.6' },
{ p: 'rasmuslerdorf',
s: '$6$rounds=5000$usesomesillystringforsalt$',
r: '$6$rounds=5000$usesomesillystri$D4IrlXatmP7rx3P3InaxBeoomnAihCKRVQP22JZ6EY47Wc6BkroIuUUBOov1i.S5KPgErtP/EN5mcO.ChWQW21' },
{ p: './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFG',
s: '$2a$12$0123456789abcdefghijke',
r: '$2a$12$0123456789abcdefghijke36bz62ZbAOKHwa0aLHwyCYl3o0lkv6q' },
{ p: './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGH',
s: '$2a$12$0123456789abcdefghijke',
r: '$2a$12$0123456789abcdefghijkeT1gjV4eikEehFL8/ZioAfE40W/Tzs.2' },
{ p: './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHI',
s: '$2a$12$0123456789abcdefghijke',
r: '$2a$12$0123456789abcdefghijkeT1gjV4eikEehFL8/ZioAfE40W/Tzs.2' }
];
var n = 0, ok = 0, i;
t.forEach(function(t) {
var r = up.crypt(t.p, t.s);
n++;
if (r === t.r) {
console.log('#' + n.toString() + ' OK');
ok++;
} else {
console.log('#' + n.toString() + ' FAIL!');
console.log(" crypt(\"" + t.p + "\", \"" + t.s + "\") -> \"" + r + "\"");
console.log(" expected \"" + t.r + "\"");
}
});
if (ok != n) {
console.log(ok.toString() +
'/' +
n.toString() +
" password tests OK. " +
(n - ok).toString() +
" tests failed.");
return false;
}
console.log("All " + n.toString() + " password tests OK.");
return true;
};
process.exit(test() ? 0 : 1);