| 1 | #!/usr/bin/perl |
| 2 | use strict; |
| 3 | use warnings; |
| 4 | |
| 5 | use Test::More tests => 16; |
| 6 | use Test::Exception; |
| 7 | |
| 8 | BEGIN { use_ok('Authen::Passphrase::Scrypt') }; |
| 9 | |
| 10 | # Vectors in the scrypt paper |
| 11 | my @vectors = ( |
| 12 | ['', '', 4, 1, 1, 64, '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906'], |
| 13 | ['password', 'NaCl', 10, 8, 16, 64, 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640'], |
| 14 | ['pleaseletmein', 'SodiumChloride', 14, 8, 1, 64, '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887'], |
| 15 | # Vector 4 omitted for performance reasons |
| 16 | ); |
| 17 | |
| 18 | for (1 .. @vectors) { |
| 19 | my ($pw, $salt, $logN, $r, $p, $len, $expected) = @{$vectors[$_ - 1]}; |
| 20 | my $result = crypto_scrypt $pw, $salt, (1 << $logN), $r, $p, $len; |
| 21 | $result = unpack 'H*', $result; |
| 22 | is $result, $expected, "Test vector $_" |
| 23 | } |
| 24 | |
| 25 | my $x = Authen::Passphrase::Scrypt->new({ |
| 26 | passphrase => 'password1' |
| 27 | }); |
| 28 | |
| 29 | ok $x->match('password1'), 'new + match'; |
| 30 | ok !$x->match('password2'), 'new + match'; |
| 31 | |
| 32 | my $test_rfc2307 = '{SCRYPT}c2NyeXB0AAwAAAAIAAAAAZ/+bp8gWcTZgEC7YQZeLLyxFeKRRdDkwbaGeFC0NkdUr/YFAWY/UwdOH4i/PxW48fXeXBDOTvGWtS3lLUgzNM0PlJbXhMOGd2bke0PvTSnW'; |
| 33 | |
| 34 | $x = Authen::Passphrase::Scrypt->from_rfc2307($test_rfc2307); |
| 35 | ok !$x->match('password1'), 'from_rfc2307 + match'; |
| 36 | ok $x->match('password2'), 'from_rfc2307 + match'; |
| 37 | |
| 38 | my $y = Authen::Passphrase::Scrypt->new( |
| 39 | passphrase => 'password2', |
| 40 | salt => $x->salt, |
| 41 | logN => $x->logN, |
| 42 | r => 8, |
| 43 | ); |
| 44 | |
| 45 | is $y->as_rfc2307, $test_rfc2307, 'as_rfc2307'; |
| 46 | |
| 47 | my $bad_rfc2307_1 = '{SCRYPT}notavalidscryptstringaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; |
| 48 | my $bad_rfc2307_2 = '{SCRYPT}c2NyeXB0AAwAAAAIAAAAAZ/+bp8gWcTZgEC7YQZeLLyxFeKRRdDkwbaGeFC0NkdUraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; |
| 49 | |
| 50 | throws_ok { Authen::Passphrase::Scrypt->new } |
| 51 | qr/passphrase not set/, 'new without passphrase'; |
| 52 | throws_ok { Authen::Passphrase::Scrypt->from_rfc2307('bad') } |
| 53 | qr/Invalid Scrypt RFC2307/, 'from_rfc2307 with bad string'; |
| 54 | throws_ok { Authen::Passphrase::Scrypt->from_rfc2307($bad_rfc2307_1) } |
| 55 | qr/Invalid Scrypt hash: should start/, 'from_rfc2307 with another bad string'; |
| 56 | throws_ok { Authen::Passphrase::Scrypt->from_rfc2307($bad_rfc2307_2) } |
| 57 | qr/Invalid Scrypt hash: bad checksum/, 'from_rfc2307 with yet another rfc2307'; |
| 58 | throws_ok { Authen::Passphrase::Scrypt->from_crypt('') } |
| 59 | qr/does not support crypt strings/, 'from_crypt'; |
| 60 | throws_ok { $y->as_crypt } |
| 61 | qr/does not support crypt strings/, 'as_crypt'; |
| 62 | throws_ok { Authen::Passphrase::Scrypt->new(passphrase => 'xkcd', r => (1 << 30), p => (1 << 30)) } |
| 63 | qr/Error in crypto_scrypt/, 'new with huge r and p'; |