Crypt-PasswdMD5-1.44/0000755000175000017500000000000015220414063012463 5ustar ronronCrypt-PasswdMD5-1.44/lib/0000755000175000017500000000000015220414063013231 5ustar ronronCrypt-PasswdMD5-1.44/lib/Crypt/0000755000175000017500000000000015220414063014332 5ustar ronronCrypt-PasswdMD5-1.44/lib/Crypt/PasswdMD5.pm0000644000175000017500000001457115220414062016446 0ustar ronronpackage Crypt::PasswdMD5; use strict; use warnings; use Crypt::URandom qw(urandom); use Digest::MD5; use Encode; use Exporter 'import'; our @EXPORT = qw/unix_md5_crypt apache_md5_crypt/; our @EXPORT_OK = (@EXPORT, 'random_md5_salt'); our $VERSION = '1.44'; # ------------------------------------------------ my($itoa64) = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; our($Magic) = q/$1$/; # Magic strings. Need 'our' because of local just below. my($max_salt_length) = 8; # ------------------------------------------------ sub apache_md5_crypt { # Change the Magic string to match the one used by Apache. local $Magic = q/$apr1$/; return unix_md5_crypt(@_); } # End of apache_md5_crypt. # ------------------------------------------------ sub random_md5_salt { my($len) = shift || $max_salt_length; my($salt) = ''; # Sanity check. $len = $max_salt_length unless ( ($len >= 1) and ($len <= $max_salt_length) ); $salt .= substr($itoa64,unpack("C",urandom(1))&0x3F,1) for (1..$len); return $salt; } # End of random_md5_salt. # ------------------------------------------------ sub to64 { my($v, $n) = @_; my($ret) = ''; while (--$n >= 0) { $ret .= substr($itoa64, $v & 0x3f, 1); $v >>= 6; } return $ret; } # End of to64. # ------------------------------------------------ sub unix_md5_crypt { my($pw, $salt) = @_; $pw = Encode::encode('utf8', $pw) if Encode::is_utf8($pw); if (defined $salt) { $salt =~ s/^\Q$Magic//; # Take care of the magic string if present. $salt =~ s/^(.*)\$.*$/$1/; # Salt can have up to 8 chars... $salt = substr($salt, 0, 8); } else { $salt = random_md5_salt(); # In case no salt was proffered. } my($ctx) = Digest::MD5 -> new; # Here we start the calculation. $ctx -> add($pw); # Original password... $ctx -> add($Magic); # ...our magic string... $ctx -> add($salt); # ...the salt... my($final) = Digest::MD5 -> new; $final -> add($pw); $final -> add($salt); $final -> add($pw); $final = $final -> digest; for (my $pl = length($pw); $pl > 0; $pl -= 16) { $ctx -> add(substr($final, 0, $pl > 16 ? 16 : $pl) ); } # Now the 'weird' xform. for (my $i = length($pw); $i; $i >>= 1) { if ($i & 1) { $ctx -> add(pack('C', 0) ); } # This comes from the original version, where a # memset() is done to $final before this loop. else { $ctx -> add(substr($pw, 0, 1) ); } } $final = $ctx -> digest; # The following is supposed to make things run slower. # In perl, perhaps it'll be *really* slow! for (my $i = 0; $i < 1000; $i++) { my($ctx1) = Digest::MD5 -> new; if ($i & 1) { $ctx1 -> add($pw); } else { $ctx1 -> add(substr($final, 0, 16) ); } if ($i % 3) { $ctx1 -> add($salt); } if ($i % 7) { $ctx1 -> add($pw); } if ($i & 1) { $ctx1 -> add(substr($final, 0, 16) ); } else { $ctx1 -> add($pw); } $final = $ctx1 -> digest; } # Final xform my($passwd); $passwd = ''; $passwd .= to64(int(unpack('C', (substr($final, 0, 1) ) ) << 16) | int(unpack('C', (substr($final, 6, 1) ) ) << 8) | int(unpack('C', (substr($final, 12, 1) ) ) ), 4); $passwd .= to64(int(unpack('C', (substr($final, 1, 1) ) ) << 16) | int(unpack('C', (substr($final, 7, 1) ) ) << 8) | int(unpack('C', (substr($final, 13, 1) ) ) ), 4); $passwd .= to64(int(unpack('C', (substr($final, 2, 1) ) ) << 16) | int(unpack('C', (substr($final, 8, 1) ) ) << 8) | int(unpack('C', (substr($final, 14, 1) ) ) ), 4); $passwd .= to64(int(unpack('C', (substr($final, 3, 1) ) ) << 16) | int(unpack('C', (substr($final, 9, 1) ) ) << 8) | int(unpack('C', (substr($final, 15, 1) ) ) ), 4); $passwd .= to64(int(unpack('C', (substr($final, 4, 1) ) ) << 16) | int(unpack('C', (substr($final, 10, 1) ) ) << 8) | int(unpack('C', (substr($final, 5, 1) ) ) ), 4); $passwd .= to64(int(unpack('C', substr($final, 11, 1) ) ), 2); return $Magic . $salt . q/$/ . $passwd; } # End of unix_md5_crypt. # ------------------------------------------------ 1; =pod =encoding utf-8 =head1 NAME Crypt::PasswdMD5 - Provide interoperable MD5-based crypt() functions =head1 SYNOPSIS use strict; use warnings; use Crypt::PasswdMD5; my($password) = 'seekrit'; my($salt) = 'pepperoni'; my($unix_crypted) = unix_md5_crypt($password, $salt); my($apache_crypted) = apache_md5_crypt($password, $salt); Or: use strict; use warnings; use Crypt::PasswdMD5 'random_md5_salt'; my($length) = 7; my($salt_1) = random_md5_salt($length); my($salt_2) = random_md5_salt(); # Default to $length == 8. =head1 DESCRIPTION C provides a function compatible with Apache's C<.htpasswd> files. This was contributed by Bryan Hart . This function is exported by default. The C provides a crypt()-compatible interface to the rather new MD5-based crypt() function found in modern operating systems. It's based on the implementation found on FreeBSD 2.2.[56]-RELEASE. This function is also exported by default. For both functions, if a salt value is not supplied, a random salt will be generated, using the function random_md5_salt(). This function is not exported by default. =head1 METHODS =head2 apache_md5_crypt($password, $salt) This sets a magic variable, and then passes all the calling parameters to L. Returns an encrypted version of the given password. Basically, it's a very poor choice for anything other than password authentication. =head2 random_md5_salt([$length]) Here, [] indicate an optional parameter. Returns a random salt of the given length. The maximum length is 8. If C<$length> is omitted, it defaults to 8. =head2 unix_md5_crypt($password, $salt) Returns an encrypted version of the given password. Basically, it's a very poor choice for anything other than password authentication. =head1 Repository L =head1 SUPPORT Bugs should be reported via the CPAN bug tracker at L =head1 LICENSE, AND DISCLAIMER See the accompanying LICENSE file. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =head1 AUTHOR Luis E. Muñoz . Maintenance by Ron Savage as of V 1.40. =cut Crypt-PasswdMD5-1.44/META.yml0000664000175000017500000000162315220414063013740 0ustar ronron--- abstract: 'Provide interoperable MD5-based crypt() functions' author: - 'Luis E. Munoz ' build_requires: ExtUtils::MakeMaker: '0' Test::More: '1.001002' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Crypt-PasswdMD5 no_index: directory: - t - inc requires: Crypt::URandom: '0' Digest::MD5: '2.53' Encode: '3.21' Exporter: '5.78' ExtUtils::MakeMaker: '7.7' strict: '0' warnings: '0' resources: bugtracker: https://github.com/ronsavage/Crypt-PasswdMD5/issues license: http://opensource.org/licenses/Perl repository: https://github.com/ronsavage/Crypt-PasswdMD5.git version: '1.44' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Crypt-PasswdMD5-1.44/LICENSE0000644000175000017500000000030215220413143013461 0ustar ronronCopyright (C) 1989, 1991 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Crypt-PasswdMD5-1.44/Changelog.ini0000644000175000017500000000604015220414062015052 0ustar ronron[Module] Name=Crypt::PasswdMD5 Changelog.Creator=Module::Metadata::Changes V 2.12 Changelog.Parser=Config::IniFiles V 3.000003 [V 1.44] Date=2026-06-29T00:00:00 Comments= <. - Fabricate some version #s for this file. - Made Passwd.pm utf-8 so we can use Luis' proper name. - Clean up code formatting. - Clean up Makefile.PL. - Use fake (ASCII) in Makefile.PL to keep Solaris happy. See RT#68478. - Clean up README. - Add Build.PL. - Add Changes and Changelog.ini. - Add META.*. - Adopt Test::More in t/basic.t. - Adopt 'use strict' and 'use warnings' to PasswdMD5.pm and t/basic.t. - Accept patch for new function random_md5_salt(), and tests, from kbrint@rufus.net. With thanx. See RT#37036. - Add xt/author/pod.t. EOT [V 1.30] Date=2004-02-17T11:21:38 Comments= <. - Initial release. EOT Crypt-PasswdMD5-1.44/Makefile.PL0000644000175000017500000000323315204160710014435 0ustar ronronuse strict; use warnings; use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. use strict; use warnings; use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. my(%params) = ( ($] ge '5.005') ? ( AUTHOR => 'Luis E. Munoz ', ABSTRACT => 'Provide interoperable MD5-based crypt() functions', ) : (), clean => { FILES => 'blib/* Makefile MANIFEST Crypt-PasswdMD5-*' }, dist => { COMPRESS => 'gzip', SUFFIX => 'gz' }, DISTNAME => 'Crypt-PasswdMD5', LICENSE => 'perl', NAME => 'Crypt::PasswdMD5', PL_FILES => {}, PREREQ_PM => { 'Crypt::URandom' => 0, 'Digest::MD5' => 2.53, 'Encode' => 3.21, 'Exporter' => 5.78, 'ExtUtils::MakeMaker' => 7.70, 'strict' => 0, 'warnings' => 0, }, TEST_REQUIRES => { 'Test::More' => 1.001002, }, VERSION_FROM => 'lib/Crypt/PasswdMD5.pm', INSTALLDIRS => 'site', EXE_FILES => [], ); if ( ($ExtUtils::MakeMaker::VERSION =~ /^\d\.\d\d$/) && ($ExtUtils::MakeMaker::VERSION > 6.30) ) { $params{LICENSE} = 'perl'; } if ($ExtUtils::MakeMaker::VERSION ge '6.46') { $params{META_MERGE} = { 'meta-spec' => { version => 2, }, resources => { bugtracker => { web => 'https://github.com/ronsavage/Crypt-PasswdMD5/issues', }, license => 'http://opensource.org/licenses/Perl', repository => { type => 'git', url => 'https://github.com/ronsavage/Crypt-PasswdMD5.git', web => 'https://github.com/ronsavage/Crypt-PasswdMD5', }, }, }; } WriteMakefile(%params); Crypt-PasswdMD5-1.44/META.json0000664000175000017500000000316515220414063014113 0ustar ronron{ "abstract" : "Provide interoperable MD5-based crypt() functions", "author" : [ "Luis E. Munoz " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Crypt-PasswdMD5", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Crypt::URandom" : "0", "Digest::MD5" : "2.53", "Encode" : "3.21", "Exporter" : "5.78", "ExtUtils::MakeMaker" : "7.7", "strict" : "0", "warnings" : "0" } }, "test" : { "requires" : { "Test::More" : "1.001002" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/ronsavage/Crypt-PasswdMD5/issues" }, "license" : [ "http://opensource.org/licenses/Perl" ], "repository" : { "type" : "git", "url" : "https://github.com/ronsavage/Crypt-PasswdMD5.git", "web" : "https://github.com/ronsavage/Crypt-PasswdMD5" } }, "version" : "1.44", "x_serialization_backend" : "JSON::PP version 4.16" } Crypt-PasswdMD5-1.44/Changes0000644000175000017500000000520715220413650013763 0ustar ronronRevision history for Perl extension Crypt::PasswdMD5. 1.44 2026-06-29 - Replace the file LICENSE-GPL-3 with the file LICENSE containing what is recommended at https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html - Patch the source code reference to refer to this LICENSE file. 1.43 2026-05-23T08:14:00 - Accept pull request from Paul Howarth to replace use of the cryptographically weak rand() function with the much stronger Crypt::URandom::urandom(). With thanx. - Add Encode, Exporter, ExtUtils::MakeMaker to Makefile.PL. - Add files AI_POLICY.md & SECURITY.md. - Delete file LICENSE. - Add file LICENSE-GPL-3 with the latest version from https://fsf.org/. 1.42 2022-07-13T16:20:00 - Accept pull request from Dmitry Karasik, to handle the case where the password has the utf8 bit set. With thanx. - Update t/basic.t to use Encode and to test the utf8 bit setting. - Very slightly reformat the source code of PasswdMD5.pm and basic.t. 1.41 2021-02-01T15:56:00 - Adopt new repo structure. See http://savage.net.au/Ron/html/My.Workflow.for.Building.Distros.html. - Reformat Makefile.PL. - Add t/00.*. - Update POD to change RT to github. 1.40 2013-09-30T15:32:00 - No code changes. - Maintenance by Ron Savage . - Fabricate some version #s for this file. - Made Passwd.pm utf-8 so we can use Luis' proper name. - Clean up code formatting. - Clean up Makefile.PL. - Use fake (ASCII) ñ in Makefile.PL to keep Solaris happy. See RT#68478. - Clean up README. - Add Build.PL. - Add Changes and Changelog.ini. - Add META.*. - Adopt Test::More in t/basic.t. - Adopt 'use strict' and 'use warnings' to PasswdMD5.pm and t/basic.t. - Accept patch for new function random_md5_salt(), and tests, from kbrint@rufus.net. With thanx. See RT#37036. - Add xt/author/pod.t. 1.30 2004-02-17T11:21:38 - luismunoz@cpan.org. - Modified the POD so that ABSTRACT can work. - Added usage example for apache_md5_crypt(). 1.20 2004-02-17T11:04:35 - luismunoz@cpan.org. - Added patch for random salts from John Peacock (Thanks John!). - De-MS-DOS-ified the file. - Replaced some '' with q// to make Emacs color highlighting happy. - Added CVS docs. - Completed the missing sections of the POD documentation. - Changed my email address to the Perl-related one for consistency. 1.10 2001-07-06 - luismunoz@cpan.org. - Use Digest::MD5 instead of the (obsolete) MD5. 1.09 2000-10-06 - wrowe@lnd.com. - Export apache_md5_crypt by default. 1.08 1999-04-02 - bryan@eai.com. - Added apache_md5_crypt to create a valid hash for use in .htpasswd files. 1.00 1998-07-10 - Luis E. Munoz . - Initial release. Crypt-PasswdMD5-1.44/MANIFEST0000644000175000017500000000060015220414063013610 0ustar ronronAI_POLICY.md Changelog.ini Changes lib/Crypt/PasswdMD5.pm LICENSE Makefile.PL MANIFEST This list of files MANIFEST.SKIP README SECURITY.md t/00.versions.t t/00.versions.tx t/basic.t t/random.salt.t xt/author/pod.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Crypt-PasswdMD5-1.44/MANIFEST.SKIP0000644000175000017500000000114414106404517014366 0ustar ronron# Avoid version control files. ,v$ \B\.cvsignore$ \B\.git\b \B\.gitignore\b \B\.svn\b \bCVS\b \bRCS\b # Avoid Makemaker generated and utility files. \bblib \bblibdirs$ \bpm_to_blib$ \bMakefile$ \bMakeMaker-\d # Avoid Module::Build generated and utility files. \b_build \bBuild$ \bBuild.bat$ # Avoid Devel::Cover generated files \bcover_db # Avoid temp and backup files. ~$ \#$ \.# \.bak$ \.old$ \.rej$ \.tmp$ # Avoid OS-specific files/dirs # Mac OSX metadata \B\.DS_Store # Mac OSX SMB mount metadata files \B\._ # Avoid UltraEdit files. \.prj$ \.pui$ ^MYMETA.yml$ ^MYMETA\.json$ ^Crypt-PasswdMD5-.* Crypt-PasswdMD5-1.44/xt/0000755000175000017500000000000015220414063013116 5ustar ronronCrypt-PasswdMD5-1.44/xt/author/0000755000175000017500000000000015220414063014420 5ustar ronronCrypt-PasswdMD5-1.44/xt/author/pod.t0000644000175000017500000000020414106404517015370 0ustar ronronuse Test::More; eval "use Test::Pod 1.45"; plan skip_all => "Test::Pod 1.45 required for testing POD" if $@; all_pod_files_ok(); Crypt-PasswdMD5-1.44/README0000644000175000017500000000255214106404517013354 0ustar ronronREADME file for Crypt::PasswdMD5. See also: CHANGES and Changelog.ini. Warning: WinZip 8.1 and 9.0 both contain an 'accidental' bug which stops them recognizing POSIX-style directory structures in valid tar files. You are better off using a reliable tool such as InfoZip: ftp://ftp.info-zip.org/pub/infozip/ 1 Installing from a Unix-like distro ------------------------------------ shell>gunzip Crypt-PasswdMD5-1.40.tgz shell>tar mxvf Crypt-PasswdMD5-1.40.tar On Unix-like systems, assuming you have installed Module::Build V 0.25+: shell>perl Build.PL shell>./Build shell>./Build test shell>./Build install On MS Windows-like systems, assuming you have installed Module::Build V 0.25+: shell>perl Build.PL shell>perl Build shell>perl Build test shell>perl Build install Alternately, without Module::Build, you do this: Note: 'make' on MS Windows-like systems may be called 'nmake' or 'dmake'. shell>perl Makefile.PL shell>make shell>make test shell>su (for Unix-like systems) shell>make install shell>exit (for Unix-like systems) On all systems: Run PasswdMD5.pm through your favourite pod2html translator. 2 Installing from an ActiveState distro --------------------------------------- shell>unzip Crypt-PasswdMD5-1.40.zip shell>ppm install --location=. Crypt-PasswdMD5 shell>del Crypt-PasswdMD5-1.40.ppd shell>del PPM-Crypt-PasswdMD5-1.40.tar.gz Crypt-PasswdMD5-1.44/t/0000755000175000017500000000000015220414063012726 5ustar ronronCrypt-PasswdMD5-1.44/t/basic.t0000644000175000017500000000214614263462540014210 0ustar ronronuse strict; use warnings; use Test::More; # ------------------------------------------------ use_ok('Encode'); use_ok('Crypt::PasswdMD5'); my($phrase1) = "hello world\n"; my($stage1) = '$1$1234$BhY1eAOOs7IED4HLA5T5o.'; $|=1; ok(unix_md5_crypt($phrase1, '1234') eq $stage1, 'Hashing of a simple phrase + salt'); ok(unix_md5_crypt($phrase1, $stage1) eq $stage1, 'Rehash (check) of the phrase'); my($t) = unix_md5_crypt('', $$); ok(unix_md5_crypt('', $t) eq $t, 'Hashing/rehashing of the empty password'); $t = unix_md5_crypt('test4'); my($salt) = ($t =~ m/\$.+\$(.+)\$/); ok(unix_md5_crypt('test4', $salt) eq $t, 'Make sure null salt works'); # Warning: Do not remove the () around ($salt). $t = apache_md5_crypt('test5'); ($salt) = ($t =~ m/\$.+\$(.+)\$/); ok(apache_md5_crypt('test5', $salt) eq $t, 'And again with the Apache Variant'); ok($t =~ /^\$apr1\$/, '$t now has the correct value'); my($phrase2) = "\x{dead}\x{beef}"; my($phrase3) = Encode::encode('utf8', $phrase2); ok(unix_md5_crypt($phrase2, '1234') eq unix_md5_crypt($phrase3, '1234'), 'Hashing of a utf8 password'); done_testing; Crypt-PasswdMD5-1.44/t/random.salt.t0000644000175000017500000000071714106404517015347 0ustar ronronuse strict; use warnings; use Crypt::PasswdMD5 'random_md5_salt'; use Test::More; # ------------------------------------------------ sub length_is { my $in = shift; my $out = shift; my $salt = random_md5_salt($in); ok($out == length($salt), "random_md5_salt(). Input: $in. Output length: $out"); } # End of length_is. # ------------------------------------------------ length_is($_, $_) for (1..8); length_is(0, 8); length_is(9, 8); done_testing; Crypt-PasswdMD5-1.44/t/00.versions.t0000644000175000017500000000107115204152402015176 0ustar ronron#/usr/bin/env perl use strict; use warnings; # I tried 'require'-ing modules but that did not work. use Crypt::PasswdMD5; # For the version #. use Test::More; use Crypt::URandom; use Digest::MD5; use strict; use warnings; # ---------------------- pass('All external modules loaded'); my(@modules) = qw / Crypt::URandom Digest::MD5 strict warnings /; diag "Testing Crypt::PasswdMD5 V $Crypt::PasswdMD5::VERSION"; for my $module (@modules) { no strict 'refs'; my($ver) = ${$module . '::VERSION'} || 'N/A'; diag "Using $module V $ver"; } done_testing; Crypt-PasswdMD5-1.44/t/00.versions.tx0000644000175000017500000000077314106404517015405 0ustar ronron#/usr/bin/env perl use strict; use warnings; # I tried 'require'-ing modules but that did not work. use <: $module_name :>; # For the version #. use Test::More; <: $module_list_1 :> # ---------------------- pass('All external modules loaded'); my(@modules) = qw / <: $module_list_2 :> /; diag "Testing <: $module_name :> V $<: $module_name :>::VERSION"; for my $module (@modules) { no strict 'refs'; my($ver) = ${$module . '::VERSION'} || 'N/A'; diag "Using $module V $ver"; } done_testing; Crypt-PasswdMD5-1.44/AI_POLICY.md0000644000175000017500000001303615204153212014356 0ustar ronron# AI Policy > **TL;DR** — AI tools assist our workflow at every stage. Humans remain in control of every decision, every review, and every release. --- ## Overview This document describes how artificial intelligence tools are used in the maintenance and development of this project. It is intended to be transparent with our contributors, users, and the broader open-source community about the role AI plays — and, equally importantly, the role it does **not** play. We believe in honest, clear communication about AI-assisted workflows. This policy will be updated as our practices evolve. --- ## Our Guiding Principle **AI assists. Humans decide.** The maintainers who have been stewarding this project for years remain fully responsible for every line of code that ships. AI tools extend our capacity to review, research, and improve — they do not replace human judgment, expertise, or accountability. --- ## How AI Is Used in This Project ### 1. Code and Issue Analysis AI tools help us process and understand incoming issues, pull requests, and code changes at scale. This includes: - Summarising issue reports and identifying patterns across similar bugs - Analysing code diffs for potential problems, regressions, or style inconsistencies - Surfacing relevant context from the codebase, documentation, and prior discussions - Flagging potential security concerns for human review This analysis is **always** used as input to human decision-making, never as a substitute for it. ### 2. Draft Pull Requests AI may generate draft pull requests as a starting point for a fix, a refactor, or an improvement. These drafts: - Are clearly labelled as AI-generated when created - Represent a first pass only — they are never considered complete or correct without human review - May be substantially reworked, rejected, or replaced entirely by maintainers Think of these drafts the way you would think of a junior contributor's first attempt: useful raw material that still needs experienced eyes. ### 3. Human Review of Every Pull Request **Every pull request — whether AI-drafted or human-authored — is reviewed by a human maintainer before it can be merged.** During review, maintainers actively use AI as a tool to assist their own thinking: - Asking AI to explain or justify specific implementation choices - Challenging AI-generated code and requesting alternative approaches - Using AI to research edge cases, relevant standards, or upstream behaviour - Requesting targeted rewrites of individual sections based on review feedback The maintainer's judgment always takes precedence. AI answers are treated as input to be verified, not conclusions to be accepted. ### 4. Test Coverage and Defect Detection AI helps us improve the quality and completeness of our test suite by: - Suggesting test cases for edge conditions and failure modes - Identifying gaps in existing test coverage - Proposing tests that target known classes of defects or security issues - Helping reproduce and characterise reported bugs All suggested tests are reviewed and validated by maintainers before being committed. ### 5. Security Review AI tools assist in identifying potential security issues, including: - Common vulnerability patterns (injection, insecure defaults, deprecated APIs, etc.) - Dependencies with known CVEs - Code paths that may warrant closer scrutiny Security findings from AI are **always** verified by a human maintainer. We do not act on AI-flagged security issues without independent assessment. --- ## What AI Does Not Do To be explicit about the limits of AI involvement in this project: | ❌ AI does not… | ✅ A human maintainer does… | |---|---| | Approve or merge pull requests | Review and decide on every PR | | Make architectural decisions | Own all design and direction choices | | Triage and close issues autonomously | Assess and respond to all issues | | Publish releases | Tag, build, and release manually | | Represent the project publicly | Communicate on behalf of the project | --- ## Releases Releases are performed manually by the same long-standing maintainers as always. The release process — including changelog review, version tagging, and publication — uses standard Perl ecosystem tooling (e.g. ExtUtils::MakeMaker, Dist::Zilla, Module::Build) but involves no AI-driven automation. Every release is initiated, supervised, and published by a human maintainer. AI may assist in drafting changelogs or release notes, but these are always reviewed and edited before publication. --- ## Attribution and Transparency Where AI has played a material role in generating code or content within a pull request, we aim to note this in the PR description (e.g. via a `Generated-By` or `AI-Assisted` label or note). We do not consider AI the author of any contribution — the maintainer who reviewed and approved the work takes responsibility for it. --- ## Why We Do This Open-source software is built on trust. Our users and downstream dependants trust us to ship correct, secure, and well-considered code. AI tools help us do that work better — but they do not change who is responsible for the outcome. We use AI because it makes our maintainers more effective, not because it replaces them. --- ## Questions and Feedback If you have questions about our use of AI, or concerns about a specific pull request or change, please open an issue or start a discussion. We are committed to being open about our process. --- *Last updated: 2026-03-23* *This policy is maintained by the project maintainers and subject to revision as AI tooling and community norms evolve.* Crypt-PasswdMD5-1.44/SECURITY.md0000644000175000017500000000772315204153450014267 0ustar ronronThis is the Security Policy for the Perl Crypt::PasswdMD5 distribution. The latest version of the Security Policy can be found in the [git repository for Crypt::PasswdMD5](https://github.com/ronsavage/Crypt::PasswdMD5). This text is based on the CPAN Security Group's Guidelines for Adding a Security Policy to Perl Distributions (version 1.1.0) https://security.metacpan.org/docs/guides/security-policy-for-authors.html # How to Report a Security Vulnerability Security vulnerabilities can be reported by e-mail to the current project maintainers at . Please include as many details as possible, including code samples or test cases, so that we can reproduce the issue. Check that your report does not expose any sensitive data, such as passwords, tokens, or personal information. If you would like any help with triaging the issue, or if the issue is being actively exploited, please copy the report to the CPAN Security Group (CPANSec) at . Please *do not* use the public issue reporting system on RT or GitHub issues for reporting security vulnerabilities. Please do not disclose the security vulnerability in public forums until past any proposed date for public disclosure, or it has been made public by the maintainers or CPANSec. That includes patches or pull requests. For more information, see [Report a Security Issue](https://security.metacpan.org/docs/report.html) on the CPANSec website. ## Response to Reports The maintainer(s) aim to acknowledge your security report as soon as possible. However, this project is maintained by a single person in their spare time, and they cannot guarantee a rapid response. If you have not received a response from them within a week, then please send a reminder to them and copy the report to CPANSec at . Please note that the initial response to your report will be an acknowledgement, with a possible query for more information. It will not necessarily include any fixes for the issue. The project maintainer(s) may forward this issue to the security contacts for other projects where we believe it is relevant. This may include embedded libraries, system libraries, prerequisite modules or downstream software that uses this software. They may also forward this issue to CPANSec. # Which Software This Policy Applies To Any security vulnerabilities in Crypt::PasswdMD5 are covered by this policy. Security vulnerabilities are considered anything that allows users to execute unauthorised code, access unauthorised resources, or to have an adverse impact on accessibility or performance of a system. Security vulnerabilities in upstream software (embedded libraries, prerequisite modules or system libraries, or in Perl), are not covered by this policy unless they affect Crypt::PasswdMD5, or Crypt::PasswdMD5 can be used to exploit vulnerabilities in them. Security vulnerabilities in downstream software (any software that uses Crypt::PasswdMD5, or plugins to it that are not included with the Crypt::PasswdMD5 distribution) are not covered by this policy. ## Supported Versions of Crypt::PasswdMD5 The maintainer(s) will release security fixes for the latest version of Crypt::PasswdMD5. Note that the Crypt::PasswdMD5 project only supports major versions of Perl released in the past ten (10) years, even though Crypt::PasswdMD5 will run on older versions of Perl. If a security fix requires the maintainers to increase the minimum version of Perl that is supported, then they may do so. # Installation and Usage Issues The distribution metadata specifies minimum versions of prerequisites that are required for Crypt::PasswdMD5 to work. However, some of these prerequisites may have security vulnerabilities, and you should ensure that you are using up-to-date versions of these prerequisites. Where security vulnerabilities are known, the metadata may indicate newer versions as recommended. ## Usage Please see the software documentation for further information.