Authen-Passphrase-0.008000755001750001750 011713235602 15007 5ustar00zeframzefram000000000000Authen-Passphrase-0.008/META.yml000444001750001750 546411713235576 16440 0ustar00zeframzefram000000000000--- abstract: 'hashed passwords/passphrases as objects' author: - 'Andrew Main (Zefram) ' build_requires: MIME::Base64: 2.21 Module::Build: 0 Test::More: 0 perl: 5.006 strict: 0 warnings: 0 configure_requires: Module::Build: 0 perl: 5.006 strict: 0 warnings: 0 dynamic_config: 0 generated_by: 'Module::Build version 0.38, CPAN::Meta::Converter version 2.112621' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Authen-Passphrase provides: Authen::Passphrase: file: lib/Authen/Passphrase.pm version: 0.008 Authen::Passphrase::AcceptAll: file: lib/Authen/Passphrase/AcceptAll.pm version: 0.008 Authen::Passphrase::BigCrypt: file: lib/Authen/Passphrase/BigCrypt.pm version: 0.008 Authen::Passphrase::BlowfishCrypt: file: lib/Authen/Passphrase/BlowfishCrypt.pm version: 0.008 Authen::Passphrase::Clear: file: lib/Authen/Passphrase/Clear.pm version: 0.008 Authen::Passphrase::Crypt16: file: lib/Authen/Passphrase/Crypt16.pm version: 0.008 Authen::Passphrase::DESCrypt: file: lib/Authen/Passphrase/DESCrypt.pm version: 0.008 Authen::Passphrase::EggdropBlowfish: file: lib/Authen/Passphrase/EggdropBlowfish.pm version: 0.008 Authen::Passphrase::LANManager: file: lib/Authen/Passphrase/LANManager.pm version: 0.008 Authen::Passphrase::LANManagerHalf: file: lib/Authen/Passphrase/LANManagerHalf.pm version: 0.008 Authen::Passphrase::MD5Crypt: file: lib/Authen/Passphrase/MD5Crypt.pm version: 0.008 Authen::Passphrase::MySQL323: file: lib/Authen/Passphrase/MySQL323.pm version: 0.008 Authen::Passphrase::MySQL41: file: lib/Authen/Passphrase/MySQL41.pm version: 0.008 Authen::Passphrase::NTHash: file: lib/Authen/Passphrase/NTHash.pm version: 0.008 Authen::Passphrase::NetscapeMail: file: lib/Authen/Passphrase/NetscapeMail.pm version: 0.008 Authen::Passphrase::PHPass: file: lib/Authen/Passphrase/PHPass.pm version: 0.008 Authen::Passphrase::RejectAll: file: lib/Authen/Passphrase/RejectAll.pm version: 0.008 Authen::Passphrase::SaltedDigest: file: lib/Authen/Passphrase/SaltedDigest.pm version: 0.008 Authen::Passphrase::VMSPurdy: file: lib/Authen/Passphrase/VMSPurdy.pm version: 0.008 requires: Authen::DecHpwd: 2.003 Carp: 0 Crypt::DES: 0 Crypt::Eksblowfish::Bcrypt: 0.008 Crypt::Eksblowfish::Uklblowfish: 0.008 Crypt::MySQL: 0.03 Crypt::PasswdMD5: 1.0 Crypt::UnixCrypt_XS: 0.08 Data::Entropy::Algorithms: 0 Digest: 1.00 Digest::MD4: 1.2 Digest::MD5: 1.9953 Digest::SHA: 0 MIME::Base64: 2.21 Module::Runtime: 0.011 Params::Classify: 0 parent: 0 perl: 5.006 strict: 0 warnings: 0 resources: license: http://dev.perl.org/licenses/ version: 0.008 Authen-Passphrase-0.008/SIGNATURE000644001750001750 1004711713235602 16454 0ustar00zeframzefram000000000000This file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.68. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 SHA1 4ff607a9628b3a53d1d5f493d07f80c62e05a1cc .gitignore SHA1 35ad1741a2e8227aa927f65735bc60253412a468 Build.PL SHA1 66892da20c7745991fd39ca7b1d3760d532a3a97 Changes SHA1 b3dbe8d80575d887abec73ceb39d52596e510571 MANIFEST SHA1 61126660bd129b1f4b1dc9cf2477ffa1049dc93a META.json SHA1 683a1207e98036d1af45f84afa1f32c68db5c7da META.yml SHA1 a4df8e97ccd390a42212af5a9f4d0986c85e7a5f Makefile.PL SHA1 4ce3500e0561cedc483673a918e6da960b169bda README SHA1 9e0c16edc63873594d30d569537d469ca7b21bf7 lib/Authen/Passphrase.pm SHA1 a023195088f0aae1a528fbb2911a606041b05b48 lib/Authen/Passphrase/AcceptAll.pm SHA1 46869a335237a2710ee4766fcd457b8b51b56a85 lib/Authen/Passphrase/BigCrypt.pm SHA1 c258c203f227b3edefeb20add41a9c3d2d5a45da lib/Authen/Passphrase/BlowfishCrypt.pm SHA1 8ef489ef2319e2d32208ccfc161def8692fa2fbb lib/Authen/Passphrase/Clear.pm SHA1 d221e22b9248ad5d25ee2b1b2a298083ab1fcbca lib/Authen/Passphrase/Crypt16.pm SHA1 336e4289f8dabb81dabfee444d0d0e082d2098f3 lib/Authen/Passphrase/DESCrypt.pm SHA1 c8115f18ecf9311fab5eaccd02692fd7fdd7be6d lib/Authen/Passphrase/EggdropBlowfish.pm SHA1 a02b462c3c62a34df09e3f36e2779dfc7823a50d lib/Authen/Passphrase/LANManager.pm SHA1 3709df52ff5709859ef14995810b1a450102f7ad lib/Authen/Passphrase/LANManagerHalf.pm SHA1 3ef6611b31b3c9f7f3df0720dc3366fe5f4c3f7a lib/Authen/Passphrase/MD5Crypt.pm SHA1 b55f6385b2a72a3c54c3a02fe80a5fadcbedff91 lib/Authen/Passphrase/MySQL323.pm SHA1 4e54f5b1745ddf18b353917f849c96606187d843 lib/Authen/Passphrase/MySQL41.pm SHA1 67c654ee5ccd3fb9e9c81bf1ce62cd76ea68631a lib/Authen/Passphrase/NTHash.pm SHA1 c945e262da2dbaaa560c62ec96452b87da03b6cf lib/Authen/Passphrase/NetscapeMail.pm SHA1 5ebc6d58d440440b0649b5eeb32c06cb9640bdf6 lib/Authen/Passphrase/PHPass.pm SHA1 e9435e9f46ed4b168746f2ee4a2a7770c5f391cc lib/Authen/Passphrase/RejectAll.pm SHA1 c681e467e3ad1dceb49ad85845ab6a0b4f4b4b35 lib/Authen/Passphrase/SaltedDigest.pm SHA1 c899b1dd540b115ac8274649c0ac1ed76eea72c0 lib/Authen/Passphrase/VMSPurdy.pm SHA1 701b95f420406bb412f27ce12bbabd4e2c388284 t/acceptall.t SHA1 c3888dbc795188d78a5498fed6167143d9aaed8f t/bigcrypt.t SHA1 a62299eeccc77e682893549122cba19558b6f5b9 t/blowfishcrypt.t SHA1 63691c2ef336fddaa8f9a131d8bc32539c5395b5 t/clear.t SHA1 022e065813caf9d462df1a52c7c48ad04feafbb0 t/crypt16.t SHA1 006723ca9e3d56b57444f55e4cd5c9da76f26410 t/eggdropblowfish.t SHA1 eb7784180618d43171420d6c72f7d64210c4c6bf t/extdescrypt.t SHA1 e625976a80c74e79718278ce36f50dfa40c72cad t/gendescrypt.t SHA1 2fd7ec5f8a364a541d161249bb8132e78846ded7 t/intdescrypt.t SHA1 4168299f662fa8c10f2924790fb6a7887c9c3e9d t/lanman.t SHA1 b45c94717b50731f513a60a3b8b792d0610c85da t/lanmanhalf.t SHA1 b5b993f5a8141fd3562893f69af313b70bc0a074 t/md5crypt.t SHA1 183801ccda7843e9a07746395618a9b4e9a5f94b t/mysql323.t SHA1 7b4dedc232b78764aa493216818ec5d62944d5cb t/mysql41.t SHA1 957e5eb52221c1ccb139984757e00774dc49a398 t/netscapemail.t SHA1 0334ae266aa54c7b03019b95bf156afac05ac288 t/nthash.t SHA1 1f09f3f17eb280eec2791d2dffdfc3936fabe173 t/phpass.t SHA1 904d9a4f76525e2303e4b0c168c68230f223c8de t/pod_cvg.t SHA1 65c75abdef6f01a5d1588a307f2ddfe2333dc961 t/pod_syn.t SHA1 e3962e176588f0498b58b16c989fa1a674ee861f t/rejectall.t SHA1 3a48f131cf21940c853f01690ccf19c18f6a0eac t/smd5.t SHA1 dec2ee0c0b163930850cf1942485877a855fe45d t/ssha.t SHA1 c9ef4b2237f83808e82f864775684a42c1a4f43c t/traddescrypt.t SHA1 66c4083e0684fdc049a1fdcff3e93f0cdf80e120 t/vmspurdy.t -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) iEYEARECAAYFAk8tO34ACgkQOV9mt2VyAVHkAACeMgXakr7kFcTJWZdRKkMigwe0 kc0AmgM9GAbozkMGecF0mB2/066nzQyy =k1za -----END PGP SIGNATURE----- Authen-Passphrase-0.008/MANIFEST000444001750001750 211211713235576 16303 0ustar00zeframzefram000000000000.gitignore Build.PL Changes MANIFEST META.json META.yml Makefile.PL README lib/Authen/Passphrase.pm lib/Authen/Passphrase/AcceptAll.pm lib/Authen/Passphrase/BigCrypt.pm lib/Authen/Passphrase/BlowfishCrypt.pm lib/Authen/Passphrase/Clear.pm lib/Authen/Passphrase/Crypt16.pm lib/Authen/Passphrase/DESCrypt.pm lib/Authen/Passphrase/EggdropBlowfish.pm lib/Authen/Passphrase/LANManager.pm lib/Authen/Passphrase/LANManagerHalf.pm lib/Authen/Passphrase/MD5Crypt.pm lib/Authen/Passphrase/MySQL323.pm lib/Authen/Passphrase/MySQL41.pm lib/Authen/Passphrase/NTHash.pm lib/Authen/Passphrase/NetscapeMail.pm lib/Authen/Passphrase/PHPass.pm lib/Authen/Passphrase/RejectAll.pm lib/Authen/Passphrase/SaltedDigest.pm lib/Authen/Passphrase/VMSPurdy.pm t/acceptall.t t/bigcrypt.t t/blowfishcrypt.t t/clear.t t/crypt16.t t/eggdropblowfish.t t/extdescrypt.t t/gendescrypt.t t/intdescrypt.t t/lanman.t t/lanmanhalf.t t/md5crypt.t t/mysql323.t t/mysql41.t t/netscapemail.t t/nthash.t t/phpass.t t/pod_cvg.t t/pod_syn.t t/rejectall.t t/smd5.t t/ssha.t t/traddescrypt.t t/vmspurdy.t SIGNATURE Added here by Module::Build Authen-Passphrase-0.008/Changes000444001750001750 2111411713235576 16470 0ustar00zeframzefram000000000000version 0.008; 2012-02-04 * bugfix: avoid passing magic variables $1 et al into functions where they might unexpectedly change value * bugfix: in A::P::SaltedDigest, when loading digest modules, use bugfixed version of Module::Runtime (which works around a bug in Perl 5.8 and 5.10 regarding loading context-sensitive modules) * in base class documentation, indicate which algorithms should be preferred for new applications, and discuss side-channel attacks * in A::P::BlowfishCrypt documentation, discuss selection of cost parameter * for A::P::MySQL41, get sha1() from Digest::SHA rather than Digest::SHA1, because Digest::SHA is included in the core distribution * add many cross links in documentation * documentation typo fixes * include META.json in distribution * convert .cvsignore to .gitignore * add MYMETA.json to .cvsignore version 0.007; 2010-07-30 * bugfix: in A::P::SaltedDigest, use "[0-9a-zA-Z_]" instead of "\w" in regexps where only ASCII characters are desired * bugfix: in A::P::BlowfishCrypt, require bugfixed version of Crypt::Eksblowfish (for memory leak fix) * bugfix: in A::P::SaltedDigest, require bugfixed version of Module::Runtime (for ASCII restriction of module name syntax) * in A::P::EggdropBlowfish, use Crypt::Eksblowfish::Uklblowfish instead of Crypt::Blowfish to remove limitation on passphrase length * abandon use of the "fields" module * use simpler "parent" pragma in place of "base" * in documentation, use the term "truth value" instead of the less precise "boolean" * in A::P documentation, add MooseX::Types::Authen::Passphrase to "see also" list * check for required Perl version at runtime * use full stricture in test suite * in Build.PL, explicitly declare configure-time requirements * remove bogus "exit 0" from Build.PL * add MYMETA.yml to .cvsignore version 0.006; 2009-03-07 * bugfix: in A::P::SaltedDigest, use "[0-9]" instead of "\d" in regexps where only ASCII digits are desired * bugfix: require bugfixed versions of Authen::DecHpwd, Crypt::Eksblowfish::Bcrypt, and Crypt::UnixCrypt_XS (for UTF8 scalar handling) * bugfix: require bugfixed version of Authen::DecHpwd (for not crashing) * bugfix: require bugfixed version of Module::Runtime (for $SIG{__DIE__} handling) * avoid "\x{}" in regexp character classes, for compatibility with perl v5.6 * in documentation for A::P::SaltedDigest, briefly discuss the new generation of hash algorithms * test POD syntax and coverage, and rename some internal functions to satisfy the coverage test * drop prototypes from method subs (where the prototypes have no effect) * in tests, avoid unreliable "\S" regexp element * build with Module::Build instead of ExtUtils::MakeMaker * complete dependency list * more precise Crypt::Eksblowfish::Bcrypt dependency instead of Crypt::Eksblowfish dependency * include signature in distribution * in documentation, separate "license" section from "copyright" section version 0.005; 2007-01-21 * avoid "my __PACKAGE__", for compatibility with perl v5.6 * point to Crypt::SaltedHash from documentation for A::P::SaltedDigest * remove bogus link to Crypt::Passwd from documentation for A::P::SaltedDigest * grammar fix in documentation for A::P::LANManager * punctuation fix in documentation for A::P::Crypt16 version 0.004; 2006-09-01 * implement Eggdrop blowfish.mod algorithm in Authen::Passphrase::EggdropBlowfish based on the Crypt::Blowfish module; initially limited to passphrases up to 56 bytes * in A::P::VMSPurdy, change ->hash_hex method to output in uppercase, as used in crypt strings * in A::P::VMSPurdy, add a "salt_hex =>" constructor parameter and a ->salt_hex method, handling salt in the hexadecimal format used in crypt strings * in documentation for A::P::DESCrypt, move the security warning to apply to both the traditional and extended schemes * in documentation for A::P::MySQL323, be more explicit about storage format * documentation markup fix in A::P::BlowfishCrypt version 0.003; 2006-08-31 * implement VMS Purdy polynomial algorithm family (crypt identifiers $VMS1$, $VMS2$, and $VMS3$) in Authen::Passphrase::VMSPurdy based on the Authen::DecHpwd module * implement phpass algorithm (crypt identifier $P$) in Authen::Passphrase::PHPass * implement MySQL v3.23 algorithm in Authen::Passphrase::MySQL323 based on the Crypt::MySQL module * implement MySQL v4.1 algorithm in Authen::Passphrase::MySQL41 * in from_crypt, when handling known but unimplemented schemes, say so instead of not recognising the scheme identifier * move from_crypt and from_rfc2307 parsing code from Authen::Passphrase into scheme-specific modules * put all data stored in objects into canonical form, to avoid propagating dualvars or other oddities * document {CRYPT16}, ambiguously used by Exim * make {CRYPT} documentation more explicit * fix a bogus reference to DES in the documentation of A::P::BlowfishCrypt version 0.002; 2006-08-12 * implement LAN Manager hash scheme (RFC 2307 identifiers {LANMAN} and {LANM}) in Authen::Passphrase::LANManager, along with separable halves (crypt identifier $LM$) in Authen::Passphrase::LANManagerHalf * implement Netscape Mail Server's MD5-based scheme (RFC 2307 identifier {NS-MTA-MD5}) in Authen::Passphrase::NetscapeMail * implement crypt16 from Ultrix in Authen::Passphrase::Crypt16 * implement bigcrypt from Digital Unix in Authen::Passphrase::BigCrypt * implement RFC 2307 scheme identifier {MD4} (plain MD4) * implement RFC 2307 scheme identifier {RMD160} (plain RIPEMD-160) * implement RFC 2307 scheme identifier {MSNT} (NT-Hash) * implement crypt scheme identifier $NT$ (NT-Hash with a different textual format from $3$) * implement RFC 2307 scheme identifier {WM-CRY} (synonym for {CRYPT}) * add a "passphrase =>" constructor parameter to A::P::BlowfishCrypt->new, A::P::DESCrypt->new, A::P::MD5Crypt->new, A::P::NTHash->new, and A::P::SaltedDigest->new (such a parameter also exists in the new A::P::BigCrypt->new, A::P::Crypt16->new, A::P::LANManager->new, A::P::LANManagerHalf->new, and A::P::NetscapeMail->new) * add a "salt_random =>" constructor parameter to A::P::BlowfishCrypt->new, A::P::DESCrypt->new, A::P::MD5Crypt->new, and A::P::SaltedDigest->new (such a parameter also exists in the new A::P::BigCrypt->new, A::P::Crypt16->new and A::P::NetscapeMail->new) * in A::P::SaltedDigest, accept bare package names and related forms, and references to blessed objects, as algorithm identifiers * in the from_crypt and from_rfc2307 constructors, reject strings containing spaces or control characters * in Authen::Passphrase::MD5Crypt, refuse to put a space character into a crypt string * in Authen::Passphrase::Clear, refuse to put spaces or control characters into an RFC 2307 string * in Authen::Passphrase::MD5Crypt, check that the salt string contains only bytes * prohibit the base class from_crypt and from_rfc2307 constructors being called on subclasses * in testing Authen::Passphrase::NTHash, check case handling * rewrite the from_crypt constructor to use scheme identifiers as such, the way from_rfc2307 already does * in documentation for the from_crypt constructor, list all known scheme identifiers * in documentation for the from_rfc2307 constructor, list known pseudo-schemes (where instead of a passphrase hash there is a reference to some other authentication mechanism) * discuss resistance to brute force attacks in documentation * more realistic example salts in the synopsis of A::P::MD5Crypt and A::P::SaltedDigest version 0.001; 2006-08-06 * implement Blowfish-based crypt() scheme (crypt identifiers $2$ and $2a$) in Authen::Passphrase::BlowfishCrypt, based on the new Crypt::Eksblowfish::Bcrypt module * include MIME::Base64 in dependency list in Makefile.PL * versioned dependencies * add test t/intdescrypt.t for the full DESCrypt interface * test full SaltedDigest interface in t/smd5.t and t/ssha.t * test full NTHash interface in t/nthash.t * use "=> 0" instead of "=> undef" in unversioned dependencies in Makefile.PL * in the Authen::Passphrase constructors, note the effects of the runtime loading of specific recogniser class modules * comment on the origins of the MD5-based and Blowfish-based crypt() schemes * corrected copyright year in README version 0.000; 2006-05-23 * initial released version Authen-Passphrase-0.008/README000444001750001750 260311713235576 16037 0ustar00zeframzefram000000000000NAME Authen::Passphrase - hashed passwords/passphrases as objects DESCRIPTION This is the base class for a system of objects that encapsulate passphrases. An object of this type is a passphrase recogniser: its job is to recognise whether an offered passphrase is the right one. For security, such passphrase recognisers usually do not themselves know the passphrase they are looking for; they can merely recognise it when they see it. There are many schemes in use to achieve this effect, and the intent of this class is to provide a consistent interface to them all, hiding the details. The CPAN package Authen-Passphrase contains implementations of several specific passphrase schemes in addition to the base class. See the specific classes for notes on the security properties of each scheme. In new systems, if there is a choice of which passphrase algorithm to use, it is recommended to use Authen::Passphrase::SaltedDigest or Authen::Passphrase::BlowfishCrypt. Most other schemes are too weak for new applications, and should be used only for backward compatibility. INSTALLATION perl Build.PL ./Build ./Build test ./Build install AUTHOR Andrew Main (Zefram) COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Authen-Passphrase-0.008/.gitignore000444001750001750 17211713235576 17126 0ustar00zeframzefram000000000000/Build /Makefile /_build /blib /META.json /META.yml /MYMETA.json /MYMETA.yml /Makefile.PL /SIGNATURE /Authen-Passphrase-* Authen-Passphrase-0.008/Makefile.PL000444001750001750 230211713235576 17125 0ustar00zeframzefram000000000000# Note: this file was auto-generated by Module::Build::Compat version 0.3800 require 5.006; unless (eval "use Module::Build::Compat 0.02; 1" ) { print "This module requires Module::Build to install itself.\n"; require ExtUtils::MakeMaker; my $yn = ExtUtils::MakeMaker::prompt (' Install Module::Build now from CPAN?', 'y'); unless ($yn =~ /^y/i) { die " *** Cannot install without Module::Build. Exiting ...\n"; } require Cwd; require File::Spec; require CPAN; # Save this 'cause CPAN will chdir all over the place. my $cwd = Cwd::cwd(); CPAN::Shell->install('Module::Build::Compat'); CPAN::Shell->expand("Module", "Module::Build::Compat")->uptodate or die "Couldn't install Module::Build, giving up.\n"; chdir $cwd or die "Cannot chdir() back to $cwd: $!"; } eval "use Module::Build::Compat 0.02; 1" or die $@; Module::Build::Compat->run_build_pl(args => \@ARGV); my $build_script = 'Build'; $build_script .= '.com' if $^O eq 'VMS'; exit(0) unless(-e $build_script); # cpantesters convention require Module::Build; Module::Build::Compat->write_makefile(build_class => 'Module::Build'); Authen-Passphrase-0.008/META.json000444001750001750 1047411713235576 16625 0ustar00zeframzefram000000000000{ "abstract" : "hashed passwords/passphrases as objects", "author" : [ "Andrew Main (Zefram) " ], "dynamic_config" : 0, "generated_by" : "Module::Build version 0.38, CPAN::Meta::Converter version 2.112621", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Authen-Passphrase", "prereqs" : { "build" : { "requires" : { "MIME::Base64" : "2.21", "Module::Build" : 0, "Test::More" : 0, "perl" : "5.006", "strict" : 0, "warnings" : 0 } }, "configure" : { "requires" : { "Module::Build" : 0, "perl" : "5.006", "strict" : 0, "warnings" : 0 } }, "runtime" : { "requires" : { "Authen::DecHpwd" : "2.003", "Carp" : 0, "Crypt::DES" : 0, "Crypt::Eksblowfish::Bcrypt" : "0.008", "Crypt::Eksblowfish::Uklblowfish" : "0.008", "Crypt::MySQL" : "0.03", "Crypt::PasswdMD5" : "1.0", "Crypt::UnixCrypt_XS" : "0.08", "Data::Entropy::Algorithms" : 0, "Digest" : "1.00", "Digest::MD4" : "1.2", "Digest::MD5" : "1.9953", "Digest::SHA" : 0, "MIME::Base64" : "2.21", "Module::Runtime" : "0.011", "Params::Classify" : 0, "parent" : 0, "perl" : "5.006", "strict" : 0, "warnings" : 0 } } }, "provides" : { "Authen::Passphrase" : { "file" : "lib/Authen/Passphrase.pm", "version" : "0.008" }, "Authen::Passphrase::AcceptAll" : { "file" : "lib/Authen/Passphrase/AcceptAll.pm", "version" : "0.008" }, "Authen::Passphrase::BigCrypt" : { "file" : "lib/Authen/Passphrase/BigCrypt.pm", "version" : "0.008" }, "Authen::Passphrase::BlowfishCrypt" : { "file" : "lib/Authen/Passphrase/BlowfishCrypt.pm", "version" : "0.008" }, "Authen::Passphrase::Clear" : { "file" : "lib/Authen/Passphrase/Clear.pm", "version" : "0.008" }, "Authen::Passphrase::Crypt16" : { "file" : "lib/Authen/Passphrase/Crypt16.pm", "version" : "0.008" }, "Authen::Passphrase::DESCrypt" : { "file" : "lib/Authen/Passphrase/DESCrypt.pm", "version" : "0.008" }, "Authen::Passphrase::EggdropBlowfish" : { "file" : "lib/Authen/Passphrase/EggdropBlowfish.pm", "version" : "0.008" }, "Authen::Passphrase::LANManager" : { "file" : "lib/Authen/Passphrase/LANManager.pm", "version" : "0.008" }, "Authen::Passphrase::LANManagerHalf" : { "file" : "lib/Authen/Passphrase/LANManagerHalf.pm", "version" : "0.008" }, "Authen::Passphrase::MD5Crypt" : { "file" : "lib/Authen/Passphrase/MD5Crypt.pm", "version" : "0.008" }, "Authen::Passphrase::MySQL323" : { "file" : "lib/Authen/Passphrase/MySQL323.pm", "version" : "0.008" }, "Authen::Passphrase::MySQL41" : { "file" : "lib/Authen/Passphrase/MySQL41.pm", "version" : "0.008" }, "Authen::Passphrase::NTHash" : { "file" : "lib/Authen/Passphrase/NTHash.pm", "version" : "0.008" }, "Authen::Passphrase::NetscapeMail" : { "file" : "lib/Authen/Passphrase/NetscapeMail.pm", "version" : "0.008" }, "Authen::Passphrase::PHPass" : { "file" : "lib/Authen/Passphrase/PHPass.pm", "version" : "0.008" }, "Authen::Passphrase::RejectAll" : { "file" : "lib/Authen/Passphrase/RejectAll.pm", "version" : "0.008" }, "Authen::Passphrase::SaltedDigest" : { "file" : "lib/Authen/Passphrase/SaltedDigest.pm", "version" : "0.008" }, "Authen::Passphrase::VMSPurdy" : { "file" : "lib/Authen/Passphrase/VMSPurdy.pm", "version" : "0.008" } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ] }, "version" : "0.008" } Authen-Passphrase-0.008/Build.PL000444001750001750 214111713235576 16450 0ustar00zeframzefram000000000000{ use 5.006; } use warnings; use strict; use Module::Build; Module::Build->new( module_name => "Authen::Passphrase", license => "perl", configure_requires => { "Module::Build" => 0, "perl" => "5.006", "strict" => 0, "warnings" => 0, }, build_requires => { "MIME::Base64" => "2.21", "Module::Build" => 0, "Test::More" => 0, "perl" => "5.006", "strict" => 0, "warnings" => 0, }, requires => { "Authen::DecHpwd" => "2.003", "Carp" => 0, "Crypt::DES" => 0, "Crypt::Eksblowfish::Bcrypt" => "0.008", "Crypt::Eksblowfish::Uklblowfish" => "0.008", "Crypt::MySQL" => "0.03", "Crypt::PasswdMD5" => "1.0", "Crypt::UnixCrypt_XS" => "0.08", "Data::Entropy::Algorithms" => 0, "Digest" => "1.00", "Digest::MD4" => "1.2", "Digest::MD5" => "1.9953", "Digest::SHA" => 0, "MIME::Base64" => "2.21", "Module::Runtime" => "0.011", "Params::Classify" => 0, "parent" => 0, "perl" => "5.006", "strict" => 0, "warnings" => 0, }, dynamic_config => 0, meta_add => { distribution_type => "module" }, create_makefile_pl => "passthrough", sign => 1, )->create_build_script; 1; Authen-Passphrase-0.008/lib000755001750001750 011713235576 15567 5ustar00zeframzefram000000000000Authen-Passphrase-0.008/lib/Authen000755001750001750 011713235576 17013 5ustar00zeframzefram000000000000Authen-Passphrase-0.008/lib/Authen/Passphrase.pm000444001750001750 4355311713235576 21651 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase - hashed passwords/passphrases as objects =head1 SYNOPSIS use Authen::Passphrase; $ppr = Authen::Passphrase->from_crypt($passwd); $ppr = Authen::Passphrase->from_rfc2307($userPassword); if($ppr->match($passphrase)) { ... $passphrase = $ppr->passphrase; $crypt = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION This is the base class for a system of objects that encapsulate passphrases. An object of this type is a passphrase recogniser: its job is to recognise whether an offered passphrase is the right one. For security, such passphrase recognisers usually do not themselves know the passphrase they are looking for; they can merely recognise it when they see it. There are many schemes in use to achieve this effect, and the intent of this class is to provide a consistent interface to them all, hiding the details. The CPAN package Authen-Passphrase contains implementations of several specific passphrase schemes in addition to the base class. See the specific classes for notes on the security properties of each scheme. In new systems, if there is a choice of which passphrase algorithm to use, it is recommended to use L or L. Most other schemes are too weak for new applications, and should be used only for backward compatibility. =head2 Side-channel cryptanalysis Both the Authen-Passphrase framework and most of the underlying cryptographic algorithm implementations are vulnerable to side-channel cryptanalytic attacks. However, the impact of this is quite limited. Unlike the case of symmetric encryption, where a side-channel attack can extract the plaintext directly, the cryptographic operations involved in passphrase recognition don't directly process the correct passphrase. A sophisticated side-channel attack, applied when offering incorrect passphrases for checking, could potentially extract salt (from the operation of the hashing algorithm) and the target hash value (from the comparison of hash values). This would enable a cryptanalytic or brute-force attack on the passphrase recogniser to be performed offline. This is not a disaster; the very intent of storing only a hash of the correct passphrase is that leakage of these stored values doesn't compromise the passphrase. In a typical usage scenario for this framework, the side-channel attacks that can be mounted are very restricted. If authenticating network users, typically an attacker has no access at all to power consumption, electromagnetic emanation, and other such side channels. The only side channel that is readily available is timing, and the precision of timing measurements is significantly blunted by the normal processes of network communication. For example, it would not normally be feasible to mount a timing attack against hash value comparison (to see how far through the values the first mismatch was). Perl as a whole has not been built as a platform for side-channel-resistant cryptography, so hardening Authen-Passphrase and its underlying algorithms is not feasible. In any serious use of Perl for cryptography, including for authentication using Authen-Passphrase, an analysis should be made of the exposure to side-channel attacks, and if necessary efforts made to further blunt the timing channel. One timing attack that is very obviously feasible over the network is to determine which of several passphrase hashing algorithms is being used. This can potentially distinguish between classes of user accounts, or distinguish between existing and non-existing user accounts when an attacker is guessing usernames. To obscure this information requires an extreme restriction of the timing channel, most likely by explicitly pausing to standardise the amount of time spent on authentication. This defence also rules out essentially all other timing attacks. =head1 PASSPHRASE ENCODINGS Because hashed passphrases frequently need to be stored, various encodings of them have been devised. This class has constructors and methods to support these. =head2 crypt encoding The Unix crypt() function, which performs passphrase hashing, returns hashes in a textual format intended to be stored in a text file. In particular, such hashes are stored in /etc/passwd (and now /etc/shadow) to control access to Unix user accounts. The same textual format has been adopted and extended by other passphrase-handling software such as password crackers. For historical reasons, there are several different syntaxes used in this format. The original DES-based password scheme represents its hashes simply as a string of thirteen base 64 digits. An extended variant of this scheme uses nineteen base 64 digits, preceded by an "B<_>" marker. A more general syntax was developed later, which starts the string with "B<$>", an alphanumeric scheme identifier, and another "B<$>". In addition to actual passphrase hashes, the crypt format can also represent a couple of special cases. The empty string indicates that there is no access control; it is possible to login without giving a passphrase. Finally, any string that is not a possible output of crypt() may be used to prevent login completely; "B<*>" is the usual choice, but other strings are used too. crypt strings are intended to be used in text files that use colon and newline characters as delimiters. This module treats the crypt string syntax as being limited to ASCII graphic characters excluding colon. =head2 RFC 2307 encoding RFC 2307 describes an encoding system for passphrase hashes, to be used in the "B" attribute in LDAP databases. It encodes hashes as ASCII text, and supports several passphrase schemes in an extensible way by starting the encoding with an alphanumeric scheme identifier enclosed in braces. There are several standard scheme identifiers. The "B<{CRYPT}>" scheme allows the use of any crypt encoding. This module treats the RFC 2307 string syntax as being limited to ASCII graphic characters. The RFC 2307 encoding is a good one, and is recommended for storage and exchange of passphrase hashes. =cut package Authen::Passphrase; { use 5.006; } use warnings; use strict; use Carp qw(croak); use MIME::Base64 2.21 qw(decode_base64); use Module::Runtime 0.011 qw(use_module); our $VERSION = "0.008"; =head1 CONSTRUCTORS =over =item Authen::Passphrase->from_crypt(PASSWD) Returns a passphrase recogniser object matching the supplied crypt encoding. This constructor may only be called on the base class, not any subclass. The specific passphrase recogniser class is loaded at runtime, so successfully loading C does not guarantee that it will be possible to use a specific type of passphrase recogniser. If necessary, check separately for presence and loadability of the recogniser class. Known scheme identifiers: =over =item B<$1$> A baroque passphrase scheme based on MD5, designed by Poul-Henning Kamp and originally implemented in FreeBSD. See L. =item B<$2$> =item B<$2a$> Two versions of a passphrase scheme based on Blowfish, designed by Niels Provos and David Mazieres for OpenBSD. See L. =item B<$3$> The NT-Hash scheme, which stores the MD4 hash of the passphrase expressed in Unicode. See L. =item B<$IPB2$> Invision Power Board 2.x salted MD5 =item B<$K4$> Kerberos AFS DES =item B<$LM$> Half of the Microsoft LAN Manager hash scheme. The two halves of a LAN Manager hash can be separated and manipulated independently; this represents such an isolated half. See L. =item B<$NT$> The NT-Hash scheme, which stores the MD4 hash of the passphrase expressed in Unicode. See L. The B<$3$> identifier refers to the same hash algorithm, but has a slightly different textual format (an extra "B<$>"). =item B<$P$> Portable PHP password hash (phpass), based on MD5. See L. =item B<$VMS1$> =item B<$VMS2$> =item B<$VMS3$> Three variants of the Purdy polynomial system used in VMS. See L. =item B<$af$> Kerberos v4 TGT =item B<$apr1$> A variant of the B<$1$> scheme, used by Apache. =item B<$krb5$> Kerberos v5 TGT =back The historical formats supported are: =over =item "I" ("I" represents a base 64 digit.) The original DES-based Unix password hash scheme. See L. =item "B<_>I" ("I" represents a base 64 digit.) Extended DES-based passphrase hash scheme from BSDi. See L. =item "" Accept any passphrase. See L. =item "B<*>" To handle historical practice, anything non-empty but shorter than 13 characters and not starting with "B<$>" is treated as deliberately rejecting all passphrases. (See L.) Anything 13 characters or longer, or starting with "B<$>", that is not recognised as a hash is treated as an error. =back There are also two different passphrase schemes that use a crypt string consisting of 24 base 64 digits. One is named "bigcrypt" and appears in HP-UX, Digital Unix, and OSF/1 (see L). The other is named "crypt16" and appears in Ultrix and Tru64 (see L). These schemes conflict. Neither of them is accepted as a crypt string by this constructor; such strings are regarded as invalid encodings. =cut my %crypt_scheme_handler = ( "1" => [ "Authen::Passphrase::MD5Crypt", 0.003 ], "2" => [ "Authen::Passphrase::BlowfishCrypt", 0.007 ], "2a" => [ "Authen::Passphrase::BlowfishCrypt", 0.007 ], "3" => [ "Authen::Passphrase::NTHash", 0.003 ], "IPB2" => sub($) { croak '$IPB2$ is unimplemented' }, "K4" => sub($) { croak '$K4$ is unimplemented' }, "LM" => [ "Authen::Passphrase::LANManagerHalf", 0.003 ], "NT" => [ "Authen::Passphrase::NTHash", 0.003 ], "P" => [ "Authen::Passphrase::PHPass", 0.003 ], "VMS1" => [ "Authen::Passphrase::VMSPurdy", 0.006 ], "VMS2" => [ "Authen::Passphrase::VMSPurdy", 0.006 ], "VMS3" => [ "Authen::Passphrase::VMSPurdy", 0.006 ], "af" => sub($) { croak '$af$ is unimplemented' }, "apr1" => sub($) { croak '$apr1$ is unimplemented' }, "krb5" => sub($) { croak '$krb5$ is unimplemented' }, ); sub from_crypt { my($class, $passwd) = @_; croak "crypt string \"$passwd\" not supported for $class" unless $class eq __PACKAGE__; my $handler; if($passwd =~ /\A\$([0-9A-Za-z]+)\$/) { my $scheme = $1; $handler = $crypt_scheme_handler{$scheme}; croak "unrecognised crypt scheme \$$scheme\$" unless defined $handler; } elsif($passwd =~ m#\A(?:[^\$].{12}|_.{19})\z#s) { $handler = [ "Authen::Passphrase::DESCrypt", 0.006 ]; } elsif($passwd eq "") { $handler = [ "Authen::Passphrase::AcceptAll", 0.003 ]; } elsif($passwd =~ /\A[^\$].{0,11}\z/s) { $handler = [ "Authen::Passphrase::RejectAll", 0.003 ]; } else { croak "bad crypt syntax in \"$passwd\""; } if(ref($handler) eq "CODE") { return $handler->($passwd); } else { my($modname, $modver) = @$handler; return use_module($modname, $modver)->from_crypt($passwd); } } =item Authen::Passphrase->from_rfc2307(USERPASSWORD) Returns a passphrase recogniser object matching the supplied RFC 2307 encoding. This constructor may only be called on the base class, not any subclass. The specific passphrase recogniser class is loaded at runtime. See the note about this for the L constructor above. Known scheme identifiers: =over =item B<{CLEARTEXT}> Passphrase stored in cleartext. See L. =item B<{CRYPT}> The scheme identifier is followed by a crypt string. =item B<{CRYPT16}> Used ambiguously by Exim, to refer to either crypt16 (see L) or bigcrypt (see L) depending on compilation options. This is a bug, resulting from a confusion between the two algorithms. This module does not support any meaning for this scheme identifier. =item B<{K5KEY}> Not a real passphrase scheme, but a placeholder to indicate that a Kerberos key stored separately should be checked against. No data follows the scheme identifier. =item B<{KERBEROS}> Not a real passphrase scheme, but a placeholder to indicate that Kerberos should be invoked to check against a user's passphrase. The scheme identifier is followed by the user's username, in the form "IB<@>I". =item B<{LANM}> Synonym for B<{LANMAN}>, used by CommuniGate Pro. =item B<{LANMAN}> The Microsoft LAN Manager hash scheme. See L. =item B<{MD4}> The MD4 digest of the passphrase is stored. See L. =item B<{MD5}> The MD5 digest of the passphrase is stored. See L. =item B<{MSNT}> The NT-Hash scheme, which stores the MD4 hash of the passphrase expressed in Unicode. See L. =item B<{NS-MTA-MD5}> An MD5-based scheme used by Netscape Mail Server. See L. =item B<{RMD160}> The RIPEMD-160 digest of the passphrase is stored. See L. =item B<{SASL}> Not a real passphrase scheme, but a placeholder to indicate that SASL should be invoked to check against a user's passphrase. The scheme identifier is followed by the user's username. =item B<{SHA}> The SHA-1 digest of the passphrase is stored. See L. =item B<{SMD5}> The MD5 digest of the passphrase plus a salt is stored. See L. =item B<{SSHA}> The SHA-1 digest of the passphrase plus a salt is stored. See L. =item B<{UNIX}> Not a real passphrase scheme, but a placeholder to indicate that Unix mechanisms should be used to check against a Unix user's login passphrase. The scheme identifier is followed by the user's username. =item B<{WM-CRY}> Synonym for B<{CRYPT}>, used by CommuniGate Pro. =back =cut my %rfc2307_scheme_handler = ( "CLEARTEXT" => [ "Authen::Passphrase::Clear", 0.003 ], # "CRYPT" is handled specially "CRYPT16" => sub($) { croak "{CRYPT16} is ambiguous" }, "K5KEY" => sub($) { croak "{K5KEY} is a placeholder" }, "KERBEROS" => sub($) { croak "{KERBEROS} is a placeholder" }, "LANM" => [ "Authen::Passphrase::LANManager", 0.003 ], "LANMAN" => [ "Authen::Passphrase::LANManager", 0.003 ], "MD4" => [ "Authen::Passphrase::SaltedDigest", 0.008 ], "MD5" => [ "Authen::Passphrase::SaltedDigest", 0.008 ], "MSNT" => [ "Authen::Passphrase::NTHash", 0.003 ], "NS-MTA-MD5" => [ "Authen::Passphrase::NetscapeMail", 0.003 ], "RMD160" => [ "Authen::Passphrase::SaltedDigest", 0.008 ], "SASL" => sub($) { croak "{SASL} is a placeholder" }, "SHA" => [ "Authen::Passphrase::SaltedDigest", 0.008 ], "SMD5" => [ "Authen::Passphrase::SaltedDigest", 0.008 ], "SSHA" => [ "Authen::Passphrase::SaltedDigest", 0.008 ], "UNIX" => sub($) { croak "{UNIX} is a placeholder" }, # "WM-CRY" is handled specially ); sub from_rfc2307 { my($class, $userpassword) = @_; if($userpassword =~ m#\A\{(?i:crypt|wm-cry)\}(.*)\z#s) { my $passwd = $1; return $class->from_crypt($passwd); } croak "RFC 2307 string \"$userpassword\" not supported for $class" unless $class eq __PACKAGE__; $userpassword =~ /\A\{([-0-9a-z]+)\}/i or croak "bad RFC 2307 syntax in \"$userpassword\""; my $scheme = uc($1); my $handler = $rfc2307_scheme_handler{$scheme}; croak "unrecognised RFC 2307 scheme {$scheme}" unless defined $handler; if(ref($handler) eq "CODE") { return $handler->($userpassword); } else { my($modname, $modver) = @$handler; return use_module($modname, $modver) ->from_rfc2307($userpassword); } } =back =head1 METHODS =over =item $ppr->match(PASSPHRASE) Checks whether the supplied passphrase is correct. Returns a truth value. =item $ppr->passphrase If a matching passphrase can be easily determined by the passphrase recogniser then this method will return it. This is only feasible for very weak passphrase schemes. The method Cs if it is infeasible. =item $ppr->as_crypt Encodes the passphrase recogniser in crypt format and returns the encoded result. Cs if the passphrase recogniser cannot be represented in this form. =item $ppr->as_rfc2307 Encodes the passphrase recogniser in RFC 2307 format and returns the encoded result. Cs if the passphrase recogniser cannot be represented in this form. =cut sub as_rfc2307 { "{CRYPT}".$_[0]->as_crypt } =back =head1 SUBCLASSING This class is designed to be subclassed, and cannot be instantiated alone. Any subclass must implement the L method. That is the minimum required. Subclasses should implement the L and L methods and the L and L constructors wherever appropriate, with the following exception. If a passphrase scheme has a crypt encoding but no native RFC 2307 encoding, so it can be RFC 2307 encoded only by using the "B<{CRYPT}>" scheme, then L and L should I be implemented by the class. There is a default implementation of the L method that uses "B<{CRYPT}>" and L, and a default implementation of the L method that recognises "B<{CRYPT}>" and passes the embedded crypt string to the L constructor. Implementation of the L method is entirely optional. It should be attempted only for schemes that are so ludicrously weak as to allow passphrases to be cracked reliably in a short time. Dictionary attacks are not appropriate implementations. =head1 SEE ALSO L, L, RFC 2307 =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase000755001750001750 011713235576 21124 5ustar00zeframzefram000000000000Authen-Passphrase-0.008/lib/Authen/Passphrase/VMSPurdy.pm000444001750001750 2526211713235576 23337 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::VMSPurdy - passphrases with the VMS Purdy polynomial system =head1 SYNOPSIS use Authen::Passphrase::VMSPurdy; $ppr = Authen::Passphrase::VMSPurdy->new( username => "jrandom", salt => 25362, hash_hex => "832a0c270179584a"); $ppr = Authen::Passphrase::VMSPurdy->new( username => "jrandom", salt_random => 1, passphrase => "passphrase"); $ppr = Authen::Passphrase::VMSPurdy->from_crypt( '$VMS3$1263832A0C270179584AJRANDOM'); $ppr = Authen::Passphrase::VMSPurdy->from_rfc2307( '{CRYPT}$VMS3$1263832A0C270179584AJRANDOM'); $algorithm = $ppr->algorithm; $username = $ppr->username; $salt = $ppr->salt; $hash = $ppr->hash; $hash_hex = $ppr->hash_hex; if($ppr->match($passphrase)) { ... $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using one of the Purdy polynomial hash functions used in VMS. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The core of the Purdy polynomial hashing algorithm transforms one 64-bit number into another 64-bit number. It was developed by George B. Purdy, and described in the paper "A High Security Log-in Procedure" which can be found at L. For practical use in passphrase hashing, the Purdy polynomial must be augmented by a procedure to turn a variable-length passphrase into the initial 64-bit number to be hashed. In VMS this pre-hashing phase also incorporates the username of the account to which access is being controlled, in order to prevent identical passphrases yielding identical hashes. This is a form of salting. Another salt parameter, a 16-bit integer, is also included, this one going under the name "salt". There are three variants of the pre-hashing algorithm. The original version, known as "B" and used during field testing of VMS 2.0, truncates or space-pads the username to a fixed length. The second version, known as "B" and used from VMS 2.0 up to (but not including) VMS 5.4, properly handles the variable-length nature of the username. The third version, known as "B" and used from VMS 5.4 onwards, performs some extra bit rotations to avoid aliasing problems when pre-hashing long strings. All three versions are supported by this module. VMS heavily restricts the composition of both usernames and passphrases. They may only contain alphanumerics, "B<$>", and "B<_>". Case is insignificant. Usernames must be between 1 and 31 characters long, and passphrases must be between 1 and 32 characters long. This module enforces these rules. An invalid passphrase is never accepted as matching. =cut package Authen::Passphrase::VMSPurdy; { use 5.006; } use warnings; use strict; use Authen::DecHpwd 2.003 qw(lgi_hpwd UAI_C_PURDY UAI_C_PURDY_V UAI_C_PURDY_S); use Authen::Passphrase 0.003; use Carp qw(croak); use Data::Entropy::Algorithms 0.000 qw(rand_int); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::VMSPurdy->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the VMS Purdy polynomial algorithm family. The following attributes may be given: =over =item B A string indicating which variant of the algorithm is to be used. Valid values are "B" (the original), "B" (modified to use full length of the username), and "B" (extra rotations to avoid aliasing when processing long strings). Default "B". =item B A string to be used as the `username' salt parameter. It is limited to VMS username syntax. =item B The salt, as an integer in the range [0, 65536). =item B The salt, as a string of four hexadecimal digits. The first two digits must give the least-significant byte and the last two give the most-significant byte, with most-significant nybble first within each byte. =item B Causes salt to be generated randomly. The value given for this attribute is ignored. The source of randomness may be controlled by the facility described in L. =item B The hash, as a string of eight bytes. =item B The hash, as a string of 16 hexadecimal digits. =item B A passphrase that will be accepted. It is limited to VMS passphrase syntax. =back The username and salt must be given, and either the hash or the passphrase. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "algorithm") { croak "algorithm specified redundantly" if exists $self->{algorithm}; $value =~ m#\APURDY(?:|_V|_S)\z# or croak "not a valid algorithm"; $self->{algorithm} = "$value"; } elsif($attr eq "username") { croak "username specified redundantly" if exists $self->{username}; $value =~ m#\A[_\$0-9A-Za-z]{1,31}\z# or croak "not a valid VMS username"; $self->{username} = uc("$value"); } elsif($attr eq "salt") { croak "salt specified redundantly" if exists $self->{salt}; $value == int($value) && $value >= 0 && $value < 65536 or croak "not a valid salt"; $self->{salt} = 0+$value; } elsif($attr eq "salt_hex") { croak "salt specified redundantly" if exists $self->{salt}; $value =~ /\A([0-9a-fA-F]{2})([0-9a-fA-F]{2})\z/ or croak "not a valid salt"; $self->{salt} = hex($2.$1); } elsif($attr eq "salt_random") { croak "salt specified redundantly" if exists $self->{salt}; $self->{salt} = rand_int(65536); } elsif($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{8}\z# or croak "not a valid raw hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_hex") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[0-9A-Fa-f]{16}\z# or croak "not a valid hexadecimal hash"; $self->{hash} = pack("H*", $value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $self->_passphrase_acceptable($value) or croak "can't accept that passphrase"; $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } $self->{algorithm} = "PURDY_S" unless exists $self->{algorithm}; croak "username not specified" unless exists $self->{username}; croak "salt not specified" unless exists $self->{salt}; $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =item Authen::Passphrase::VMSPurdy->from_crypt(PASSWD) Generates a new passphrase recogniser object using the VMS Purdy polynomial algorithm family, from a crypt string. The string must consist of an algorithm identifier, the salt in hexadecimal, the hash in hexadecimal, then the username. The salt must be given as four hexadecimal digits, the first two giving the least-significant byte and the last two giving the most-significant byte, with most-significant nybble first within each byte. The algorithm identifier must be "B<$VMS1$>" for "B", "B<$VMS2$>" for "B", or "B<$VMS3$>" for "B". The whole crypt string must be uppercase. =cut my %decode_crypt_alg_num = ( "1" => "PURDY", "2" => "PURDY_V", "3" => "PURDY_S", ); sub from_crypt { my($class, $passwd) = @_; if($passwd =~ /\A\$VMS([123])\$/) { my $alg = $1; $passwd =~ /\A\$VMS[123]\$([0-9A-F]{4}) ([0-9A-F]{16})([_\$0-9A-Z]{1,31})\z/x or croak "malformed \$VMS${alg}\$ data"; my($salt, $hash, $un) = ($1, $2, $3); return $class->new(algorithm => $decode_crypt_alg_num{$alg}, username => $un, salt_hex => $salt, hash_hex => $hash); } return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::VMSPurdy->from_rfc2307(USERPASSWORD) Generates a new passphrase recogniser object using the VMS Purdy polynomial algorithm family, from an RFC 2307 string. The string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =back =head1 METHODS =over =item $ppr->algorithm Returns the algorithm variant identifier string. It may be "B" (the original), "B" (modified to use full length of the username), and "B" (extra rotations to avoid aliasing when processing long strings). =cut sub algorithm { my($self) = @_; return $self->{algorithm}; } =item $ppr->username Returns the username string. All alphabetic characters in it are uppercase, which is the canonical form. =cut sub username { my($self) = @_; return $self->{username}; } =item $ppr->salt Returns the salt, as an integer. =cut sub salt { my($self) = @_; return $self->{salt}; } =item $ppr->salt_hex Returns the salt, as a string of four hexadecimal digits. The first two digits give the least-significant byte and the last two give the most-significant byte, with most-significant nybble first within each byte. =cut sub salt_hex { my($self) = @_; return sprintf("%02X%02X", $self->{salt} & 0xff, $self->{salt} >> 8); } =item $ppr->hash Returns the hash value, as a string of eight bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_hex Returns the hash value, as a string of 16 uppercase hexadecimal digits. =cut sub hash_hex { my($self) = @_; return uc(unpack("H*", $self->{hash})); } =item $ppr->match(PASSPHRASE) =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. =cut sub _passphrase_acceptable { my($self, $passphrase) = @_; return $passphrase =~ /\A[_\$0-9A-Za-z]{1,32}\z/; } my %hpwd_alg_num = ( PURDY => UAI_C_PURDY, PURDY_V => UAI_C_PURDY_V, PURDY_S => UAI_C_PURDY_S, ); sub _hash_of { my($self, $passphrase) = @_; return lgi_hpwd($self->{username}, uc($passphrase), $hpwd_alg_num{$self->{algorithm}}, $self->{salt}); } sub match { my($self, $passphrase) = @_; return $self->_passphrase_acceptable($passphrase) && $self->_hash_of($passphrase) eq $self->{hash}; } my %crypt_alg_num = ( PURDY => "1", PURDY_V => "2", PURDY_S => "3", ); sub as_crypt { my($self) = @_; return "\$VMS".$crypt_alg_num{$self->{algorithm}}."\$". $self->salt_hex.$self->hash_hex.$self->{username}; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/LANManagerHalf.pm000444001750001750 1347211713235576 24346 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::LANManagerHalf - passphrases using half the LAN Manager algorithm =head1 SYNOPSIS use Authen::Passphrase::LANManagerHalf; $ppr = Authen::Passphrase::LANManagerHalf->new( hash_hex => "855c3697d9979e78"); $ppr = Authen::Passphrase::LANManagerHalf->new( passphrase => "passphr"); $ppr = Authen::Passphrase::LANManagerHalf->from_crypt( '$LM$855c3697d9979e78'); $ppr = Authen::Passphrase::LANManagerHalf->from_rfc2307( '{CRYPT}$LM$855c3697d9979e78'); $hash = $ppr->hash; $hash_hex = $ppr->hash_hex; if($ppr->match($passphrase)) { ... $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates half of a passphrase hashed using the Microsoft LAN Manager hash function. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. For the complete LAN Manager hash function, see L. In a spectacularly bad design decision, the Microsoft LAN Manager hash function splits the passphrase into two parts and hashes them separately. It is therefore possible to separate the halves of a LAN Manager hash, and do things with them (such as crack them) separately. This class is about using such a hash half on its own. The half hash algorithm can be used on up to seven Latin-1 characters of passphrase. First the passphrase is folded to uppercase, and zero-padded to seven bytes. Then the seven bytes are used as a 56-bit DES key, to encrypt the fixed plaintext block "KGS!@#$%". The eight byte ciphertext block is the half hash. There is no salt. I Don't even think about using this seriously. It's an exceptionally weak design, flawed in pretty much every respect. =cut package Authen::Passphrase::LANManagerHalf; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Crypt::DES; our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::LANManagerHalf->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the LAN Manager half hash algorithm. The following attributes may be given: =over =item B The hash, as a string of 8 bytes. =item B The hash, as a string of 16 hexadecimal digits. =item B A passphrase that will be accepted. =back Either the hash or the passphrase must be given. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{8}\z# or croak "not a valid LAN Manager half hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_hex") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[0-9A-Fa-f]{16}\z# or croak "\"$value\" is not a valid ". "hex LAN Manager half hash"; $self->{hash} = pack("H*", $value); } elsif($attr eq "passphrase") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $self->_passphrase_acceptable($value) or croak "can't accept a passphrase exceeding". " seven bytes"; $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =item Authen::Passphrase::LANManagerHalf->from_crypt(PASSWD) Generates a new LAN Manager half passphrase recogniser object from a crypt string. The crypt string must consist of "B<$LM$>" followed by the hash in lowercase hexadecimal. =cut sub from_crypt { my($class, $passwd) = @_; if($passwd =~ /\A\$LM\$/) { $passwd =~ m#\A\$LM\$([0-9a-f]{16})\z# or croak "malformed \$LM\$ data"; my $hash = $1; return $class->new(hash_hex => $hash); } return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::LANManagerHalf->from_rfc2307(USERPASSWORD) Generates a new LAN Manager half passphrase recogniser object from an RFC 2307 string. The string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =back =head1 METHODS =over =item $ppr->hash Returns the hash value, as a string of 8 bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_hex Returns the hash value, as a string of 16 hexadecimal digits. =cut sub hash_hex { my($self) = @_; return unpack("H*", $self->{hash}); } =item $ppr->match(PASSPHRASE) =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. =cut sub _passphrase_acceptable { my($self, $passphrase) = @_; return $passphrase =~ /\A[\x00-\xff]{0,7}\z/; } sub _hash_of { my($self, $passphrase) = @_; $passphrase = uc($passphrase); $passphrase = "\0".$passphrase."\0\0\0\0\0\0\0\0"; my $key = ""; for(my $i = 0; $i != 8; $i++) { my $a = ord(substr($passphrase, $i, 1)); my $b = ord(substr($passphrase, $i+1, 1)); $key .= chr((($b >> $i) | ($a << (8-$i))) & 0xfe); } return Crypt::DES->new($key)->encrypt("KGS!\@#\$%"); } sub match { my($self, $passphrase) = @_; return $self->_passphrase_acceptable($passphrase) && $self->_hash_of($passphrase) eq $self->{hash}; } sub as_crypt { my($self) = @_; return "\$LM\$".$self->hash_hex; } =back =head1 SEE ALSO L, L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/Crypt16.pm000444001750001750 1725211713235576 23116 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::Crypt16 - passphrases using Ultrix crypt16 algorithm =head1 SYNOPSIS use Authen::Passphrase::Crypt16; $ppr = Authen::Passphrase::Crypt16->new( salt_base64 => "qi", hash_base64 => "8H8R7OM4xMUNMPuRAZxlY."); $ppr = Authen::Passphrase::Crypt16->new( salt_random => 12, passphrase => "passphrase"); $salt = $ppr->salt; $salt_base64 = $ppr->salt_base64_2; $hash = $ppr->hash; $hash_base64 = $ppr->hash_base64; $ppr0 = $ppr->first_half; $ppr1 = $ppr->second_half; if($ppr->match($passphrase)) { ... =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the "crypt16" hash function found in Ultrix and Tru64. Do not confuse this with the "bigcrypt" found on HP-UX, Digital Unix, and OSF/1 (for which see L). This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. This is a derivation of the original DES-based crypt function found on all Unices (see L). The first eight bytes of the passphrase are used as a DES key to encrypt the all-bits-zero block through 20 rounds of (12-bit) salted DES. (The standard crypt function does this, but with 25 encryption rounds instead of 20.) Then the next eight bytes, or the null string if the passphrase is eight bytes or shorter, are used as a DES key to encrypt the all-bits-zero block through 5 rounds of salted DES with the same salt. The two eight-byte ciphertexts are concatenated to form the sixteen-byte hash. A password hash of this scheme is conventionally represented in ASCII as a 24-character string using a base 64 encoding. The first two characters give the salt, the next eleven give the hash of the first half, and the last eleven give the hash of the second half. A hash thus encoded is used as a crypt string, on those systems where the crypt16 algorithm is part of crypt(), but the syntax clashes with that of bigcrypt. This module does not treat it as a crypt string syntax. Because the two halves of the passphrase are hashed separately, it is possible to manipulate (e.g., crack) a half hash in isolation. See L for handling of a single half. I This is a fatally flawed design, often providing I security than the plain DES scheme alone. Do not use seriously. =cut package Authen::Passphrase::Crypt16; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Authen::Passphrase::DESCrypt; use Carp qw(croak); use Crypt::UnixCrypt_XS 0.08 qw(base64_to_block base64_to_int12); use Data::Entropy::Algorithms 0.000 qw(rand_int); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTOR =over =item Authen::Passphrase::Crypt16->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the crypt16 hash algorithm. The following attributes may be given: =over =item B The salt, as an integer in the range [0, 4096). =item B The salt, as a string of two base 64 digits. =item B Causes salt to be generated randomly. The value given for this attribute must be 12, indicating generation of 12 bits of salt. The source of randomness may be controlled by the facility described in L. =item B The hash, as a string of 16 bytes. =item B The hash, as a string of 22 base 64 digits. =item B A passphrase that will be accepted. =back The salt must be given, and either the hash or the passphrase. =cut sub new { my $class = shift; my $self = bless({}, $class); my $salt; my $hash; my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "salt") { croak "salt specified redundantly" if defined $salt; croak "\"$value\" is not a valid salt" unless $value == int($value) && $value >= 0 && $value < 4096; $salt = $value; } elsif($attr eq "salt_base64") { croak "salt specified redundantly" if defined $salt; $value =~ m#\A[./0-9A-Za-z]{2}\z# or croak "\"$value\" is not a valid salt"; $salt = base64_to_int12($value); } elsif($attr eq "salt_random") { croak "salt specified redundantly" if defined $salt; croak "\"$value\" is not a valid salt size" unless $value == 12; $salt = rand_int(1 << $value); } elsif($attr eq "hash") { croak "hash specified redundantly" if defined($hash) || defined($passphrase); $value =~ m#\A[\x00-\xff]{16}\z# or croak "not a valid crypt16 hash"; $hash = $value; } elsif($attr eq "hash_base64") { croak "hash specified redundantly" if defined($hash) || defined($passphrase); $value =~ m#\A(?:[./0-9A-Za-z]{10}[.26AEIMQUYcgkosw]) {2}\z#x or croak "\"$value\" is not a valid ". "encoded hash"; $hash = base64_to_block(substr($value, 0, 11)). base64_to_block(substr($value, 11)); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if defined($hash) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } croak "salt not specified" unless defined $salt; if(defined $passphrase) { $self->{first_half} = Authen::Passphrase::DESCrypt ->new(nrounds => 20, salt => $salt, passphrase => substr($passphrase, 0, 8)); $self->{second_half} = Authen::Passphrase::DESCrypt ->new(nrounds => 5, salt => $salt, passphrase => length($passphrase) > 8 ? substr($passphrase, 8) : ""); } elsif(defined $hash) { $self->{first_half} = Authen::Passphrase::DESCrypt ->new(nrounds => 20, salt => $salt, hash => substr($hash, 0, 8)); $self->{second_half} = Authen::Passphrase::DESCrypt ->new(nrounds => 5, salt => $salt, hash => substr($hash, 8, 8)); } else { croak "hash not specified"; } return $self; } =back =head1 METHODS =over =item $ppr->salt Returns the salt, as a Perl integer. =cut sub salt { my($self) = @_; return $self->{first_half}->salt; } =item $ppr->salt_base64_2 Returns the salt, as a string of two base 64 digits. =cut sub salt_base64_2 { my($self) = @_; return $self->{first_half}->salt_base64_2; } =item $ppr->hash Returns the hash value, as a string of 16 bytes. =cut sub hash { my($self) = @_; return $self->{first_half}->hash.$self->{second_half}->hash; } =item $ppr->hash_base64 Returns the hash value, as a string of 22 base 64 digits. This is the concatenation of the base 64 encodings of the two hashes, rather than a base64 encoding of the combined hash. =cut sub hash_base64 { my($self) = @_; return $self->{first_half}->hash_base64. $self->{second_half}->hash_base64; } =item $ppr->first_half Returns the hash of the first half of the passphrase, as an L passphrase recogniser. =cut sub first_half { my($self) = @_; return $self->{first_half}; } =item $ppr->second_half Returns the hash of the second half of the passphrase, as an L passphrase recogniser. =cut sub second_half { my($self) = @_; return $self->{second_half}; } =item $ppr->match(PASSPHRASE) This method is part of the standard L interface. =cut sub match { my($self, $passphrase) = @_; return $self->{first_half}->match(substr($passphrase, 0, 8)) && $self->{second_half}->match( length($passphrase) > 8 ? substr($passphrase, 8) : ""); } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/PHPass.pm000444001750001750 2312011713235576 22773 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::PHPass - passphrases using the phpass algorithm =head1 SYNOPSIS use Authen::Passphrase::PHPass; $ppr = Authen::Passphrase::PHPass->new( cost => 10, salt => "NaClNaCl", hash_base64 => "ObRxTm/.EiiYN02xUeAQs/"); $ppr = Authen::Passphrase::PHPass->new( cost => 10, salt_random => 1, passphrase => "passphrase"); $ppr = Authen::Passphrase::PHPass->from_crypt( '$P$8NaClNaClObRxTm/.EiiYN02xUeAQs/'); $ppr = Authen::Passphrase::PHPass->from_rfc2307( '{CRYPT}$P$8NaClNaClObRxTm/.EiiYN02xUeAQs/'); $cost = $ppr->cost; $cost_base64 = $ppr->cost_base64; $cost = $ppr->nrounds_log2; $cost_base64 = $ppr->nrounds_log2_base64; $salt = $ppr->salt; $hash = $ppr->hash; $hash_base64 = $ppr->hash_base64; if($ppr->match($passphrase)) { ... $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the phpass algorithm invented by Solar Designer and described at L. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The phpass algorithm is based on the MD5 message digest algorithm. There is an eight-byte salt, which is conventionally restricted to consist of base 64 digits. There is also a cost parameter that controls the expense of hashing. First the salt and passphrase are concatenated and hashed by MD5. Then, 2^cost times, the hash from the previous stage is concatenated with the passphrase and hashed by MD5. The passphrase hash is the output from the final iteration. The passphrase hash is represented in ASCII using the crypt format with prefix "B<$P$>". The first character after the format prefix is a base 64 digit giving the cost parameter. The next eight characters are the salt. The salt is followed by 22 base 64 digits giving the hash. The base 64 digits are "B<.>", "B", "B<0>" to "B<9>", "B" to "B", "B" to "B" (in ASCII order). =cut package Authen::Passphrase::PHPass; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Data::Entropy::Algorithms 0.000 qw(rand_bits); use Digest::MD5 1.99_53 (); our $VERSION = "0.008"; use parent "Authen::Passphrase"; my $base64_digits = "./0123456789ABCDEFGHIJKLMNOPQRST". "UVWXYZabcdefghijklmnopqrstuvwxyz"; sub _en_base64($) { my($bytes) = @_; my $nbytes = length($bytes); my $npadbytes = 2 - ($nbytes + 2) % 3; $bytes .= "\0" x $npadbytes; my $digits = ""; for(my $i = 0; $i < $nbytes; $i += 3) { my $v = ord(substr($bytes, $i, 1)) | (ord(substr($bytes, $i+1, 1)) << 8) | (ord(substr($bytes, $i+2, 1)) << 16); $digits .= substr($base64_digits, $v & 0x3f, 1) . substr($base64_digits, ($v >> 6) & 0x3f, 1) . substr($base64_digits, ($v >> 12) & 0x3f, 1) . substr($base64_digits, ($v >> 18) & 0x3f, 1); } substr $digits, -$npadbytes, $npadbytes, ""; return $digits; } sub _de_base64($) { my($digits) = @_; my $ndigits = length($digits); my $npadbytes = 3 - ($ndigits + 3) % 4; $digits .= "." x $npadbytes; my $bytes = ""; for(my $i = 0; $i < $ndigits; $i += 4) { my $v = index($base64_digits, substr($digits,$i,1)) | (index($base64_digits, substr($digits,$i+1,1)) << 6) | (index($base64_digits, substr($digits,$i+2,1)) << 12) | (index($base64_digits, substr($digits,$i+3,1)) << 18); $bytes .= chr($v & 0xff) . chr(($v >> 8) & 0xff) . chr(($v >> 16) & 0xff); } substr $bytes, -$npadbytes, $npadbytes, ""; return $bytes; } =head1 CONSTRUCTORS =over =item Authen::Passphrase::PHPass->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the phpass algorithm. The following attributes may be given: =over =item B Base-two logarithm of the number of hashing rounds to perform. =item B Base-two logarithm of the number of hashing rounds to perform, expressed as a single base 64 digit. =item B Synonym for B. =item B Synonym for B. =item B The salt, as an eight-byte string. =item B Causes salt to be generated randomly. The value given for this attribute is ignored. The salt will be a string of eight base 64 digits. The source of randomness may be controlled by the facility described in L. =item B The hash, as a 16-byte string. =item B The hash, as a string of 22 base 64 digits. =item B A passphrase that will be accepted. =back The cost and salt must be given, and either the hash or the passphrase. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "cost" || $attr eq "nrounds_log2") { croak "cost specified redundantly" if exists $self->{cost}; croak "\"$value\" is not a valid cost parameter" unless $value == int($value) && $value >= 0 && $value <= 30; $self->{cost} = 0+$value; } elsif($attr eq "cost_base64" || $attr eq "nrounds_log2_base64") { croak "cost specified redundantly" if exists $self->{cost}; croak "\"$value\" is not a valid cost parameter" unless $value =~ m#\A[./0-9A-S]\z#; $self->{cost} = index($base64_digits, $value); } elsif($attr eq "salt") { croak "salt specified redundantly" if exists $self->{salt}; $value =~ m#\A[\x00-\xff]{8}\z# or croak "\"$value\" is not a valid salt"; $self->{salt} = "$value"; } elsif($attr eq "salt_random") { croak "salt specified redundantly" if exists $self->{salt}; $self->{salt} = _en_base64(rand_bits(48)); } elsif($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{16}\z# or croak "not a valid raw hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_base64") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[./0-9A-Za-z]{21}[./01]\z# or croak "\"$value\" is not a valid hash"; $self->{hash} = _de_base64($value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } croak "cost not specified" unless exists $self->{cost}; croak "salt not specified" unless exists $self->{salt}; $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =item Authen::Passphrase::PHPass->from_crypt(PASSWD) Generates a new phpass passphrase recogniser object from a crypt string. The crypt string must consist of "B<$P$>", one base 64 character encoding the cost, the salt, then 22 base 64 digits giving the hash. The salt must be exactly 8 characters long, and cannot contain any character that cannot appear in a crypt string. =cut sub from_crypt { my($class, $passwd) = @_; if($passwd =~ /\A\$P\$/) { $passwd =~ m#\A\$P\$([./0-9A-Za-z])([!-9;-~]{8}) ([./0-9A-Za-z]{22})\z#x or croak "malformed \$P\$ data"; my($cost, $salt, $hash) = ($1, $2, $3); return $class->new(cost_base64 => $cost, salt => $salt, hash_base64 => $hash); } return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::PHPass->from_rfc2307(USERPASSWORD) Generates a new phpass passphrase recogniser object from an RFC 2307 string. The string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =back =head1 METHODS =over =item $ppr->cost Returns the base-two logarithm of the number of hashing rounds that will be performed. =cut sub cost { my($self) = @_; return $self->{cost}; } =item $ppr->cost_base64 Returns the base-two logarithm of the number of hashing rounds that will be performed, expressed as a single base 64 digit. =cut sub cost_base64 { my($self) = @_; return substr($base64_digits, $self->{cost}, 1); } =item $ppr->nrounds_log2 Synonym for L. =cut *nrounds_log2 = \&cost; =item $ppr->nrounds_log2_base64 Synonym for L. =cut *nrounds_log2_base64 = \&cost_base64; =item $ppr->salt Returns the salt, as a string of eight bytes. =cut sub salt { my($self) = @_; return $self->{salt}; } =item $ppr->hash Returns the hash value, as a string of 16 bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_base64 Returns the hash value, as a string of 22 base 64 digits. =cut sub hash_base64 { my($self) = @_; return _en_base64($self->{hash}); } =item $ppr->match(PASSPHRASE) =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. =cut sub _hash_of { my($self, $passphrase) = @_; my $ctx = Digest::MD5->new; $ctx->add($self->{salt}); $ctx->add($passphrase); my $hash = $ctx->digest; for(my $i = 1 << $self->{cost}; $i--; ) { $ctx = Digest::MD5->new; $ctx->add($hash); $ctx->add($passphrase); $hash = $ctx->digest; } return $hash; } sub match { my($self, $passphrase) = @_; return $self->_hash_of($passphrase) eq $self->{hash}; } sub as_crypt { my($self) = @_; croak "can't put this salt into a crypt string" if $self->{salt} =~ /[^!-9;-~]/; return "\$P\$".$self->cost_base64.$self->{salt}.$self->hash_base64; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/DESCrypt.pm000444001750001750 3451211713235576 23301 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::DESCrypt - passphrases using the DES-based Unix crypt() =head1 SYNOPSIS use Authen::Passphrase::DESCrypt; $ppr = Authen::Passphrase::DESCrypt->new( salt_base64 => "my", hash_base64 => "TYK.j.88/9s"); $ppr = Authen::Passphrase::DESCrypt->new( salt_random => 12, passphrase => "passphrase"); $ppr = Authen::Passphrase::DESCrypt ->from_crypt('myTYK.j.88/9s'); $ppr = Authen::Passphrase::DESCrypt->new( fold => 1, initial => "xyzzy!!!", nrounds => 500, salt_base64 => "quux", hash_base64 => "QCKcHlgVsRY"); $fold = $ppr->fold; $initial = $ppr->initial; $initial_base64 = $ppr->initial_base64; $nrounds = $ppr->nrounds; $nrounds_base64 = $ppr->nrounds_base64_4; $salt = $ppr->salt; $salt_base64 = $ppr->salt_base64_2; $salt_base64 = $ppr->salt_base64_4; $hash = $ppr->hash; $hash_base64 = $ppr->hash_base64; if($ppr->match($passphrase)) { ... $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using some form of the DES-based Unix crypt() hash function. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The crypt() function in a modern Unix actually supports several different passphrase schemes. That is not what this class is about. This class is concerned only with one family of schemes, variants of the DES-based scheme that crypt() originally implemented, which confusingly is usually referred to merely as "crypt()". To handle the whole range of passphrase schemes supported by the modern crypt(), see the L constructor and the L method in L. I this password scheme is weak by modern standards, and in any case does not support a large password space. Cracking crypt()ed passwords has been a routine activity since the early 1990s. This scheme is supported for compatibility reasons only, and should not be used except when compatibility is required. Do not use this in the design of any new system or for new passwords in any system that supports better passphrase schemes. =head2 The traditional DES-based Unix crypt() password scheme The traditional Unix crypt() password scheme is based on the DES block encryption algorithm. Using the password as a 56-bit key, it passes a 64-bit data block, initialised to zero, through the encryption function 25 times, and the hash is the 64-bit output of this process. A 12-bit salt is used to tweak the encryption algorithm. The 56-bit key is extracted from the password in a very poor way. Only the first eight bytes of the password are used, and any remainder is ignored. This makes it impossible to use a passphrase, rather than a password, hence the terminology in this section. Of the eight bytes used, the top bit is also ignored; this function hails from the days of pure ASCII. A password hash of this scheme is conventionally represented in ASCII as a 13-character string using a base 64 encoding. The base 64 digits are "B<.>", "B", "B<0>" to "B<9>", "B" to "B", "B" to "B" (in ASCII order). The first two characters give the 12-bit salt. The remaining eleven characters give the 64-bit hash. Because the base 64 encoding can represent 66 bits in eleven digits, more than the 64 required, the last character of the string can only take sixteen of the base 64 digit values. =head2 Variant DES-based Unix crypt() passphrase schemes To make password cracking more difficult, historically some Unix sites modified the crypt() function to be incompatible with the standard one. This was easily achieved by initialising the data block to something other than the standard all-bits-zero. Another variation used was to increase the number of encryption rounds, which makes cracking take longer in addition to being non-standard. Password hashes on such a system looked normal but were not interoperable with standard crypt() implementations. To interpret them properly it is necessary to know the modified parameters. BSDi standardised an extended DES-based scheme. The salt is extended to 24 bits, and the number of encryption rounds is variable. Passphrases longer than 8 characters are handled by an additional step that folds (hashes) them down to 8 characters, rather than just throwing away the characters after the eighth. Passphrase hashes in this scheme are conventionally represented in ASCII as a "B<_>" followed by 19 characters of base 64. The first four base 64 digits give the number of encryption rounds, the next four give the salt, and the remaining eleven give the hash. =cut package Authen::Passphrase::DESCrypt; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Crypt::UnixCrypt_XS 0.08 qw( fold_password crypt_rounds base64_to_block block_to_base64 base64_to_int24 int24_to_base64 base64_to_int12 int12_to_base64 ); use Data::Entropy::Algorithms 0.000 qw(rand_int); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::DESCrypt->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the generalised DES-based crypt() algorithm. The following attributes may be given: =over =item B Truth value indicating whether the BSDi passphrase folding scheme should be used for long passphrases. Default false, for compatibility with the original DES-based scheme. =item B The initial data block to encrypt, as a string of exactly eight bytes. Default all bits zero, for compatibility with the original DES-based scheme. =item B The initial data block to encrypt, as a string of eleven base 64 digits. =item B The number of encryption rounds to use, as a Perl integer. Default 25, for compatibility with the original DES-based scheme. =item B The number of encryption rounds to use, as a string of four base 64 digits. =item B The salt, as an integer in the range [0, 16777216). =item B The salt, as a string of two or four base 64 digits. =item B Causes salt to be generated randomly. The value given for this attribute must be either 12 or 24, giving the number of bits of salt to generate. The source of randomness may be controlled by the facility described in L. =item B The hash (output of encryption), as a string of exactly eight bytes. =item B The hash, as a string of eleven base 64 digits. =item B A passphrase that will be accepted. =back The salt must be given, and either the hash or the passphrase. The other parameters default to those used in the original DES-based crypt(). =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "fold") { croak "foldness specified redundantly" if exists $self->{fold}; $self->{fold} = !!$value; } elsif($attr eq "initial") { croak "initial block specified redundantly" if exists $self->{initial}; $value =~ m#\A[\x00-\xff]{8}\z# or croak "not a valid raw block"; $self->{initial} = "$value"; } elsif($attr eq "initial_base64") { croak "initial block specified redundantly" if exists $self->{initial}; $value =~ m#\A[./0-9A-Za-z]{10}[.26AEIMQUYcgkosw]\z# or croak "\"$value\" is not a valid ". "encoded block"; $self->{initial} = base64_to_block($value); } elsif($attr eq "nrounds") { croak "number of rounds specified redundantly" if exists $self->{nrounds}; croak "\"$value\" is not a valid number of rounds" unless $value == int($value) && $value >= 0; $self->{nrounds} = 0+$value; } elsif($attr eq "nrounds_base64") { croak "number of rounds specified redundantly" if exists $self->{nrounds}; croak "\"$value\" is not a valid number of rounds" unless $value =~ m#\A[./0-9A-Za-z]{4}\z#; $self->{nrounds} = base64_to_int24($value); } elsif($attr eq "salt") { croak "salt specified redundantly" if exists $self->{salt}; croak "\"$value\" is not a valid salt" unless $value == int($value) && $value >= 0 && $value < 16777216; $self->{salt} = 0+$value; } elsif($attr eq "salt_base64") { croak "salt specified redundantly" if exists $self->{salt}; $value =~ m#\A(?:[./0-9A-Za-z]{2}|[./0-9A-Za-z]{4})\z# or croak "\"$value\" is not a valid salt"; $self->{salt} = length($value) == 2 ? base64_to_int12($value) : base64_to_int24($value); } elsif($attr eq "salt_random") { croak "salt specified redundantly" if exists $self->{salt}; croak "\"$value\" is not a valid salt size" unless $value == 12 || $value == 24; $self->{salt} = rand_int(1 << $value); } elsif($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{8}\z# or croak "not a valid raw hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_base64") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[./0-9A-Za-z]{10}[.26AEIMQUYcgkosw]\z# or croak "\"$value\" is not a valid ". "encoded hash"; $self->{hash} = base64_to_block($value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } $self->{fold} = !!0 unless exists $self->{fold}; $self->{initial} = "\0\0\0\0\0\0\0\0" unless exists $self->{initial}; $self->{nrounds} = 25 unless exists $self->{nrounds}; croak "salt not specified" unless exists $self->{salt}; $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =item Authen::Passphrase::DESCrypt->from_crypt(PASSWD) Generates a new passphrase recogniser object using the DES-based crypt() algorithm, from a crypt string. Two forms of crypt string are supported. The first form of crypt string must consist of 13 base 64 digits. The first two give the salt, and the next eleven give the hash. Long passphrases are not folded, the initial block is all bits zero, and 25 encryption rounds are performed. The second form of crypt string must consist of an "B<_>" followed by 19 base 64 digits. The first four give the number of encryption rounds, the next four give the salt, and the next eleven give the hash. Long passphrases are folded, and the initial block is all bits zero. =cut sub from_crypt { my($class, $passwd) = @_; if($passwd =~ /\A[^\$].{12}\z/s) { $passwd =~ m#\A([./0-9A-Za-z]{2})([./0-9A-Za-z]{11})\z# or croak "malformed DES crypt data"; my($salt, $hash) = ($1, $2); return $class->new(salt_base64 => $salt, hash_base64 => $hash); } elsif($passwd =~ /\A_.{19}\z/s) { $passwd =~ m#\A_([./0-9A-Za-z]{4})([./0-9A-Za-z]{4}) ([./0-9A-Za-z]{11})\z#x or croak "malformed _ data"; my($nr, $salt, $hash) = ($1, $2, $3); return $class->new(fold => 1, nrounds_base64 => $nr, salt_base64 => $salt, hash_base64 => $hash); } return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::DESCrypt->from_rfc2307(USERPASSWORD) Generates a new passphrase recogniser object using the DES-based crypt() algorithm, from an RFC 2307 string. The string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =back =head1 METHODS =over =item $ppr->fold Returns a truth value indicating whether passphrase folding is used. =cut sub fold { my($self) = @_; return $self->{fold}; } =item $ppr->initial Returns the initial block, as a string of eight bytes. =cut sub initial { my($self) = @_; return $self->{initial}; } =item $ppr->initial_base64 Returns the initial block, as a string of eleven base 64 digits. =cut sub initial_base64 { my($self) = @_; return block_to_base64($self->{initial}); } =item $ppr->nrounds Returns the number of encryption rounds, as a Perl integer. =cut sub nrounds { my($self) = @_; return $self->{nrounds}; } =item $ppr->nrounds_base64_4 Returns the number of encryption rounds, as a string of four base 64 digits. =cut sub nrounds_base64_4 { my($self) = @_; return int24_to_base64($self->{nrounds}); } =item $ppr->salt Returns the salt, as a Perl integer. =cut sub salt { my($self) = @_; return $self->{salt}; } =item $ppr->salt_base64_2 Returns the salt, as a string of two base 64 digits. Cs if it doesn't fit into two digits. =cut sub salt_base64_2 { my($self) = @_; my $salt = $self->{salt}; croak "salt $salt doesn't fit into two digits" if $salt >= 4096; return int12_to_base64($salt); } =item $ppr->salt_base64_4 Returns the salt, as a string of four base 64 digits. =cut sub salt_base64_4 { my($self) = @_; return int24_to_base64($self->{salt}); } =item $ppr->hash Returns the hash value, as a string of eight bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_base64 Returns the hash value, as a string of eleven base 64 digits. =cut sub hash_base64 { my($self) = @_; return block_to_base64($self->{hash}); } =item $ppr->match(PASSPHRASE) =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. =cut sub _hash_of { my($self, $passphrase) = @_; $passphrase = fold_password($passphrase) if $self->{fold}; return crypt_rounds($passphrase, $self->{nrounds}, $self->{salt}, $self->{initial}); } sub match { my($self, $passphrase) = @_; return $self->_hash_of($passphrase) eq $self->{hash}; } sub as_crypt { my($self) = @_; if(!$self->{fold} && $self->{initial} eq "\0\0\0\0\0\0\0\0" && $self->{nrounds} == 25 && $self->{salt} < 4096) { return $self->salt_base64_2.$self->hash_base64; } elsif($self->{fold} && $self->{initial} eq "\0\0\0\0\0\0\0\0") { return "_".$self->nrounds_base64_4.$self->salt_base64_4. $self->hash_base64; } else { croak "passphrase can't be expressed as a crypt string"; } } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/AcceptAll.pm000444001750001750 526711713235576 23461 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::AcceptAll - accept any passphrase =head1 SYNOPSIS use Authen::Passphrase::AcceptAll; $ppr = Authen::Passphrase::AcceptAll->new; $ppr = Authen::Passphrase::AcceptAll ->from_crypt(""); $ppr = Authen::Passphrase::AcceptAll ->from_rfc2307("{CRYPT}"); if($ppr->match($passphrase)) { ... $passphrase = $ppr->passphrase; $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class is a passphrase recogniser that accepts any passphrase whatsoever. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. This type of passphrase recogniser is obviously of no use at all in controlling access to any resource. Its use is to permit a resource to be public in a system that expects some type of passphrase access control. =cut package Authen::Passphrase::AcceptAll; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); our $VERSION = "0.008"; use parent "Authen::Passphrase"; # There is only one object of this class, and its content is # insignificant. =head1 CONSTRUCTORS =over =item Authen::Passphrase::AcceptAll->new Returns an accept-all passphrase recogniser object. The same object is returned from each call. =cut { my $singleton = bless({}); sub new { $singleton } } =item Authen::Passphrase::AcceptAll->from_crypt("") Returns an accept-all passphrase recogniser object. The same object is returned from each call. The argument must be the empty string. =cut sub from_crypt { my($class, $passwd) = @_; return $class->new if $passwd eq ""; return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::AcceptAll->from_rfc2307(USERPASSWORD) Generates a new accept-all passphrase recogniser object from an RFC 2307 string. The string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =back =head1 METHODS =over =item $ppr->match(PASSPHRASE) =item $ppr->passphrase =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. The L method always returns true, and the L method returns the empty string (the shortest of the infinite number of correct passphrases). =cut sub match { 1 } sub passphrase { "" } sub as_crypt { "" } =back =head1 SEE ALSO L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/RejectAll.pm000444001750001750 532111713235576 23465 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::RejectAll - reject all passphrases =head1 SYNOPSIS use Authen::Passphrase::RejectAll; $ppr = Authen::Passphrase::RejectAll->new; $ppr = Authen::Passphrase::RejectAll ->from_crypt("*"); $ppr = Authen::Passphrase::RejectAll ->from_rfc2307("{CRYPT}*"); if($ppr->match($passphrase)) { ... $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class is a passphrase recogniser that accepts any passphrase whatsoever. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. This type of passphrase recogniser is obviously of no use at all in controlling access to any resource. Its use is to permit a resource to be completely inaccessible in a system that expects some type of passphrase access control. =cut package Authen::Passphrase::RejectAll; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); our $VERSION = "0.008"; use parent "Authen::Passphrase"; # There is only one object of this class, and its content is # insignificant. =head1 CONSTRUCTORS =over =item Authen::Passphrase::RejectAll->new Returns a reject-all passphrase recogniser object. The same object is returned from each call. =cut { my $singleton = bless({}); sub new { $singleton } } =item Authen::Passphrase::RejectAll->from_crypt(PASSWD) Returns a reject-all passphrase recogniser object. The same object is returned from each call. The argument, a crypt string, must be between one and twelve (inclusive) characters long and must not start with "B<$>". =cut sub from_crypt { my($class, $passwd) = @_; if($passwd =~ /\A[^\$].{0,11}\z/s) { $passwd =~ /\A[!-#\%-9;-~][!-9;-~]{0,11}\z/ or croak "malformed reject-all crypt data"; return $class->new; } return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::RejectAll->from_rfc2307(USERPASSWORD) Generates a new reject-all passphrase recogniser object from an RFC 2307 string. The string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =back =head1 METHODS =over =item $ppr->match(PASSPHRASE) =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. The L method always returns false. =cut sub match { 0 } sub as_crypt { "*" } =back =head1 SEE ALSO L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/MySQL323.pm000444001750001750 755011713235576 23023 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::MySQL323 - passphrases using the MySQL v3.23 algorithm =head1 SYNOPSIS use Authen::Passphrase::MySQL323; $ppr = Authen::Passphrase::MySQL323->new( hash_hex => "2af8a0a82c8f9086"); $ppr = Authen::Passphrase::MySQL323->new( passphrase => "passphrase"); $hash = $ppr->hash; $hash_hex = $ppr->hash_hex; if($ppr->match($passphrase)) { ... =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the algorithm used by MySQL from version 3.23. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The MySQL v3.23 hash scheme is composed entirely of linear operations. It accepts an arbitrarily long passphrase, and ignores all space and tab characters. No salt is used. 62 bits of hash are generated. Each character influences only a minority of the result bits, so similar passphrases of the same length have noticeably similar hashes. In MySQL the hash is represented as a string of sixteen lowercase hexadecimal digits. I This is not a serious cryptographic algorithm. Do not use for any security purpose. =cut package Authen::Passphrase::MySQL323; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Crypt::MySQL 0.03 qw(password); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTOR =over =item Authen::Passphrase::MySQL323->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the MySQL v3.23 algorithm. The following attributes may be given: =over =item B The hash, as a string of eight bytes. The first and fifth bytes must have their top bit clear. =item B The hash, as a string of 16 hexadecimal digits. =item B A passphrase that will be accepted. =back Either the hash or the passphrase must be given. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A(?:[\x00-\x7f][\x00-\xff]{3}){2}\z# or croak "not a valid MySQL v3.23 hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_hex") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A(?:[0-7][0-9A-Fa-f]{7}){2}\z# or croak "\"$value\" is not a valid ". "hex MySQL v3.23 hash"; $self->{hash} = pack("H*", $value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =back =head1 METHODS =over =item $ppr->hash Returns the hash value, as a string of eight bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_hex Returns the hash value, as a string of 16 hexadecimal digits. =cut sub hash_hex { my($self) = @_; return unpack("H*", $self->{hash}); } =item $ppr->match(PASSPHRASE) This method is part of the standard L interface. =cut sub _hash_of { my($self, $passphrase) = @_; return pack("H*", password($passphrase)); } sub match { my($self, $passphrase) = @_; return $self->_hash_of($passphrase) eq $self->{hash}; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/BlowfishCrypt.pm000444001750001750 2442511713235576 24445 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::BlowfishCrypt - passphrases using the Blowfish-based Unix crypt() =head1 SYNOPSIS use Authen::Passphrase::BlowfishCrypt; $ppr = Authen::Passphrase::BlowfishCrypt->new( cost => 8, salt => "sodium__chloride", hash_base64 => "BPZijhMHLvPeNMHd6XwZyNamOXVBTPi"); $ppr = Authen::Passphrase::BlowfishCrypt->new( cost => 8, salt_random => 1, passphrase => "passphrase"); $ppr = Authen::Passphrase::BlowfishCrypt->from_crypt( '$2a$08$a07iYVTrVz7hYEvtakjiXOB'. 'PZijhMHLvPeNMHd6XwZyNamOXVBTPi'); $ppr = Authen::Passphrase::BlowfishCrypt->from_rfc2307( '{CRYPT}$2a$08$a07iYVTrVz7hYEvtakjiXOB'. 'PZijhMHLvPeNMHd6XwZyNamOXVBTPi'); $key_nul = $ppr->key_nul; $cost = $ppr->cost; $cost = $ppr->keying_nrounds_log2; $salt = $ppr->salt; $salt_base64 = $ppr->salt_base64; $hash = $ppr->hash; $hash_base64 = $ppr->hash_base64; if($ppr->match($passphrase)) { ... $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the Blowfish-based Unix crypt() hash function, known as "bcrypt". This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The crypt() function in a modern Unix actually supports several different passphrase schemes. This class is concerned only with one particular scheme, a Blowfish-based algorithm designed by Niels Provos and David Mazieres for OpenBSD. To handle the whole range of passphrase schemes supported by the modern crypt(), see the L constructor and the L method in L. The Blowfish-based crypt() scheme uses a variant of Blowfish called "Eksblowfish", for "expensive key schedule Blowfish". It has the cryptographic strength of Blowfish, and a very slow key setup phase to resist brute-force attacks. There is a "cost" parameter to the scheme: the length of key setup is proportional to 2^cost. There is a 128-bit salt. Up to 72 characters of the passphrase will be used; any more will be ignored. The cost, salt, and passphrase are all used to (very slowly) key Eksblowfish. Once key setup is done, the string "OrpheanBeholderScryDoubt" (three Blowfish blocks long) is encrypted 64 times in ECB mode. The final byte of the ciphertext is then dropped, yielding a 23-byte hash. In the crypt() function the salt and hash are represented in ASCII using a base 64 encoding. The base 64 digits are "B<.>", "B", "B" to "B", "B" to "B", "B<0>" to "B<9>" (in that order). The 16-byte salt is represented as 22 base 64 digits, and the 23-byte hash as 31 base 64 digits. This algorithm is intended for situations where the efficiency of a brute force attack is a concern. It is suitable for use in new applications where this requirement exists. If that is not a concern, and it suffices to merely make brute force the most efficient attack, see L for more efficient hash algorithms. Choice of the cost parameter is critical, due to the need to trade off expense of brute-force attack against speed of legitimate passphrase verification. A traditional target is that verification should take about one second on widely-available hardware. (Algorithms that are concerned about brute force speed but lack a cost parameter have often aimed for this, with respect to hardware available at the time of the algorithm's introduction.) As of 2011, this is achieved with a cost parameter around 14. =cut package Authen::Passphrase::BlowfishCrypt; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Crypt::Eksblowfish::Bcrypt 0.008 qw(bcrypt_hash en_base64 de_base64); use Data::Entropy::Algorithms 0.000 qw(rand_bits); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::BlowfishCrypt->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the Blowfish-based crypt() algorithm. The following attributes may be given: =over =item B Truth value indicating whether to append a NUL to the passphrase before using it as a key. The algorithm as originally devised does not do this, but it was later modified to do it. The version that does append NUL is to be preferred. Default true. =item B Base-two logarithm of the number of keying rounds to perform. =item B Synonym for B. =item B The salt, as a 16-byte string. =item B The salt, as a string of 22 base 64 digits. =item B Causes salt to be generated randomly. The value given for this attribute is ignored. The source of randomness may be controlled by the facility described in L. =item B The hash, as a 23-byte string. =item B The hash, as a string of 31 base 64 digits. =item B A passphrase that will be accepted. =back The cost and salt must be given, and either the hash or the passphrase. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "key_nul") { croak "foldness specified redundantly" if exists $self->{fold}; $self->{key_nul} = !!$value; } elsif($attr eq "cost" || $attr eq "keying_nrounds_log2") { croak "cost specified redundantly" if exists $self->{cost}; croak "\"$value\" is not a valid cost parameter" unless $value == int($value) && $value >= 0; $self->{cost} = 0+$value; } elsif($attr eq "salt") { croak "salt specified redundantly" if exists $self->{salt}; $value =~ m#\A[\x00-\xff]{16}\z# or croak "\"$value\" is not a valid raw salt"; $self->{salt} = "$value"; } elsif($attr eq "salt_base64") { croak "salt specified redundantly" if exists $self->{salt}; croak "\"$value\" is not a valid salt" unless length($value) == 22; $self->{salt} = de_base64($value); } elsif($attr eq "salt_random") { croak "salt specified redundantly" if exists $self->{salt}; $self->{salt} = rand_bits(128); } elsif($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{23}\z# or croak "not a valid raw hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_base64") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); croak "\"$value\" is not a valid hash" unless length($value) == 31; $self->{hash} = de_base64($value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } $self->{key_nul} = !!1 unless exists $self->{key_nul}; croak "cost not specified" unless exists $self->{cost}; croak "salt not specified" unless exists $self->{salt}; $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =item Authen::Passphrase::BlowfishCrypt->from_crypt(PASSWD) Generates a new passphrase recogniser object using the Blowfish-based crypt() algorithm, from a crypt string. The crypt string must start with "B<$2$>" for the version that does not append NUL to the key, or "B<$2a$>" for the version that does. The next two characters must be decimal digits giving the cost parameter. This must be followed by "B<$>", 22 base 64 digits giving the salt, and finally 31 base 64 digits giving the hash. =cut sub from_crypt { my($class, $passwd) = @_; if($passwd =~ /\A(\$2a?\$)/) { $passwd =~ m#\A\$2(a?)\$([0-9]{2})\$ ([./A-Za-z0-9]{22})([./A-Za-z0-9]{31})\z#x or croak "malformed $1 data"; my($kn, $cost, $salt, $hash) = ($1, $2, $3, $4); return $class->new(key_nul => $kn, cost => $cost, salt_base64 => $salt, hash_base64 => $hash); } return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::BlowfishCrypt->from_rfc2307(USERPASSWORD) Generates a new passphrase recogniser object using the Blowfish-based crypt() algorithm, from an RFC 2307 string. The string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =back =head1 METHODS =over =item $ppr->key_nul Returns a truth value indicating whether a NUL will be appended to the passphrase before using it as a key. =cut sub key_nul { my($self) = @_; return $self->{key_nul}; } =item $ppr->cost Returns the base-two logarithm of the number of keying rounds that will be performed. =cut sub cost { my($self) = @_; return $self->{cost}; } =item $ppr->keying_nrounds_log2 Synonym for L. =cut *keying_nrounds_log2 = \&cost; =item $ppr->salt Returns the salt, as a string of sixteen bytes. =cut sub salt { my($self) = @_; return $self->{salt}; } =item $ppr->salt_base64 Returns the salt, as a string of 22 base 64 digits. =cut sub salt_base64 { my($self) = @_; return en_base64($self->{salt}); } =item $ppr->hash Returns the hash value, as a string of 23 bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_base64 Returns the hash value, as a string of 31 base 64 digits. =cut sub hash_base64 { my($self) = @_; return en_base64($self->{hash}); } =item $ppr->match(PASSPHRASE) =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. =cut sub _hash_of { my($self, $passphrase) = @_; return bcrypt_hash({ key_nul => $self->{key_nul}, cost => $self->{cost}, salt => $self->{salt}, }, $passphrase); } sub match { my($self, $passphrase) = @_; return $self->_hash_of($passphrase) eq $self->{hash}; } sub as_crypt { my($self) = @_; croak "passphrase can't be expressed as a crypt string" if $self->{cost} > 99; return sprintf("\$2%s\$%02d\$%s%s", $self->key_nul ? "a" : "", $self->cost, $self->salt_base64, $self->hash_base64); } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/BigCrypt.pm000444001750001750 1730211713235576 23365 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::BigCrypt - passphrases using bigcrypt algorithm =head1 SYNOPSIS use Authen::Passphrase::BigCrypt; $ppr = Authen::Passphrase::BigCrypt->new( salt_base64 => "qi", hash_base64 => "yh4XPJGsOZ2MEAyLkfWqeQ"); $ppr = Authen::Passphrase::BigCrypt->new( salt_random => 12, passphrase => "passphrase"); $salt = $ppr->salt; $salt_base64 = $ppr->salt_base64_2; $hash = $ppr->hash; $hash_base64 = $ppr->hash_base64; $pprs = $ppr->sections; if($ppr->match($passphrase)) { ... =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the "bigcrypt" hash function found in HP-UX, Digital Unix, OSF/1, and some other flavours of Unix. Do not confuse this with the "crypt16" found on Ultrix and Tru64 (for which see L). This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. This is a derivation of the original DES-based crypt function found on all Unices (see L). The first eight bytes of the passphrase are used as a DES key to encrypt the all-bits-zero block through 25 rounds of (12-bit) salted DES, just like the original crypt. Then, if the passphrase is longer than eight bytes, the next eight bytes are used as a DES key to encrypt the all-bits-zero block through 25 rounds of salted DES, using as salt the first 12 bits of the hash of the first section. Then, if the passphrase is longer than sixteen bytes, the next eight bytes are used, with salt consisting of the first 12 bits of the hash of the second section. This repeats until the entire passphrase has been used. The hashes of all the sections are concatenated to form the final hash. A password hash of this scheme is conventionally represented in ASCII using the base 64 encoding of the underlying DES-based crypt function. The first two characters give the salt for the first section, the next eleven give the hash of the first section, the next eleven give the hash of the second section, and so on. A hash thus encoded is used as a crypt string, on those systems where the bigcrypt algorithm is part of crypt(), but the syntax clashes with that of crypt16. This module does not treat it as a crypt string syntax. Because the sections of the passphrase are hashed separately, it is possible to manipulate (e.g., crack) a section hash in isolation. See L for handling of a single section. I This is a fatally flawed design, often providing I security than the plain DES scheme alone. Do not use seriously. =cut package Authen::Passphrase::BigCrypt; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Authen::Passphrase::DESCrypt; use Carp qw(croak); use Crypt::UnixCrypt_XS 0.08 qw(base64_to_block base64_to_int12); use Data::Entropy::Algorithms 0.000 qw(rand_int); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTOR =over =item Authen::Passphrase::BigCrypt->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the bigcrypt hash algorithm. The following attributes may be given: =over =item B The salt for the first section, as an integer in the range [0, 4096). =item B The salt for the first section, as a string of two base 64 digits. =item B Causes salt for the first section to be generated randomly. The value given for this attribute must be 12, indicating generation of 12 bits of salt. The source of randomness may be controlled by the facility described in L. =item B The hash, as a string of bytes. =item B The hash, as a string of base 64 digits. =item B A passphrase that will be accepted. =back The salt for the first section must be given, and either the hash or the passphrase. =cut sub new { my $class = shift; my $salt; my @hashes; my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "salt") { croak "salt specified redundantly" if defined $salt; croak "\"$value\" is not a valid salt" unless $value == int($value) && $value >= 0 && $value < 4096; $salt = $value; } elsif($attr eq "salt_base64") { croak "salt specified redundantly" if defined $salt; $value =~ m#\A[./0-9A-Za-z]{2}\z# or croak "\"$value\" is not a valid salt"; $salt = base64_to_int12($value); } elsif($attr eq "salt_random") { croak "salt specified redundantly" if defined $salt; croak "\"$value\" is not a valid salt size" unless $value == 12; $salt = rand_int(1 << $value); } elsif($attr eq "hash") { croak "hash specified redundantly" if @hashes || defined($passphrase); $value =~ m#\A(?:[\x00-\xff]{8})+\z# or croak "not a valid bigcrypt hash"; push @hashes, $1 while $value =~ /(.{8})/sg; } elsif($attr eq "hash_base64") { croak "hash specified redundantly" if @hashes || defined($passphrase); $value =~ m#\A(?:[./0-9A-Za-z]{10}[.26AEIMQUYcgkosw]) +\z#x or croak "\"$value\" is not a valid ". "encoded hash"; while($value =~ /(.{11})/sg) { my $b64 = $1; push @hashes, base64_to_block($b64); } } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if @hashes || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } croak "salt not specified" unless defined $salt; my @sections; if(defined $passphrase) { my $nsegs = $passphrase eq "" ? 1 : ((length($passphrase) + 7) >> 3); for(my $i = 0; $i != $nsegs; $i++) { push @sections, Authen::Passphrase::DESCrypt ->new(salt => $salt, passphrase => substr($passphrase, $i << 3, 8)); $salt = base64_to_int12( substr($sections[-1]->hash_base64, 0, 2)); } } elsif(@hashes) { foreach my $hash (@hashes) { push @sections, Authen::Passphrase::DESCrypt ->new(salt => $salt, hash => $hash); $salt = base64_to_int12( substr($sections[-1]->hash_base64, 0, 2)); } } else { croak "hash not specified"; } return bless(\@sections, $class); } =back =head1 METHODS =over =item $ppr->salt Returns the salt for the first section, as a Perl integer. =cut sub salt { $_[0]->[0]->salt } =item $ppr->salt_base64_2 Returns the salt for the first section, as a string of two base 64 digits. =cut sub salt_base64_2 { $_[0]->[0]->salt_base64_2 } =item $ppr->hash Returns the hash value, as a string of bytes. =cut sub hash { join("", map { $_->hash } @{$_[0]}) } =item $ppr->hash_base64 Returns the hash value, as a string of base 64 digits. This is the concatenation of the base 64 encodings of the section hashes, rather than a base64 encoding of the combined hash. =cut sub hash_base64 { join("", map { $_->hash_base64 } @{$_[0]}) } =item $ppr->sections Returns a reference to an array of L passphrase recognisers for the sections of the passphrase. =cut sub sections { [ @{$_[0]} ] } =item $ppr->match(PASSPHRASE) This method is part of the standard L interface. =cut sub match { my Authen::Passphrase::BigCrypt $self = shift; my($passphrase) = @_; my $nsegs = $passphrase eq "" ? 1 : ((length($passphrase) + 7) >> 3); return 0 unless $nsegs == @$self; for(my $i = $nsegs; $i--; ) { return 0 unless $self->[$i] ->match(substr($passphrase, $i << 3, 8)); } return 1; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/MySQL41.pm000444001750001750 732311713235576 22736 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::MySQL41 - passphrases using the MySQL v4.1 algorithm =head1 SYNOPSIS use Authen::Passphrase::MySQL41; $ppr = Authen::Passphrase::MySQL41->new( hash_hex => "9CD12C48C4C5DD62914B". "3FABB93131746E9E9115"); $ppr = Authen::Passphrase::MySQL41->new( passphrase => "passphrase"); $hash = $ppr->hash; $hash_hex = $ppr->hash_hex; if($ppr->match($passphrase)) { ... =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the algorithm used by MySQL from version 4.1. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The MySQL v4.1 hash scheme is based on the SHA-1 digest algorithm. The passphrase is first hashed using SHA-1, then the output of that stage is hashed using SHA-1 again. The final hash is the output of the second SHA-1. No salt is used. In MySQL the hash is represented as a "B<*>" followed by 40 uppercase hexadecimal digits. The lack of salt is a weakness in this scheme. Salted SHA-1 is a better scheme; see L. =cut package Authen::Passphrase::MySQL41; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Digest::SHA qw(sha1); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTOR =over =item Authen::Passphrase::MySQL41->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the MySQL v4.1 algorithm. The following attributes may be given: =over =item B The hash, as a string of 20 bytes. =item B The hash, as a string of 40 hexadecimal digits. =item B A passphrase that will be accepted. =back Either the hash or the passphrase must be given. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{20}\z# or croak "not a valid MySQL v4.1 hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_hex") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[0-9A-Fa-f]{40}\z# or croak "\"$value\" is not a valid ". "hex MySQL v4.1 hash"; $self->{hash} = pack("H*", $value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =back =head1 METHODS =over =item $ppr->hash Returns the hash value, as a string of 20 bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_hex Returns the hash value, as a string of 40 uppercase hexadecimal digits. =cut sub hash_hex { my($self) = @_; return uc(unpack("H*", $self->{hash})); } =item $ppr->match(PASSPHRASE) This method is part of the standard L interface. =cut sub _hash_of { my($self, $passphrase) = @_; return sha1(sha1($passphrase)); } sub match { my($self, $passphrase) = @_; return $self->_hash_of($passphrase) eq $self->{hash}; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/LANManager.pm000444001750001750 1401611713235576 23546 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::LANManager - passphrases using the LAN Manager hash algorithm =head1 SYNOPSIS use Authen::Passphrase::LANManager; $ppr = Authen::Passphrase::LANManager->new( hash_hex => "855c3697d9979e78ac404c4ba2c66533"); $ppr = Authen::Passphrase::LANManager->new( passphrase => "passphrase"); $ppr = Authen::Passphrase::LANManager->from_rfc2307( "{LANMAN}855c3697d9979e78ac404c4ba2c66533"); $hash = $ppr->hash; $hash_hex = $ppr->hash_hex; $ppr0 = $ppr->first_half; $ppr1 = $ppr->second_half; if($ppr->match($passphrase)) { ... $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the Microsoft LAN Manager hash function. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The hash algorithm can be used on up to fourteen Latin-1 characters of passphrase. First the passphrase is folded to uppercase, and zero-padded to fourteen bytes. Then it is split into two halves. Each seven-byte half is used as a 56-bit DES key, to encrypt the fixed plaintext block "KGS!@#$%". The eight-byte ciphertexts are concatenated to form the sixteen-byte hash. There is no salt. Because the two halves of the passphrase are hashed separately, it is possible to manipulate (e.g., crack) a half hash in isolation. See L. I Don't even think about using this seriously. It's an exceptionally weak design, flawed in pretty much every respect. =cut package Authen::Passphrase::LANManager; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Authen::Passphrase::LANManagerHalf; use Carp qw(croak); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::LANManager->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the LAN Manager hash algorithm. The following attributes may be given: =over =item B The hash, as a string of 16 bytes. =item B The hash, as a string of 32 hexadecimal digits. =item B A passphrase that will be accepted. =back Either the hash or the passphrase must be given. =cut sub new { my $class = shift; my $self = bless({}, $class); my $hash; my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "hash") { croak "hash specified redundantly" if defined($hash) || defined($passphrase); $value =~ m#\A[\x00-\xff]{16}\z# or croak "not a valid LAN Manager hash"; $hash = $value; } elsif($attr eq "hash_hex") { croak "hash specified redundantly" if defined($hash) || defined($passphrase); $value =~ m#\A[0-9A-Fa-f]{32}\z# or croak "\"$value\" is not a valid ". "hex LAN Manager hash"; $hash = pack("H*", $value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if defined($hash) || defined($passphrase); $self->_passphrase_acceptable($value) or croak "can't accept a passphrase exceeding". " fourteen bytes"; $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } if(defined $passphrase) { $self->{first_half} = Authen::Passphrase::LANManagerHalf ->new(passphrase => substr($passphrase, 0, 7)); $self->{second_half} = Authen::Passphrase::LANManagerHalf ->new(passphrase => length($passphrase) > 7 ? substr($passphrase, 7, 7) : ""); } elsif(defined $hash) { $self->{first_half} = Authen::Passphrase::LANManagerHalf ->new(hash => substr($hash, 0, 8)); $self->{second_half} = Authen::Passphrase::LANManagerHalf ->new(hash => substr($hash, 8, 8)); } else { croak "hash not specified"; } return $self; } =item Authen::Passphrase::LANManager->from_rfc2307(USERPASSWORD) Generates a LAN Manager passphrase recogniser from the supplied RFC2307 encoding. The string must consist of "B<{LANMAN}>" (or its synonym "B<{LANM}>") followed by the hash in hexadecimal; case is ignored. =cut sub from_rfc2307 { my($class, $userpassword) = @_; if($userpassword =~ /\A\{(?i:lanm(?:an)?)\}/) { $userpassword =~ /\A\{.*?\}([0-9a-fA-F]{32})\z/ or croak "malformed {LANMAN} data"; my $hash = $1; return $class->new(hash_hex => $hash); } return $class->SUPER::from_rfc2307($userpassword); } =back =head1 METHODS =over =item $ppr->hash Returns the hash value, as a string of 16 bytes. =cut sub hash { my($self) = @_; return $self->{first_half}->hash.$self->{second_half}->hash; } =item $ppr->hash_hex Returns the hash value, as a string of 32 hexadecimal digits. =cut sub hash_hex { my($self) = @_; return unpack("H*", $self->hash); } =item $ppr->first_half Returns the hash of the first half of the passphrase, as an L passphrase recogniser. =cut sub first_half { my($self) = @_; return $self->{first_half}; } =item $ppr->second_half Returns the hash of the second half of the passphrase, as an L passphrase recogniser. =cut sub second_half { my($self) = @_; return $self->{second_half}; } =item $ppr->match(PASSPHRASE) =item $ppr->as_rfc2307 These methods are part of the standard L interface. =cut sub _passphrase_acceptable { my($self, $passphrase) = @_; return $passphrase =~ /\A[\x00-\xff]{0,14}\z/; } sub match { my($self, $passphrase) = @_; return $self->_passphrase_acceptable($passphrase) && $self->{first_half}->match(substr($passphrase, 0, 7)) && $self->{second_half}->match( length($passphrase) > 7 ? substr($passphrase, 7, 7) : ""); } sub as_rfc2307 { my($self) = @_; return "{LANMAN}".$self->hash_hex; } =back =head1 SEE ALSO L, L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/EggdropBlowfish.pm000444001750001750 1210311713235576 24721 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::EggdropBlowfish - passphrases using Eggdrop's blowfish.mod =head1 SYNOPSIS use Authen::Passphrase::EggdropBlowfish; $ppr = Authen::Passphrase::EggdropBlowfish->new( hash_base64 => "9tpsG/61YqX/"); $ppr = Authen::Passphrase::EggdropBlowfish->new( passphrase => "passphrase"); $hash = $ppr->hash; $hash_base64 = $ppr->hash_base64; if($ppr->match($passphrase)) { ... =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the Blowfish-based algorithm used in Eggdrop's blowfish.mod. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. This hash scheme uses no salt, and does not accept a zero-length passphrase. It uses the passphrase as a Blowfish key to encrypt a standard plaintext block. The hash is the ciphertext block. The standard Blowfish key schedule only accepts keys from 8 to 56 bytes long; this algorithm relaxes that requirement and accepts any non-zero length. Up to 72 bytes of passphrase/key are significant; any more are ignored. In Eggdrop the hash is represented as a "B<+>" followed by twelve base 64 digits. The first six digits encode the second half of the hash, and the last six encode the first half. Within each half the bytes are encoded in reverse order. The base 64 digits are "B<.>", "B", "B<0>" to "B<9>", "B" to "B", "B" to "B" (in that order). I The hash is small by modern standards, and the lack of salt is a weakness in this scheme. For a scheme that makes better use of Blowfish see L. =cut package Authen::Passphrase::EggdropBlowfish; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Crypt::Eksblowfish::Uklblowfish 0.008; our $VERSION = "0.008"; use parent "Authen::Passphrase"; my $b64_digits = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; sub _en_base64($) { my($bytes) = @_; my $digits = ""; foreach my $word (reverse unpack("N*", $bytes)) { for(my $i = 6; $i--; $word >>= 6) { $digits .= substr($b64_digits, $word & 0x3f, 1); } } return $digits; } sub _de_base64($) { my($digits) = @_; my @words; while($digits =~ /(......)/sg) { my $wdig = $1; my $word = 0; for(my $i = 6; $i--; ) { $word <<= 6; $word |= index($b64_digits, substr($wdig, $i, 1)); } push @words, $word; } return pack("N*", reverse @words); } =head1 CONSTRUCTOR =over =item Authen::Passphrase::EggdropBlowfish->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the Eggdrop blowfish.mod algorithm. The following attributes may be given: =over =item B The hash, as a string of eight bytes. =item B The hash, as a string of twelve base 64 digits. =item B A passphrase that will be accepted. =back Either the hash or the passphrase must be given. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{8}\z# or croak "not a valid hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_base64") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A(?:[./0-9a-zA-Z]{5}[./01]){2}\z# or croak "\"$value\" is not a valid ". "base 64 hash"; $self->{hash} = _de_base64($value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $value ne "" or croak "can't accept null passphrase"; $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =back =head1 METHODS =over =item $ppr->hash Returns the hash value, as a string of eight bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_base64 Returns the hash value, as a string of twelve base 64 digits. =cut sub hash_base64 { my($self) = @_; return _en_base64($self->{hash}); } =item $ppr->match(PASSPHRASE) This method is part of the standard L interface. =cut sub _hash_of { my($self, $passphrase) = @_; $passphrase = substr($passphrase, 0, 72); my $cipher = Crypt::Eksblowfish::Uklblowfish->new($passphrase); return $cipher->encrypt("\xde\xad\xd0\x61\x23\xf6\xb0\x95"); } sub match { my($self, $passphrase) = @_; return $passphrase ne "" && $self->_hash_of($passphrase) eq $self->{hash}; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/SaltedDigest.pm000444001750001750 2774111713235576 24226 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::SaltedDigest - passphrases using the generic salted digest algorithm =head1 SYNOPSIS use Authen::Passphrase::SaltedDigest; $ppr = Authen::Passphrase::SaltedDigest->new( algorithm => "SHA-1", salt_hex => "a9f524b1e819e96d8cc7". "a04d5471e8b10c84e596", hash_hex => "8270d9d1a345d3806ab2". "3b0385702e10f1acc943"); $ppr = Authen::Passphrase::SaltedDigest->new( algorithm => "SHA-1", salt_random => 20, passphrase => "passphrase"); $ppr = Authen::Passphrase::SaltedDigest->from_rfc2307( "{SSHA}gnDZ0aNF04BqsjsDhXAuEPGsy". "UOp9SSx6BnpbYzHoE1UceixDITllg=="); $algorithm = $ppr->algorithm; $salt = $ppr->salt; $salt_hex = $ppr->salt_hex; $hash = $ppr->hash; $hash_hex = $ppr->hash_hex; if($ppr->match($passphrase)) { ... $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using a generic digest-algorithm-based scheme. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The salt is an arbitrary string of bytes. It is appended to passphrase, and the combined string is passed through a specified message digest algorithm. The output of the message digest algorithm is the passphrase hash. The strength depends entirely on the choice of digest algorithm, so choose according to the level of security required. SHA-1 is suitable for most applications, but recent work has revealed weaknesses in the basic structure of MD5, SHA-1, SHA-256, and all similar digest algorithms. A new generation of digest algorithms emerged in 2008, centred around NIST's competition to design SHA-3. Once these algorithms have been subjected to sufficient cryptanalysis, the survivors will be preferred over SHA-1 and its generation. Digest algorithms are generally designed to be as efficient to compute as possible for their level of cryptographic strength. An unbroken digest algorithm makes brute force the most efficient way to attack it, but makes no effort to resist a brute force attack. This is a concern in some passphrase-using applications. The use of this kind of passphrase scheme is generally recommended for new systems. Choice of digest algorithm is important: SHA-1 is suitable for most applications. If efficiency of brute force attack is a concern, see L for an algorithm designed to be expensive to compute. =cut package Authen::Passphrase::SaltedDigest; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Data::Entropy::Algorithms 0.000 qw(rand_bits); use Digest 1.00; use MIME::Base64 2.21 qw(encode_base64 decode_base64); use Module::Runtime 0.011 qw(is_valid_module_name use_module); use Params::Classify 0.000 qw(is_string is_blessed); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::SaltedDigest->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the generic salted digest algorithm. The following attributes may be given: =over =item B Specifies the algorithm to use. If it is a reference to a blessed object, it must be possible to call the L method on that object to generate a digest context object. If it is a string containing the subsequence "::" then it specifies a module to use. A plain package name in bareword syntax, optionally preceded by "::" (so that top-level packages can be recognised as such), is taken as a class name, on which the L method will be called to generate a digest context object. The package name may optionally be followed by "-" to cause automatic loading of the module, and the "-" (if present) may optionally be followed by a version number that will be checked against. For example, "Digest::MD5-1.99_53" would load the L module and check that it is at least version 1.99_53 (which is the first version that can be used by this module). A string not containing "::" and which is understood by L<< Digest->new|Digest/"OO INTERFACE" >> will be passed to that function to generate a digest context object. Any other type of algorithm specifier has undefined behaviour. The digest context objects must support at least the standard C and C methods. =item B The salt, as a raw string of bytes. Defaults to the empty string, yielding an unsalted scheme. =item B The salt, as a string of hexadecimal digits. Defaults to the empty string, yielding an unsalted scheme. =item B Causes salt to be generated randomly. The value given for this attribute must be a non-negative integer, giving the number of bytes of salt to generate. (The same length as the hash is recommended.) The source of randomness may be controlled by the facility described in L. =item B The hash, as a string of bytes. =item B The hash, as a string of hexadecimal digits. =item B A passphrase that will be accepted. =back The digest algorithm must be given, and either the hash or the passphrase. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "algorithm") { croak "algorithm specified redundantly" if exists $self->{algorithm}; $self->{algorithm} = $value; } elsif($attr eq "salt") { croak "salt specified redundantly" if exists $self->{salt}; $value =~ m#\A[\x00-\xff]*\z# or croak "\"$value\" is not a valid salt"; $self->{salt} = "$value"; } elsif($attr eq "salt_hex") { croak "salt specified redundantly" if exists $self->{salt}; $value =~ m#\A(?:[0-9A-Fa-f]{2})+\z# or croak "\"$value\" is not a valid salt"; $self->{salt} = pack("H*", $value); } elsif($attr eq "salt_random") { croak "salt specified redundantly" if exists $self->{salt}; croak "\"$value\" is not a valid salt length" unless $value == int($value) && $value >= 0; $self->{salt} = rand_bits($value * 8); } elsif($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]*\z# or croak "\"$value\" is not a valid hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_hex") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A(?:[0-9A-Fa-f]{2})+\z# or croak "\"$value\" is not a valid hash"; $self->{hash} = pack("H*", $value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } croak "algorithm not specified" unless exists $self->{algorithm}; $self->{salt} = "" unless exists $self->{salt}; if(defined $passphrase) { $self->{hash} = $self->_hash_of($passphrase); } elsif(exists $self->{hash}) { croak "not a valid ".$self->{algorithm}." hash" unless length($self->{hash}) == length($self->_hash_of("")); } else { croak "hash not specified"; } return $self; } =item Authen::Passphrase::SaltedDigest->from_rfc2307(USERPASSWORD) Generates a salted-digest passphrase recogniser from the supplied RFC2307 encoding. The scheme identifier gives the digest algorithm and controls whether salt is permitted. It is followed by a base 64 string, using standard MIME base 64, which encodes the concatenation of the hash and salt. The scheme identifiers accepted are "B<{MD4}>" (unsalted MD4), "B<{MD5}>" (unsalted MD5), "B<{RMD160}>" (unsalted RIPEMD-160), "B<{SHA}>" (unsalted SHA-1), "B<{SMD5}>" (salted MD5), and "B<{SSHA}>" (salted SHA-1). All scheme identifiers are recognised case-insensitively. =cut my %rfc2307_scheme_meaning = ( "MD4" => ["MD4", 16, 0], "MD5" => ["MD5", 16, 0], "RMD160" => ["Crypt::RIPEMD160-", 20, 0], "SHA" => ["SHA-1", 20, 0], "SMD5" => ["MD5", 16, 1], "SSHA" => ["SHA-1", 20, 1], ); sub from_rfc2307 { my($class, $userpassword) = @_; return $class->SUPER::from_rfc2307($userpassword) unless $userpassword =~ /\A\{([-0-9A-Za-z]+)\}/; my $scheme = uc($1); my $meaning = $rfc2307_scheme_meaning{$scheme}; return $class->SUPER::from_rfc2307($userpassword) unless defined $meaning; croak "malformed {$scheme} data" unless $userpassword =~ m#\A\{.*?\} ((?>(?:[A-Za-z0-9+/]{4})*) (?:|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=| [A-Za-z0-9+/][AQgw]==))\z#x; my $b64 = $1; my $hash_and_salt = decode_base64($b64); my($algorithm, $hash_len, $salt_allowed) = @$meaning; croak "insufficient hash data for {$scheme}" if length($hash_and_salt) < $hash_len; croak "too much hash data for {$scheme}" if !$salt_allowed && length($hash_and_salt) > $hash_len; return $class->new(algorithm => $algorithm, salt => substr($hash_and_salt, $hash_len), hash => substr($hash_and_salt, 0, $hash_len)); } =back =head1 METHODS =over =item $ppr->algorithm Returns the digest algorithm, in the same form as supplied to the constructor. =cut sub algorithm { my($self) = @_; return $self->{algorithm}; } =item $ppr->salt Returns the salt, in raw form. =cut sub salt { my($self) = @_; return $self->{salt}; } =item $ppr->salt_hex Returns the salt, as a string of hexadecimal digits. =cut sub salt_hex { my($self) = @_; return unpack("H*", $self->{salt}); } =item $ppr->hash Returns the hash value, in raw form. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_hex Returns the hash value, as a string of hexadecimal digits. =cut sub hash_hex { my($self) = @_; return unpack("H*", $self->{hash}); } =item $ppr->match(PASSPHRASE) =item $ppr->as_rfc2307 These methods are part of the standard L interface. Only passphrase recognisers using certain well-known digest algorithms can be represented in RFC 2307 form. =cut sub _hash_of { my($self, $passphrase) = @_; my $alg = $self->{algorithm}; my $ctx; if(is_string($alg)) { if($alg =~ /::/) { $alg =~ /\A(?:::)?([0-9a-zA-Z_:]+) (-([0-9][0-9_]*(?:\._*[0-9][0-9_]*)?)?)?\z/x or croak "module spec `$alg' not understood"; my($pkgname, $load_p, $modver) = ($1, $2, $3); croak "bad package name `$pkgname'" unless is_valid_module_name($pkgname); if($load_p) { if(defined $modver) { $modver =~ tr/_//d; use_module($pkgname, $modver); } else { use_module($pkgname); } } $ctx = $pkgname->new; } else { $ctx = Digest->new($alg); } } elsif(is_blessed($alg)) { $ctx = $alg->new; } else { croak "algorithm specifier `$alg' is of an unrecognised type"; } $ctx->add($passphrase); $ctx->add($self->{salt}); return $ctx->digest; } sub match { my($self, $passphrase) = @_; return $self->_hash_of($passphrase) eq $self->{hash}; } my %rfc2307_scheme_for_digest_name = ( "MD4" => "MD4", "MD5" => "MD5", "SHA-1" => "SHA", "SHA1" => "SHA", ); my %rfc2307_scheme_for_package_name = ( "Crypt::RIPEMD160" => "RMD160", "Digest::MD4" => "MD4", "Digest::MD5" => "MD5", "Digest::MD5::Perl" => "MD5", "Digest::Perl::MD4" => "MD4", "Digest::SHA" => "SHA", "Digest::SHA::PurePerl" => "SHA", "Digest::SHA1" => "SHA", "MD5" => "MD5", "RIPEMD160" => "RMD160", ); sub as_rfc2307 { my($self) = @_; my $alg = $self->{algorithm}; my $scheme; if(is_string($alg)) { if($alg =~ /::/) { $scheme = $rfc2307_scheme_for_package_name{$1} if $alg =~ /\A(?:::)? ([0-9a-zA-Z_:]+)(?:-[0-9._]*)?\z/x; } else { $scheme = $rfc2307_scheme_for_digest_name{$alg}; } } croak "don't know RFC 2307 scheme identifier for digest algorithm $alg" unless defined $scheme; return "{".($self->{salt} eq "" ? "" : "S").$scheme."}". encode_base64($self->{hash}.$self->{salt}, ""); } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/NetscapeMail.pm000444001750001750 1370511713235576 24212 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::NetscapeMail - passphrases using Netscape Mail Server's method =head1 SYNOPSIS use Authen::Passphrase::NetscapeMail; $ppr = Authen::Passphrase::NetscapeMail->new( salt => "8fd9d0a03491ce8f99cfbc9ab39f0dd5", hash_hex => "983757d7b519e86d9b5d472aca4eea3a"); $ppr = Authen::Passphrase::NetscapeMail->new( salt_random => 1, passphrase => "passphrase"); $ppr = Authen::Passphrase::NetscapeMail->from_rfc2307( "{NS-MTA-MD5}8fd9d0a03491ce8f99cfbc9ab39f0dd5". "983757d7b519e86d9b5d472aca4eea3a"); $salt = $ppr->salt; $hash = $ppr->hash; $hash_hex = $ppr->hash_hex; if($ppr->match($passphrase)) { ... $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the algorithm used by Netscape Mail Server. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The Netscape Mail Server scheme is based on the MD5 digest algorithm. The passphrase and a salt are concatenated, along with some fixed bytes, and this record is hashed through MD5. The output of MD5 is the password hash. This algorithm is deprecated, and is supported for compatibility only. Prefer the mechanism of L. =cut package Authen::Passphrase::NetscapeMail; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Data::Entropy::Algorithms 0.000 qw(rand_bits); use Digest::MD5 1.99_53 (); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::NetscapeMail->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the Netscape Mail Server algorithm. The following attributes may be given: =over =item B The salt, as a raw 32-byte string. It may be any 32-byte string, but it is conventionally limited to lowercase hexadecimal digits. =item B Causes salt to be generated randomly. The value given for this attribute is ignored. The salt will be a string of 32 lowercase hexadecimal digits. The source of randomness may be controlled by the facility described in L. =item B The hash, as a string of 16 bytes. =item B The hash, as a string of 32 hexadecimal digits. =item B A passphrase that will be accepted. =back The salt must be given, and either the hash or the passphrase. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "salt") { croak "salt specified redundantly" if exists $self->{salt}; $value =~ m#\A[\x00-\xff]{32}\z# or croak "not a valid salt"; $self->{salt} = "$value"; } elsif($attr eq "salt_random") { croak "salt specified redundantly" if exists $self->{salt}; $self->{salt} = unpack("H*", rand_bits(128)); } elsif($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{16}\z# or croak "not a valid MD5 hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_hex") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[0-9A-Fa-f]{32}\z# or croak "\"$value\" is not a valid ". "hex MD5 hash"; $self->{hash} = pack("H*", $value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } croak "salt not specified" unless exists $self->{salt}; $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =item Authen::Passphrase::NetscapeMail->from_rfc2307(USERPASSWORD) Generates a new Netscape Mail Server passphrase recogniser object from an RFC 2307 string. The string must consist of "B<{NS-MTA-MD5}>" (case insensitive) followed by the hash in case-insensitive hexadecimal and then the salt. The salt must be exactly 32 characters long, and cannot contain any character that cannot appear in an RFC 2307 string. =cut sub from_rfc2307 { my($class, $userpassword) = @_; if($userpassword =~ /\A\{(?i:ns-mta-md5)\}/) { $userpassword =~ /\A\{.*?\}([0-9a-fA-F]{32})([!-~]{32})\z/ or croak "malformed {NS-MTA-MD5} data"; my($hash, $salt) = ($1, $2); return $class->new(salt => $salt, hash_hex => $hash); } return $class->SUPER::from_rfc2307($userpassword); } =back =head1 METHODS =over =item $ppr->salt Returns the salt value, as a string of 32 bytes. =cut sub salt { my($self) = @_; return $self->{salt}; } =item $ppr->hash Returns the hash value, as a string of 16 bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_hex Returns the hash value, as a string of 32 hexadecimal digits. =cut sub hash_hex { my($self) = @_; return unpack("H*", $self->{hash}); } =item $ppr->match(PASSPHRASE) =item $ppr->as_rfc2307 These methods are part of the standard L interface. =cut sub _hash_of { my($self, $passphrase) = @_; my $ctx = Digest::MD5->new; $ctx->add($self->{salt}); $ctx->add("\x59"); $ctx->add($passphrase); $ctx->add("\xf7"); $ctx->add($self->{salt}); return $ctx->digest; } sub match { my($self, $passphrase) = @_; return $self->_hash_of($passphrase) eq $self->{hash}; } sub as_rfc2307 { my($self) = @_; croak "can't put this salt into an RFC 2307 string" if $self->{salt} =~ /[^!-~]/; return "{NS-MTA-MD5}".$self->hash_hex.$self->{salt}; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/Clear.pm000444001750001750 523511713235576 22652 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::Clear - cleartext passphrases =head1 SYNOPSIS use Authen::Passphrase::Clear; $ppr = Authen::Passphrase::Clear->new("passphrase"); if($ppr->match($passphrase)) { ... $passphrase = $ppr->passphrase; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class is a passphrase recogniser that accepts some particular passphrase which it knows. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. I Storing a passphrase in cleartext, as this class does, is a very bad idea. It means that anyone who sees the passphrase file immediately knows all the passphrases. Do not use this unless you really know what you're doing. =cut package Authen::Passphrase::Clear; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); our $VERSION = "0.008"; use parent "Authen::Passphrase"; # An object of this class is a blessed scalar containing the passphrase. =head1 CONSTRUCTORS =over =item Authen::Passphrase::Clear->new(PASSPHRASE) Returns a passphrase recogniser object that stores the specified passphrase in cleartext and accepts only that passphrase. =cut sub new { my($class, $passphrase) = @_; $passphrase = "$passphrase"; return bless(\$passphrase, $class); } =item Authen::Passphrase::Clear->from_rfc2307(USERPASSWORD) Generates a cleartext passphrase recogniser from the supplied RFC2307 encoding. The string must consist of "B<{CLEARTEXT}>" (case insensitive) followed by the passphrase. =cut sub from_rfc2307 { my($class, $userpassword) = @_; if($userpassword =~ /\A\{(?i:cleartext)\}/) { $userpassword =~ /\A\{.*?\}([!-~]*)\z/ or croak "malformed {CLEARTEXT} data"; my $text = $1; return $class->new($text); } return $class->SUPER::from_rfc2307($userpassword); } =back =head1 METHODS =over =item $ppr->match(PASSPHRASE) =item $ppr->passphrase =item $ppr->as_rfc2307 These methods are part of the standard L interface. The L method trivially works. =cut sub match { my($self, $passphrase) = @_; return $passphrase eq $$self; } sub passphrase { ${$_[0]} } sub as_rfc2307 { my($self) = @_; croak "can't put this passphrase into an RFC 2307 string" if $$self =~ /[^!-~]/; return "{CLEARTEXT}".$$self; } =back =head1 SEE ALSO L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/NTHash.pm000444001750001750 1307711713235576 22774 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::NTHash - passphrases using the NT-Hash algorithm =head1 SYNOPSIS use Authen::Passphrase::NTHash; $ppr = Authen::Passphrase::NTHash->new( hash_hex => "7f8fe03093cc84b267b109625f6bbf4b"); $ppr = Authen::Passphrase::NTHash->new( passphrase => "passphrase"); $ppr = Authen::Passphrase::NTHash->from_crypt( '$3$$7f8fe03093cc84b267b109625f6bbf4b'); $ppr = Authen::Passphrase::NTHash->from_rfc2307( '{MSNT}7f8fe03093cc84b267b109625f6bbf4b'); $hash = $ppr->hash; $hash_hex = $ppr->hash_hex; if($ppr->match($passphrase)) { ... $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the NT-Hash function. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The NT-Hash scheme is based on the MD4 digest algorithm. Up to 128 characters of passphrase (characters beyond the 128th are ignored) are represented in Unicode, and hashed using MD4. No salt is used. I MD4 is a weak hash algorithm by current standards, and the lack of salt is a design flaw in this scheme. Use this for compatibility only, not by choice. =cut package Authen::Passphrase::NTHash; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Digest::MD4 1.2 qw(md4); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::NTHash->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the NT-Hash algorithm. The following attributes may be given: =over =item B The hash, as a string of 16 bytes. =item B The hash, as a string of 32 hexadecimal digits. =item B A passphrase that will be accepted. =back Either the hash or the passphrase must be given. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "hash") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[\x00-\xff]{16}\z# or croak "not a valid MD4 hash"; $self->{hash} = "$value"; } elsif($attr eq "hash_hex") { croak "hash specified redundantly" if exists($self->{hash}) || defined($passphrase); $value =~ m#\A[0-9A-Fa-f]{32}\z# or croak "\"$value\" is not a valid ". "hex MD4 hash"; $self->{hash} = pack("H*", $value); } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } $self->{hash} = $self->_hash_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash}; return $self; } =item Authen::Passphrase::NTHash->from_crypt(PASSWD) Generates a new NT-Hash passphrase recogniser object from a crypt string. Two forms are accepted. In the first form, the he crypt string must consist of "B<$3$$>" (note the extra "B<$>") followed by the hash in lowercase hexadecimal. In the second form, the he crypt string must consist of "B<$NT$>" followed by the hash in lowercase hexadecimal. =cut sub from_crypt { my($class, $passwd) = @_; if($passwd =~ /\A\$3\$/) { $passwd =~ m#\A\$3\$\$([0-9a-f]{32})\z# or croak "malformed \$3\$ data"; my $hash = $1; return $class->new(hash_hex => $hash); } elsif($passwd =~ /\A\$NT\$/) { $passwd =~ m#\A\$NT\$([0-9a-f]{32})\z# or croak "malformed \$NT\$ data"; my $hash = $1; return $class->new(hash_hex => $hash); } return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::NTHash->from_rfc2307(USERPASSWORD) Generates a new NT-Hash passphrase recogniser object from an RFC 2307 string. Two forms are accepted. In the first form, the string must consist of "B<{MSNT}>" followed by the hash in hexadecimal; case is ignored. In the second form, the string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =cut sub from_rfc2307 { my($class, $userpassword) = @_; if($userpassword =~ /\A\{(?i:msnt)\}/) { $userpassword =~ /\A\{.*?\}([0-9a-fA-F]{32})\z/ or croak "malformed {MSNT} data"; my $hash = $1; return $class->new(hash_hex => $hash); } return $class->SUPER::from_rfc2307($userpassword); } =back =head1 METHODS =over =item $ppr->hash Returns the hash value, as a string of 16 bytes. =cut sub hash { my($self) = @_; return $self->{hash}; } =item $ppr->hash_hex Returns the hash value, as a string of 32 hexadecimal digits. =cut sub hash_hex { my($self) = @_; return unpack("H*", $self->{hash}); } =item $ppr->match(PASSPHRASE) =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. =cut sub _hash_of { my($self, $passphrase) = @_; $passphrase = substr($passphrase, 0, 128); $passphrase =~ s/(.)/pack("v", ord($1))/eg; return md4($passphrase); } sub match { my($self, $passphrase) = @_; return $self->_hash_of($passphrase) eq $self->{hash}; } sub as_crypt { my($self) = @_; return "\$3\$\$".$self->hash_hex; } sub as_rfc2307 { my($self) = @_; return "{MSNT}".$self->hash_hex; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/lib/Authen/Passphrase/MD5Crypt.pm000444001750001750 2005411713235576 23247 0ustar00zeframzefram000000000000=head1 NAME Authen::Passphrase::MD5Crypt - passphrases using the MD5-based Unix crypt() =head1 SYNOPSIS use Authen::Passphrase::MD5Crypt; $ppr = Authen::Passphrase::MD5Crypt->new( salt => "Vd3f8aG6", hash_base64 => "GcsdF4YCXb0PM2UmXjIoI1"); $ppr = Authen::Passphrase::MD5Crypt->new( salt_random => 1, passphrase => "passphrase"); $ppr = Authen::Passphrase::MD5Crypt->from_crypt( '$1$Vd3f8aG6$GcsdF4YCXb0PM2UmXjIoI1'); $ppr = Authen::Passphrase::MD5Crypt->from_rfc2307( '{CRYPT}$1$Vd3f8aG6$GcsdF4YCXb0PM2UmXjIoI1'); $salt = $ppr->salt; $hash_base64 = $ppr->hash_base64; if($ppr->match($passphrase)) { ... $passwd = $ppr->as_crypt; $userPassword = $ppr->as_rfc2307; =head1 DESCRIPTION An object of this class encapsulates a passphrase hashed using the MD5-based Unix crypt() hash function. This is a subclass of L, and this document assumes that the reader is familiar with the documentation for that class. The crypt() function in a modern Unix actually supports several different passphrase schemes. This class is concerned only with one particular scheme, an MD5-based algorithm designed by Poul-Henning Kamp and originally implemented in FreeBSD. To handle the whole range of passphrase schemes supported by the modern crypt(), see the L constructor and the L method in L. The MD5-based crypt() scheme uses the whole passphrase, a salt which can in principle be an arbitrary byte string, and the MD5 message digest algorithm. First the passphrase and salt are hashed together, yielding an MD5 message digest. Then a new digest is constructed, hashing together the passphrase, the salt, and the first digest, all in a rather complex form. Then this digest is passed through a thousand iterations of a function which rehashes it together with the passphrase and salt in a manner that varies between rounds. The output of the last of these rounds is the resulting passphrase hash. In the crypt() function the raw hash output is then represented in ASCII as a 22-character string using a base 64 encoding. The base 64 digits are "B<.>", "B", "B<0>" to "B<9>", "B" to "B", "B" to "B" (in ASCII order). Because the base 64 encoding can represent 132 bits in 22 digits, more than the 128 required, the last digit can only take four of the base 64 digit values. An additional complication is that the bytes of the raw algorithm output are permuted in a bizarre order before being represented in base 64. There is no tradition of handling these passphrase hashes in raw binary form. The textual encoding described above, including the final permutation, is used universally, so this class does not support any binary format. The complex algorithm was designed to be slow to compute, in order to resist brute force attacks. However, the complexity is fixed, and the operation of Moore's Law has rendered it far less expensive than intended. If efficiency of a brute force attack is a concern, see L. =cut package Authen::Passphrase::MD5Crypt; { use 5.006; } use warnings; use strict; use Authen::Passphrase 0.003; use Carp qw(croak); use Crypt::PasswdMD5 1.0 qw(unix_md5_crypt); use Data::Entropy::Algorithms 0.000 qw(rand_int); our $VERSION = "0.008"; use parent "Authen::Passphrase"; =head1 CONSTRUCTORS =over =item Authen::Passphrase::MD5Crypt->new(ATTR => VALUE, ...) Generates a new passphrase recogniser object using the MD5-based crypt() algorithm. The following attributes may be given: =over =item B The salt, as a raw string. It may be any byte string, but in crypt() usage it is conventionally limited to zero to eight base 64 digits. =item B Causes salt to be generated randomly. The value given for this attribute is ignored. The salt will be a string of eight base 64 digits. The source of randomness may be controlled by the facility described in L. =item B The hash, as a string of 22 base 64 digits. This is the final part of what crypt() outputs. =item B A passphrase that will be accepted. =back The salt must be given, and either the hash or the passphrase. =cut sub new { my $class = shift; my $self = bless({}, $class); my $passphrase; while(@_) { my $attr = shift; my $value = shift; if($attr eq "salt") { croak "salt specified redundantly" if exists $self->{salt}; $value =~ m#\A[\x00-\xff]*\z# or croak "not a valid salt"; $self->{salt} = "$value"; } elsif($attr eq "salt_random") { croak "salt specified redundantly" if exists $self->{salt}; $self->{salt} = ""; for(my $i = 8; $i--; ) { $self->{salt} .= chr(rand_int(64)); } $self->{salt} =~ tr#\x00-\x3f#./0-9A-Za-z#; } elsif($attr eq "hash_base64") { croak "hash specified redundantly" if exists($self->{hash_base64}) || defined($passphrase); $value =~ m#\A[./0-9A-Za-z]{21}[./01]\z# or croak "\"$value\" is not a valid ". "MD5-based crypt() hash"; $self->{hash_base64} = "$value"; } elsif($attr eq "passphrase") { croak "passphrase specified redundantly" if exists($self->{hash_base64}) || defined($passphrase); $passphrase = $value; } else { croak "unrecognised attribute `$attr'"; } } croak "salt not specified" unless exists $self->{salt}; $self->{hash_base64} = $self->_hash_base64_of($passphrase) if defined $passphrase; croak "hash not specified" unless exists $self->{hash_base64}; return $self; } =item Authen::Passphrase::MD5Crypt->from_crypt(PASSWD) Generates a new passphrase recogniser object using the MD5-based crypt() algorithm, from a crypt string. The crypt string must consist of "B<$1$>", the salt, "B<$>", then 22 base 64 digits giving the hash. The salt may be up to 8 characters long, and cannot contain "B<$>" or any character that cannot appear in a crypt string. =cut sub from_crypt { my($class, $passwd) = @_; if($passwd =~ /\A\$1\$/) { $passwd =~ m:\A\$1\$([!-#%-9;-~]{0,8})\$([./0-9A-Za-z]{22})\z: or croak "malformed \$1\$ data"; my($salt, $hash) = ($1, $2); return $class->new(salt => $salt, hash_base64 => $hash); } return $class->SUPER::from_crypt($passwd); } =item Authen::Passphrase::MD5Crypt->from_rfc2307(USERPASSWORD) Generates a new passphrase recogniser object using the MD5-based crypt() algorithm, from an RFC 2307 string. The string must consist of "B<{CRYPT}>" (case insensitive) followed by an acceptable crypt string. =back =head1 METHODS =over =item $ppr->salt Returns the salt, in raw form. =cut sub salt { my($self) = @_; return $self->{salt}; } =item $ppr->hash_base64 Returns the hash value, as a string of 22 base 64 digits. =cut sub hash_base64 { my($self) = @_; return $self->{hash_base64}; } =item $ppr->match(PASSPHRASE) =item $ppr->as_crypt =item $ppr->as_rfc2307 These methods are part of the standard L interface. Not every passphrase recogniser of this type can be represented as a crypt string: the crypt format only allows the salt to be up to eight bytes, and it cannot contain any NUL or "B<$>" characters. =cut sub _hash_base64_of { my($self, $passphrase) = @_; die "can't use a crypt-incompatible salt yet ". "(need generalised Crypt::MD5Passwd)" if $self->{salt} =~ /[^\!-\#\%-9\;-\~]/ || length($self->{salt}) > 8; my $hash = unix_md5_crypt($passphrase, $self->{salt}); $hash =~ s/\A.*\$//; return $hash; } sub match { my($self, $passphrase) = @_; return $self->_hash_base64_of($passphrase) eq $self->{hash_base64}; } sub as_crypt { my($self) = @_; croak "can't put this salt into a crypt string" if $self->{salt} =~ /[^\!-\#\%-9\;-\~]/ || length($self->{salt}) > 8; return "\$1\$".$self->{salt}."\$".$self->{hash_base64}; } =back =head1 SEE ALSO L, L =head1 AUTHOR Andrew Main (Zefram) =head1 COPYRIGHT Copyright (C) 2006, 2007, 2009, 2010, 2012 Andrew Main (Zefram) =head1 LICENSE This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Authen-Passphrase-0.008/t000755001750001750 011713235576 15264 5ustar00zeframzefram000000000000Authen-Passphrase-0.008/t/intdescrypt.t000444001750001750 522711713235576 20164 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 58; BEGIN { use_ok "Authen::Passphrase::DESCrypt"; } my $ppr = Authen::Passphrase::DESCrypt ->new(fold => 1, initial_base64 => "6UN3gAqtTbM", nrounds_base64 => "xIw.", salt_base64 => "a.rS", hash_base64 => "7KB8x6lwIKQ"); ok $ppr; ok $ppr->fold; is $ppr->initial, "\x22\x06\x45\xb0\xcd\xb9\x7e\x76"; is $ppr->initial_base64, "6UN3gAqtTbM"; is $ppr->nrounds, 247101; is $ppr->nrounds_base64_4, "xIw."; is $ppr->salt, 8089638; eval { $ppr->salt_base64_2 }; isnt $@, ""; is $ppr->salt_base64_4, "a.rS"; is $ppr->hash, "\x25\x63\x4a\xf4\x8c\x7c\x51\x67"; is $ppr->hash_base64, "7KB8x6lwIKQ"; $ppr = Authen::Passphrase::DESCrypt ->new(fold => 0, initial => "\xd7\xa4\x74\xf6\xe1\x42\x84\x4d", nrounds => 9968263, salt => 10354060, hash => "\x86\x8d\xe9\xf0\x5e\x4f\x8a\x82"); ok $ppr; ok !$ppr->fold; is $ppr->initial, "\xd7\xa4\x74\xf6\xe1\x42\x84\x4d"; is $ppr->initial_base64, "puFoxi30V2o"; is $ppr->nrounds, 9968263; is $ppr->nrounds_base64_4, "5e/a"; is $ppr->salt, 10354060; eval { $ppr->salt_base64_2 }; isnt $@, ""; is $ppr->salt_base64_4, "AqTb"; is $ppr->hash, "\x86\x8d\xe9\xf0\x5e\x4f\x8a\x82"; is $ppr->hash_base64, "Vcrdw3tDWc6"; $ppr = Authen::Passphrase::DESCrypt ->new(salt_base64 => "ab", hash => "\x86\x8d\xe9\xf0\x5e\x4f\x8a\x82"); ok $ppr; ok !$ppr->fold; is $ppr->initial, "\x00\x00\x00\x00\x00\x00\x00\x00"; is $ppr->initial_base64, "..........."; is $ppr->nrounds, 25; is $ppr->nrounds_base64_4, "N..."; is $ppr->salt, 2534; is $ppr->salt_base64_2, "ab"; is $ppr->salt_base64_4, "ab.."; is $ppr->hash, "\x86\x8d\xe9\xf0\x5e\x4f\x8a\x82"; is $ppr->hash_base64, "Vcrdw3tDWc6"; $ppr = Authen::Passphrase::DESCrypt ->new(salt => 2534, hash => "\x86\x8d\xe9\xf0\x5e\x4f\x8a\x82"); ok $ppr; ok !$ppr->fold; is $ppr->initial, "\x00\x00\x00\x00\x00\x00\x00\x00"; is $ppr->initial_base64, "..........."; is $ppr->nrounds, 25; is $ppr->nrounds_base64_4, "N..."; is $ppr->salt, 2534; is $ppr->salt_base64_2, "ab"; is $ppr->salt_base64_4, "ab.."; is $ppr->hash, "\x86\x8d\xe9\xf0\x5e\x4f\x8a\x82"; is $ppr->hash_base64, "Vcrdw3tDWc6"; $ppr = Authen::Passphrase::DESCrypt ->new(salt => 2534, passphrase => "wibble"); ok $ppr; ok !$ppr->fold; is $ppr->initial_base64, "..........."; is $ppr->nrounds_base64_4, "N..."; is $ppr->salt_base64_4, "ab.."; is $ppr->hash_base64, "Fj33Wj0Z5j."; $ppr = Authen::Passphrase::DESCrypt ->new(salt_random => 12, passphrase => "wibble"); ok $ppr; ok !$ppr->fold; is $ppr->initial_base64, "..........."; is $ppr->nrounds_base64_4, "N..."; like $ppr->salt_base64_4, qr/\A..\.\.\z/; is length($ppr->hash), 8; ok $ppr->match("wibble"); 1; Authen-Passphrase-0.008/t/phpass.t000444001750001750 544311713235576 17112 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 100; BEGIN { use_ok "Authen::Passphrase::PHPass"; } my $ppr = Authen::Passphrase::PHPass ->new(nrounds_log2 => 8, salt => "V7qMYJaN", hash => "ABCDEFGHIJKLMNOP"); ok $ppr; is $ppr->cost, 8; is $ppr->cost_base64, "6"; is $ppr->nrounds_log2, 8; is $ppr->nrounds_log2_base64, "6"; is $ppr->salt, "V7qMYJaN"; is $ppr->hash, "ABCDEFGHIJKLMNOP"; is $ppr->hash_base64, "/7oE2JYF5VIG8h2HBtoHE/"; $ppr = Authen::Passphrase::PHPass ->new(cost => 8, salt => "V7qMYJaN", hash_base64 => "/7oE2JYF5VIG8h2HBtoHE/"); ok $ppr; is $ppr->cost, 8; is $ppr->cost_base64, "6"; is $ppr->nrounds_log2, 8; is $ppr->nrounds_log2_base64, "6"; is $ppr->salt, "V7qMYJaN"; is $ppr->hash, "ABCDEFGHIJKLMNOP"; is $ppr->hash_base64, "/7oE2JYF5VIG8h2HBtoHE/"; $ppr = Authen::Passphrase::PHPass ->new(cost_base64 => "6", salt => "V7qMYJaN", passphrase => "wibble"); ok $ppr; is $ppr->cost, 8; is $ppr->cost_base64, "6"; is $ppr->nrounds_log2, 8; is $ppr->nrounds_log2_base64, "6"; is $ppr->salt, "V7qMYJaN"; is $ppr->hash_base64, "DLIv8lDL.KgHUVyVKxhSH."; $ppr = Authen::Passphrase::PHPass ->new(nrounds_log2_base64 => "6", salt_random => 1, passphrase => "wibble"); ok $ppr; is $ppr->cost, 8; is $ppr->cost_base64, "6"; is $ppr->nrounds_log2, 8; is $ppr->nrounds_log2_base64, "6"; like $ppr->salt, qr#\A[./0-9A-Za-z]{8}\z#; is length($ppr->hash), 16; ok $ppr->match("wibble"); $ppr = Authen::Passphrase::PHPass ->from_crypt('$P$8NaClNaClMeOtoCi6dkB5NlSyY.wFQ.'); ok $ppr; is $ppr->cost, 10; is $ppr->salt, "NaClNaCl"; is $ppr->hash_base64, "MeOtoCi6dkB5NlSyY.wFQ."; $ppr = Authen::Passphrase::PHPass ->from_rfc2307('{CrYpT}$P$8NaClNaClMeOtoCi6dkB5NlSyY.wFQ.'); ok $ppr; is $ppr->cost, 10; is $ppr->salt, "NaClNaCl"; is $ppr->hash_base64, "MeOtoCi6dkB5NlSyY.wFQ."; my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) ([^ \n]+) *//; my($cost_base64, $salt, $hash_base64) = ($1, $2, $3, $4); $ppr = Authen::Passphrase::PHPass ->new(cost_base64 => $cost_base64, salt => $salt, hash_base64 => $hash_base64); ok $ppr; is $ppr->cost_base64, $cost_base64; is $ppr->salt, $salt; is $ppr->hash_base64, $hash_base64; eval { $ppr->passphrase }; isnt $@, ""; my $crypt_string = "\$P\$".$cost_base64.$salt.$hash_base64; is $ppr->as_crypt, $crypt_string; is $ppr->as_rfc2307, "{CRYPT}$crypt_string"; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ 6 MVeiwNN2 Z9ajy4aaEmIhSGxgfIMbF/ 3 tWgAqczl uHKlOhHYT1V80gVQxgypw. 0 7 Fi0425wg bQvE6tzjOfMPGgENlndLm/ 1 8 EP62lbrh mf/uFiTNicupnEEbqAbK70 foo 9 /.ksQxvw hZ7Sdy4MmLyS15OJjhbrG1 supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/mysql323.t000444001750001750 201611713235576 17202 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 59; BEGIN { use_ok "Authen::Passphrase::MySQL323"; } my $ppr = Authen::Passphrase::MySQL323->new(passphrase => "wibble"); ok $ppr; is $ppr->hash, "\x1d\x1a\x1e\x8f\x50\xfe\xa4\xe3"; is $ppr->hash_hex, "1d1a1e8f50fea4e3"; my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) *//; my $hash_hex = $1; my $hash = pack("H*", $hash_hex); $ppr = Authen::Passphrase::MySQL323 ->new(($i++ & 1) ? (hash => $hash) : (hash_hex => $hash_hex)); ok $ppr; is $ppr->hash_hex, lc($hash_hex); is $ppr->hash, $hash; eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; eval { $ppr->as_rfc2307 }; isnt $@, ""; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ 5030573512345671 606717756665BCE6 0 606717496665BCBA 1 7c786c222596437b foo 6873f3091d7dad18 supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/ssha.t000444001750001750 303011713235576 16540 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 70; use MIME::Base64 2.21 qw(encode_base64); BEGIN { use_ok "Authen::Passphrase::SaltedDigest"; } my $ppr = Authen::Passphrase::SaltedDigest ->from_rfc2307("{SSHA}Su3QumFIRp1xFfRZ49hwaJmme+r1iVoM"); ok $ppr; is $ppr->algorithm, "SHA-1"; is $ppr->salt_hex, "f5895a0c"; is $ppr->hash_hex, "4aedd0ba6148469d7115f459e3d8706899a67bea"; my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) ([^ \n]+) *//; my($salt_hex, $hash_hex) = ($1, $2); my $salt = pack("H*", $salt_hex); my $hash = pack("H*", $hash_hex); my $ppr = Authen::Passphrase::SaltedDigest ->new(algorithm => "SHA-1", ($i & 1) ? (salt => $salt) : (salt_hex => $salt_hex), ($i & 2) ? (hash => $hash) : (hash_hex => $hash_hex)); $i++; ok $ppr; is $ppr->salt_hex, $salt_hex; is $ppr->salt, $salt; is $ppr->hash_hex, $hash_hex; is $ppr->hash, $hash; eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; is $ppr->as_rfc2307, "{SSHA}".encode_base64($hash.$salt, ""); $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ 616263 a9993e364706816aba3e25717850c26c9cd0d89d 717765 7cd928d1e6457c57c01f3c9442177fc62cafa56f 0 212121 2fee6a4e9b98f3bd6de8b1960cfb37f8b44d8bb1 1 787878 76cdd1408a02a44687fe87c98f8dc43678c4ef5f foo 707966 b264504de2719cebf898608cf950e1da5f3ae28f supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/vmspurdy.t000444001750001750 1033411713235576 17520 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 110; BEGIN { use_ok "Authen::Passphrase::VMSPurdy"; } my $ppr = Authen::Passphrase::VMSPurdy ->new(username => "jrandom", salt => 1234, passphrase => "wibble"); ok $ppr; is $ppr->algorithm, "PURDY_S"; is $ppr->username, "JRANDOM"; is $ppr->salt, 1234; is $ppr->salt_hex, "D204"; is $ppr->hash, "\x2c\xef\x67\x47\x77\xa5\x48\x80"; is $ppr->hash_hex, "2CEF674777A54880"; is $ppr->as_crypt, '$VMS3$D2042CEF674777A54880JRANDOM'; is $ppr->as_rfc2307, '{CRYPT}$VMS3$D2042CEF674777A54880JRANDOM'; $ppr = Authen::Passphrase::VMSPurdy ->new(algorithm => "PURDY", username => "jrandom", salt => 1234, passphrase => "wibble"); ok $ppr; is $ppr->algorithm, "PURDY"; is $ppr->username, "JRANDOM"; is $ppr->salt, 1234; is $ppr->salt_hex, "D204"; is $ppr->hash, "\xee\xf2\xac\x3d\xe0\xd9\x86\xa7"; is $ppr->hash_hex, "EEF2AC3DE0D986A7"; is $ppr->as_crypt, '$VMS1$D204EEF2AC3DE0D986A7JRANDOM'; is $ppr->as_rfc2307, '{CRYPT}$VMS1$D204EEF2AC3DE0D986A7JRANDOM'; $ppr = Authen::Passphrase::VMSPurdy ->new(algorithm => "PURDY_V", username => "jrandom", salt => 1234, passphrase => "wibble"); ok $ppr; is $ppr->algorithm, "PURDY_V"; is $ppr->username, "JRANDOM"; is $ppr->salt, 1234; is $ppr->salt_hex, "D204"; is $ppr->hash, "\xe3\x76\xee\x1b\x7a\xfa\xd4\x64"; is $ppr->hash_hex, "E376EE1B7AFAD464"; is $ppr->as_crypt, '$VMS2$D204E376EE1B7AFAD464JRANDOM'; is $ppr->as_rfc2307, '{CRYPT}$VMS2$D204E376EE1B7AFAD464JRANDOM'; $ppr = Authen::Passphrase::VMSPurdy ->new(algorithm => "PURDY_S", username => "jrandom", salt => 1234, passphrase => "WiBbLe"); ok $ppr; is $ppr->algorithm, "PURDY_S"; is $ppr->username, "JRANDOM"; is $ppr->salt, 1234; is $ppr->salt_hex, "D204"; is $ppr->hash, "\x2c\xef\x67\x47\x77\xa5\x48\x80"; is $ppr->hash_hex, "2CEF674777A54880"; is $ppr->as_crypt, '$VMS3$D2042CEF674777A54880JRANDOM'; is $ppr->as_rfc2307, '{CRYPT}$VMS3$D2042CEF674777A54880JRANDOM'; $ppr = Authen::Passphrase::VMSPurdy ->new(username => "jrandom", salt_random => 1, passphrase => "wibble"); is $ppr->algorithm, "PURDY_S"; is $ppr->username, "JRANDOM"; ok $ppr->salt >= 0 && $ppr->salt < 65536; like $ppr->salt_hex, qr/\A[0-9A-F]{4}\z/; is length($ppr->hash), 8; like $ppr->hash_hex, qr/\A[0-9A-F]{16}\z/; ok $ppr->match("wibble"); $ppr = Authen::Passphrase::VMSPurdy ->from_crypt('$VMS3$D43D6E82B577FBB9CFD4ORINOCO'); ok $ppr; is $ppr->algorithm, "PURDY_S"; is $ppr->username, "ORINOCO"; is $ppr->salt, 15828; is $ppr->salt_hex, "D43D"; is $ppr->hash, "\x6e\x82\xb5\x77\xfb\xb9\xcf\xd4"; is $ppr->hash_hex, "6E82B577FBB9CFD4"; is $ppr->as_crypt, '$VMS3$D43D6E82B577FBB9CFD4ORINOCO'; is $ppr->as_rfc2307, '{CRYPT}$VMS3$D43D6E82B577FBB9CFD4ORINOCO'; $ppr = Authen::Passphrase::VMSPurdy ->from_rfc2307('{CrYpT}$VMS3$D43D6E82B577FBB9CFD4ORINOCO'); ok $ppr; is $ppr->algorithm, "PURDY_S"; is $ppr->username, "ORINOCO"; is $ppr->salt, 15828; is $ppr->salt_hex, "D43D"; is $ppr->hash, "\x6e\x82\xb5\x77\xfb\xb9\xcf\xd4"; is $ppr->hash_hex, "6E82B577FBB9CFD4"; is $ppr->as_crypt, '$VMS3$D43D6E82B577FBB9CFD4ORINOCO'; is $ppr->as_rfc2307, '{CRYPT}$VMS3$D43D6E82B577FBB9CFD4ORINOCO'; foreach my $badpass ("", "a b", "1!", "oaoaoaoaoaoaoaoaoaoaoaoaoaoaoaoab") { eval { Authen::Passphrase::VMSPurdy ->new(username => "jrandom", salt => 1234, passphrase => $badpass); }; isnt $@, ""; } my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) ([^ \n]+) ([^ \n]+) *//; my($algorithm, $username, $salt, $hash_hex) = ($1, $2, $3, $4); $ppr = Authen::Passphrase::VMSPurdy ->new(algorithm => $algorithm, username => $username, salt => $salt, hash_hex => $hash_hex); ok $ppr; is $ppr->algorithm, $algorithm; is $ppr->username, uc($username); is $ppr->salt, $salt; is $ppr->hash, pack("H*", $hash_hex); is $ppr->hash_hex, uc($hash_hex); eval { $ppr->passphrase }; isnt $@, ""; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ PURDY Chekov 63412 6ec0aed034aca888 0 PURDY_S Kirk 5623 4e9c1cf8b461c7ff 1 PURDY_V Spock 9084 7d63771C2BC9bb96 foo PURDY_V Sulu 645 0bcedbfcec4dee1d supercalifragilisticexpialidocio Authen-Passphrase-0.008/t/pod_cvg.t000444001750001750 27311713235576 17211 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More; plan skip_all => "Test::Pod::Coverage not available" unless eval "use Test::Pod::Coverage; 1"; Test::Pod::Coverage::all_pod_coverage_ok(); 1; Authen-Passphrase-0.008/t/extdescrypt.t000444001750001750 240411713235576 20164 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 77; BEGIN { use_ok "Authen::Passphrase::DESCrypt"; } my $ppr = Authen::Passphrase::DESCrypt->from_crypt("_cD..NaClP7NemfyIO3Y"); ok $ppr; ok $ppr->fold; is $ppr->initial_base64, "..........."; is $ppr->nrounds, 1000; is $ppr->salt_base64_4, "NaCl"; is $ppr->hash_base64, "P7NemfyIO3Y"; my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) ([^ \n]+) *//; my($nrounds, $salt, $hash) = ($1, $2, $3); $ppr = Authen::Passphrase::DESCrypt ->new(fold => 1, nrounds_base64 => $nrounds, salt_base64 => $salt, hash_base64 => $hash); ok $ppr; ok $ppr->fold; is $ppr->initial_base64, "..........."; is $ppr->nrounds_base64_4, $nrounds; is $ppr->salt_base64_4, $salt; is $ppr->hash_base64, $hash; eval { $ppr->passphrase }; isnt $@, ""; is $ppr->as_crypt, "_".$nrounds.$salt.$hash; is $ppr->as_rfc2307, "{CRYPT}_".$nrounds.$salt.$hash; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ fiO. zjn3 EwD4x5Zn7lY i9O/ VDnK bXjK3LN9iE2 0 3Ro. TEkq ACp9yg0cqDM 1 I4l. wIO. yaNPU/4ioNk foo eGu. aKa2 YN9krx1eBSE supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/rejectall.t000444001750001750 130711713235576 17554 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 14; BEGIN { use_ok "Authen::Passphrase::RejectAll"; } my $ppr = Authen::Passphrase::RejectAll->new; ok $ppr; my $ppr1 = Authen::Passphrase::RejectAll->from_crypt("*"); is $ppr1, $ppr; eval { Authen::Passphrase::RejectAll->from_crypt("............."); }; isnt $@, ""; $ppr1 = Authen::Passphrase::RejectAll->from_rfc2307("{CrYpT}*"); is $ppr1, $ppr; eval { Authen::Passphrase::RejectAll->from_rfc2307("{CrYpT}............."); }; isnt $@, ""; foreach my $passphrase("", qw(0 1 foo supercalifragilisticexpialidocious)) { ok !$ppr->match($passphrase); } eval { $ppr->passphrase }; isnt $@, ""; is $ppr->as_crypt, "*"; is $ppr->as_rfc2307, "{CRYPT}*"; 1; Authen-Passphrase-0.008/t/gendescrypt.t000444001750001750 217611713235576 20143 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 71; BEGIN { use_ok "Authen::Passphrase::DESCrypt"; } my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) ([^ \n]+) ([^ \n]+) *//; my($nrounds, $salt, $initial, $hash) = ($1, $2, $3, $4); my $ppr = Authen::Passphrase::DESCrypt ->new(fold => 1, initial_base64 => $initial, nrounds_base64 => $nrounds, salt_base64 => $salt, hash_base64 => $hash); ok $ppr; ok $ppr->fold; is $ppr->nrounds_base64_4, $nrounds; is $ppr->salt_base64_4, $salt; is $ppr->initial_base64, $initial; is $ppr->hash_base64, $hash; eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; eval { $ppr->as_rfc2307 }; isnt $@, ""; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ xIw. Alif bXjK3LN9iE2 6UN3gAqtTbM Eoz. jn35 ACp9yg0cqDM puFoxi30V2o 0 6.d. UyXU yaNPU/4ioNk ZxMRQY8Bpdo 1 Ogc. qu8. YN9krx1eBSE Vcrdw3DtWc6 foo bAy. XCaN EwD4x5Zn7lY 7KB8x6lwKIQ supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/md5crypt.t000444001750001750 317611713235576 17364 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 69; BEGIN { use_ok "Authen::Passphrase::MD5Crypt"; } my $ppr = Authen::Passphrase::MD5Crypt ->new(salt => "NaCl", passphrase => "wibble"); ok $ppr; is $ppr->salt, "NaCl"; is $ppr->hash_base64, "xdhxXxtV42/rvGFe//aQu/"; $ppr = Authen::Passphrase::MD5Crypt ->new(salt_random => 1, passphrase => "wibble"); ok $ppr; like $ppr->salt, qr#\A[./0-9A-Za-z]{8}\z#; like $ppr->hash_base64, qr#\A[./0-9A-Za-z]{22}\z#; ok $ppr->match("wibble"); $ppr = Authen::Passphrase::MD5Crypt ->from_crypt('$1$Vd3f8aG6$2vsEqBwwsrvUdUYK40Dtm/'); ok $ppr; is $ppr->salt, "Vd3f8aG6"; is $ppr->hash_base64, "2vsEqBwwsrvUdUYK40Dtm/"; $ppr = Authen::Passphrase::MD5Crypt ->from_rfc2307('{CrYpT}$1$Vd3f8aG6$2vsEqBwwsrvUdUYK40Dtm/'); ok $ppr; is $ppr->salt, "Vd3f8aG6"; is $ppr->hash_base64, "2vsEqBwwsrvUdUYK40Dtm/"; my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) *//; my($salt, $hash) = ($1, $2); $ppr = Authen::Passphrase::MD5Crypt ->new(salt => $salt, hash_base64 => $hash); ok $ppr; is $ppr->salt, $salt; is $ppr->hash_base64, $hash; eval { $ppr->passphrase }; isnt $@, ""; is $ppr->as_crypt, "\$1\$".$salt."\$".$hash; is $ppr->as_rfc2307, "{CRYPT}\$1\$".$salt."\$".$hash; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ .ek8tjGw JlwHaPpGUeCpzvx6DSYt.0 ZoDb0wM1 TSZxQ/qndpG1yB9HqCMHg/ 0 Z7/4DX0p 6IBWggA5iXUKnYI7xhl6R1 1 RveEKWw9 //PkU.geQpEJRr7JoK7ey/ foo Tdb1JRjV CTqZJJGDNwtm6ScQ2w6md/ supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/crypt16.t000444001750001750 366511713235576 17130 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 83; BEGIN { use_ok "Authen::Passphrase::Crypt16"; } my $ppr = Authen::Passphrase::Crypt16 ->new(salt => 1234, hash => "abcdefghABCDEFGH"); ok $ppr; is $ppr->salt, 1234; is $ppr->salt_base64_2, "GH"; is $ppr->hash, "abcdefghABCDEFGH"; is $ppr->hash_base64, "MK7XN4JaNqUEI71F2J4FoU"; my $h0 = $ppr->first_half; ok $h0; is $h0->fold, !!0; is $h0->initial, "\0\0\0\0\0\0\0\0"; is $h0->nrounds, 20; is $h0->salt, 1234; is $h0->hash_base64, "MK7XN4JaNqU"; my $h1 = $ppr->second_half; ok $h1; is $h1->fold, !!0; is $h1->initial, "\0\0\0\0\0\0\0\0"; is $h1->nrounds, 5; is $h1->salt, 1234; is $h1->hash_base64, "EI71F2J4FoU"; $ppr = Authen::Passphrase::Crypt16 ->new(salt => 1234, passphrase => "wibble"); ok $ppr; is $ppr->salt, 1234; is $ppr->hash_base64, "QYUQgj6nmd.g/xAujudtXo"; $ppr = Authen::Passphrase::Crypt16 ->new(salt => 1234, passphrase => "wibblewobble"); ok $ppr; is $ppr->salt, 1234; is $ppr->hash_base64, "1ndJ4WMAo3s.CbKCSyRbco"; $ppr = Authen::Passphrase::Crypt16 ->new(salt_random => 12, passphrase => "wibblewobble"); ok $ppr; is length($ppr->salt_base64_2), 2; is length($ppr->hash), 16; ok $ppr->match("wibblewobble"); my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) *//; my($salt, $hash) = ($1, $2); $ppr = Authen::Passphrase::Crypt16 ->new(salt_base64 => $salt, hash_base64 => $hash); ok $ppr; is $ppr->salt_base64_2, $salt; is $ppr->hash_base64, $hash; eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; eval { $ppr->as_rfc2307 }; isnt $@, ""; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ 7S ...........4VBRyAvp9nw Ur ImG9Kp15IQsO2OoWANp2qc 0 QZ 7Dztte564Tsv/MSAT.EjMA 1 Qe tZVtOlWcUdEgK.3Asz6yo. foo Uk uSoh3oV2exsgb27c/7adao supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/eggdropblowfish.t000444001750001750 313211713235576 20772 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 84; BEGIN { use_ok "Authen::Passphrase::EggdropBlowfish"; } my $ppr = Authen::Passphrase::EggdropBlowfish->new(passphrase => "wibble"); ok $ppr; is $ppr->hash, "\xdc\x05\x56\x67\x87\x9a\xac\xe1"; is $ppr->hash_base64, "vNEA50Bnj/q1"; ok $ppr->match("wibble"); $ppr = Authen::Passphrase::EggdropBlowfish->new( hash => "\xdc\x05\x56\x67\x87\x9a\xac\xe1"); ok $ppr; is $ppr->hash, "\xdc\x05\x56\x67\x87\x9a\xac\xe1"; is $ppr->hash_base64, "vNEA50Bnj/q1"; $ppr = Authen::Passphrase::EggdropBlowfish->new(hash_base64 => "vNEA50Bnj/q1"); ok $ppr; is $ppr->hash, "\xdc\x05\x56\x67\x87\x9a\xac\xe1"; is $ppr->hash_base64, "vNEA50Bnj/q1"; eval { Authen::Passphrase::EggdropBlowfish->new(passphrase => ""); }; isnt $@, ""; my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) *//; my $hash_base64 = $1; $ppr = Authen::Passphrase::EggdropBlowfish ->new(hash_base64 => $hash_base64); ok $ppr; is $ppr->hash_base64, $hash_base64; eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; eval { $ppr->as_rfc2307 }; isnt $@, ""; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; ok !$ppr->match(""); foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ v.gq8.qm3rM1 0 V6ZOx0rVGWT0 1 AINZW/4MSzQ1 foo V7/Cv0ShonY0 supercalifragilisticexpialidocious jdwmI1F5evD0 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr UlrmE/pDCZE/ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz Authen-Passphrase-0.008/t/traddescrypt.t000444001750001750 215211713235576 20316 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 77; BEGIN { use_ok "Authen::Passphrase::DESCrypt"; } my $ppr = Authen::Passphrase::DESCrypt->from_crypt("UBJcPos7octOA"); ok $ppr; ok !$ppr->fold; is $ppr->initial_base64, "..........."; is $ppr->nrounds, 25; is $ppr->salt_base64_2, "UB"; is $ppr->hash_base64, "JcPos7octOA"; my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) *//; my($salt, $hash) = ($1, $2); $ppr = Authen::Passphrase::DESCrypt ->new(salt_base64 => $salt, hash_base64 => $hash); ok $ppr; ok !$ppr->fold; is $ppr->initial_base64, "..........."; is $ppr->nrounds, 25; is $ppr->salt_base64_2, $salt; is $ppr->hash_base64, $hash; eval { $ppr->passphrase }; isnt $@, ""; is $ppr->as_crypt, $salt.$hash; is $ppr->as_rfc2307, "{CRYPT}".$salt.$hash; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ Lg 3RoTEkqxIwA f4 eGuaKa2lifE 0 Bu fiOozjn356. 1 e5 dUyXVDnKUOg foo pl I4lcqu8wIO. supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/acceptall.t000444001750001750 126311713235576 17540 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 14; BEGIN { use_ok "Authen::Passphrase::AcceptAll"; } my $ppr = Authen::Passphrase::AcceptAll->new; ok $ppr; my $ppr1 = Authen::Passphrase::AcceptAll->from_crypt(""); is $ppr1, $ppr; eval { Authen::Passphrase::AcceptAll->from_crypt("............."); }; isnt $@, ""; $ppr1 = Authen::Passphrase::AcceptAll->from_rfc2307("{CrYpT}"); is $ppr1, $ppr; eval { Authen::Passphrase::AcceptAll->from_rfc2307("{CrYpT}............."); }; isnt $@, ""; foreach my $passphrase("", qw(0 1 foo supercalifragilisticexpialidocious)) { ok $ppr->match($passphrase); } is $ppr->passphrase, ""; is $ppr->as_crypt, ""; is $ppr->as_rfc2307, "{CRYPT}"; 1; Authen-Passphrase-0.008/t/clear.t000444001750001750 131211713235576 16671 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 49; BEGIN { use_ok "Authen::Passphrase::Clear"; } my $ppr = Authen::Passphrase::Clear->from_rfc2307("{CLEARTEXT}womble"); ok $ppr; is $ppr->passphrase, "womble"; eval { Authen::Passphrase::Clear->from_rfc2307("{CRYPT}*"); }; isnt $@, ""; my @test_phrases = ("", qw(0 1 foo supercalifragilisticexpialidocious)); foreach my $rightphrase (@test_phrases) { $ppr = Authen::Passphrase::Clear->new($rightphrase); ok $ppr; foreach my $passphrase (@test_phrases) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } is $ppr->passphrase, $rightphrase; eval { $ppr->as_crypt }; isnt $@, ""; is $ppr->as_rfc2307, "{CLEARTEXT}".$rightphrase; } 1; Authen-Passphrase-0.008/t/nthash.t000444001750001750 341711713235576 17100 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 67; BEGIN { use_ok "Authen::Passphrase::NTHash"; } my $ppr = Authen::Passphrase::NTHash->new(passphrase => "wibble"); ok $ppr; is $ppr->hash, "\x53\xf0\xfa\xe7\xd5\x3b\xbe\x6c". "\x90\xf8\x43\xec\xeb\x71\xdc\xa0"; is $ppr->hash_hex, "53f0fae7d53bbe6c90f843eceb71dca0"; $ppr = Authen::Passphrase::NTHash ->from_crypt('$3$$008152e575f1b34babf315cc4971c15d'); ok $ppr; is $ppr->hash_hex, "008152e575f1b34babf315cc4971c15d"; $ppr = Authen::Passphrase::NTHash ->from_crypt('$NT$008152e575f1b34babf315cc4971c15d'); ok $ppr; is $ppr->hash_hex, "008152e575f1b34babf315cc4971c15d"; $ppr = Authen::Passphrase::NTHash ->from_rfc2307('{CrYpT}$3$$008152e575f1b34babf315cc4971c15d'); ok $ppr; is $ppr->hash_hex, "008152e575f1b34babf315cc4971c15d"; $ppr = Authen::Passphrase::NTHash ->from_rfc2307('{MsNt}008152e575f1b34BABf315cc4971c15d'); ok $ppr; is $ppr->hash_hex, "008152e575f1b34babf315cc4971c15d"; my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) *//; my $hash_hex = $1; my $hash = pack("H*", $hash_hex); $ppr = Authen::Passphrase::NTHash ->new(($i++ & 1) ? (hash => $hash) : (hash_hex => $hash_hex)); ok $ppr; is $ppr->hash_hex, lc($hash_hex); is $ppr->hash, $hash; eval { $ppr->passphrase }; isnt $@, ""; is $ppr->as_crypt, "\$3\$\$".lc($hash_hex); is $ppr->as_rfc2307, "{MSNT}".lc($hash_hex); $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ 31d6cfe0d16ae931b73c59d7e0c089c0 7bc26760a19fc23e0996daa99744ca80 0 69943C5E63B4D2C104DBBCC15138B72B 1 ac8e657f83df82beea5d43bdaf7800cc foo f5295d5b0a47abecb70ed08bdb6d4e6e supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/netscapemail.t000444001750001750 366111713235576 20261 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 67; BEGIN { use_ok "Authen::Passphrase::NetscapeMail"; } my $ppr = Authen::Passphrase::NetscapeMail ->new(salt => "abcdefghijklmnopABCDEFGHIJKLMNOP", passphrase => "wibble"); ok $ppr; is $ppr->salt, "abcdefghijklmnopABCDEFGHIJKLMNOP"; is $ppr->hash, "\x6f\xc4\xc7\x45\xd9\x6d\x05\x53". "\xd8\x95\x39\x33\x81\x75\x38\xfe"; is $ppr->hash_hex, "6fc4c745d96d0553d8953933817538fe"; $ppr = Authen::Passphrase::NetscapeMail ->new(salt_random => 1, passphrase => "wibble"); ok $ppr; like $ppr->salt, qr/\A[0-9a-f]{32}\z/; is length($ppr->hash), 16; ok $ppr->match("wibble"); $ppr = Authen::Passphrase::NetscapeMail->from_rfc2307( "{NS-MTA-MD5}f553c0b7d40a9f815638FCAC319e30c2". "45f6204ab8e103b3dc38a93fbf4d1ad1"); ok $ppr; is $ppr->salt, "45f6204ab8e103b3dc38a93fbf4d1ad1"; is $ppr->hash_hex, "f553c0b7d40a9f815638fcac319e30c2"; my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) ([^ \n]+) *//; my($salt, $hash_hex) = ($1, $2); $ppr = Authen::Passphrase::NetscapeMail ->new(salt => $salt, ($i++ & 1) ? (hash_hex => $hash_hex) : (hash => pack("H*", $hash_hex))); ok $ppr; is $ppr->salt, $salt; is $ppr->hash_hex, lc($hash_hex); is $ppr->hash, pack("H*", $hash_hex); eval { $ppr->passphrase }; isnt $@, ""; is $ppr->as_rfc2307, "{NS-MTA-MD5}".lc($hash_hex).$salt; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ hlV8:`2Q4?@^If)5(cf4xbDKV#o\Sk(` d019c4507be8652975e62871acaa7b52 te6]{4LF|aKFZ;Gcd0}Mul"Wmfg\;fn) 8178663855a984e46d55c57beecefdc2 0 PmkK.8*qCB5JDq}]d#B]8/2`sGENeHKK 8129e982919eec1a70c0a7b28e8425c3 1 m6x*g?v;,"\i[|7/rto~Su6rH?*t|L50 585C16EFA23F1FB1259318314DD78D57 foo <#O[v2gbw46=L}frBIgJ1l:Hw3Z9Wz[, f168cf3e2e5558c2b1be5841d3601e10 supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/lanman.t000444001750001750 332011713235576 17052 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 75; BEGIN { use_ok "Authen::Passphrase::LANManager"; } my $ppr = Authen::Passphrase::LANManager ->new(passphrase => "wibble"); ok $ppr; is $ppr->hash, "\xfa\x19\x61\x43\x0a\x96\xf9\xbe". "\xaa\xd3\xb4\x35\xb5\x14\x04\xee"; is $ppr->hash_hex, "fa1961430a96f9beaad3b435b51404ee"; $ppr = Authen::Passphrase::LANManager ->new(passphrase => "wibblewobble"); ok $ppr; is $ppr->hash_hex, "8ff3acd71203e5ad12f825806ba3a168"; $ppr = Authen::Passphrase::LANManager ->from_rfc2307("{LANMAN}f67023e95cc9dc1CAad3b435b51404ee"); ok $ppr; is $ppr->hash_hex, "f67023e95cc9dc1caad3b435b51404ee"; $ppr = Authen::Passphrase::LANManager ->from_rfc2307("{LANM}f67023e95cc9dc1CAad3b435b51404ee"); ok $ppr; is $ppr->hash_hex, "f67023e95cc9dc1caad3b435b51404ee"; my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) *//; my $hash_hex = $1; my $hash = pack("H*", $hash_hex); $ppr = Authen::Passphrase::LANManager ->new(($i++ & 1) ? (hash_hex => $hash_hex) : (hash => $hash)); ok $ppr; is $ppr->hash_hex, lc($hash_hex); is $ppr->hash, $hash; is $ppr->first_half->hash, substr($hash, 0, 8); is $ppr->second_half->hash, substr($hash, 8, 8); eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; is $ppr->as_rfc2307, "{LANMAN}".lc($hash_hex); $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ aad3b435b51404eeaad3b435b51404ee 25AD3B83FA6627C7AAD3B435B51404EE 0 C2265B23734E0DACAAD3B435B51404EE 1 5bfafbebfb6a0942aad3b435b51404ee foo f0e963830c0156217887ed3fba9a7ed5 supercalifragi Authen-Passphrase-0.008/t/lanmanhalf.t000444001750001750 245711713235576 17717 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 63; BEGIN { use_ok "Authen::Passphrase::LANManagerHalf"; } my $ppr = Authen::Passphrase::LANManagerHalf ->new(passphrase => "wibble"); ok $ppr; is $ppr->hash, "\xfa\x19\x61\x43\x0a\x96\xf9\xbe"; is $ppr->hash_hex, "fa1961430a96f9be"; $ppr = Authen::Passphrase::LANManagerHalf ->from_crypt('$LM$f67023e95cc9dc1c'); ok $ppr; is $ppr->hash_hex, "f67023e95cc9dc1c"; $ppr = Authen::Passphrase::LANManagerHalf ->from_rfc2307('{CRYPT}$LM$f67023e95cc9dc1c'); ok $ppr; is $ppr->hash_hex, "f67023e95cc9dc1c"; my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) *//; my $hash_hex = $1; my $hash = pack("H*", $hash_hex); $ppr = Authen::Passphrase::LANManagerHalf ->new(($i++ & 1) ? (hash_hex => $hash_hex) : (hash => $hash)); ok $ppr; is $ppr->hash_hex, lc($hash_hex); is $ppr->hash, $hash; eval { $ppr->passphrase }; isnt $@, ""; is $ppr->as_crypt, "\$LM\$".lc($hash_hex); is $ppr->as_rfc2307, "{CRYPT}\$LM\$".lc($hash_hex); $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ aad3b435b51404ee 25AD3B83FA6627C7 0 C2265B23734E0DAC 1 5bfafbebfb6a0942 foo f0e963830c015621 superca Authen-Passphrase-0.008/t/bigcrypt.t000444001750001750 523111713235576 17432 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 176; BEGIN { use_ok "Authen::Passphrase::BigCrypt"; } my $ppr = Authen::Passphrase::BigCrypt ->new(salt => 1234, hash => "abcdefghABCDEFGH"); ok $ppr; is $ppr->salt, 1234; is $ppr->salt_base64_2, "GH"; is $ppr->hash, "abcdefghABCDEFGH"; is $ppr->hash_base64, "MK7XN4JaNqUEI71F2J4FoU"; is scalar(@{$ppr->sections}), 2; my($h0, $h1) = @{$ppr->sections}; ok $h0; is $h0->fold, !!0; is $h0->initial, "\0\0\0\0\0\0\0\0"; is $h0->nrounds, 25; is $h0->salt, 1234; is $h0->hash_base64, "MK7XN4JaNqU"; ok $h1; is $h1->fold, !!0; is $h1->initial, "\0\0\0\0\0\0\0\0"; is $h1->nrounds, 25; is $h1->salt_base64_2, "MK"; is $h1->hash_base64, "EI71F2J4FoU"; $ppr = Authen::Passphrase::BigCrypt ->new(salt => 1234, passphrase => "wibble"); ok $ppr; is $ppr->salt, 1234; is $ppr->hash_base64, "pWC.A0n3XaE"; is scalar(@{$ppr->sections}), 1; is $ppr->sections->[0]->as_crypt, "GHpWC.A0n3XaE"; $ppr = Authen::Passphrase::BigCrypt ->new(salt => 1234, passphrase => "wibblewobble"); ok $ppr; is $ppr->salt, 1234; is $ppr->hash_base64, "ClcTIo/hKYMIsgSBrBO7vU"; is scalar(@{$ppr->sections}), 2; is $ppr->sections->[0]->as_crypt, "GHClcTIo/hKYM"; is $ppr->sections->[1]->as_crypt, "ClIsgSBrBO7vU"; $ppr = Authen::Passphrase::BigCrypt ->new(salt => 1234, passphrase => "wibblewobblewubble"); ok $ppr; is $ppr->salt, 1234; is $ppr->hash_base64, "ClcTIo/hKYMRkDdXYPXjHE9gaQPFUyS3U"; is scalar(@{$ppr->sections}), 3; is $ppr->sections->[0]->as_crypt, "GHClcTIo/hKYM"; is $ppr->sections->[1]->as_crypt, "ClRkDdXYPXjHE"; is $ppr->sections->[2]->as_crypt, "Rk9gaQPFUyS3U"; $ppr = Authen::Passphrase::BigCrypt ->new(salt_random => 12, passphrase => "wibblewobble"); ok $ppr; is length($ppr->salt_base64_2), 2; is length($ppr->hash), 16; ok $ppr->match("wibblewobble"); my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) *//; my($salt, $hash) = ($1, $2); $ppr = Authen::Passphrase::BigCrypt ->new(salt_base64 => $salt, hash_base64 => $hash); ok $ppr; is $ppr->salt_base64_2, $salt; is $ppr->hash_base64, $hash; eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; eval { $ppr->as_rfc2307 }; isnt $@, ""; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ 7S 4VBRyAvp9nw Ur 6e9cwNFemc. 0 QZ e2iVWSOxMVk 1 Qe KQ9Te3r2O4o foo JG w9PEfARmc7A supercal yU 7SM20XfzOvsZludTWFafCE supercalfoo vY JR2.m1Ow1WYVoCn.TiPmZw 01234567foo Cy kVuwUqTCr52CwqaDc8rfnE supercalifragili Uk U3cGYFW4ueM72AolWB5yawnxRA.6JGrikjBe.CyUFGDUbf0RYcrvYyU supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/pod_syn.t000444001750001750 23611713235576 17242 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More; plan skip_all => "Test::Pod not available" unless eval "use Test::Pod 1.00; 1"; Test::Pod::all_pod_files_ok(); 1; Authen-Passphrase-0.008/t/blowfishcrypt.t000444001750001750 633311713235576 20512 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 103; BEGIN { use_ok "Authen::Passphrase::BlowfishCrypt"; } my $ppr = Authen::Passphrase::BlowfishCrypt ->new(keying_nrounds_log2 => 8, salt => "abcdefghijklmnop", hash => "ABCDEFGHIJKLMNOPQRSTUVW"); ok $ppr; ok $ppr->key_nul; is $ppr->cost, 8; is $ppr->keying_nrounds_log2, 8; is $ppr->salt, "abcdefghijklmnop"; is $ppr->salt_base64, "WUHhXETkX0fnYkrqZU3ta."; is $ppr->hash, "ABCDEFGHIJKLMNOPQRSTUVW"; is $ppr->hash_base64, "OSHBPCTEPyfHQirKRS3NSDDQSzPTTja"; $ppr = Authen::Passphrase::BlowfishCrypt ->new(cost => 8, salt_base64 => "WUHhXETkX0fnYkrqZU3ta.", hash_base64 => "OSHBPCTEPyfHQirKRS3NSDDQSzPTTja"); ok $ppr; ok $ppr->key_nul; is $ppr->cost, 8; is $ppr->keying_nrounds_log2, 8; is $ppr->salt, "abcdefghijklmnop"; is $ppr->salt_base64, "WUHhXETkX0fnYkrqZU3ta."; is $ppr->hash, "ABCDEFGHIJKLMNOPQRSTUVW"; is $ppr->hash_base64, "OSHBPCTEPyfHQirKRS3NSDDQSzPTTja"; $ppr = Authen::Passphrase::BlowfishCrypt ->new(cost => 8, salt_base64 => "WUHhXETkX0fnYkrqZU3ta.", passphrase => "wibble"); ok $ppr; ok $ppr->key_nul; is $ppr->cost, 8; is $ppr->salt_base64, "WUHhXETkX0fnYkrqZU3ta."; is $ppr->hash_base64, "blPSuQlDs8xl6eM1xtMFFn1QKYeXCXO"; $ppr = Authen::Passphrase::BlowfishCrypt ->new(cost => 8, salt_random => 1, passphrase => "wibble"); ok $ppr; ok $ppr->key_nul; is $ppr->cost, 8; is length($ppr->salt), 16; is length($ppr->hash), 23; ok $ppr->match("wibble"); $ppr = Authen::Passphrase::BlowfishCrypt ->from_crypt('$2a$08$s5VYb9QzBzTUE3h66kH6hOQ'. 'JjrUXrZskQrnTq0SOwFkM0sRsvuzqC'); ok $ppr; ok $ppr->key_nul; is $ppr->cost, 8; is $ppr->salt_base64, "s5VYb9QzBzTUE3h66kH6hO"; is $ppr->hash_base64, "QJjrUXrZskQrnTq0SOwFkM0sRsvuzqC"; $ppr = Authen::Passphrase::BlowfishCrypt ->from_rfc2307('{CrYpT}$2a$08$s5VYb9QzBzTUE3h66kH6hOQ'. 'JjrUXrZskQrnTq0SOwFkM0sRsvuzqC'); ok $ppr; ok $ppr->key_nul; is $ppr->cost, 8; is $ppr->salt_base64, "s5VYb9QzBzTUE3h66kH6hO"; is $ppr->hash_base64, "QJjrUXrZskQrnTq0SOwFkM0sRsvuzqC"; my %pprs; while() { chomp; s/([^ \n]+) ([^ \n]+) ([^ \n]+) ([^ \n]+) *//; my($knul, $cost, $salt_base64, $hash_base64) = ($1, $2, $3, $4); $ppr = Authen::Passphrase::BlowfishCrypt ->new(key_nul => $knul, cost => $cost, salt_base64 => $salt_base64, hash_base64 => $hash_base64); ok $ppr; is !!$ppr->key_nul, !!$knul; is $ppr->cost, $cost; is $ppr->salt_base64, $salt_base64; is $ppr->hash_base64, $hash_base64; eval { $ppr->passphrase }; isnt $@, ""; my $crypt_string = "\$2".($knul ? "a" : "")."\$0".$cost."\$". $salt_base64.$hash_base64; is $ppr->as_crypt, $crypt_string; is $ppr->as_rfc2307, "{CRYPT}$crypt_string"; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ 0 6 Yn6x4nvPtEPkdmRQ74S1Q. ehVP/UL/xbYgKCilZtidy3nc5ttCeLa 0 6 EJv2xOCAoTkNo9y/BtUdLe OVbnD8L9oD7DVE7g0hJgCQO0YA7UHx2 0 0 8 b8i4onzFJ0egD/hxHXSl1O 1dSVPvRb6q5pY5kjW8sYnmfnMWAwPX2 1 1 9 jFan8v8EukXTQzWOHA3Hlu GrNPCCLl5347WLZCdCuNp2VKZOXEDYC foo 0 2 /5A.BZ8WXbFhIEZK5WP7Ku VOUYef56LKYc.4FNp0im8EX7X31EnOa supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/smd5.t000444001750001750 412211713235576 16455 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 81; use MIME::Base64 2.21 qw(encode_base64); BEGIN { use_ok "Authen::Passphrase::SaltedDigest"; } my $ppr = Authen::Passphrase::SaltedDigest ->from_rfc2307("{SMD5}1NdYklP8pSDsgowfOxOK7/x4sUA="); ok $ppr; is $ppr->algorithm, "MD5"; is $ppr->salt_hex, "fc78b140"; is $ppr->hash_hex, "d4d7589253fca520ec828c1f3b138aef"; $ppr = Authen::Passphrase::SaltedDigest ->new(algorithm => "Digest::MD5-1.99_53", salt => "NaCl", passphrase => "wibble"); ok $ppr; is $ppr->salt, "NaCl"; is $ppr->salt_hex, "4e61436c"; is $ppr->hash, "\x04\xbd\x9d\x36\xc5\xc5\x49\x79". "\x84\xa2\x67\x0e\xd2\x44\x2f\x9d"; is $ppr->hash_hex, "04bd9d36c5c5497984a2670ed2442f9d"; like $ppr->as_rfc2307, qr/\A\{SMD5\}/; $ppr = Authen::Passphrase::SaltedDigest ->new(algorithm => "MD5", salt_random => 13, passphrase => "wibble"); ok $ppr; is length($ppr->salt), 13; is length($ppr->hash), 16; like $ppr->as_rfc2307, qr/\A\{SMD5\}/; ok $ppr->match("wibble"); my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) ([^ \n]+) *//; my($salt_hex, $hash_hex) = ($1, $2); my $salt = pack("H*", $salt_hex); my $hash = pack("H*", $hash_hex); $ppr = Authen::Passphrase::SaltedDigest ->new(algorithm => "MD5", ($i & 1) ? (salt => $salt) : (salt_hex => $salt_hex), ($i & 2) ? (hash => $hash) : (hash_hex => $hash_hex)); $i++; ok $ppr; is $ppr->salt_hex, $salt_hex; is $ppr->salt, $salt; is $ppr->hash_hex, $hash_hex; is $ppr->hash, $hash; eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; is $ppr->as_rfc2307, "{SMD5}".encode_base64($hash.$salt, ""); $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ 616263 900150983cd24fb0d6963f7d28e17f72 717765 ce97e12b13baef6403b5456f8fc2ce99 0 212121 b097f957c235fd286364dc2084b2546d 1 787878 097412258a515fc61cfe73f421f58b8f foo 707966 c676f3ddf4b4ed188a89d73525ff678e supercalifragilisticexpialidocious Authen-Passphrase-0.008/t/mysql41.t000444001750001750 232111713235576 17116 0ustar00zeframzefram000000000000use warnings; use strict; use Test::More tests => 59; BEGIN { use_ok "Authen::Passphrase::MySQL41"; } my $ppr = Authen::Passphrase::MySQL41->new(passphrase => "wibble"); ok $ppr; is $ppr->hash, "\xea\x79\x1b\xbc\x44\xf8\x41\x3f\xff\x8c". "\x3e\x93\x9f\xe2\x47\x52\xd4\xe8\x4f\xc7"; is $ppr->hash_hex, "EA791BBC44F8413FFF8C3E939FE24752D4E84FC7"; my %pprs; my $i = 0; while() { chomp; s/([^ \n]+) *//; my $hash_hex = $1; my $hash = pack("H*", $hash_hex); $ppr = Authen::Passphrase::MySQL41 ->new(($i++ & 1) ? (hash => $hash) : (hash_hex => $hash_hex)); ok $ppr; is $ppr->hash_hex, uc($hash_hex); is $ppr->hash, $hash; eval { $ppr->passphrase }; isnt $@, ""; eval { $ppr->as_crypt }; isnt $@, ""; eval { $ppr->as_rfc2307 }; isnt $@, ""; $pprs{$_} = $ppr; } foreach my $rightphrase (sort keys %pprs) { my $ppr = $pprs{$rightphrase}; foreach my $passphrase (sort keys %pprs) { ok ($ppr->match($passphrase) xor $passphrase ne $rightphrase); } } 1; __DATA__ be1bdec0aa74b4dcb079943e70528096cca985f8 B12289EEF8752AD620294A64A37CD586223AB454 0 E6CC90B878B948C35E92B003C792C46C58C4AF40 1 f3a2a51a9b0f2be2468926b4132313728c250dbf foo 2bbbb6095dced8e931a3dd85dc2c2a039932ed6c supercalifragilisticexpialidocious