From fa4fcc40f2335f97765ea0daa5502400971f1a28 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 22 2020 08:32:09 +0000 Subject: perl-Digest-SHA-6.02 base --- diff --git a/Changes b/Changes new file mode 100644 index 0000000..c1b0e55 --- /dev/null +++ b/Changes @@ -0,0 +1,675 @@ +Revision history for Perl extension Digest::SHA. + +6.02 Fri Apr 20 16:25:30 MST 2018 + - silenced compiler warnings from VS2017 + -- ref. rt.cpan.org #124477 + -- thanks to Sergey Aleynikov for diagnostics + - modified addfile to return error when given a directory name + -- makes behavior consistent with GNU coreutils shaXsum + -- thanks to Scott Baker for pointing this out + +6.01 Mon Dec 25 00:08:08 MST 2017 + - added "--ignore-missing" and "--strict" options to shasum + -- consistent with GNU coreutils + -- ref. rt.cpan.org #123897 + - removed PERL_CORE preambles from test scripts + -- preambles no longer needed for core testing + -- thanks to Chris Williams for patch + -- ref. rt.cpan.org #123863 + +6.00 Fri Dec 8 22:44:44 MST 2017 + - added "tag" option (BSD-style checksums) to shasum + -- consistent with GNU sha1sum, sha224sum, etc. + -- thanks to Christopher Tubbs for suggestion + - modified SHA.pm to use XSLoader + -- falls back to DynaLoader if necessary + - decoupled Digest::SHA and Digest::SHA::PurePerl + -- scripts/tests in each module now fully independent + -- Digest::SHA::PurePerl to be phased out eventually + -- past versions will remain available + +5.98 Wed Oct 4 00:40:02 MST 2017 + - removed "portable" mode from shasum and addfile + -- rarely used, mostly in outdated systems + -- potentially confusing features (e.g. \r\r\n -> \n) + -- Universal Newlines mode (-U) a much cleaner approach + -- mimics Universal Newlines in Python + - shasum now uses Digest::SHA explicitly + -- no longer loads Digest::SHA::PurePerl as an option + -- hence no need for -R switch + -- Digest::SHA::PurePerl has its own shasum: shasumpp + +5.97 Wed Sep 6 02:23:02 MST 2017 + - added 'quiet' option to shasum + -- thanks to Chris David for suggestion and initial patch + -- ref. rt.cpan.org #122750 + - expanded shasum --help message + -- to explain use of escaped FILE names + +5.96 Wed Jul 27 20:04:34 MST 2016 + - prevented shasum from possibly running malicious code + -- remove '.' from @INC before module loading + -- ref. rt.cpan.org #116513 + - namespace cleanup (ref. rt.cpan.org #105371 and #105372) + - minor code and documentation tweaks + +5.95 Sat Jan 10 12:15:36 MST 2015 + - modified the bit-ordering test (ref. t/bitorder.t) + -- supplied directory-change preamble for CORE builds + +5.94 Sat Jan 10 00:45:28 MST 2015 + - added support for threaded builds + -- PERL_GET_NO_CONTEXT, pTHX_, aTHX_, etc. + -- employed 'const' storage class where possible + -- ref. rt.cpan.org #101260 + - simplified shabits() routine (bitwise input buffering) + -- slightly less efficient but easier to understand + -- ref. rt.cpan.org #101344 + - minor documentation tweaks and additions + +5.93 Sun Oct 26 06:00:48 MST 2014 + - corrected alignment problem in SHA struct (src/sha.h) + -- thanks to H. Merijn Brand and J. Hietaniemi for + analysis and suggested patch + - provided workaround in t/methods.t for unreliable -T test + -- Some Perl 5.8's mistake text for binary + +5.92 Sun Jun 1 00:15:44 MST 2014 + - fixed reserved-word clash when compiling with C++ + -- use 'classname' instead of 'class' + -- ref. SHA.xs (rt.cpan.org #96090) + - silenced MSC compiler warning about signed/unsigned comparison + -- ref. SHA.xs (rt.cpan.org #95830) + +5.91 Fri May 16 10:21:44 MST 2014 + - restored original 'addfile' for use on opened file handles + -- allows callbacks in place of actual files + -- ref. IO::Callback (rt.cpan.org #95643) + - re-established inheritance from Digest::base + -- to pick up future Digest enhancements automatically + - cleaned up documentation + +5.90 Wed May 7 07:57:08 MST 2014 + - consolidated all dynamic memory allocation into XSUBs + -- streamlines referencing of SHA objects + -- simplifies DESTROYing of objects + - enhanced Makefile.PL to allow 'use warnings' + -- automatically reverts to $^W for early Perls + - scrubbed C and Perl code to remove all compiler warnings + +5.89 Sat Apr 19 05:14:48 MST 2014 + - added universal newlines mode ("U") to addfile and shasum + -- based on Python Universal Newlines concept + -- newlines identical across MacOS, DOS, and UNIX + -- will deprecate portable mode ("p") in future + -- "U" mode is cleaner and more efficient + - enhanced performance + -- reduced number of dynamic memory allocations + -- sped up addfile method with use of C code + -- ref. SHA.xs (_addfilebin and _addfileuniv) + - eliminated experimental -M option in favor of new -R option + -- reverses order of digest module preference + -- undocumented: for test and development use only + - sealed memory leak in SHA.xs + -- arose only with SvPVbyte exceptions during eval + - patched inheritence bug (ref: rt.cpan.org #94830) + -- use sv_isobject/sv_derived_from instead of sv_isa + - added 'allocated' flag to SHA structure (ref. src/sha.h) + -- to guard against Perl double frees + +5.88 Mon Mar 17 08:46:10 MST 2014 + - added OUTPUT clause in SHA.xs to silence compiler warning + -- ref. shaclose() + - changed text file test (-T) to act on filehandles + -- ref. addfile portable mode + -- improves consistency when reading from STDIN + -- still must act on filenames for early Perls (< 5.6) + - added -M and -V options to shasum + -- undocumented: for development and testing use only + +5.87 Mon Feb 17 16:42:02 MST 2014 + - simplified capture of intermediate SHA states + -- can now be done via strings (ref. getstate/putstate) + -- substantially reduces size of src/sha.c + - tightened code in SHA.xs + -- added sv_isa checks when invoking methods + +5.86 Thu Jan 30 08:24:28 MST 2014 + - improved the performance of hexadecimal output functions + -- ref. 'shahex' in src/sha.c + -- thanks to Thomas Drugeon for ideas and test script + +5.85 Wed Jun 26 04:05:26 MST 2013 + - workaround for repeated calls to shaclose (ref. Bug #86295) + -- need to explicitly reset internal pointer to NULL + ref. shaclose() in SHA.xs + - corrected typos in shasum script + -- ref. Bug #85430 + +5.84 Sat Mar 9 17:36:08 MST 2013 + - untweaked Makefile.PL to remove dependencies of SHA.c + -- dependencies were breaking builds on VMS + -- retaining dependencies provides too little benefit + for cost of portable workaround + +5.83 Mon Mar 4 08:12:00 MST 2013 + - removed code for standalone C operation (no longer used) + -- eliminates need for external symbols + -- consolidates SHA and HMAC code + -- reduces size of object files + -- thanks to Marc Lehmann for suggestions + - tweaked Makefile.PL to show dependencies of SHA.c + +5.82 Thu Jan 24 04:54:12 MST 2013 + - introduced workaround to SvPVbyte bug in Perl 5.6 + -- module behavior now consistent under all Perls 5.6+ + -- ref: new test script t/unicode.t + -- SHA routines now always croak on wide chars (5.6+) + - removed "static" message schedules from C code + -- default "auto" is now just as fast + -- thread-safe option (-t) no longer necessary + -- still allowed, but ignored + -- simplifies source and header files + -- eliminates SHA_STO_CLASS and SHA_THREAD_SAFE + -- ref. Bug #82784 + -- thanks to Steve Hay for initial patch + - provided documentation to describe Unicode handling + -- ref: Bug #82378 + - updated documentation of NIST statement on SHA-1 + +5.81 Mon Jan 14 05:17:08 MST 2013 + - corrected load subroutine (SHA.pm) to prevent double-free + -- Bug #82655: Security issue - segfault + -- thanks to Victor Efimov and Nicholas Clark + for technical expertise and suggestions + +5.80 Mon Dec 10 14:15:26 MST 2012 + - obtained noticeable speedup on Intel/gcc + -- by setting -O1 and -fomit-frame-pointer + -- SHA-1 about 63% faster, SHA-2 improves 11-20% + +5.74 Sat Nov 24 03:10:18 MST 2012 + - handle wide-string input by converting to bytes first + -- viz. use SvPVbyte instead of SvPV in SHA.xs + -- thanks to Eric Brine for summary and code + +5.73 Wed Oct 31 04:32:44 MST 2012 + - provided workaround for DEC compiler bug (ref. Makefile.PL) + +5.72 Mon Sep 24 15:22:08 MST 2012 + - adjusted module installation directory for later Perls + -- As of 5.11 Perl searches 'site' first, so use that + -- ref. INSTALLDIRS in Makefile.PL + -- thanks to Robert Sedlacek for patch + +5.71 Wed Feb 29 04:06:10 MST 2012 + - prevented $! from getting clobbered in _bail() routine + -- thanks to Zefram for patch + - added example of BITS mode usage to shasum documentation + +5.70 Wed Dec 14 02:32:10 MST 2011 + - added BITS mode to addfile method and shasum + -- partial-byte inputs now possible via files/STDIN + -- allows shasum to check all 8074 NIST Msg vectors + -- previously required special programming + +5.63 Tue Nov 8 02:36:42 MST 2011 + - added code to allow very large data inputs all at once + -- previously limited to several hundred MB at a time + -- many thanks to Thomas Drugeon for his elegant patch + - removed outdated reference URLs from several test scripts + -- these URLs aren't essential, and often go stale + -- thanks to Leon Brocard for spotting this + -- ref. rt.cpan.org #68740 + +5.62 Sat May 14 04:00:34 MST 2011 + - removed unnecessary loading of MIME::Base64 module + -- thanks to dolmen for pointing this out + +5.61 Wed Mar 9 05:26:36 MST 2011 + - corrected bug in 'algorithm' method + - fixed -x option in Makefile.PL + -- not often used since it deliberately excludes + all 64-bit SHA transforms + - addressed minor documentation oversights + +5.60 Thu Mar 3 05:26:42 MST 2011 + - added new SHA-512/224 and SHA-512/256 transforms + -- ref. NIST Draft FIPS 180-4 (February 2011) + - simplified shasum by removing duplicative text + - improved efficiency of Addfile + -- expensive -T test now occurs only in portable mode + +5.50 Tue Dec 14 06:20:08 MST 2010 + - adopted convention that '-' always means STDIN + -- actual filename '-' accessed as './-' + -- accords with behavior of sha1sum/md5sum + - corrected undefined subroutine oversight in shasum + -- inadvertent migration of _bail() from SHA.pm + +5.49 Sun Dec 12 07:22:04 MST 2010 + - modified Addfile to accept all POSIX filenames + -- standard allows all characters except NUL and '/' + - updated shasum to more closely mimic sha1sum/md5sum + -- added "backslash processing" to handle newlines + and backslashes in filenames + -- now accepts all POSIX filenames via Addfile + -- thanks to Sean Burke for identifying edge cases + +5.48 Mon Jan 4 16:32:52 MST 2010 + - fixed "shasum -a0" option (ref. rt.cpan.org #53319) + -- incorrectly accepted 0 as a valid algorithm + -- thanks to Zefram for patch + - updated URL for NIST test vectors + -- ref. files t/nistbit.t, t/nistbyte.t + -- thanks to Leon Brocard for patch + +5.47 Wed Apr 30 04:00:54 MST 2008 + - modified Makefile.PL to install in core for Perls >= 5.10 + -- thanks to Jerry Hedden for patch + - changed from #include <> to #include "" in SHA.xs + -- some platforms not able to find SHA source files + -- thanks to Alexandr Ciornii for testing + - moved .pm file to appropriate lib directory + - minor addition to META.yml + +5.46 Wed Apr 9 05:04:00 MST 2008 + - modified Addfile to recognize leading and trailing + whitespace in filenames (ref. rt.cpan.org #34690) + - minor C source code modification (ref. hmac.c) + - use const in sha.c for clean builds with -Wwrite-strings + -- thanks to Robin Barker for patch + +5.45 Tue Jun 26 02:36:00 MST 2007 + - extended portability to earlier Perls + -- works on Perl 5.003 and later + -- thanks to Jim Doble for testing on legacy platforms + - updated META.yml to conform to current META spec (1.3) + - minor documentation fixes + +5.44 Sat Oct 14 00:42:44 MST 2006 + - removed SIGNATURE file from distribution + -- spurious errors from CPANPLUS can break build + - eliminated ppport.h header file + -- significantly reduces size of distribution + - modified C functions in src/hmac.c to use ANSI prototypes + -- thanks to Jarkko Hietaniemi for patch + +5.43 Sat Aug 5 02:36:18 MST 2006 + - undid Perl Best Practice of favoring 3-argument "open" + -- 3-arg version uses different semantics for "-" + causing bugs in addfile and shasum + - modified underlying C functions to use ANSI prototypes + -- requested by Steve Hay (ref. Smoke [5.9.4] 28630) + -- K&R style was causing numerous warnings from + Borland compiler + +5.42 Mon Jul 24 04:04:40 MST 2006 + - minor code changes suggested by Perl::Critic + -- e.g. no bareword filehandles, no 2-argument open's + - updated public key (ref. B538C51C) + -- previous one (0AF563FE) expired July 2, 2006 + - added documentation to warn that Base64 digests are NOT padded + -- padding must be done by user if interoperability + with other software is required + +5.41 Sat Jun 3 01:50:46 MST 2006 + - corrected addfile + -- process $file argument as a filehandle unless passed + as a SCALAR (which indicates a file name) + +5.40 Fri Jun 2 04:00:30 MST 2006 + - modified addfile to accept indirect filehandles + -- ref. rt.cpan.org #19627 and #19641 + +5.39 Sun May 28 03:22:24 MST 2006 + - modified shasum to warn rather than die for file errors + -- to follow conventions of GNU sha1sum/md5sum + +5.38 Thu May 25 02:02:02 MST 2006 + - added new capabilities to the "addfile" method + -- now able to accept file names as well as handles + -- includes mode for portable digest calculation + -- thanks to Adam Kennedy for emails and ideas + ref. File::LocalizeNewlines + - used expanded addfile interface to simplify shasum (sumfile) + -- regex a tad less general than 5.37, but handles all + known newline variants in UNIX/Windows/MacOS + - enhanced WARNING messages from shasum checkfile processing + -- to mimic behavior of md5sum + +5.37 Mon May 8 04:30:09 MST 2006 + - modified shasum to avoid file slurping (ref. sub sumfile) + - improved error handling of checksum files in shasum + -- to better mimic the behavior of md5sum + - refined line-break regex in shasum (ref. sub sumfile) + -- catches multiple CR's preceding LF + thanks to Gisle Aas for suggested patch + - changed loop vars to signed int's in shadump (ref. src/sha.c) + -- to prevent type mismatch warnings + +5.36 Mon May 8 01:38:36 MST 2006 + - fixed the "portable" option in shasum + -- normalize line-breaks in text files only + +5.35 Thu May 4 16:54:42 MST 2006 + - added "portable" option to shasum + -- to make digests match across Windows/Unix/MacOS + - enabled bundling of shasum command line options + -- to mimic behavior of md5sum + - removed \r's from text files in t/nist directory + -- resolves SIGNATURE clashes (rt.cpan.org #18983) + - changed suffix on SHA64_MAX (src/sha.h) to ULL + -- eliminates gcc warnings (rt.cpan.org #18988) + - specified minimum Perl version for module and Makefile.PL + -- closes rt.cpan.org #18984 + +5.34 Thu Feb 2 18:55:40 MST 2006 + - removed Unix-style pathnames in test scripts + -- causing problems on OpenVMS + -- thanks to Steve Peters for patch + - included latest version of Perl Portability header (ppport.h) + - added PERL_CORE check to test scripts + -- allows module to be built into Perl distribution + +5.32 Fri Dec 2 02:32:20 MST 2005 + - added POD section to shasum script + -- thanks to Gunnar Wolf for patch + - made minor code changes to silence compiler warnings + -- resulting from signed/unsigned integer mixing + - inserted code in test scripts for POD checking + -- to recover gracefully if Test::More isn't installed + +5.31 Mon Sep 5 00:52:42 MST 2005 + - added standard tests for pod and pod-coverage checking + - inserted subtest to check for failure when using + unrecognized SHA algorithm + +5.30 Sat Aug 20 16:46:08 MST 2005 + - updated docs with recent NIST statement on SHA-1 + -- advises use of larger and stronger hash functions + (i.e. SHA-224/256/384/512) for new developments + +5.29 Sun Aug 14 04:48:34 MST 2005 + - added explicit casts in "shaload" routine (ref. "ldvals") + -- thanks to E. Allen Smith for pointing out SGI compiler + warnings on IPxx-irix platforms + - updated docs with cautionary note about SHA-1 + +5.28 Wed Nov 10 15:33:20 MST 2004 + - provided more flexible formatting of SHA state files + -- entries may now contain embedded whitespace + for improved readability + - minor code cleanups + +5.27 Sun Oct 24 02:54:00 MST 2004 + - minor code cleanups + -- reduces size of dump files for SHA-1/224/256 + +5.26 Thu Oct 7 14:52:00 MST 2004 + - streamlined distribution + -- reduced NIST vector tests from 200 to 20 + -- former number was overkill + -- distro now downloads and builds more quickly + - rewrote SYNOPSIS sections in pod file + - made additional tweaks to t/8-shasum.t for portability + - cleaned up test scripts + +5.25 Sun Sep 12 18:48:00 MST 2004 + - removed non-essential test script + -- t/8-shasum.t causes problems on sparc64-linux + - reverted to using eval "require $module" in shasum + +5.24 Sun Sep 12 02:50:18 MST 2004 + - modified shasum to use barewords in "require" statements + -- ref. perl.cpan.testers (157305) + +5.23 Thu Sep 9 23:06:18 MST 2004 + - corrected bug in test script + -- use blib when invoking perl as an external + command in t/8-shasum.t + +5.22 Tue Sep 7 19:12:40 MST 2004 + - broadened SHA-384/512 support + -- to compilers with no ULLONG_MAX in limits.h + -- e.g IBM C (xlC 6.0.0) on AIX 4.3.3 + -- thanks to Chris Carey for suggestions + and technical expertise + - improved use of static storage class in transforms + -- detection of Intel arch. now done in Makefile.PL + -- NB: static not used if compiling for thread safety + - minor changes to documentation + +5.21 Mon Aug 23 04:02:00 MST 2004 + - removed 64-bit constant expressions from #if statements + -- ref. src/sha.h (lines 55, 58, and 61) + -- even if compiler supports long long's, preprocessor + may use long's when evaluating expressions + - improved test script for "shasum" (t/8-shasum.t) + -- exercises check file option (-c) + +5.20 Sun Aug 15 04:24:48 MST 2004 + - introduced "shasum" script + -- mimics the usage and behavior of "md5sum" + -- adds "-a" option to select SHA algorithm + -- for help, just type "shasum -h" + +5.10 Fri Aug 6 02:04:38 MST 2004 + - simplified module documentation + -- made it consistent with Digest::SHA::PurePerl docs + +5.03 Sat Jul 31 00:00:48 MST 2004 + - corrected HMAC-SHA-384/512 bug (cpan #7181, Adam Woodbury) + -- code was using hardwired blocksize for SHA-1/256 + -- ref. src/hmac.c, src/hmac.h + +5.02 Thu Jul 29 02:48:00 MST 2004 + - updated documentation and "dump-load.t" test script + -- to be consistent with Digest::SHA::PurePerl + - included a SIGNATURE file + -- for stronger authentication of module contents + -- ref. Module::Signature on CPAN + - corrected embarrassing misspelling in docs + -- apologies to Gisle Aas + +5.01 Fri May 21 13:08:12 MST 2004 + - check for undefined SHA handle when calling "shaclose()" + -- prevents intermittent cleanup errors during + global object destruction + +5.00 Fri May 14 04:45:00 MST 2004 + - minor documentation fixes + - restored classical style of version numbering (X.YZ) + -- previous X.Y.Z style caused installation difficulties + when using CPANPLUS + +4.3.3 Wed May 5 00:30:40 MST 2004 + - fixed bug in "strto64()" function + -- caused problems in state files with CR/LF pairs + -- thanks to Martin Thurn for testing support + +4.3.2 Wed Apr 28 03:56:00 MST 2004 + - added Makefile.PL options + -- thread-safety: -t + -- exclude 384/512 support: -x + -- e.g. perl Makefile.PL -t + - temporarily suppress dump/load tests for SHA-384/512 + -- pending clarification of problem on sun4u sparc + +4.3.1 Thu Mar 4 02:54:00 MST 2004 + - removed unused functions from XS file + -- reduces size of compiled objects + - simplified implementation of Digest::SHA object + -- now a blessed SHAPtr ref instead of blessed array ref + -- results in slight speed-up of OO operations + - streamlined underlying C source + -- used macros to consolidate repetitive code + - rewrote test scripts to depend on Test rather than Test::More + -- allows module to be checked in minimal Perl environments + - added compilation option for thread-safety + -- overrides use of static arrays + +4.3.0 Sat Feb 7 02:58:00 MST 2004 + - included SHA-384/512 support if using Microsoft C/C++ + -- uses MSVC's __int64 in place of "long long" + - enhanced portability and efficiency on diverse platforms + -- automatically sets up optimal types for 32/64-bit ops + - improved test scripts for better reporting + -- many thanks to Alex Muntada for helpful suggestions + +4.2.2 Sat Jan 31 17:10:20 MST 2004 + - repaired 32-bit SHA operations for 8-byte longs + +4.2.1 Sat Jan 24 00:56:54 MST 2004 + - modified I/O and memory management in underlying C code + -- uses Perl libraries when compiled as CPAN module + -- otherwise defaults to ANSI C libraries + -- bypasses problems in MSWin multi-threaded Perls + -- avoids "Free to wrong pool" error + -- special thanks to Robert Gilmour and Brian Gladman + for technical guidance and testing + +4.2.0 Sat Dec 27 16:08:00 MST 2003 + - added support for recently-announced SHA-224 algorithm + -- ref. FIPS 180-2 Change Notice 1 + -- also includes HMAC-SHA-224 + +4.1.0 Thu Dec 25 00:58:00 MST 2003 + - repaired "nist-vectors" test scripts for MSWin32 portability + -- use binmode for data files + +4.0.9 Wed Dec 24 02:58:22 MST 2003 + - use canonical file specs in test scripts + -- enhances portability across different OSes + - modify type declarations of objects in XS file + -- re-declare as (SV *) and cast to (AV *) SvRV(self) + -- in response to AVPtr problem on MSWin32 + +4.0.8 Thu Dec 18 23:32:00 MST 2003 + - inherits from Digest::base if installed + -- also checks for MIME::Base64 + -- still fully-functional if neither are installed + - added buffer overflow protection in underlying C code + -- ref. shahex() and shabase64() routines + -- prior code appeared impossible to exploit, but ... + -- better safe than sorry + -- does not impact runtime efficiency + - minor code cleanup + +4.0.7 Sat Dec 13 00:48:24 MST 2003 + - check for undefined SHA handle when calling "shaclose()" + -- was causing cleanup err during global destruction + +4.0.6 Thu Dec 11 02:18:00 MST 2003 + - more optimization and streamlining + -- a bit faster on non-big-endians (e.g. Intel) + - rewrote time-critical functions and methods in XS + - removed unused C functions from source files + +4.0.5 Sat Dec 6 00:02:24 MST 2003 + - performance optimizations + -- rewrote "add" method in XS + -- unrolled loops in sha256 transform + +4.0.4 Thu Dec 4 00:07:00 MST 2003 + - made Digest::SHA into a self-contained module + -- no longer depends on Digest::base + -- more convenient for users + -- no need to install Digest:: module + +4.0.3 Wed Dec 3 00:01:20 MST 2003 + - Digest::SHA now a subclass of Digest::base + -- inherits hexdigest/b64digest/addfile methods + - added "hashsize" method + - removed old "shaopen()/shawrite()/..." legacy code + -- in favor of standard, streamlined OO interface + - renamed test vector files from NIST + -- prevents problems on 8+3 filesystems + - added test for Dave Ireland's SHA-256 vector + +4.0.0 Sat Nov 29 21:14:09 MST 2003 + - major streamlining of interface (hence, major version change) + -- coordinated with Gisle Aas and J. Duque + -- goal is to produce a single SHA module + -- adheres to OO and functional styles of Digest:: + -- greatly reduces the number of interface functions + -- old functions still supported + -- use Digest::SHA ':legacy' + -- will be deprecated in near future + - rewrote all test scripts to match new interface + -- very easy to modify all 281 tests + -- old interface maps cleanly to new one + +3.0 Wed Nov 26 05:02:34 MST 2003 + - added functions that conform to Digest:: interface + -- both functional and OO styles + -- byte-oriented data only + -- continue to support original interface as well + -- necessary for bit-oriented data + - supplied formal test vectors for HMAC-SHA-256 + -- from draft-ietf-ipsec-ciph-sha-256-01.txt + - included tests for all OO methods + +2.4 Sat Nov 22 17:10:22 MST 2003 + - code cleanup + -- "sha.c" now completely free of #ifdef's + - modularized all 64-bit (long long) code + - improved readability of header files + - simplified logic of "fixdump" utility + +2.3 Wed Nov 19 03:54:31 MST 2003 + - minor optimizations and code cleanup + -- improved maintainability by reducing #ifdef's + -- sha1 transform code now easier to follow + - streamlined shadump/shaload file format + -- eliminated special "HQ" entry + -- state now held in "H" for all transforms + -- supplied "fixdump" utility to convert old format + - SHA-384/512 functions now return NULL for no 64-bit operations + -- previously they were undefined + -- no longer necessary to use eval's to test for presence + +2.2 Sun Nov 16 01:54:00 MST 2003 + - optimized the performance of the SHA-1 transform + -- around 20-30% faster than previous version + -- achieved by loop unrolling and assignment consolidation + - enhanced shaload/shadump to allow interaction with stdin/stdout + -- "$filename" argument now optional + +2.1 Sun Nov 9 03:28:04 MST 2003 + - simplified data input routines + -- length argument now optional for byte data + (special thanks to Jeffrey Friedl for this idea) + -- interface still compatible with earlier versions + -- changes will not affect existing client code + - streamlined underlying C code for easier maintenance + - provided additional tests for persistent data + +2.0 Sat Nov 1 03:55:36 MST 2003 + - added functions for HMAC-SHA-1/256/384/512 (FIPS PUB 198) + - shadump/shaload files now compatible between 32/64-bit machines + +1.01 Sat Oct 25 02:44:55 MST 2003 + - package now downloads and installs much faster + - reduced distribution size by 80% + -- pruned extensive NIST vectors to a useful subset + -- still possible to test all vectors if desired + --- see "t/nist/COPYRIGHT" file for details + - added routines to provide persistent storage of SHA states + -- shadump() and shaload() + - reduced runtime of large bitstring tests (gillogly-hard) + -- illustrates usefulness of shadump()/shaload() + +1.0 Sat Oct 18 17:35:07 MST 2003 + - documentation fixes + - code cleanup: no more compiler warnings from gcc -Wall + - added code to allow reading of intermediate digest state + -- shahex() prior to shafinish() returns current state + +0.9 Thu Oct 9 20:43:54 MST 2003 + - version updated to reflect portability check and passing + of all tests (1401) + +0.01 Wed Oct 8 22:28:05 2003 + - original version; created by h2xs 1.22 with options + -x -A -n Digest::SHA sha.h diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..bcd668c --- /dev/null +++ b/MANIFEST @@ -0,0 +1,40 @@ +Changes +Makefile.PL +MANIFEST +META.yml +README +SHA.xs +shasum +examples/dups +lib/Digest/SHA.pm +src/sdf.c +src/sha.c +src/sha.h +src/sha64bit.c +src/sha64bit.h +t/allfcns.t +t/base64.t +t/bitbuf.t +t/bitorder.t +t/fips180-4.t +t/fips198.t +t/gg.t +t/gglong.t +t/hmacsha.t +t/inheritance.t +t/ireland.t +t/methods.t +t/nistbit.t +t/nistbyte.t +t/pod.t +t/podcover.t +t/rfc2202.t +t/sha1.t +t/sha224.t +t/sha256.t +t/sha384.t +t/sha512.t +t/state.t +t/unicode.t +t/woodbury.t +typemap diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..01bdd91 --- /dev/null +++ b/META.yml @@ -0,0 +1,17 @@ +--- #YAML:1.0 +name: Digest-SHA +version: 6.02 +abstract: Perl extension for SHA-1/224/256/384/512 +license: perl +author: + - Mark Shelor, mshelor@cpan.org +requires: + perl: 5.003 +provides: + Digest::SHA: + file: lib/Digest/SHA.pm + version: 6.02 +meta-spec: + version: 1.3 + url: http://module-build.sourceforge.net/META-spec-v1.3.html +generated_by: Mark Shelor diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..af2c0c3 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,90 @@ +require 5.003000; + +use strict; +use ExtUtils::MakeMaker; +use Getopt::Std; +use Config qw(%Config); + +use vars qw($opt_t $opt_w $opt_x); + +my $PM = 'lib/Digest/SHA.pm'; +my $SHASUM = 'shasum'; + + # 'use warnings' if possible, but stay portable + +my($use_warnings, @EDITs); +my $warn_1 = 'BEGIN { $^W = 1 }'; +my $warn_0 = 'BEGIN { $^W = 0 }'; +{ + eval "require warnings; import warnings"; + $use_warnings = $@ ? 0 : 1; + + local(@ARGV) = ($PM, $SHASUM); + while (<>) { + if ( + (!$use_warnings && /^(use|no) warnings\b/) || + ( $use_warnings && /^\Q$warn_1\E # use warnings\b/) || + ( $use_warnings && /^\Q$warn_0\E # no warnings\b/)) { + push @EDITs, $ARGV; + close ARGV; + } + } +} + +if (@EDITs) { + local($^I, @ARGV) = ('', @EDITs); + while (<>) { + if ($use_warnings) { + s/^\Q$warn_1\E # (.*)$/$1/; + s/^\Q$warn_0\E # (.*)$/$1/; + } + else { + s/^(use warnings\b.*)$/$warn_1 # $1/; + s/^(no warnings\b.*)$/$warn_0 # $1/; + } + print; + } +} + +getopts('twx'); # -t is no longer used, but allow it anyway + +my @defines; +push(@defines, '-DNO_SHA_384_512') if $opt_x; +my $define = join(' ', @defines); + + # Workaround for DEC compiler bug, adapted from Digest::MD5 + +my @extra = (); +if ($^O eq 'VMS') { + if (defined($Config{ccname})) { + if (grep(/VMS_VAX/, @INC) && ($Config{ccname} eq 'DEC')) { + # VAX optimizer, even up to v6.4, gets stuck + push(@extra, OPTIMIZE => "/Optimize=(NODISJOINT)"); + } + } +} + + # Enhance performance on Intel when using gcc + +if ($Config{archname} =~ /^i[3456]86/ && $Config{ccname} eq 'gcc') { + push(@extra, OPTIMIZE => '-O1 -fomit-frame-pointer'); +} + +my $fussy = '-Wall -Wextra -Wconversion -Wcast-align -Wpointer-arith '; +push(@extra, CCFLAGS => $fussy . $Config{ccflags}) if $opt_w; + +my %attr = ( + 'NAME' => 'Digest::SHA', + 'VERSION_FROM' => $PM, + 'LIBS' => [''], + 'DEFINE' => $define, + 'INC' => '-I.', + 'EXE_FILES' => [ $SHASUM ], + 'INSTALLDIRS' => ($] >= 5.010 and $] < 5.011) ? 'perl' : 'site', + @extra, +); + +my $MMversion = $ExtUtils::MakeMaker::VERSION || '0.00_00'; +$attr{NO_META} = 1 if $MMversion ge '6.10_03'; + +WriteMakefile(%attr); diff --git a/README b/README new file mode 100644 index 0000000..502b1bb --- /dev/null +++ b/README @@ -0,0 +1,43 @@ +Digest::SHA version 6.02 +======================== + +Digest::SHA is a complete implementation of the NIST Secure Hash +Standard. It gives Perl programmers a convenient way to calculate +SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, and SHA-512/256 +message digests. The module can handle all types of input, including +partial-byte data. + +Digest::SHA is written in C for speed. If your platform lacks a +C compiler, you can install the functionally-equivalent (but much +slower) Digest::SHA::PurePerl module. + +The tests subdirectory (t/*.t) contains an extensive set of SHA +vectors compiled from various sources. + +INSTALLATION + +To install this module type the following: + + perl Makefile.PL [ options ] + make + make test + make install + +The Makefile.PL options are: + + -x : exclude support for SHA-384/512 + +DEPENDENCIES + + None + +COPYRIGHT AND LICENSE + +Copyright (C) 2003-2018 Mark Shelor + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +Please refer to the Perl Artistic License for details: + +http://search.cpan.org/perldoc?perlartistic diff --git a/SHA.xs b/SHA.xs new file mode 100644 index 0000000..d3a3baf --- /dev/null +++ b/SHA.xs @@ -0,0 +1,406 @@ +#define PERL_NO_GET_CONTEXT +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#ifdef SvPVbyte + #if PERL_REVISION == 5 && PERL_VERSION < 8 + #undef SvPVbyte + #define SvPVbyte(sv, lp) \ + (sv_utf8_downgrade((sv), 0), SvPV((sv), (lp))) + #endif +#else + #define SvPVbyte SvPV +#endif + +#ifndef dTHX + #define pTHX_ + #define aTHX_ +#endif + +#ifndef PerlIO + #define PerlIO FILE + #define PerlIO_read(f, buf, count) fread(buf, 1, count, f) +#endif + +#ifndef sv_derived_from + #include "src/sdf.c" +#endif + +#ifndef Newx + #define Newx(ptr, num, type) New(0, ptr, num, type) + #define Newxz(ptr, num, type) Newz(0, ptr, num, type) +#endif + +#include "src/sha.c" + +static const int ix2alg[] = + {1,1,1,224,224,224,256,256,256,384,384,384,512,512,512, + 512224,512224,512224,512256,512256,512256}; + +#ifndef INT2PTR +#define INT2PTR(p, i) (p) (i) +#endif + +#define MAX_WRITE_SIZE 16384 +#define IO_BUFFER_SIZE 4096 + +static SHA *getSHA(pTHX_ SV *self) +{ + if (!sv_isobject(self) || !sv_derived_from(self, "Digest::SHA")) + return(NULL); + return INT2PTR(SHA *, SvIV(SvRV(self))); +} + +MODULE = Digest::SHA PACKAGE = Digest::SHA + +PROTOTYPES: ENABLE + +int +shainit(s, alg) + SHA * s + int alg + +void +sharewind(s) + SHA * s + +unsigned long +shawrite(bitstr, bitcnt, s) + unsigned char * bitstr + unsigned long bitcnt + SHA * s + +SV * +newSHA(classname, alg) + char * classname + int alg +PREINIT: + SHA *state; +CODE: + Newxz(state, 1, SHA); + if (!shainit(state, alg)) { + Safefree(state); + XSRETURN_UNDEF; + } + RETVAL = newSV(0); + sv_setref_pv(RETVAL, classname, (void *) state); + SvREADONLY_on(SvRV(RETVAL)); +OUTPUT: + RETVAL + +SV * +clone(self) + SV * self +PREINIT: + SHA *state; + SHA *clone; +CODE: + if ((state = getSHA(aTHX_ self)) == NULL) + XSRETURN_UNDEF; + Newx(clone, 1, SHA); + RETVAL = newSV(0); + sv_setref_pv(RETVAL, sv_reftype(SvRV(self), 1), (void *) clone); + SvREADONLY_on(SvRV(RETVAL)); + Copy(state, clone, 1, SHA); +OUTPUT: + RETVAL + +void +DESTROY(s) + SHA * s +CODE: + Safefree(s); + +SV * +sha1(...) +ALIAS: + Digest::SHA::sha1 = 0 + Digest::SHA::sha1_hex = 1 + Digest::SHA::sha1_base64 = 2 + Digest::SHA::sha224 = 3 + Digest::SHA::sha224_hex = 4 + Digest::SHA::sha224_base64 = 5 + Digest::SHA::sha256 = 6 + Digest::SHA::sha256_hex = 7 + Digest::SHA::sha256_base64 = 8 + Digest::SHA::sha384 = 9 + Digest::SHA::sha384_hex = 10 + Digest::SHA::sha384_base64 = 11 + Digest::SHA::sha512 = 12 + Digest::SHA::sha512_hex = 13 + Digest::SHA::sha512_base64 = 14 + Digest::SHA::sha512224 = 15 + Digest::SHA::sha512224_hex = 16 + Digest::SHA::sha512224_base64 = 17 + Digest::SHA::sha512256 = 18 + Digest::SHA::sha512256_hex = 19 + Digest::SHA::sha512256_base64 = 20 +PREINIT: + int i; + UCHR *data; + STRLEN len; + SHA sha; + char *result; +CODE: + if (!shainit(&sha, ix2alg[ix])) + XSRETURN_UNDEF; + for (i = 0; i < items; i++) { + data = (UCHR *) (SvPVbyte(ST(i), len)); + while (len > MAX_WRITE_SIZE) { + shawrite(data, MAX_WRITE_SIZE << 3, &sha); + data += MAX_WRITE_SIZE; + len -= MAX_WRITE_SIZE; + } + shawrite(data, (ULNG) len << 3, &sha); + } + shafinish(&sha); + len = 0; + if (ix % 3 == 0) { + result = (char *) shadigest(&sha); + len = sha.digestlen; + } + else if (ix % 3 == 1) + result = shahex(&sha); + else + result = shabase64(&sha); + RETVAL = newSVpv(result, len); +OUTPUT: + RETVAL + +SV * +hmac_sha1(...) +ALIAS: + Digest::SHA::hmac_sha1 = 0 + Digest::SHA::hmac_sha1_hex = 1 + Digest::SHA::hmac_sha1_base64 = 2 + Digest::SHA::hmac_sha224 = 3 + Digest::SHA::hmac_sha224_hex = 4 + Digest::SHA::hmac_sha224_base64 = 5 + Digest::SHA::hmac_sha256 = 6 + Digest::SHA::hmac_sha256_hex = 7 + Digest::SHA::hmac_sha256_base64 = 8 + Digest::SHA::hmac_sha384 = 9 + Digest::SHA::hmac_sha384_hex = 10 + Digest::SHA::hmac_sha384_base64 = 11 + Digest::SHA::hmac_sha512 = 12 + Digest::SHA::hmac_sha512_hex = 13 + Digest::SHA::hmac_sha512_base64 = 14 + Digest::SHA::hmac_sha512224 = 15 + Digest::SHA::hmac_sha512224_hex = 16 + Digest::SHA::hmac_sha512224_base64 = 17 + Digest::SHA::hmac_sha512256 = 18 + Digest::SHA::hmac_sha512256_hex = 19 + Digest::SHA::hmac_sha512256_base64 = 20 +PREINIT: + int i; + UCHR *key = (UCHR *) ""; + UCHR *data; + STRLEN len = 0; + HMAC hmac; + char *result; +CODE: + if (items > 0) { + key = (UCHR *) (SvPVbyte(ST(items-1), len)); + } + if (hmacinit(&hmac, ix2alg[ix], key, (UINT) len) == NULL) + XSRETURN_UNDEF; + for (i = 0; i < items - 1; i++) { + data = (UCHR *) (SvPVbyte(ST(i), len)); + while (len > MAX_WRITE_SIZE) { + hmacwrite(data, MAX_WRITE_SIZE << 3, &hmac); + data += MAX_WRITE_SIZE; + len -= MAX_WRITE_SIZE; + } + hmacwrite(data, (ULNG) len << 3, &hmac); + } + hmacfinish(&hmac); + len = 0; + if (ix % 3 == 0) { + result = (char *) hmacdigest(&hmac); + len = hmac.digestlen; + } + else if (ix % 3 == 1) + result = hmachex(&hmac); + else + result = hmacbase64(&hmac); + RETVAL = newSVpv(result, len); +OUTPUT: + RETVAL + +int +hashsize(self) + SV * self +ALIAS: + Digest::SHA::hashsize = 0 + Digest::SHA::algorithm = 1 +PREINIT: + SHA *state; +CODE: + if ((state = getSHA(aTHX_ self)) == NULL) + XSRETURN_UNDEF; + RETVAL = ix ? state->alg : (int) (state->digestlen << 3); +OUTPUT: + RETVAL + +void +add(self, ...) + SV * self +PREINIT: + int i; + UCHR *data; + STRLEN len; + SHA *state; +PPCODE: + if ((state = getSHA(aTHX_ self)) == NULL) + XSRETURN_UNDEF; + for (i = 1; i < items; i++) { + data = (UCHR *) (SvPVbyte(ST(i), len)); + while (len > MAX_WRITE_SIZE) { + shawrite(data, MAX_WRITE_SIZE << 3, state); + data += MAX_WRITE_SIZE; + len -= MAX_WRITE_SIZE; + } + shawrite(data, (ULNG) len << 3, state); + } + XSRETURN(1); + +SV * +digest(self) + SV * self +ALIAS: + Digest::SHA::digest = 0 + Digest::SHA::hexdigest = 1 + Digest::SHA::b64digest = 2 +PREINIT: + STRLEN len; + SHA *state; + char *result; +CODE: + if ((state = getSHA(aTHX_ self)) == NULL) + XSRETURN_UNDEF; + shafinish(state); + len = 0; + if (ix == 0) { + result = (char *) shadigest(state); + len = state->digestlen; + } + else if (ix == 1) + result = shahex(state); + else + result = shabase64(state); + RETVAL = newSVpv(result, len); + sharewind(state); +OUTPUT: + RETVAL + +SV * +_getstate(self) + SV * self +PREINIT: + SHA *state; + UCHR buf[256]; + UCHR *ptr = buf; +CODE: + if ((state = getSHA(aTHX_ self)) == NULL) + XSRETURN_UNDEF; + Copy(digcpy(state), ptr, state->alg <= SHA256 ? 32 : 64, UCHR); + ptr += state->alg <= SHA256 ? 32 : 64; + Copy(state->block, ptr, state->alg <= SHA256 ? 64 : 128, UCHR); + ptr += state->alg <= SHA256 ? 64 : 128; + ptr = w32mem(ptr, state->blockcnt); + ptr = w32mem(ptr, state->lenhh); + ptr = w32mem(ptr, state->lenhl); + ptr = w32mem(ptr, state->lenlh); + ptr = w32mem(ptr, state->lenll); + RETVAL = newSVpv((char *) buf, (STRLEN) (ptr - buf)); +OUTPUT: + RETVAL + +void +_putstate(self, packed_state) + SV * self + SV * packed_state +PREINIT: + UINT bc; + STRLEN len; + SHA *state; + UCHR *data; +PPCODE: + if ((state = getSHA(aTHX_ self)) == NULL) + XSRETURN_UNDEF; + data = (UCHR *) SvPV(packed_state, len); + if (len != (state->alg <= SHA256 ? 116U : 212U)) + XSRETURN_UNDEF; + data = statecpy(state, data); + Copy(data, state->block, state->blocksize >> 3, UCHR); + data += (state->blocksize >> 3); + bc = memw32(data), data += 4; + if (bc >= (state->alg <= SHA256 ? 512U : 1024U)) + XSRETURN_UNDEF; + state->blockcnt = bc; + state->lenhh = memw32(data), data += 4; + state->lenhl = memw32(data), data += 4; + state->lenlh = memw32(data), data += 4; + state->lenll = memw32(data); + XSRETURN(1); + +void +_addfilebin(self, f) + SV * self + PerlIO * f +PREINIT: + SHA *state; + int n; + UCHR in[IO_BUFFER_SIZE]; +PPCODE: + if (!f || (state = getSHA(aTHX_ self)) == NULL) + XSRETURN_UNDEF; + while ((n = (int) PerlIO_read(f, in, sizeof(in))) > 0) + shawrite(in, (ULNG) n << 3, state); + XSRETURN(1); + +void +_addfileuniv(self, f) + SV * self + PerlIO * f +PREINIT: + UCHR c; + int n; + int cr = 0; + UCHR *src, *dst; + UCHR in[IO_BUFFER_SIZE+1]; + SHA *state; +PPCODE: + if (!f || (state = getSHA(aTHX_ self)) == NULL) + XSRETURN_UNDEF; + while ((n = (int) PerlIO_read(f, in+1, IO_BUFFER_SIZE)) > 0) { + for (dst = in, src = in + 1; n; n--) { + c = *src++; + if (!cr) { + if (c == '\015') + cr = 1; + else + *dst++ = c; + } + else { + if (c == '\015') + *dst++ = '\012'; + else if (c == '\012') { + *dst++ = '\012'; + cr = 0; + } + else { + *dst++ = '\012'; + *dst++ = c; + cr = 0; + } + } + } + shawrite(in, (ULNG) (dst - in) << 3, state); + } + if (cr) { + in[0] = '\012'; + shawrite(in, 1UL << 3, state); + } + XSRETURN(1); diff --git a/examples/dups b/examples/dups new file mode 100755 index 0000000..f6976ee --- /dev/null +++ b/examples/dups @@ -0,0 +1,62 @@ +#!perl + + # dups: simple script for showing duplicate files + +=head1 NAME + +dups - Show Duplicate Files + +=head1 SYNOPSIS + + Usage: dups files ... + + dups is a fast script for discovering duplicate files. It + achieves its efficiency by comparing file digests rather than the + file contents themselves, the latter being much larger in general. + + The NIST Secure Hash Algorithm (SHA) is highly collision-resistant, + meaning that two files with the same SHA digest have an almost + certain probability of being identical. + + The dups script works by computing the SHA-1 digest of each file + and looking for matches. The search can reveal more than one set + of duplicates, so the output is written as follows: + + match1_file1 + match1_file2 + match1_file3 + etc. + + match2_file1 + match2_file2 + etc. + +=head1 AUTHOR + +Mark Shelor + +=head1 SEE ALSO + +Perl module L or L + +=cut + +use strict; +use Digest::SHA; + +die "usage: dups files ...\n" unless @ARGV; + +my @files = grep { -f $_ } @ARGV; + +my %dups; +for (@files) { + my $digest = Digest::SHA->new->addfile($_, "b")->hexdigest; + push(@{$dups{$digest}}, $_); +} + +for (keys %dups) { + my $ref = $dups{$_}; + if (scalar(@$ref) > 1) { + print join("\n\t", @$ref), "\n\n"; + } +} diff --git a/lib/Digest/SHA.pm b/lib/Digest/SHA.pm new file mode 100644 index 0000000..dccc0e7 --- /dev/null +++ b/lib/Digest/SHA.pm @@ -0,0 +1,820 @@ +package Digest::SHA; + +require 5.003000; + +use strict; +use warnings; +use vars qw($VERSION @ISA @EXPORT_OK $errmsg); +use Fcntl qw(O_RDONLY O_RDWR); +use integer; + +$VERSION = '6.02'; + +require Exporter; +@ISA = qw(Exporter); +@EXPORT_OK = qw( + $errmsg + hmac_sha1 hmac_sha1_base64 hmac_sha1_hex + hmac_sha224 hmac_sha224_base64 hmac_sha224_hex + hmac_sha256 hmac_sha256_base64 hmac_sha256_hex + hmac_sha384 hmac_sha384_base64 hmac_sha384_hex + hmac_sha512 hmac_sha512_base64 hmac_sha512_hex + hmac_sha512224 hmac_sha512224_base64 hmac_sha512224_hex + hmac_sha512256 hmac_sha512256_base64 hmac_sha512256_hex + sha1 sha1_base64 sha1_hex + sha224 sha224_base64 sha224_hex + sha256 sha256_base64 sha256_hex + sha384 sha384_base64 sha384_hex + sha512 sha512_base64 sha512_hex + sha512224 sha512224_base64 sha512224_hex + sha512256 sha512256_base64 sha512256_hex); + +# Inherit from Digest::base if possible + +eval { + require Digest::base; + push(@ISA, 'Digest::base'); +}; + +# The following routines aren't time-critical, so they can be left in Perl + +sub new { + my($class, $alg) = @_; + $alg =~ s/\D+//g if defined $alg; + if (ref($class)) { # instance method + if (!defined($alg) || ($alg == $class->algorithm)) { + sharewind($class); + return($class); + } + return shainit($class, $alg) ? $class : undef; + } + $alg = 1 unless defined $alg; + return $class->newSHA($alg); +} + +BEGIN { *reset = \&new } + +sub add_bits { + my($self, $data, $nbits) = @_; + unless (defined $nbits) { + $nbits = length($data); + $data = pack("B*", $data); + } + $nbits = length($data) * 8 if $nbits > length($data) * 8; + shawrite($data, $nbits, $self); + return($self); +} + +sub _bail { + my $msg = shift; + + $errmsg = $!; + $msg .= ": $!"; + require Carp; + Carp::croak($msg); +} + +{ + my $_can_T_filehandle; + + sub _istext { + local *FH = shift; + my $file = shift; + + if (! defined $_can_T_filehandle) { + local $^W = 0; + my $istext = eval { -T FH }; + $_can_T_filehandle = $@ ? 0 : 1; + return $_can_T_filehandle ? $istext : -T $file; + } + return $_can_T_filehandle ? -T FH : -T $file; + } +} + +sub _addfile { + my ($self, $handle) = @_; + + my $n; + my $buf = ""; + + while (($n = read($handle, $buf, 4096))) { + $self->add($buf); + } + _bail("Read failed") unless defined $n; + + $self; +} + +sub addfile { + my ($self, $file, $mode) = @_; + + return(_addfile($self, $file)) unless ref(\$file) eq 'SCALAR'; + + $mode = defined($mode) ? $mode : ""; + my ($binary, $UNIVERSAL, $BITS) = + map { $_ eq $mode } ("b", "U", "0"); + + ## Always interpret "-" to mean STDIN; otherwise use + ## sysopen to handle full range of POSIX file names. + ## If $file is a directory, force an EISDIR error + ## by attempting to open with mode O_RDWR + + local *FH; + $file eq '-' and open(FH, '< -') + or sysopen(FH, $file, -d $file ? O_RDWR : O_RDONLY) + or _bail('Open failed'); + + if ($BITS) { + my ($n, $buf) = (0, ""); + while (($n = read(FH, $buf, 4096))) { + $buf =~ tr/01//cd; + $self->add_bits($buf); + } + _bail("Read failed") unless defined $n; + close(FH); + return($self); + } + + binmode(FH) if $binary || $UNIVERSAL; + if ($UNIVERSAL && _istext(*FH, $file)) { + $self->_addfileuniv(*FH); + } + else { $self->_addfilebin(*FH) } + close(FH); + + $self; +} + +sub getstate { + my $self = shift; + + my $alg = $self->algorithm or return; + my $state = $self->_getstate or return; + my $nD = $alg <= 256 ? 8 : 16; + my $nH = $alg <= 256 ? 32 : 64; + my $nB = $alg <= 256 ? 64 : 128; + my($H, $block, $blockcnt, $lenhh, $lenhl, $lenlh, $lenll) = + $state =~ /^(.{$nH})(.{$nB})(.{4})(.{4})(.{4})(.{4})(.{4})$/s; + for ($alg, $H, $block, $blockcnt, $lenhh, $lenhl, $lenlh, $lenll) { + return unless defined $_; + } + + my @s = (); + push(@s, "alg:" . $alg); + push(@s, "H:" . join(":", unpack("H*", $H) =~ /.{$nD}/g)); + push(@s, "block:" . join(":", unpack("H*", $block) =~ /.{2}/g)); + push(@s, "blockcnt:" . unpack("N", $blockcnt)); + push(@s, "lenhh:" . unpack("N", $lenhh)); + push(@s, "lenhl:" . unpack("N", $lenhl)); + push(@s, "lenlh:" . unpack("N", $lenlh)); + push(@s, "lenll:" . unpack("N", $lenll)); + join("\n", @s) . "\n"; +} + +sub putstate { + my($class, $state) = @_; + + my %s = (); + for (split(/\n/, $state)) { + s/^\s+//; + s/\s+$//; + next if (/^(#|$)/); + my @f = split(/[:\s]+/); + my $tag = shift(@f); + $s{$tag} = join('', @f); + } + + # H and block may contain arbitrary values, but check everything else + grep { $_ == $s{'alg'} } (1,224,256,384,512,512224,512256) or return; + length($s{'H'}) == ($s{'alg'} <= 256 ? 64 : 128) or return; + length($s{'block'}) == ($s{'alg'} <= 256 ? 128 : 256) or return; + { + no integer; + for (qw(blockcnt lenhh lenhl lenlh lenll)) { + 0 <= $s{$_} or return; + $s{$_} <= 4294967295 or return; + } + $s{'blockcnt'} < ($s{'alg'} <= 256 ? 512 : 1024) or return; + } + + my $packed_state = ( + pack("H*", $s{'H'}) . + pack("H*", $s{'block'}) . + pack("N", $s{'blockcnt'}) . + pack("N", $s{'lenhh'}) . + pack("N", $s{'lenhl'}) . + pack("N", $s{'lenlh'}) . + pack("N", $s{'lenll'}) + ); + + return $class->new($s{'alg'})->_putstate($packed_state); +} + +sub dump { + my $self = shift; + my $file = shift; + + my $state = $self->getstate or return; + $file = "-" if (!defined($file) || $file eq ""); + + local *FH; + open(FH, "> $file") or return; + print FH $state; + close(FH); + + return($self); +} + +sub load { + my $class = shift; + my $file = shift; + + $file = "-" if (!defined($file) || $file eq ""); + + local *FH; + open(FH, "< $file") or return; + my $str = join('', ); + close(FH); + + $class->putstate($str); +} + +eval { + require XSLoader; + XSLoader::load('Digest::SHA', $VERSION); + 1; +} or do { + require DynaLoader; + push @ISA, 'DynaLoader'; + Digest::SHA->bootstrap($VERSION); +}; + +1; +__END__ + +=head1 NAME + +Digest::SHA - Perl extension for SHA-1/224/256/384/512 + +=head1 SYNOPSIS + +In programs: + + # Functional interface + + use Digest::SHA qw(sha1 sha1_hex sha1_base64 ...); + + $digest = sha1($data); + $digest = sha1_hex($data); + $digest = sha1_base64($data); + + $digest = sha256($data); + $digest = sha384_hex($data); + $digest = sha512_base64($data); + + # Object-oriented + + use Digest::SHA; + + $sha = Digest::SHA->new($alg); + + $sha->add($data); # feed data into stream + + $sha->addfile(*F); + $sha->addfile($filename); + + $sha->add_bits($bits); + $sha->add_bits($data, $nbits); + + $sha_copy = $sha->clone; # make copy of digest object + $state = $sha->getstate; # save current state to string + $sha->putstate($state); # restore previous $state + + $digest = $sha->digest; # compute digest + $digest = $sha->hexdigest; + $digest = $sha->b64digest; + +From the command line: + + $ shasum files + + $ shasum --help + +=head1 SYNOPSIS (HMAC-SHA) + + # Functional interface only + + use Digest::SHA qw(hmac_sha1 hmac_sha1_hex ...); + + $digest = hmac_sha1($data, $key); + $digest = hmac_sha224_hex($data, $key); + $digest = hmac_sha256_base64($data, $key); + +=head1 ABSTRACT + +Digest::SHA is a complete implementation of the NIST Secure Hash Standard. +It gives Perl programmers a convenient way to calculate SHA-1, SHA-224, +SHA-256, SHA-384, SHA-512, SHA-512/224, and SHA-512/256 message digests. +The module can handle all types of input, including partial-byte data. + +=head1 DESCRIPTION + +Digest::SHA is written in C for speed. If your platform lacks a +C compiler, you can install the functionally equivalent (but much +slower) L module. + +The programming interface is easy to use: it's the same one found +in CPAN's L module. So, if your applications currently +use L and you'd prefer the stronger security of SHA, +it's a simple matter to convert them. + +The interface provides two ways to calculate digests: all-at-once, +or in stages. To illustrate, the following short program computes +the SHA-256 digest of "hello world" using each approach: + + use Digest::SHA qw(sha256_hex); + + $data = "hello world"; + @frags = split(//, $data); + + # all-at-once (Functional style) + $digest1 = sha256_hex($data); + + # in-stages (OOP style) + $state = Digest::SHA->new(256); + for (@frags) { $state->add($_) } + $digest2 = $state->hexdigest; + + print $digest1 eq $digest2 ? + "whew!\n" : "oops!\n"; + +To calculate the digest of an n-bit message where I is not a +multiple of 8, use the I method. For example, consider +the 446-bit message consisting of the bit-string "110" repeated +148 times, followed by "11". Here's how to display its SHA-1 +digest: + + use Digest::SHA; + $bits = "110" x 148 . "11"; + $sha = Digest::SHA->new(1)->add_bits($bits); + print $sha->hexdigest, "\n"; + +Note that for larger bit-strings, it's more efficient to use the +two-argument version I, where I<$data> is +in the customary packed binary format used for Perl strings. + +The module also lets you save intermediate SHA states to a string. The +I method generates portable, human-readable text describing +the current state of computation. You can subsequently restore that +state with I to resume where the calculation left off. + +To see what a state description looks like, just run the following: + + use Digest::SHA; + print Digest::SHA->new->add("Shaw" x 1962)->getstate; + +As an added convenience, the Digest::SHA module offers routines to +calculate keyed hashes using the HMAC-SHA-1/224/256/384/512 +algorithms. These services exist in functional form only, and +mimic the style and behavior of the I, I, and +I functions. + + # Test vector from draft-ietf-ipsec-ciph-sha-256-01.txt + + use Digest::SHA qw(hmac_sha256_hex); + print hmac_sha256_hex("Hi There", chr(0x0b) x 32), "\n"; + +=head1 UNICODE AND SIDE EFFECTS + +Perl supports Unicode strings as of version 5.6. Such strings may +contain wide characters, namely, characters whose ordinal values are +greater than 255. This can cause problems for digest algorithms such +as SHA that are specified to operate on sequences of bytes. + +The rule by which Digest::SHA handles a Unicode string is easy +to state, but potentially confusing to grasp: the string is interpreted +as a sequence of byte values, where each byte value is equal to the +ordinal value (viz. code point) of its corresponding Unicode character. +That way, the Unicode string 'abc' has exactly the same digest value as +the ordinary string 'abc'. + +Since a wide character does not fit into a byte, the Digest::SHA +routines croak if they encounter one. Whereas if a Unicode string +contains no wide characters, the module accepts it quite happily. +The following code illustrates the two cases: + + $str1 = pack('U*', (0..255)); + print sha1_hex($str1); # ok + + $str2 = pack('U*', (0..256)); + print sha1_hex($str2); # croaks + +Be aware that the digest routines silently convert UTF-8 input into its +equivalent byte sequence in the native encoding (cf. utf8::downgrade). +This side effect influences only the way Perl stores the data internally, +but otherwise leaves the actual value of the data intact. + +=head1 NIST STATEMENT ON SHA-1 + +NIST acknowledges that the work of Prof. Xiaoyun Wang constitutes a +practical collision attack on SHA-1. Therefore, NIST encourages the +rapid adoption of the SHA-2 hash functions (e.g. SHA-256) for applications +requiring strong collision resistance, such as digital signatures. + +ref. L + +=head1 PADDING OF BASE64 DIGESTS + +By convention, CPAN Digest modules do B pad their Base64 output. +Problems can occur when feeding such digests to other software that +expects properly padded Base64 encodings. + +For the time being, any necessary padding must be done by the user. +Fortunately, this is a simple operation: if the length of a Base64-encoded +digest isn't a multiple of 4, simply append "=" characters to the end +of the digest until it is: + + while (length($b64_digest) % 4) { + $b64_digest .= '='; + } + +To illustrate, I is computed to be + + ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0 + +which has a length of 43. So, the properly padded version is + + ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= + +=head1 EXPORT + +None by default. + +=head1 EXPORTABLE FUNCTIONS + +Provided your C compiler supports a 64-bit type (e.g. the I of C99, or I<__int64> used by Microsoft C/C++), all of these +functions will be available for use. Otherwise, you won't be able +to perform the SHA-384 and SHA-512 transforms, both of which require +64-bit operations. + +I + +=over 4 + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +Logically joins the arguments into a single string, and returns +its SHA-1/224/256/384/512 digest encoded as a binary string. + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +Logically joins the arguments into a single string, and returns +its SHA-1/224/256/384/512 digest encoded as a hexadecimal string. + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +Logically joins the arguments into a single string, and returns +its SHA-1/224/256/384/512 digest encoded as a Base64 string. + +It's important to note that the resulting string does B contain +the padding characters typical of Base64 encodings. This omission is +deliberate, and is done to maintain compatibility with the family of +CPAN Digest modules. See L for details. + +=back + +I + +=over 4 + +=item B + +Returns a new Digest::SHA object. Allowed values for I<$alg> are 1, +224, 256, 384, 512, 512224, or 512256. It's also possible to use +common string representations of the algorithm (e.g. "sha256", +"SHA-384"). If the argument is missing, SHA-1 will be used by +default. + +Invoking I as an instance method will reset the object to the +initial state associated with I<$alg>. If the argument is missing, +the object will continue using the same algorithm that was selected +at creation. + +=item B + +This method has exactly the same effect as I. In fact, +I is just an alias for I. + +=item B + +Returns the number of digest bits for this object. The values are +160, 224, 256, 384, 512, 224, and 256 for SHA-1, SHA-224, SHA-256, +SHA-384, SHA-512, SHA-512/224 and SHA-512/256, respectively. + +=item B + +Returns the digest algorithm for this object. The values are 1, +224, 256, 384, 512, 512224, and 512256 for SHA-1, SHA-224, SHA-256, +SHA-384, SHA-512, SHA-512/224, and SHA-512/256, respectively. + +=item B + +Returns a duplicate copy of the object. + +=item B + +Logically joins the arguments into a single string, and uses it to +update the current digest state. In other words, the following +statements have the same effect: + + $sha->add("a"); $sha->add("b"); $sha->add("c"); + $sha->add("a")->add("b")->add("c"); + $sha->add("a", "b", "c"); + $sha->add("abc"); + +The return value is the updated object itself. + +=item B + +=item B + +Updates the current digest state by appending bits to it. The +return value is the updated object itself. + +The first form causes the most-significant I<$nbits> of I<$data> +to be appended to the stream. The I<$data> argument is in the +customary binary format used for Perl strings. + +The second form takes an ASCII string of "0" and "1" characters as +its argument. It's equivalent to + + $sha->add_bits(pack("B*", $bits), length($bits)); + +So, the following two statements do the same thing: + + $sha->add_bits("111100001010"); + $sha->add_bits("\xF0\xA0", 12); + +Note that SHA-1 and SHA-2 use I +for their internal state. This means that + + $sha3->add_bits("110"); + +is equivalent to + + $sha3->add_bits("1")->add_bits("1")->add_bits("0"); + +=item B + +Reads from I until EOF, and appends that data to the current +state. The return value is the updated object itself. + +=item B + +Reads the contents of I<$filename>, and appends that data to the current +state. The return value is the updated object itself. + +By default, I<$filename> is simply opened and read; no special modes +or I/O disciplines are used. To change this, set the optional I<$mode> +argument to one of the following values: + + "b" read file in binary mode + + "U" use universal newlines + + "0" use BITS mode + +The "U" mode is modeled on Python's "Universal Newlines" concept, whereby +DOS and Mac OS line terminators are converted internally to UNIX newlines +before processing. This ensures consistent digest values when working +simultaneously across multiple file systems. B, namely those passing Perl's I<-T> test; binary files +are processed with no translation whatsoever. + +The BITS mode ("0") interprets the contents of I<$filename> as a logical +stream of bits, where each ASCII '0' or '1' character represents a 0 or +1 bit, respectively. All other characters are ignored. This provides +a convenient way to calculate the digest values of partial-byte data +by using files, rather than having to write separate programs employing +the I method. + +=item B + +Returns a string containing a portable, human-readable representation +of the current SHA state. + +=item B + +Returns a Digest::SHA object representing the SHA state contained +in I<$str>. The format of I<$str> matches the format of the output +produced by method I. If called as a class method, a new +object is created; if called as an instance method, the object is reset +to the state contained in I<$str>. + +=item B + +Writes the output of I to I<$filename>. If the argument is +missing, or equal to the empty string, the state information will be +written to STDOUT. + +=item B + +Returns a Digest::SHA object that results from calling I on +the contents of I<$filename>. If the argument is missing, or equal to +the empty string, the state information will be read from STDIN. + +=item B + +Returns the digest encoded as a binary string. + +Note that the I method is a read-once operation. Once it +has been performed, the Digest::SHA object is automatically reset +in preparation for calculating another digest value. Call +I<$sha-Eclone-Edigest> if it's necessary to preserve the +original digest state. + +=item B + +Returns the digest encoded as a hexadecimal string. + +Like I, this method is a read-once operation. Call +I<$sha-Eclone-Ehexdigest> if it's necessary to preserve +the original digest state. + +=item B + +Returns the digest encoded as a Base64 string. + +Like I, this method is a read-once operation. Call +I<$sha-Eclone-Eb64digest> if it's necessary to preserve +the original digest state. + +It's important to note that the resulting string does B contain +the padding characters typical of Base64 encodings. This omission is +deliberate, and is done to maintain compatibility with the family of +CPAN Digest modules. See L for details. + +=back + +I + +=over 4 + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +Returns the HMAC-SHA-1/224/256/384/512 digest of I<$data>/I<$key>, +with the result encoded as a binary string. Multiple I<$data> +arguments are allowed, provided that I<$key> is the last argument +in the list. + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +Returns the HMAC-SHA-1/224/256/384/512 digest of I<$data>/I<$key>, +with the result encoded as a hexadecimal string. Multiple I<$data> +arguments are allowed, provided that I<$key> is the last argument +in the list. + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +Returns the HMAC-SHA-1/224/256/384/512 digest of I<$data>/I<$key>, +with the result encoded as a Base64 string. Multiple I<$data> +arguments are allowed, provided that I<$key> is the last argument +in the list. + +It's important to note that the resulting string does B contain +the padding characters typical of Base64 encodings. This omission is +deliberate, and is done to maintain compatibility with the family of +CPAN Digest modules. See L for details. + +=back + +=head1 SEE ALSO + +L, L + +The Secure Hash Standard (Draft FIPS PUB 180-4) can be found at: + +L + +The Keyed-Hash Message Authentication Code (HMAC): + +L + +=head1 AUTHOR + + Mark Shelor + +=head1 ACKNOWLEDGMENTS + +The author is particularly grateful to + + Gisle Aas + H. Merijn Brand + Sean Burke + Chris Carey + Alexandr Ciornii + Chris David + Jim Doble + Thomas Drugeon + Julius Duque + Jeffrey Friedl + Robert Gilmour + Brian Gladman + Jarkko Hietaniemi + Adam Kennedy + Mark Lawrence + Andy Lester + Alex Muntada + Steve Peters + Chris Skiscim + Martin Thurn + Gunnar Wolf + Adam Woodbury + +"who by trained skill rescued life from such great billows and such thick +darkness and moored it in so perfect a calm and in so brilliant a light" +- Lucretius + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2003-2018 Mark Shelor + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +L + +=cut diff --git a/shasum b/shasum new file mode 100755 index 0000000..46a7162 --- /dev/null +++ b/shasum @@ -0,0 +1,337 @@ +#!perl + + ## shasum: filter for computing SHA digests (ref. sha1sum/md5sum) + ## + ## Copyright (C) 2003-2018 Mark Shelor, All Rights Reserved + ## + ## Version: 6.02 + ## Fri Apr 20 16:25:30 MST 2018 + + ## shasum SYNOPSIS adapted from GNU Coreutils sha1sum. Add + ## "-a" option for algorithm selection, + ## "-U" option for Universal Newlines support, and + ## "-0" option for reading bit strings. + +BEGIN { pop @INC if $INC[-1] eq '.' } + +use strict; +use warnings; +use Fcntl; +use Getopt::Long; +use Digest::SHA qw($errmsg); + +my $POD = <<'END_OF_POD'; + +=head1 NAME + +shasum - Print or Check SHA Checksums + +=head1 SYNOPSIS + + Usage: shasum [OPTION]... [FILE]... + Print or check SHA checksums. + With no FILE, or when FILE is -, read standard input. + + -a, --algorithm 1 (default), 224, 256, 384, 512, 512224, 512256 + -b, --binary read in binary mode + -c, --check read SHA sums from the FILEs and check them + --tag create a BSD-style checksum + -t, --text read in text mode (default) + -U, --UNIVERSAL read in Universal Newlines mode + produces same digest on Windows/Unix/Mac + -0, --01 read in BITS mode + ASCII '0' interpreted as 0-bit, + ASCII '1' interpreted as 1-bit, + all other characters ignored + + The following five options are useful only when verifying checksums: + --ignore-missing don't fail or report status for missing files + -q, --quiet don't print OK for each successfully verified file + -s, --status don't output anything, status code shows success + --strict exit non-zero for improperly formatted checksum lines + -w, --warn warn about improperly formatted checksum lines + + -h, --help display this help and exit + -v, --version output version information and exit + + When verifying SHA-512/224 or SHA-512/256 checksums, indicate the + algorithm explicitly using the -a option, e.g. + + shasum -a 512224 -c checksumfile + + The sums are computed as described in FIPS PUB 180-4. When checking, + the input should be a former output of this program. The default + mode is to print a line with checksum, a character indicating type + (`*' for binary, ` ' for text, `U' for UNIVERSAL, `^' for BITS), + and name for each FILE. The line starts with a `\' character if the + FILE name contains either newlines or backslashes, which are then + replaced by the two-character sequences `\n' and `\\' respectively. + + Report shasum bugs to mshelor@cpan.org + +=head1 DESCRIPTION + +Running I is often the quickest way to compute SHA message +digests. The user simply feeds data to the script through files or +standard input, and then collects the results from standard output. + +The following command shows how to compute digests for typical inputs +such as the NIST test vector "abc": + + perl -e "print qq(abc)" | shasum + +Or, if you want to use SHA-256 instead of the default SHA-1, simply say: + + perl -e "print qq(abc)" | shasum -a 256 + +Since I mimics the behavior of the combined GNU I, +I, I, I, and I programs, +you can install this script as a convenient drop-in replacement. + +Unlike the GNU programs, I encompasses the full SHA standard by +allowing partial-byte inputs. This is accomplished through the BITS +option (I<-0>). The following example computes the SHA-224 digest of +the 7-bit message I<0001100>: + + perl -e "print qq(0001100)" | shasum -0 -a 224 + +=head1 AUTHOR + +Copyright (C) 2003-2018 Mark Shelor . + +=head1 SEE ALSO + +I is implemented using the Perl module L. + +=cut + +END_OF_POD + +my $VERSION = "6.02"; + +sub usage { + my($err, $msg) = @_; + + $msg = "" unless defined $msg; + if ($err) { + warn($msg . "Type shasum -h for help\n"); + exit($err); + } + my($USAGE) = $POD =~ /SYNOPSIS(.+?)^=/sm; + $USAGE =~ s/^\s*//; + $USAGE =~ s/\s*$//; + $USAGE =~ s/^ //gm; + print $USAGE, "\n"; + exit($err); +} + + + ## Sync stdout and stderr by forcing a flush after every write + +select((select(STDOUT), $| = 1)[0]); +select((select(STDERR), $| = 1)[0]); + + + ## Collect options from command line + +my ($alg, $binary, $check, $text, $status, $quiet, $warn, $help); +my ($version, $BITS, $UNIVERSAL, $tag, $strict, $ignore_missing); + +eval { Getopt::Long::Configure ("bundling") }; +GetOptions( + 'b|binary' => \$binary, 'c|check' => \$check, + 't|text' => \$text, 'a|algorithm=i' => \$alg, + 's|status' => \$status, 'w|warn' => \$warn, + 'q|quiet' => \$quiet, + 'h|help' => \$help, 'v|version' => \$version, + '0|01' => \$BITS, + 'U|UNIVERSAL' => \$UNIVERSAL, + 'tag' => \$tag, + 'strict' => \$strict, + 'ignore-missing' => \$ignore_missing, +) or usage(1, ""); + + + ## Deal with help requests and incorrect uses + +usage(0) + if $help; +usage(1, "shasum: Ambiguous file mode\n") + if scalar(grep {defined $_} + ($binary, $text, $BITS, $UNIVERSAL)) > 1; +usage(1, "shasum: --warn option used only when verifying checksums\n") + if $warn && !$check; +usage(1, "shasum: --status option used only when verifying checksums\n") + if $status && !$check; +usage(1, "shasum: --quiet option used only when verifying checksums\n") + if $quiet && !$check; +usage(1, "shasum: --ignore-missing option used only when verifying checksums\n") + if $ignore_missing && !$check; +usage(1, "shasum: --strict option used only when verifying checksums\n") + if $strict && !$check; +usage(1, "shasum: --tag does not support --text mode\n") + if $tag && $text; +usage(1, "shasum: --tag does not support Universal Newlines mode\n") + if $tag && $UNIVERSAL; +usage(1, "shasum: --tag does not support BITS mode\n") + if $tag && $BITS; + + + ## Default to SHA-1 unless overridden by command line option + +my %isAlg = map { $_ => 1 } (1, 224, 256, 384, 512, 512224, 512256); +$alg = 1 unless defined $alg; +usage(1, "shasum: Unrecognized algorithm\n") unless $isAlg{$alg}; + +my %Tag = map { $_ => "SHA$_" } (1, 224, 256, 384, 512); +$Tag{512224} = "SHA512/224"; +$Tag{512256} = "SHA512/256"; + + + ## Display version information if requested + +if ($version) { + print "$VERSION\n"; + exit(0); +} + + + ## Try to figure out if the OS is DOS-like. If it is, + ## default to binary mode when reading files, unless + ## explicitly overridden by command line "--text" or + ## "--UNIVERSAL" options. + +my $isDOSish = ($^O =~ /^(MSWin\d\d|os2|dos|mint|cygwin)$/); +if ($isDOSish) { $binary = 1 unless $text || $UNIVERSAL } + +my $modesym = $binary ? '*' : ($UNIVERSAL ? 'U' : ($BITS ? '^' : ' ')); + + + ## Read from STDIN (-) if no files listed on command line + +@ARGV = ("-") unless @ARGV; + + + ## sumfile($file): computes SHA digest of $file + +sub sumfile { + my $file = shift; + + my $mode = $binary ? 'b' : ($UNIVERSAL ? 'U' : ($BITS ? '0' : '')); + my $digest = eval { Digest::SHA->new($alg)->addfile($file, $mode) }; + if ($@) { warn "shasum: $file: $errmsg\n"; return } + $digest->hexdigest; +} + + + ## %len2alg: maps hex digest length to SHA algorithm + +my %len2alg = (40 => 1, 56 => 224, 64 => 256, 96 => 384, 128 => 512); +$len2alg{56} = 512224 if $alg == 512224; +$len2alg{64} = 512256 if $alg == 512256; + + + ## unescape: convert backslashed filename to plain filename + +sub unescape { + $_ = shift; + s/\\\\/\0/g; + s/\\n/\n/g; + s/\0/\\/g; + return $_; +} + + + ## verify: confirm the digest values in a checksum file + +sub verify { + my $checkfile = shift; + my ($err, $fmt_errs, $read_errs, $match_errs) = (0, 0, 0, 0); + my ($num_fmt_OK, $num_OK) = (0, 0); + my ($bslash, $sum, $fname, $rsp, $digest, $isOK); + + local *FH; + $checkfile eq '-' and open(FH, '< -') + and $checkfile = 'standard input' + or sysopen(FH, $checkfile, O_RDONLY) + or die "shasum: $checkfile: $!\n"; + while () { + next if /^#/; + if (/^[ \t]*\\?SHA/) { + $modesym = '*'; + ($bslash, $alg, $fname, $sum) = + /^[ \t]*(\\?)SHA(\S+) \((.+)\) = ([\da-fA-F]+)/; + $alg =~ tr{/}{}d if defined $alg; + } + else { + ($bslash, $sum, $modesym, $fname) = + /^[ \t]*(\\?)([\da-fA-F]+)[ \t]([ *^U])(.+)/; + $alg = defined $sum ? $len2alg{length($sum)} : undef; + } + if (grep { ! defined $_ } ($alg, $sum, $modesym, $fname) or + ! $isAlg{$alg}) { + warn("shasum: $checkfile: $.: improperly " . + "formatted SHA checksum line\n") if $warn; + $fmt_errs++; + $err = 1 if $strict; + next; + } + $num_fmt_OK++; + $fname = unescape($fname) if $bslash; + next if $ignore_missing && ! -e $fname; + $rsp = "$fname: "; + ($binary, $text, $UNIVERSAL, $BITS) = + map { $_ eq $modesym } ('*', ' ', 'U', '^'); + $isOK = 0; + unless ($digest = sumfile($fname)) { + $rsp .= "FAILED open or read\n"; + $err = 1; $read_errs++; + } + elsif (lc($sum) eq $digest) { + $rsp .= "OK\n"; + $isOK = 1; + $num_OK++; + } + else { $rsp .= "FAILED\n"; $err = 1; $match_errs++ } + print $rsp unless ($status || ($quiet && $isOK)); + } + close(FH); + if (! $num_fmt_OK) { + warn("shasum: $checkfile: no properly formatted " . + "SHA checksum lines found\n"); + $err = 1; + } + elsif (! $status) { + warn("shasum: WARNING: $fmt_errs line" . ($fmt_errs>1? + 's are':' is') . " improperly formatted\n") if $fmt_errs; + warn("shasum: WARNING: $read_errs listed file" . + ($read_errs>1?'s':'') . " could not be read\n") if $read_errs; + warn("shasum: WARNING: $match_errs computed checksum" . + ($match_errs>1?'s':'') . " did NOT match\n") if $match_errs; + } + if ($ignore_missing && ! $num_OK && $num_fmt_OK) { + warn("shasum: $checkfile: no file was verified\n") + unless $status; + $err = 1; + } + return($err == 0); +} + + + ## Verify or compute SHA checksums of requested files + +my($file, $digest); +my $STATUS = 0; +for $file (@ARGV) { + if ($check) { $STATUS = 1 unless verify($file) } + elsif ($digest = sumfile($file)) { + if ($file =~ /[\n\\]/) { + $file =~ s/\\/\\\\/g; $file =~ s/\n/\\n/g; + print "\\"; + } + unless ($tag) { print "$digest $modesym$file\n" } + else { print "$Tag{$alg} ($file) = $digest\n" } + } + else { $STATUS = 1 } +} +exit($STATUS); diff --git a/src/sdf.c b/src/sdf.c new file mode 100644 index 0000000..e74f8e0 --- /dev/null +++ b/src/sdf.c @@ -0,0 +1,100 @@ +/* Extracted from perl-5.004/universal.c, contributed by Graham Barr */ + +static SV * +isa_lookup(stash, name, len, level) +HV *stash; +char *name; +int len; +int level; +{ + AV* av; + GV* gv; + GV** gvp; + HV* hv = Nullhv; + + if (!stash) + return &sv_undef; + + if(strEQ(HvNAME(stash), name)) + return &sv_yes; + + if (level > 100) + croak("Recursive inheritance detected"); + + gvp = (GV**)hv_fetch(stash, "::ISA::CACHE::", 14, FALSE); + + if (gvp && (gv = *gvp) != (GV*)&sv_undef && (hv = GvHV(gv))) { + SV* sv; + SV** svp = (SV**)hv_fetch(hv, name, len, FALSE); + if (svp && (sv = *svp) != (SV*)&sv_undef) + return sv; + } + + gvp = (GV**)hv_fetch(stash,"ISA",3,FALSE); + + if (gvp && (gv = *gvp) != (GV*)&sv_undef && (av = GvAV(gv))) { + if(!hv) { + gvp = (GV**)hv_fetch(stash, "::ISA::CACHE::", 14, TRUE); + + gv = *gvp; + + if (SvTYPE(gv) != SVt_PVGV) + gv_init(gv, stash, "::ISA::CACHE::", 14, TRUE); + + hv = GvHVn(gv); + } + if(hv) { + SV** svp = AvARRAY(av); + I32 items = AvFILL(av) + 1; + while (items--) { + SV* sv = *svp++; + HV* basestash = gv_stashsv(sv, FALSE); + if (!basestash) { + if (dowarn) + warn("Can't locate package %s for @%s::ISA", + SvPVX(sv), HvNAME(stash)); + continue; + } + if(&sv_yes == isa_lookup(basestash, name, len, level + 1)) { + (void)hv_store(hv,name,len,&sv_yes,0); + return &sv_yes; + } + } + (void)hv_store(hv,name,len,&sv_no,0); + } + } + + return &sv_no; +} + +static bool +sv_derived_from(sv, name) +SV * sv ; +char * name ; +{ + SV *rv; + char *type; + HV *stash; + + stash = Nullhv; + type = Nullch; + + if (SvGMAGICAL(sv)) + mg_get(sv) ; + + if (SvROK(sv)) { + sv = SvRV(sv); + type = sv_reftype(sv,0); + if(SvOBJECT(sv)) + stash = SvSTASH(sv); + } + else { + stash = gv_stashsv(sv, FALSE); + } + + return (type && strEQ(type,name)) || + (stash && isa_lookup(stash, name, strlen(name), 0) == &sv_yes) + ? TRUE + : FALSE ; + +} diff --git a/src/sha.c b/src/sha.c new file mode 100644 index 0000000..bc337eb --- /dev/null +++ b/src/sha.c @@ -0,0 +1,540 @@ +/* + * sha.c: routines to compute SHA-1/224/256/384/512 digests + * + * Ref: NIST FIPS PUB 180-4 Secure Hash Standard + * + * Copyright (C) 2003-2018 Mark Shelor, All Rights Reserved + * + * Version: 6.02 + * Fri Apr 20 16:25:30 MST 2018 + * + */ + +#include +#include +#include +#include +#include +#include "sha.h" +#include "sha64bit.h" + +#define W32 SHA32 /* useful abbreviations */ +#define C32 SHA32_CONST +#define SR32 SHA32_SHR +#define SL32 SHA32_SHL +#define LO32 SHA_LO32 +#define UCHR unsigned char +#define UINT unsigned int +#define ULNG unsigned long +#define VP void * + +#define ROTR(x, n) (SR32(x, n) | SL32(x, 32-(n))) +#define ROTL(x, n) (SL32(x, n) | SR32(x, 32-(n))) + +#define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Pa(x, y, z) ((x) ^ (y) ^ (z)) +#define Ma(x, y, z) (((x) & (y)) | ((z) & ((x) | (y)))) + +#define SIGMA0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SIGMA1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define sigma0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SR32(x, 3)) +#define sigma1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SR32(x, 10)) + +#define K1 C32(0x5a827999) /* SHA-1 constants */ +#define K2 C32(0x6ed9eba1) +#define K3 C32(0x8f1bbcdc) +#define K4 C32(0xca62c1d6) + +static const W32 K256[64] = /* SHA-224/256 constants */ +{ + C32(0x428a2f98), C32(0x71374491), C32(0xb5c0fbcf), C32(0xe9b5dba5), + C32(0x3956c25b), C32(0x59f111f1), C32(0x923f82a4), C32(0xab1c5ed5), + C32(0xd807aa98), C32(0x12835b01), C32(0x243185be), C32(0x550c7dc3), + C32(0x72be5d74), C32(0x80deb1fe), C32(0x9bdc06a7), C32(0xc19bf174), + C32(0xe49b69c1), C32(0xefbe4786), C32(0x0fc19dc6), C32(0x240ca1cc), + C32(0x2de92c6f), C32(0x4a7484aa), C32(0x5cb0a9dc), C32(0x76f988da), + C32(0x983e5152), C32(0xa831c66d), C32(0xb00327c8), C32(0xbf597fc7), + C32(0xc6e00bf3), C32(0xd5a79147), C32(0x06ca6351), C32(0x14292967), + C32(0x27b70a85), C32(0x2e1b2138), C32(0x4d2c6dfc), C32(0x53380d13), + C32(0x650a7354), C32(0x766a0abb), C32(0x81c2c92e), C32(0x92722c85), + C32(0xa2bfe8a1), C32(0xa81a664b), C32(0xc24b8b70), C32(0xc76c51a3), + C32(0xd192e819), C32(0xd6990624), C32(0xf40e3585), C32(0x106aa070), + C32(0x19a4c116), C32(0x1e376c08), C32(0x2748774c), C32(0x34b0bcb5), + C32(0x391c0cb3), C32(0x4ed8aa4a), C32(0x5b9cca4f), C32(0x682e6ff3), + C32(0x748f82ee), C32(0x78a5636f), C32(0x84c87814), C32(0x8cc70208), + C32(0x90befffa), C32(0xa4506ceb), C32(0xbef9a3f7), C32(0xc67178f2) +}; + +static const W32 H01[8] = /* SHA-1 initial hash value */ +{ + C32(0x67452301), C32(0xefcdab89), C32(0x98badcfe), C32(0x10325476), + C32(0xc3d2e1f0), C32(0x00000000), C32(0x00000000), C32(0x00000000) +}; + +static const W32 H0224[8] = /* SHA-224 initial hash value */ +{ + C32(0xc1059ed8), C32(0x367cd507), C32(0x3070dd17), C32(0xf70e5939), + C32(0xffc00b31), C32(0x68581511), C32(0x64f98fa7), C32(0xbefa4fa4) +}; + +static const W32 H0256[8] = /* SHA-256 initial hash value */ +{ + C32(0x6a09e667), C32(0xbb67ae85), C32(0x3c6ef372), C32(0xa54ff53a), + C32(0x510e527f), C32(0x9b05688c), C32(0x1f83d9ab), C32(0x5be0cd19) +}; + +static void sha1(SHA *s, UCHR *block) /* SHA-1 transform */ +{ + W32 a, b, c, d, e; + W32 W[16]; + W32 *wp = W; + W32 *H = s->H32; + + SHA32_SCHED(W, block); + +/* + * Use SHA-1 alternate method from FIPS PUB 180-4 (ref. 6.1.3) + * + * To improve performance, unroll the loop and consolidate assignments + * by changing the roles of variables "a" through "e" at each step. + * Note that the variable "T" is no longer needed. + */ + +#define M1(a, b, c, d, e, f, k, w) \ + e += ROTL(a, 5) + f(b, c, d) + k + w; \ + b = ROTL(b, 30) + +#define M11(f, k, w) M1(a, b, c, d, e, f, k, w); +#define M12(f, k, w) M1(e, a, b, c, d, f, k, w); +#define M13(f, k, w) M1(d, e, a, b, c, f, k, w); +#define M14(f, k, w) M1(c, d, e, a, b, f, k, w); +#define M15(f, k, w) M1(b, c, d, e, a, f, k, w); + +#define W11(s) W[(s+ 0) & 0xf] +#define W12(s) W[(s+13) & 0xf] +#define W13(s) W[(s+ 8) & 0xf] +#define W14(s) W[(s+ 2) & 0xf] + +#define A1(s) (W11(s) = ROTL(W11(s) ^ W12(s) ^ W13(s) ^ W14(s), 1)) + + a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; + + M11(Ch, K1, *wp++); M12(Ch, K1, *wp++); M13(Ch, K1, *wp++); + M14(Ch, K1, *wp++); M15(Ch, K1, *wp++); M11(Ch, K1, *wp++); + M12(Ch, K1, *wp++); M13(Ch, K1, *wp++); M14(Ch, K1, *wp++); + M15(Ch, K1, *wp++); M11(Ch, K1, *wp++); M12(Ch, K1, *wp++); + M13(Ch, K1, *wp++); M14(Ch, K1, *wp++); M15(Ch, K1, *wp++); + M11(Ch, K1, *wp ); M12(Ch, K1, A1( 0)); M13(Ch, K1, A1( 1)); + M14(Ch, K1, A1( 2)); M15(Ch, K1, A1( 3)); M11(Pa, K2, A1( 4)); + M12(Pa, K2, A1( 5)); M13(Pa, K2, A1( 6)); M14(Pa, K2, A1( 7)); + M15(Pa, K2, A1( 8)); M11(Pa, K2, A1( 9)); M12(Pa, K2, A1(10)); + M13(Pa, K2, A1(11)); M14(Pa, K2, A1(12)); M15(Pa, K2, A1(13)); + M11(Pa, K2, A1(14)); M12(Pa, K2, A1(15)); M13(Pa, K2, A1( 0)); + M14(Pa, K2, A1( 1)); M15(Pa, K2, A1( 2)); M11(Pa, K2, A1( 3)); + M12(Pa, K2, A1( 4)); M13(Pa, K2, A1( 5)); M14(Pa, K2, A1( 6)); + M15(Pa, K2, A1( 7)); M11(Ma, K3, A1( 8)); M12(Ma, K3, A1( 9)); + M13(Ma, K3, A1(10)); M14(Ma, K3, A1(11)); M15(Ma, K3, A1(12)); + M11(Ma, K3, A1(13)); M12(Ma, K3, A1(14)); M13(Ma, K3, A1(15)); + M14(Ma, K3, A1( 0)); M15(Ma, K3, A1( 1)); M11(Ma, K3, A1( 2)); + M12(Ma, K3, A1( 3)); M13(Ma, K3, A1( 4)); M14(Ma, K3, A1( 5)); + M15(Ma, K3, A1( 6)); M11(Ma, K3, A1( 7)); M12(Ma, K3, A1( 8)); + M13(Ma, K3, A1( 9)); M14(Ma, K3, A1(10)); M15(Ma, K3, A1(11)); + M11(Pa, K4, A1(12)); M12(Pa, K4, A1(13)); M13(Pa, K4, A1(14)); + M14(Pa, K4, A1(15)); M15(Pa, K4, A1( 0)); M11(Pa, K4, A1( 1)); + M12(Pa, K4, A1( 2)); M13(Pa, K4, A1( 3)); M14(Pa, K4, A1( 4)); + M15(Pa, K4, A1( 5)); M11(Pa, K4, A1( 6)); M12(Pa, K4, A1( 7)); + M13(Pa, K4, A1( 8)); M14(Pa, K4, A1( 9)); M15(Pa, K4, A1(10)); + M11(Pa, K4, A1(11)); M12(Pa, K4, A1(12)); M13(Pa, K4, A1(13)); + M14(Pa, K4, A1(14)); M15(Pa, K4, A1(15)); + + H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; +} + +static void sha256(SHA *s, UCHR *block) /* SHA-224/256 transform */ +{ + W32 a, b, c, d, e, f, g, h, T1; + W32 W[16]; + const W32 *kp = K256; + W32 *wp = W; + W32 *H = s->H32; + + SHA32_SCHED(W, block); + +/* + * Use same technique as in sha1() + * + * To improve performance, unroll the loop and consolidate assignments + * by changing the roles of variables "a" through "h" at each step. + * Note that the variable "T2" is no longer needed. + */ + +#define M2(a, b, c, d, e, f, g, h, w) \ + T1 = h + SIGMA1(e) + Ch(e, f, g) + (*kp++) + w; \ + h = T1 + SIGMA0(a) + Ma(a, b, c); d += T1; + +#define W21(s) W[(s+ 0) & 0xf] +#define W22(s) W[(s+14) & 0xf] +#define W23(s) W[(s+ 9) & 0xf] +#define W24(s) W[(s+ 1) & 0xf] + +#define A2(s) (W21(s) += sigma1(W22(s)) + W23(s) + sigma0(W24(s))) + +#define M21(w) M2(a, b, c, d, e, f, g, h, w) +#define M22(w) M2(h, a, b, c, d, e, f, g, w) +#define M23(w) M2(g, h, a, b, c, d, e, f, w) +#define M24(w) M2(f, g, h, a, b, c, d, e, w) +#define M25(w) M2(e, f, g, h, a, b, c, d, w) +#define M26(w) M2(d, e, f, g, h, a, b, c, w) +#define M27(w) M2(c, d, e, f, g, h, a, b, w) +#define M28(w) M2(b, c, d, e, f, g, h, a, w) + + a = H[0]; b = H[1]; c = H[2]; d = H[3]; + e = H[4]; f = H[5]; g = H[6]; h = H[7]; + + M21( *wp++); M22( *wp++); M23( *wp++); M24( *wp++); + M25( *wp++); M26( *wp++); M27( *wp++); M28( *wp++); + M21( *wp++); M22( *wp++); M23( *wp++); M24( *wp++); + M25( *wp++); M26( *wp++); M27( *wp++); M28( *wp ); + M21(A2( 0)); M22(A2( 1)); M23(A2( 2)); M24(A2( 3)); + M25(A2( 4)); M26(A2( 5)); M27(A2( 6)); M28(A2( 7)); + M21(A2( 8)); M22(A2( 9)); M23(A2(10)); M24(A2(11)); + M25(A2(12)); M26(A2(13)); M27(A2(14)); M28(A2(15)); + M21(A2( 0)); M22(A2( 1)); M23(A2( 2)); M24(A2( 3)); + M25(A2( 4)); M26(A2( 5)); M27(A2( 6)); M28(A2( 7)); + M21(A2( 8)); M22(A2( 9)); M23(A2(10)); M24(A2(11)); + M25(A2(12)); M26(A2(13)); M27(A2(14)); M28(A2(15)); + M21(A2( 0)); M22(A2( 1)); M23(A2( 2)); M24(A2( 3)); + M25(A2( 4)); M26(A2( 5)); M27(A2( 6)); M28(A2( 7)); + M21(A2( 8)); M22(A2( 9)); M23(A2(10)); M24(A2(11)); + M25(A2(12)); M26(A2(13)); M27(A2(14)); M28(A2(15)); + + H[0] += a; H[1] += b; H[2] += c; H[3] += d; + H[4] += e; H[5] += f; H[6] += g; H[7] += h; +} + +#include "sha64bit.c" + +#define BITSET(s, pos) s[(pos) >> 3] & (UCHR) (0x01 << (7 - (pos) % 8)) +#define SETBIT(s, pos) s[(pos) >> 3] |= (UCHR) (0x01 << (7 - (pos) % 8)) +#define CLRBIT(s, pos) s[(pos) >> 3] &= (UCHR) ~(0x01 << (7 - (pos) % 8)) +#define NBYTES(nbits) (((nbits) + 7) >> 3) +#define HEXLEN(nbytes) ((nbytes) << 1) +#define B64LEN(nbytes) (((nbytes) % 3 == 0) ? ((nbytes) / 3) * 4 \ + : ((nbytes) / 3) * 4 + ((nbytes) % 3) + 1) + +/* w32mem: writes 32-bit word to memory in big-endian order */ +static UCHR *w32mem(UCHR *mem, W32 w32) +{ + int i; + + for (i = 0; i < 4; i++) + *mem++ = (UCHR) (SR32(w32, 24-i*8) & 0xff); + return(mem); +} + +/* memw32: returns 32-bit word from memory written in big-endian order */ +static W32 memw32(UCHR *mem) +{ + int i; + W32 w = 0; + + for (i = 0; i < 4; i++) + w = (w << 8) + *mem++; + return(w); +} + +/* digcpy: writes current state to digest buffer */ +static UCHR *digcpy(SHA *s) +{ + int i; + UCHR *d = s->digest; + W32 *p32 = s->H32; + W64 *p64 = s->H64; + + if (s->alg <= SHA256) + for (i = 0; i < 8; i++, d += 4) + w32mem(d, *p32++); + else + for (i = 0; i < 8; i++, d += 8) { + w32mem(d, (W32) ((*p64 >> 16) >> 16)); + w32mem(d+4, (W32) (*p64++ & SHA32_MAX)); + } + return(s->digest); +} + +/* statecpy: writes buffer to current state (opposite of digcpy) */ +static UCHR *statecpy(SHA *s, UCHR *buf) +{ + int i; + W32 *p32 = s->H32; + W64 *p64 = s->H64; + + if (s->alg <= SHA256) + for (i = 0; i < 8; i++, buf += 4) + *p32++ = memw32(buf); + else + for (i = 0; i < 8; i++, buf += 8) + *p64++ = (((W64)memw32(buf) << 16) << 16) + + memw32(buf+4); + return(buf); +} + +#define SHA_INIT(s, algo, transform) \ + do { \ + Zero(s, 1, SHA); \ + s->alg = algo; s->sha = sha ## transform; \ + if (s->alg <= SHA256) \ + Copy(H0 ## algo, s->H32, 8, SHA32); \ + else \ + Copy(H0 ## algo, s->H64, 8, SHA64); \ + s->blocksize = SHA ## algo ## _BLOCK_BITS; \ + s->digestlen = SHA ## algo ## _DIGEST_BITS >> 3; \ + } while (0) + +/* sharewind: resets digest object */ +static void sharewind(SHA *s) +{ + if (s->alg == SHA1) SHA_INIT(s, 1, 1); + else if (s->alg == SHA224) SHA_INIT(s, 224, 256); + else if (s->alg == SHA256) SHA_INIT(s, 256, 256); + else if (s->alg == SHA384) SHA_INIT(s, 384, 512); + else if (s->alg == SHA512) SHA_INIT(s, 512, 512); + else if (s->alg == SHA512224) SHA_INIT(s, 512224, 512); + else if (s->alg == SHA512256) SHA_INIT(s, 512256, 512); +} + +/* shainit: initializes digest object */ +static int shainit(SHA *s, int alg) +{ + if (alg >= SHA384 && !sha_384_512) + return 0; + if (alg != SHA1 && alg != SHA224 && alg != SHA256 && + alg != SHA384 && alg != SHA512 && + alg != SHA512224 && alg != SHA512256) + return 0; + s->alg = alg; + sharewind(s); + return 1; +} + +/* shadirect: updates state directly (w/o going through s->block) */ +static ULNG shadirect(UCHR *bitstr, ULNG bitcnt, SHA *s) +{ + ULNG savecnt = bitcnt; + + while (bitcnt >= s->blocksize) { + s->sha(s, bitstr); + bitstr += (s->blocksize >> 3); + bitcnt -= s->blocksize; + } + if (bitcnt > 0) { + Copy(bitstr, s->block, NBYTES(bitcnt), char); + s->blockcnt = bitcnt; + } + return(savecnt); +} + +/* shabytes: updates state for byte-aligned data in s->block */ +static ULNG shabytes(UCHR *bitstr, ULNG bitcnt, SHA *s) +{ + UINT offset; + UINT nbits; + ULNG savecnt = bitcnt; + + offset = s->blockcnt >> 3; + if (s->blockcnt + bitcnt >= s->blocksize) { + nbits = s->blocksize - s->blockcnt; + Copy(bitstr, s->block+offset, nbits>>3, char); + bitcnt -= nbits; + bitstr += (nbits >> 3); + s->sha(s, s->block), s->blockcnt = 0; + shadirect(bitstr, bitcnt, s); + } + else { + Copy(bitstr, s->block+offset, NBYTES(bitcnt), char); + s->blockcnt += bitcnt; + } + return(savecnt); +} + +/* shabits: updates state for bit-aligned data in s->block */ +static ULNG shabits(UCHR *bitstr, ULNG bitcnt, SHA *s) +{ + ULNG i; + + for (i = 0UL; i < bitcnt; i++) { + if (BITSET(bitstr, i)) + SETBIT(s->block, s->blockcnt); + else + CLRBIT(s->block, s->blockcnt); + if (++s->blockcnt == s->blocksize) + s->sha(s, s->block), s->blockcnt = 0; + } + return(bitcnt); +} + +/* shawrite: triggers a state update using data in bitstr/bitcnt */ +static ULNG shawrite(UCHR *bitstr, ULNG bitcnt, SHA *s) +{ + if (!bitcnt) + return(0); + if (SHA_LO32(s->lenll += bitcnt) < bitcnt) + if (SHA_LO32(++s->lenlh) == 0) + if (SHA_LO32(++s->lenhl) == 0) + s->lenhh++; + if (s->blockcnt == 0) + return(shadirect(bitstr, bitcnt, s)); + else if (s->blockcnt % 8 == 0) + return(shabytes(bitstr, bitcnt, s)); + else + return(shabits(bitstr, bitcnt, s)); +} + +/* shafinish: pads remaining block(s) and computes final digest state */ +static void shafinish(SHA *s) +{ + UINT lenpos, lhpos, llpos; + + lenpos = s->blocksize == SHA1_BLOCK_BITS ? 448 : 896; + lhpos = s->blocksize == SHA1_BLOCK_BITS ? 56 : 120; + llpos = s->blocksize == SHA1_BLOCK_BITS ? 60 : 124; + SETBIT(s->block, s->blockcnt), s->blockcnt++; + while (s->blockcnt > lenpos) + if (s->blockcnt < s->blocksize) + CLRBIT(s->block, s->blockcnt), s->blockcnt++; + else + s->sha(s, s->block), s->blockcnt = 0; + while (s->blockcnt < lenpos) + CLRBIT(s->block, s->blockcnt), s->blockcnt++; + if (s->blocksize > SHA1_BLOCK_BITS) { + w32mem(s->block + 112, s->lenhh); + w32mem(s->block + 116, s->lenhl); + } + w32mem(s->block + lhpos, s->lenlh); + w32mem(s->block + llpos, s->lenll); + s->sha(s, s->block); +} + +#define shadigest(state) digcpy(state) + +/* xmap: translation map for hexadecimal encoding */ +static const char xmap[] = + "0123456789abcdef"; + +/* shahex: returns pointer to current digest (hexadecimal) */ +static char *shahex(SHA *s) +{ + UINT i; + char *h; + UCHR *d; + + d = digcpy(s); + s->hex[0] = '\0'; + if (HEXLEN((size_t) s->digestlen) >= sizeof(s->hex)) + return(s->hex); + for (i = 0, h = s->hex; i < s->digestlen; i++) { + *h++ = xmap[(*d >> 4) & 0x0f]; + *h++ = xmap[(*d++ ) & 0x0f]; + } + *h = '\0'; + return(s->hex); +} + +/* bmap: translation map for Base 64 encoding */ +static const char bmap[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* encbase64: encodes input (0 to 3 bytes) into Base 64 */ +static void encbase64(UCHR *in, UINT n, char *out) +{ + UCHR byte[3] = {0, 0, 0}; + + out[0] = '\0'; + if (n < 1 || n > 3) + return; + Copy(in, byte, n, UCHR); + out[0] = bmap[byte[0] >> 2]; + out[1] = bmap[((byte[0] & 0x03) << 4) | (byte[1] >> 4)]; + out[2] = bmap[((byte[1] & 0x0f) << 2) | (byte[2] >> 6)]; + out[3] = bmap[byte[2] & 0x3f]; + out[n+1] = '\0'; +} + +/* shabase64: returns pointer to current digest (Base 64) */ +static char *shabase64(SHA *s) +{ + UINT n; + UCHR *q; + char out[5]; + + q = digcpy(s); + s->base64[0] = '\0'; + if (B64LEN((size_t) s->digestlen) >= sizeof(s->base64)) + return(s->base64); + for (n = s->digestlen; n > 3; n -= 3, q += 3) { + encbase64(q, 3, out); + strcat(s->base64, out); + } + encbase64(q, n, out); + strcat(s->base64, out); + return(s->base64); +} + +/* hmacinit: initializes HMAC-SHA digest object */ +static HMAC *hmacinit(HMAC *h, int alg, UCHR *key, UINT keylen) +{ + UINT i; + SHA ksha; + + Zero(h, 1, HMAC); + if (!shainit(&h->isha, alg)) + return(NULL); + if (!shainit(&h->osha, alg)) + return(NULL); + if (keylen <= h->osha.blocksize / 8) + Copy(key, h->key, keylen, char); + else { + if (!shainit(&ksha, alg)) + return(NULL); + shawrite(key, keylen * 8, &ksha); + shafinish(&ksha); + Copy(digcpy(&ksha), h->key, ksha.digestlen, char); + } + h->digestlen = h->osha.digestlen; + for (i = 0; i < h->osha.blocksize / 8; i++) + h->key[i] ^= 0x5c; + shawrite(h->key, h->osha.blocksize, &h->osha); + for (i = 0; i < h->isha.blocksize / 8; i++) + h->key[i] ^= (0x5c ^ 0x36); + shawrite(h->key, h->isha.blocksize, &h->isha); + Zero(h->key, sizeof(h->key), char); + return(h); +} + +/* hmacwrite: triggers a state update using data in bitstr/bitcnt */ +static ULNG hmacwrite(UCHR *bitstr, ULNG bitcnt, HMAC *h) +{ + return(shawrite(bitstr, bitcnt, &h->isha)); +} + +/* hmacfinish: computes final digest state */ +static void hmacfinish(HMAC *h) +{ + shafinish(&h->isha); + shawrite(digcpy(&h->isha), h->isha.digestlen * 8, &h->osha); + shafinish(&h->osha); +} + +#define hmacdigest(h) digcpy(&(h)->osha) + +/* hmachex: returns pointer to digest (hexadecimal) */ +static char *hmachex(HMAC *h) +{ + return(shahex(&h->osha)); +} + +/* hmacbase64: returns pointer to digest (Base 64) */ +static char *hmacbase64(HMAC *h) +{ + return(shabase64(&h->osha)); +} diff --git a/src/sha.h b/src/sha.h new file mode 100644 index 0000000..f659928 --- /dev/null +++ b/src/sha.h @@ -0,0 +1,160 @@ +/* + * sha.h: header file for SHA-1/224/256/384/512 routines + * + * Ref: NIST FIPS PUB 180-4 Secure Hash Standard + * + * Copyright (C) 2003-2018 Mark Shelor, All Rights Reserved + * + * Version: 6.02 + * Fri Apr 20 16:25:30 MST 2018 + * + */ + +#ifndef _INCLUDE_SHA_H_ +#define _INCLUDE_SHA_H_ + +#include + +#define SHA32_MAX 4294967295U + +#define SHA32_SHR(x, n) ((x) >> (n)) +#define SHA32_SHL(x, n) ((x) << (n)) + +#define SHA64_SHR(x, n) ((x) >> (n)) +#define SHA64_SHL(x, n) ((x) << (n)) + +#define SHA32_ALIGNED +#define SHA64_ALIGNED + +#define SHA_LO32(x) (x) + +#if USHRT_MAX == SHA32_MAX + #define SHA32 unsigned short + #define SHA32_CONST(c) c ## U +#elif UINT_MAX == SHA32_MAX + #define SHA32 unsigned int + #define SHA32_CONST(c) c ## U +#elif ULONG_MAX == SHA32_MAX + #define SHA32 unsigned long + #define SHA32_CONST(c) c ## UL +#else + #undef SHA32_ALIGNED + #undef SHA_LO32 + #define SHA_LO32(x) ((x) & SHA32_MAX) + #undef SHA32_SHR + #define SHA32_SHR(x, n) (SHA_LO32(x) >> (n)) + #define SHA32 unsigned long + #define SHA32_CONST(c) c ## UL +#endif + +#if defined(ULONG_LONG_MAX) || defined(ULLONG_MAX) || defined(HAS_LONG_LONG) + #define SHA_ULL_EXISTS +#endif + +#if (((ULONG_MAX >> 16) >> 16) >> 16) >> 15 == 1UL + #define SHA64 unsigned long + #define SHA64_CONST(c) c ## UL +#elif defined(SHA_ULL_EXISTS) && defined(LONGLONGSIZE) && LONGLONGSIZE == 8 + #define SHA64 unsigned long long + #define SHA64_CONST(c) c ## ULL +#elif defined(SHA_ULL_EXISTS) + #undef SHA64_ALIGNED + #undef SHA64_SHR + #define SHA64_MAX 18446744073709551615ULL + #define SHA64_SHR(x, n) (((x) & SHA64_MAX) >> (n)) + #define SHA64 unsigned long long + #define SHA64_CONST(c) c ## ULL + + /* The following cases detect compilers that + * support 64-bit types in a non-standard way */ + +#elif defined(_MSC_VER) /* Microsoft C */ + #define SHA64 unsigned __int64 + #define SHA64_CONST(c) (SHA64) c +#endif + +#if defined(SHA64) && !defined(NO_SHA_384_512) + #define SHA_384_512 +#endif + +#if defined(BYTEORDER) && (BYTEORDER & 0xffff) == 0x4321 + #if defined(SHA32_ALIGNED) + #define SHA32_SCHED(W, b) Copy(b, W, 64, char) + #endif + #if defined(SHA64) && defined(SHA64_ALIGNED) + #define SHA64_SCHED(W, b) Copy(b, W, 128, char) + #endif +#endif + +#if !defined(SHA32_SCHED) + #define SHA32_SCHED(W, b) { int t; SHA32 *q = W; \ + for (t = 0; t < 16; t++, b += 4) *q++ = \ + (SHA32) b[0] << 24 | (SHA32) b[1] << 16 | \ + (SHA32) b[2] << 8 | (SHA32) b[3]; } +#endif + +#if defined(SHA64) && !defined(SHA64_SCHED) + #define SHA64_SCHED(W, b) { int t; SHA64 *q = W; \ + for (t = 0; t < 16; t++, b += 8) *q++ = \ + (SHA64) b[0] << 56 | (SHA64) b[1] << 48 | \ + (SHA64) b[2] << 40 | (SHA64) b[3] << 32 | \ + (SHA64) b[4] << 24 | (SHA64) b[5] << 16 | \ + (SHA64) b[6] << 8 | (SHA64) b[7]; } +#endif + +#define SHA1 1 +#define SHA224 224 +#define SHA256 256 +#define SHA384 384 +#define SHA512 512 +#define SHA512224 512224 +#define SHA512256 512256 + +#define SHA1_BLOCK_BITS 512 +#define SHA224_BLOCK_BITS SHA1_BLOCK_BITS +#define SHA256_BLOCK_BITS SHA1_BLOCK_BITS +#define SHA384_BLOCK_BITS 1024 +#define SHA512_BLOCK_BITS SHA384_BLOCK_BITS +#define SHA512224_BLOCK_BITS SHA512_BLOCK_BITS +#define SHA512256_BLOCK_BITS SHA512_BLOCK_BITS + +#define SHA1_DIGEST_BITS 160 +#define SHA224_DIGEST_BITS 224 +#define SHA256_DIGEST_BITS 256 +#define SHA384_DIGEST_BITS 384 +#define SHA512_DIGEST_BITS 512 +#define SHA512224_DIGEST_BITS 224 +#define SHA512256_DIGEST_BITS 256 + +#define SHA_MAX_BLOCK_BITS SHA512_BLOCK_BITS +#define SHA_MAX_DIGEST_BITS SHA512_DIGEST_BITS +#define SHA_MAX_HEX_LEN (SHA_MAX_DIGEST_BITS / 4) +#define SHA_MAX_BASE64_LEN (1 + (SHA_MAX_DIGEST_BITS / 6)) + +#if !defined(SHA64) + #define SHA64 SHA32 +#endif + +typedef struct SHA { + int alg; + void (*sha)(struct SHA *, unsigned char *); + SHA32 H32[8]; + SHA64 H64[8]; + unsigned char block[SHA_MAX_BLOCK_BITS/8]; + unsigned int blockcnt; + unsigned int blocksize; + SHA32 lenhh, lenhl, lenlh, lenll; + unsigned char digest[SHA_MAX_DIGEST_BITS/8]; + unsigned int digestlen; + char hex[SHA_MAX_HEX_LEN+1]; + char base64[SHA_MAX_BASE64_LEN+1]; +} SHA; + +typedef struct { + SHA isha; + SHA osha; + unsigned int digestlen; + unsigned char key[SHA_MAX_BLOCK_BITS/8]; +} HMAC; + +#endif /* _INCLUDE_SHA_H_ */ diff --git a/src/sha64bit.c b/src/sha64bit.c new file mode 100644 index 0000000..146fb4c --- /dev/null +++ b/src/sha64bit.c @@ -0,0 +1,117 @@ +/* + * sha64bit.c: routines to compute SHA-384/512 digests + * + * Ref: NIST FIPS PUB 180-4 Secure Hash Standard + * + * Copyright (C) 2003-2018 Mark Shelor, All Rights Reserved + * + * Version: 6.02 + * Fri Apr 20 16:25:30 MST 2018 + * + */ + +#ifdef SHA_384_512 + +#undef sha_384_512 +#undef W64 +#undef sha512 +#undef H0384 +#undef H0512 +#undef H0512224 +#undef H0512256 + +#define sha_384_512 1 + +#define W64 SHA64 /* useful abbreviations */ +#define C64 SHA64_CONST +#define SR64 SHA64_SHR +#define SL64 SHA64_SHL + +#define ROTRQ(x, n) (SR64(x, n) | SL64(x, 64-(n))) +#define SIGMAQ0(x) (ROTRQ(x, 28) ^ ROTRQ(x, 34) ^ ROTRQ(x, 39)) +#define SIGMAQ1(x) (ROTRQ(x, 14) ^ ROTRQ(x, 18) ^ ROTRQ(x, 41)) +#define sigmaQ0(x) (ROTRQ(x, 1) ^ ROTRQ(x, 8) ^ SR64(x, 7)) +#define sigmaQ1(x) (ROTRQ(x, 19) ^ ROTRQ(x, 61) ^ SR64(x, 6)) + +static const W64 K512[80] = /* SHA-384/512 constants */ +{ +C64(0x428a2f98d728ae22), C64(0x7137449123ef65cd), C64(0xb5c0fbcfec4d3b2f), +C64(0xe9b5dba58189dbbc), C64(0x3956c25bf348b538), C64(0x59f111f1b605d019), +C64(0x923f82a4af194f9b), C64(0xab1c5ed5da6d8118), C64(0xd807aa98a3030242), +C64(0x12835b0145706fbe), C64(0x243185be4ee4b28c), C64(0x550c7dc3d5ffb4e2), +C64(0x72be5d74f27b896f), C64(0x80deb1fe3b1696b1), C64(0x9bdc06a725c71235), +C64(0xc19bf174cf692694), C64(0xe49b69c19ef14ad2), C64(0xefbe4786384f25e3), +C64(0x0fc19dc68b8cd5b5), C64(0x240ca1cc77ac9c65), C64(0x2de92c6f592b0275), +C64(0x4a7484aa6ea6e483), C64(0x5cb0a9dcbd41fbd4), C64(0x76f988da831153b5), +C64(0x983e5152ee66dfab), C64(0xa831c66d2db43210), C64(0xb00327c898fb213f), +C64(0xbf597fc7beef0ee4), C64(0xc6e00bf33da88fc2), C64(0xd5a79147930aa725), +C64(0x06ca6351e003826f), C64(0x142929670a0e6e70), C64(0x27b70a8546d22ffc), +C64(0x2e1b21385c26c926), C64(0x4d2c6dfc5ac42aed), C64(0x53380d139d95b3df), +C64(0x650a73548baf63de), C64(0x766a0abb3c77b2a8), C64(0x81c2c92e47edaee6), +C64(0x92722c851482353b), C64(0xa2bfe8a14cf10364), C64(0xa81a664bbc423001), +C64(0xc24b8b70d0f89791), C64(0xc76c51a30654be30), C64(0xd192e819d6ef5218), +C64(0xd69906245565a910), C64(0xf40e35855771202a), C64(0x106aa07032bbd1b8), +C64(0x19a4c116b8d2d0c8), C64(0x1e376c085141ab53), C64(0x2748774cdf8eeb99), +C64(0x34b0bcb5e19b48a8), C64(0x391c0cb3c5c95a63), C64(0x4ed8aa4ae3418acb), +C64(0x5b9cca4f7763e373), C64(0x682e6ff3d6b2b8a3), C64(0x748f82ee5defb2fc), +C64(0x78a5636f43172f60), C64(0x84c87814a1f0ab72), C64(0x8cc702081a6439ec), +C64(0x90befffa23631e28), C64(0xa4506cebde82bde9), C64(0xbef9a3f7b2c67915), +C64(0xc67178f2e372532b), C64(0xca273eceea26619c), C64(0xd186b8c721c0c207), +C64(0xeada7dd6cde0eb1e), C64(0xf57d4f7fee6ed178), C64(0x06f067aa72176fba), +C64(0x0a637dc5a2c898a6), C64(0x113f9804bef90dae), C64(0x1b710b35131c471b), +C64(0x28db77f523047d84), C64(0x32caab7b40c72493), C64(0x3c9ebe0a15c9bebc), +C64(0x431d67c49c100d4c), C64(0x4cc5d4becb3e42b6), C64(0x597f299cfc657e2a), +C64(0x5fcb6fab3ad6faec), C64(0x6c44198c4a475817) +}; + +static const W64 H0384[8] = /* SHA-384 initial hash value */ +{ +C64(0xcbbb9d5dc1059ed8), C64(0x629a292a367cd507), C64(0x9159015a3070dd17), +C64(0x152fecd8f70e5939), C64(0x67332667ffc00b31), C64(0x8eb44a8768581511), +C64(0xdb0c2e0d64f98fa7), C64(0x47b5481dbefa4fa4) +}; + +static const W64 H0512[8] = /* SHA-512 initial hash value */ +{ +C64(0x6a09e667f3bcc908), C64(0xbb67ae8584caa73b), C64(0x3c6ef372fe94f82b), +C64(0xa54ff53a5f1d36f1), C64(0x510e527fade682d1), C64(0x9b05688c2b3e6c1f), +C64(0x1f83d9abfb41bd6b), C64(0x5be0cd19137e2179) +}; + +static const W64 H0512224[8] = /* SHA-512/224 initial hash value */ +{ +C64(0x8c3d37c819544da2), C64(0x73e1996689dcd4d6), C64(0x1dfab7ae32ff9c82), +C64(0x679dd514582f9fcf), C64(0x0f6d2b697bd44da8), C64(0x77e36f7304c48942), +C64(0x3f9d85a86a1d36c8), C64(0x1112e6ad91d692a1) +}; + +static const W64 H0512256[8] = /* SHA-512/256 initial hash value */ +{ +C64(0x22312194fc2bf72c), C64(0x9f555fa3c84c64c2), C64(0x2393b86b6f53b151), +C64(0x963877195940eabd), C64(0x96283ee2a88effe3), C64(0xbe5e1e2553863992), +C64(0x2b0199fc2c85b8aa), C64(0x0eb72ddc81c52ca2) +}; + +static void sha512(SHA *s, unsigned char *block) /* SHA-384/512 transform */ +{ + W64 a, b, c, d, e, f, g, h, T1, T2; + W64 W[80]; + W64 *H = s->H64; + int t; + + SHA64_SCHED(W, block); + for (t = 16; t < 80; t++) + W[t] = sigmaQ1(W[t-2]) + W[t-7] + sigmaQ0(W[t-15]) + W[t-16]; + a = H[0]; b = H[1]; c = H[2]; d = H[3]; + e = H[4]; f = H[5]; g = H[6]; h = H[7]; + for (t = 0; t < 80; t++) { + T1 = h + SIGMAQ1(e) + Ch(e, f, g) + K512[t] + W[t]; + T2 = SIGMAQ0(a) + Ma(a, b, c); + h = g; g = f; f = e; e = d + T1; + d = c; c = b; b = a; a = T1 + T2; + } + H[0] += a; H[1] += b; H[2] += c; H[3] += d; + H[4] += e; H[5] += f; H[6] += g; H[7] += h; +} + +#endif /* #ifdef SHA_384_512 */ diff --git a/src/sha64bit.h b/src/sha64bit.h new file mode 100644 index 0000000..8517993 --- /dev/null +++ b/src/sha64bit.h @@ -0,0 +1,26 @@ +/* + * sha64bit.h: placeholder values for 64-bit data and routines + * + * Ref: NIST FIPS PUB 180-4 Secure Hash Standard + * + * Copyright (C) 2003-2018 Mark Shelor, All Rights Reserved + * + * Version: 6.02 + * Fri Apr 20 16:25:30 MST 2018 + * + * The following macros supply placeholder values that enable the + * sha.c module to successfully compile when 64-bit integer types + * aren't present. + * + * They are appropriately redefined in sha64bit.c if the compiler + * provides a 64-bit type (i.e. when SHA_384_512 is defined). + * + */ + +#define sha_384_512 0 +#define W64 SHA64 +#define sha512 NULL +#define H0384 H01 +#define H0512 H01 +#define H0512224 H01 +#define H0512256 H01 diff --git a/t/allfcns.t b/t/allfcns.t new file mode 100644 index 0000000..c2de21c --- /dev/null +++ b/t/allfcns.t @@ -0,0 +1,16 @@ +use strict; +use Digest::SHA qw( + hmac_sha1 hmac_sha1_base64 hmac_sha1_hex + hmac_sha224 hmac_sha224_base64 hmac_sha224_hex + hmac_sha256 hmac_sha256_base64 hmac_sha256_hex + hmac_sha384 hmac_sha384_base64 hmac_sha384_hex + hmac_sha512 hmac_sha512_base64 hmac_sha512_hex + sha1 sha1_base64 sha1_hex + sha224 sha224_base64 sha224_hex + sha256 sha256_base64 sha256_hex + sha384 sha384_base64 sha384_hex + sha512 sha512_base64 sha512_hex); + +print "1..1\n"; + +print "ok 1\n"; diff --git a/t/base64.t b/t/base64.t new file mode 100644 index 0000000..6ebba00 --- /dev/null +++ b/t/base64.t @@ -0,0 +1,29 @@ +use strict; +use Digest::SHA qw(sha1_base64 sha224_base64 sha256_base64 + sha384_base64 sha512_base64); + +my $in = "abc"; +my @out = map { eval } ; +my @fcn = (\&sha1_base64, \&sha224_base64, \&sha256_base64, + \&sha384_base64, \&sha512_base64); + +print "1..", scalar @out, "\n"; + +my $testnum = 1; +while (@out) { + my $fcn = shift @fcn; + my $rsp = shift @out; + my $skip = &$fcn("") ? 0 : 1; + unless ($skip) { + print "not " unless &$fcn($in) eq $rsp; + } + print "ok ", $testnum++, $skip ? " # skip: no 64-bit" : "", "\n"; +} + +__DATA__ +"qZk+NkcGgWq6PiVxeFDCbJzQ2J0" +"Iwl9IjQF2CKGQqR3vaJVsyqtvOS9oLP342ydpw" +"ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0" +"ywB1P0WjXou1oD1pmsZQBycsMqsO3tFjGotgWkP/W+2AhgcroefMI1i67KE0yCWn" +"3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw" + diff --git a/t/bitbuf.t b/t/bitbuf.t new file mode 100644 index 0000000..4cf4032 --- /dev/null +++ b/t/bitbuf.t @@ -0,0 +1,59 @@ +use strict; +use Digest::SHA; + +my $numtests = 4; +print "1..$numtests\n"; + + # Here's the bitstring to test against, and its SHA-1 digest + +my $ONEBITS = pack("B*", "1" x 80000); +my $digest = "11003389959355c2773af6b0f36d842fe430ec49"; + +my $state = Digest::SHA->new("sHa1"); +my $testnum = 1; + +$state->add_bits($ONEBITS, 80000); +print "not " unless $state->hexdigest eq $digest; +print "ok ", $testnum++, "\n"; + + # buffer using a series of increasingly large bitstrings + +# Note that (1 + 2 + ... + 399) + 200 = 80000 + +for (1 .. 399) { + $state->add_bits($ONEBITS, $_); +} +$state->add_bits($ONEBITS, 200); + +print "not " unless $state->hexdigest eq $digest; +print "ok ", $testnum++, "\n"; + + # create a buffer-alignment nuisance + +$state = Digest::SHA->new("1"); + +$state->add_bits($ONEBITS, 1); +for (1 .. 99) { + $state->add_bits($ONEBITS, 800); +} +$state->add_bits($ONEBITS, 799); + +print "not " unless $state->hexdigest eq $digest; +print "ok ", $testnum++, "\n"; + + # buffer randomly-sized bitstrings + +my $reps = 80000; +my $maxbits = 8 * 127; + +$state = Digest::SHA->new(1); + +while ($reps > $maxbits) { + my $num = int(rand($maxbits)); + $state->add_bits($ONEBITS, $num); + $reps -= $num; +} +$state->add_bits($ONEBITS, $reps); + +print "not " unless $state->hexdigest eq $digest; +print "ok ", $testnum++, "\n"; diff --git a/t/bitorder.t b/t/bitorder.t new file mode 100644 index 0000000..750f3b5 --- /dev/null +++ b/t/bitorder.t @@ -0,0 +1,18 @@ +use strict; +use Digest::SHA; + +my $numtests = 2; +print "1..$numtests\n"; + +my $testnum = 1; +my $s1 = Digest::SHA->new; +my $s2 = Digest::SHA->new; +my $d1 = $s1->add_bits("110")->hexdigest; +my $d2 = $s2->add_bits("1")->add_bits("1")->add_bits("0")->hexdigest; +print "not " unless $d1 eq $d2; +print "ok ", $testnum++, "\n"; + +$d1 = $s1->add_bits("111100001010")->hexdigest; +$d2 = $s2->add_bits("\xF0\xA0", 12)->hexdigest; +print "not " unless $d1 eq $d2; +print "ok ", $testnum++, "\n"; diff --git a/t/fips180-4.t b/t/fips180-4.t new file mode 100644 index 0000000..161a934 --- /dev/null +++ b/t/fips180-4.t @@ -0,0 +1,30 @@ +use strict; +use Digest::SHA qw(sha512_hex sha512224_hex sha512256_hex); + +my @vecs = map { eval } ; + +my $numtests = scalar(@vecs) / 2; +print "1..$numtests\n"; + +my $skip = sha512_hex("") ? 0 : 1; + +for (1 .. $numtests) { + my $data = shift @vecs; + my $digest = shift @vecs; + unless ($skip) { + my $rsp = ($_ <= $numtests/2) ? + sha512224_hex($data) : sha512256_hex($data); + print "not " unless $rsp eq $digest; + } + print "ok ", $_, $skip ? " # skip: no 64-bit" : "", "\n"; +} + +__DATA__ +"abc" +"4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa" +"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +"23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9" +"abc" +"53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23" +"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +"3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a" diff --git a/t/fips198.t b/t/fips198.t new file mode 100644 index 0000000..da0c156 --- /dev/null +++ b/t/fips198.t @@ -0,0 +1,28 @@ +use strict; +use Digest::SHA qw(hmac_sha1_hex); + +my @data = map { "Sample #$_" } (1 .. 4); + +my @out = ( + "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a", + "0922d3405faa3d194f82a45830737d5cc6c75d24", + "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa", + "9ea886efe268dbecce420c7524df32e0751a2a26" +); + +my @keys = ("", "", "", ""); + +for (0x00 .. 0x00+63) { $keys[0] .= chr($_) } +for (0x30 .. 0x30+19) { $keys[1] .= chr($_) } +for (0x50 .. 0x50+99) { $keys[2] .= chr($_) } +for (0x70 .. 0x70+48) { $keys[3] .= chr($_) } + +my $numtests = scalar @data; +print "1..$numtests\n"; + +my $testnum = 1; +while (@data) { + print "not " unless hmac_sha1_hex(shift @data, shift @keys) + eq shift @out; + print "ok ", $testnum++, "\n"; +} diff --git a/t/gg.t b/t/gg.t new file mode 100644 index 0000000..af0f5d6 --- /dev/null +++ b/t/gg.t @@ -0,0 +1,56 @@ +# Test against short bitwise vectors from Jim Gillogly and Francois Grieu + +use strict; +use Digest::SHA; + +# SHA-1 Test Vectors +# +# In the following we use the notation bitstring#n to mean a bitstring +# repeated n (in decimal) times, and we use | for concatenation. +# Therefore 110#3|1 is 1101101101. +# +# 110#148|11 : CE7387AE 577337BE 54EA94F8 2C842E8B E76BC3E1 +# 110#149 : DE244F06 3142CB2F 4C903B7F 7660577F 9E0D8791 +# 110#149|1 : A3D29824 27AE39C8 920CA5F4 99D6C2BD 71EBF03C +# 110#149|11 : 351AAB58 FF93CF12 AF7D5A58 4CFC8F7D 81023D10 +# +# 110#170 : 99638692 1E480D4E 2955E727 5DF3522C E8F5AB6E +# 110#170|1 : BB5F4AD4 8913F51B 157EB985 A5C2034B 8243B01B +# 110#170|11 : 9E92C554 2237B957 BA2244E8 141FDB66 DEC730A5 +# 110#171 : 2103E454 DA4491F4 E32DD425 A3341DC9 C2A90848 +# +# 011#490 : B4B18049 DE405027 528CD9E7 4B2EC540 D4E6F06B +# 011#490|0 : 34C63356 B3087427 20AB9669 14EB0FC9 26E4294B +# 011#490|01 : 75FACE18 02B9F84F 326368AB 06E73E05 02E9EA34 +# 011#491 : 7C2C3D62 F6AEC28D 94CDF93F 02E739E7 490698A1 + +my @vecs = ( + "110",148,"11","ce7387ae577337be54ea94f82c842e8be76bc3e1", + "110",149,"","de244f063142cb2f4c903b7f7660577f9e0d8791", + "110",149,"1","a3d2982427ae39c8920ca5f499d6c2bd71ebf03c", + "110",149,"11","351aab58ff93cf12af7d5a584cfc8f7d81023d10", + "110",170,"","996386921e480d4e2955e7275df3522ce8f5ab6e", + "110",170,"1","bb5f4ad48913f51b157eb985a5c2034b8243b01b", + "110",170,"11","9e92c5542237b957ba2244e8141fdb66dec730a5", + "110",171,"","2103e454da4491f4e32dd425a3341dc9c2a90848", + "011",490,"","b4b18049de405027528cd9e74b2ec540d4e6f06b", + "011",490,"0","34c63356b308742720ab966914eb0fc926e4294b", + "011",490,"01","75face1802b9f84f326368ab06e73e0502e9ea34", + "011",491,"","7c2c3d62f6aec28d94cdf93f02e739e7490698a1", +); + +my $numtests = scalar(@vecs) / 4; +print "1..$numtests\n"; + +my $testnum = 1; +my $sha = Digest::SHA->new(1); + +while (@vecs) { + my $frag = shift @vecs; + my $reps = shift @vecs; + my $tail = shift @vecs; + my $bitstr = ($frag x $reps) . $tail; + print "not " unless $sha->add_bits($bitstr)->hexdigest + eq shift @vecs; + print "ok ", $testnum++, "\n"; +} diff --git a/t/gglong.t b/t/gglong.t new file mode 100644 index 0000000..5551eef --- /dev/null +++ b/t/gglong.t @@ -0,0 +1,78 @@ +# Test against long bitwise vectors from Jim Gillogly and Francois Grieu + +use strict; +use Digest::SHA; + +# SHA-1 Test Vectors +# +# In the following we use the notation bitstring#n to mean a bitstring +# repeated n (in decimal) times, and we use | for concatenation. +# Therefore 110#3|1 is 1101101101. +# +# Here is a set near 2^32 bits to test the roll-over in the length +# field from one to two 32-bit words: +# +# 110#1431655764|11 1eef5a18 969255a3 b1793a2a 955c7ec2 8cd221a5 +# 110#1431655765| 7a1045b9 14672afa ce8d90e6 d19b3a6a da3cb879 +# 110#1431655765|1 d5e09777 a94f1ea9 240874c4 8d9fecb6 b634256b +# 110#1431655765|11 eb256904 3c3014e5 1b2862ae 6eb5fb4e 0b851d99 +# +# 011#1431655764|01 4CB0C4EF 69143D5B F34FC35F 1D4B19F6 ECCAE0F2 +# 011#1431655765 47D92F91 1FC7BB74 DE00ADFC 4E981A81 05556D52 +# 011#1431655765|0 A3D7438C 589B0B93 2AA91CC2 446F06DF 9ABC73F0 +# 011#1431655765|01 3EEE3E1E 28DEDE2C A444D68D A5675B2F AAAB3203 + +my @vec110 = ( # 110 rep 1431655764 + "11", "1eef5a18969255a3b1793a2a955c7ec28cd221a5", + "110", "7a1045b914672aface8d90e6d19b3a6ada3cb879", + "1101", "d5e09777a94f1ea9240874c48d9fecb6b634256b", + "11011", "eb2569043c3014e51b2862ae6eb5fb4e0b851d99" +); + +my @vec011 = ( # 011 rep 1431655764 + "01", "4cb0c4ef69143d5bf34fc35f1d4b19f6eccae0f2", + "011", "47d92f911fc7bb74de00adfc4e981a8105556d52", + "0110", "a3d7438c589b0b932aa91cc2446f06df9abc73f0", + "01101", "3eee3e1e28dede2ca444d68da5675b2faaab3203" +); + +my($STATE110, $STATE011) = ('', ''); +for (1 .. 8) { my $line = ; $STATE110 .= $line } +for (1 .. 8) { my $line = ; $STATE011 .= $line } + +my $testnum = 1; +print "1..", scalar(@vec110)/2 + scalar(@vec011)/2, "\n"; + +my $state110 = Digest::SHA->putstate($STATE110); +while (@vec110) { + my $state = $state110->clone; + $state->add_bits(shift @vec110); + print "not " unless $state->hexdigest eq (shift @vec110); + print "ok ", $testnum++, "\n"; +} + +my $state011 = Digest::SHA->putstate($STATE011); +while (@vec011) { + my $state = $state011->clone; + $state->add_bits(shift @vec011); + print "not " unless $state->hexdigest eq (shift @vec011); + print "ok ", $testnum++, "\n"; +} + +__DATA__ +alg:1 +H:dfc51a14:87b4a4b7:ecf19acd:8cbbe40e:03a435f8:00000000:00000000:00000000 +block:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d +blockcnt:508 +lenhh:0 +lenhl:0 +lenlh:0 +lenll:4294967292 +alg:1 +H:7950cbe2:86a45aa0:91ff7dff:29015b42:3912e764:00000000:00000000:00000000 +block:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6 +blockcnt:508 +lenhh:0 +lenhl:0 +lenlh:0 +lenll:4294967292 diff --git a/t/hmacsha.t b/t/hmacsha.t new file mode 100644 index 0000000..a4e6f5c --- /dev/null +++ b/t/hmacsha.t @@ -0,0 +1,63 @@ +# HMAC-SHA-256 test vectors from draft-ietf-ipsec-ciph-sha-256-01.txt + +use strict; +use Digest::SHA qw(hmac_sha256 hmac_sha256_hex); + +my @data = map { eval } ; + +my $numtests = scalar @data; +print "1..$numtests\n"; + +my $k1 = join( "", map { chr } (1 .. 32) ); +my $k2 = join( "", map { chr } (1 .. 37) ); + +my @keys = ( + $k1, + $k1, + $k1, + chr(0x0b) x 32, + "Jefe", + chr(0xaa) x 32, + $k2, + chr(0x0c) x 32, + chr(0xaa) x 80, + chr(0xaa) x 80 +); + +my @out = ( + "a21b1f5d4cf4f73a4dd939750f7a066a7f98cc131cb16a6692759021cfab8181", + "104fdc1257328f08184ba73131c53caee698e36119421149ea8c712456697d30", + "470305fc7e40fe34d3eeb3e773d95aab73acf0fd060447a5eb4595bf33a9d1a3", + "198a607eb44bfbc69903a0f1cf2bbdc5ba0aa3f3d9ae3c1c7a3b1696a0b68cf7", + "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", + "cdcb1220d1ecccea91e53aba3092f962e549fe6ce9ed7fdc43191fbde45c30b0", + "d4633c17f6fb8d744c66dee0f8f074556ec4af55ef07998541468eb49bd2e917", + "7546af01841fc09b1ab9c3749a5f1c17d4f589668a587b2700a9c97c1193cf42", + "6953025ed96f0c09f80a96f78e6538dbe2e7b820e3dd970e7ddd39091b32352f", + "6355ac22e890d0a3c8481a5ca4825bc884d3e7a1ff98a2fc2ac7d8e064c3b2e6" +); + + # do first one using multi-argument data feed and binary output + +my $testnum = 1; +my @args = split(//, shift @data); +print "not " unless hmac_sha256(@args, shift @keys) eq pack("H*", shift @out); +print "ok ", $testnum++, "\n"; + +while (@data) { + print "not " unless hmac_sha256_hex(shift @data, shift @keys) + eq shift @out; + print "ok ", $testnum++, "\n"; +} + +__DATA__ +"abc" +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopqabcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +"Hi There" +"what do ya want for nothing?" +chr(0xdd) x 50 +chr(0xcd) x 50 +"Test With Truncation" +"Test Using Larger Than Block-Size Key - Hash Key First" +"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" diff --git a/t/inheritance.t b/t/inheritance.t new file mode 100644 index 0000000..5880e6e --- /dev/null +++ b/t/inheritance.t @@ -0,0 +1,17 @@ +# Adapted from script by Mark Lawrence (ref. rt.cpan.org #94830) + +use strict; +use Digest::SHA qw(sha1); + +package P1; +use vars qw(@ISA); +@ISA = ("Digest::SHA"); + +package main; + +print "1..1\n"; + +my $data = 'a'; +my $d = P1->new; +print "not " unless $d->add($data)->digest eq sha1($data); +print "ok 1\n"; diff --git a/t/ireland.t b/t/ireland.t new file mode 100644 index 0000000..ef1ed33 --- /dev/null +++ b/t/ireland.t @@ -0,0 +1,37 @@ +# David Ireland's test vector - SHA-256 digest of "a" x 536870912 + +# Adapted from Julius Duque's original script (t/24-ireland.tmp) +# - modified to use state cache via putstate method + +use strict; +use Digest::SHA; + +print "1..1\n"; + +my $rsp = "b9045a713caed5dff3d3b783e98d1ce5778d8bc331ee4119d707072312af06a7"; + +my $sha; +if ($sha = Digest::SHA->putstate(join('', ))) { + $sha->add("aa"); + print "not " unless $sha->hexdigest eq $rsp; + print "ok 1\n"; +} +else { print "not ok 1\n" } + +__DATA__ + + # Verify comments/blank lines ignored in state data + +alg:256 +H:dd75eb45:02d4f043:06b41193:6fda751d:73064db9:787d54e1:52dc3fe0:48687dfa + +block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00 +blockcnt:496 + +lenhh:0 +lenhl:0 +lenlh:0 + +# Note: add'ing two more bytes will cause lenll (below) to overflow + +lenll:4294967280 diff --git a/t/methods.t b/t/methods.t new file mode 100644 index 0000000..1522f99 --- /dev/null +++ b/t/methods.t @@ -0,0 +1,96 @@ +use strict; +use FileHandle; +use Digest::SHA; + +my @out = ( + "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0", + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", +); + +my $numtests = 6 + scalar @out; +print "1..$numtests\n"; + + # attempt to use an invalid algorithm, and check for failure + +my $testnum = 1; +my $NSA = "SHA-42"; # No Such Algorithm +print "not " if Digest::SHA->new($NSA); +print "ok ", $testnum++, "\n"; + +my $tempfile = "methods.tmp"; +END { unlink $tempfile if $tempfile } + + # test OO methods using first two SHA-256 vectors from NIST + +my $fh = FileHandle->new($tempfile, "w"); +binmode($fh); +print $fh "bcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; +$fh->close; + +my $sha = Digest::SHA->new()->reset("SHA-256")->new(); +$sha->add_bits("a", 5)->add_bits("001"); + +my $rsp = shift(@out); +print "not " unless $sha->clone->add("b", "c")->b64digest eq $rsp; +print "ok ", $testnum++, "\n"; + +$rsp = shift(@out); + + # test addfile with bareword filehandle + +open(FILE, "<$tempfile"); +binmode(FILE); +print "not " unless + $sha->clone->addfile(*FILE)->hexdigest eq $rsp; +print "ok ", $testnum++, "\n"; +close(FILE); + + # test addfile with indirect filehandle + +$fh = FileHandle->new($tempfile, "r"); +binmode($fh); +print "not " unless $sha->clone->addfile($fh)->hexdigest eq $rsp; +print "ok ", $testnum++, "\n"; +$fh->close; + + # test addfile using file name instead of handle + +print "not " unless $sha->addfile($tempfile, "b")->hexdigest eq $rsp; +print "ok ", $testnum++, "\n"; + + # test addfile "universal newlines" mode + +$fh = FileHandle->new($tempfile, "w"); +binmode($fh); +print $fh "MacOS\r" . "MSDOS\r\n" . "UNIX\n" . "Quirky\r\r\n"; +$fh->close; + +my $d = $sha->new(1)->addfile($tempfile, "U")->hexdigest; +if ($d eq "f4c6855783c737c7e224873c90e80a9df5c2bc97") { + print "ok ", $testnum++, "\n"; +} +elsif ($d eq "42335d4a517a5e31399e948e9d842bafd9194d8f") { + print "ok ", $testnum++, " # skip: flaky -T\n"; +} +else { + print "not ok ", $testnum++, "\n"; +} + + # test addfile BITS mode + +$fh = FileHandle->new($tempfile, "w"); +print $fh "0100010"; # using NIST 7-bit test vector +$fh->close; + +print "not " unless $sha->new(1)->addfile($tempfile, "0")->hexdigest eq + "04f31807151181ad0db278a1660526b0aeef64c2"; +print "ok ", $testnum++, "\n"; + +$fh = FileHandle->new($tempfile, "w"); +binmode($fh); +print $fh map(chr, (0..127)); # this is actually NIST 2-bit test +$fh->close; # vector "01" (other chars ignored) + +print "not " unless $sha->new(1)->addfile($tempfile, "0")->hexdigest eq + "ec6b39952e1a3ec3ab3507185cf756181c84bbe2"; +print "ok ", $testnum++, "\n"; diff --git a/t/nistbit.t b/t/nistbit.t new file mode 100644 index 0000000..eef1271 --- /dev/null +++ b/t/nistbit.t @@ -0,0 +1,56 @@ +# Test against SHA-1 Sample Vectors from NIST + +use strict; +use Digest::SHA; + +my $nist_hashes = <new(1); +for (@lines) { + next unless /^[\d ^]/; + $message .= $_; + next unless /\^\s*$/; + my @vals = $message =~ /\d+/g; $message = ""; + my $count = shift(@vals); + my $bit = shift(@vals); + my $bitstr = ""; + while (@vals) { + $bitstr .= $bit x shift(@vals); + $bit = 1 - $bit; + } + print "not " unless uc($sha->add_bits($bitstr)->hexdigest) + eq shift(@hashes); + print "ok ", $testnum++, "\n"; +} diff --git a/t/nistbyte.t b/t/nistbyte.t new file mode 100644 index 0000000..1bdafa6 --- /dev/null +++ b/t/nistbyte.t @@ -0,0 +1,57 @@ +# Test against SHA-1 Sample Vectors from NIST + +use strict; +use Digest::SHA; + +my $nist_hashes = <new(1); +for (@lines) { + next unless /^[\d ^]/; + $message .= $_; + next unless /\^\s*$/; + my @vals = $message =~ /\d+/g; $message = ""; + my $count = shift(@vals); + my $bit = shift(@vals); + my $bitstr = ""; + while (@vals) { + $bitstr .= $bit x shift(@vals); + $bit = 1 - $bit; + } + print "not " unless + uc($sha->add(pack("B*", $bitstr))->hexdigest) + eq shift(@hashes); + print "ok ", $testnum++, "\n"; +} diff --git a/t/pod.t b/t/pod.t new file mode 100644 index 0000000..201480c --- /dev/null +++ b/t/pod.t @@ -0,0 +1,24 @@ +use strict; + +my $skip; + +BEGIN { + eval "use Test::More"; + $skip = $@ ? 1 : 0; + unless ($skip) { + eval "use Test::Pod 1.00"; + $skip = 2 if $@; + } +} + +if ($skip == 1) { + print "1..0 # Skipped: Test::More not installed\n"; + exit; +} + +if ($skip == 2) { + print "1..0 # Skipped: Test::Pod 1.00 required for testing POD\n"; + exit; +} + +all_pod_files_ok(); diff --git a/t/podcover.t b/t/podcover.t new file mode 100644 index 0000000..da6ffb2 --- /dev/null +++ b/t/podcover.t @@ -0,0 +1,32 @@ +use strict; +use Digest::SHA; + +my $skip; + +BEGIN { + eval "use Test::More"; + $skip = $@ ? 1 : 0; + unless ($skip) { + eval "use Test::Pod::Coverage 0.08"; + $skip = 2 if $@; + } +} + +if ($skip == 1) { + print "1..0 # Skipped: Test::More not installed\n"; + exit; +} + +if ($skip == 2) { + print "1..0 # Skipped: Test::Pod::Coverage 0.08 required\n"; + exit; +} + +my @privfcns = qw( + newSHA + shainit + sharewind + shawrite +); + +all_pod_coverage_ok( { also_private => \@privfcns } ); diff --git a/t/rfc2202.t b/t/rfc2202.t new file mode 100644 index 0000000..3006625 --- /dev/null +++ b/t/rfc2202.t @@ -0,0 +1,43 @@ +use strict; +use Digest::SHA qw(hmac_sha1_hex); + +my @data = map { eval } ; + +my $numtests = scalar @data; +print "1..$numtests\n"; + +my @keys = ( + chr(0x0b) x 20, + "Jefe", + chr(0xaa) x 20, + join("", map { chr } (1 .. 25)), + chr(0x0c) x 20, + chr(0xaa) x 80, + chr(0xaa) x 80 +); + +my @out = ( + "b617318655057264e28bc0b6fb378c8ef146be00", + "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + "125d7342b9ac11cd91a39af48aa17b4f63f175d3", + "4c9007f4026250c6bc8414f9bf50c86c2d7235da", + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91" +); + +my $testnum = 1; +while (@data) { + print "not " unless hmac_sha1_hex(shift @data, shift @keys) + eq shift @out; + print "ok ", $testnum++, "\n"; +} + +__DATA__ +"Hi There" +"what do ya want for nothing?" +chr(0xdd) x 50 +chr(0xcd) x 50 +"Test With Truncation" +"Test Using Larger Than Block-Size Key - Hash Key First" +"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" diff --git a/t/sha1.t b/t/sha1.t new file mode 100644 index 0000000..2c8313d --- /dev/null +++ b/t/sha1.t @@ -0,0 +1,22 @@ +use strict; +use Digest::SHA qw(sha1_hex); + +my @vecs = map { eval } ; + +my $numtests = scalar(@vecs) / 2; +print "1..$numtests\n"; + +for (1 .. $numtests) { + my $data = shift @vecs; + my $digest = shift @vecs; + print "not " unless sha1_hex($data) eq $digest; + print "ok ", $_, "\n"; +} + +__DATA__ +"abc" +"a9993e364706816aba3e25717850c26c9cd0d89d" +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +"84983e441c3bd26ebaae4aa1f95129e5e54670f1" +"a" x 1000000 +"34aa973cd4c4daa4f61eeb2bdbad27316534016f" diff --git a/t/sha224.t b/t/sha224.t new file mode 100644 index 0000000..ab70b31 --- /dev/null +++ b/t/sha224.t @@ -0,0 +1,22 @@ +use strict; +use Digest::SHA qw(sha224_hex); + +my @vecs = map { eval } ; + +my $numtests = scalar(@vecs) / 2; +print "1..$numtests\n"; + +for (1 .. $numtests) { + my $data = shift @vecs; + my $digest = shift @vecs; + print "not " unless sha224_hex($data) eq $digest; + print "ok ", $_, "\n"; +} + +__DATA__ +"abc" +"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" +"a" x 1000000 +"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67" diff --git a/t/sha256.t b/t/sha256.t new file mode 100644 index 0000000..72c1e8d --- /dev/null +++ b/t/sha256.t @@ -0,0 +1,22 @@ +use strict; +use Digest::SHA qw(sha256_hex); + +my @vecs = map { eval } ; + +my $numtests = scalar(@vecs) / 2; +print "1..$numtests\n"; + +for (1 .. $numtests) { + my $data = shift @vecs; + my $digest = shift @vecs; + print "not " unless sha256_hex($data) eq $digest; + print "ok ", $_, "\n"; +} + +__DATA__ +"abc" +"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" +"a" x 1000000 +"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" diff --git a/t/sha384.t b/t/sha384.t new file mode 100644 index 0000000..2739449 --- /dev/null +++ b/t/sha384.t @@ -0,0 +1,26 @@ +use strict; +use Digest::SHA qw(sha384_hex); + +my @vecs = map { eval } ; + +my $numtests = scalar(@vecs) / 2; +print "1..$numtests\n"; + +my $skip = sha384_hex("") ? 0 : 1; + +for (1 .. $numtests) { + my $data = shift @vecs; + my $digest = shift @vecs; + unless ($skip) { + print "not " unless sha384_hex($data) eq $digest; + } + print "ok ", $_, $skip ? " # skip: no 64-bit" : "", "\n"; +} + +__DATA__ +"abc" +"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" +"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039" +"a" x 1000000 +"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985" diff --git a/t/sha512.t b/t/sha512.t new file mode 100644 index 0000000..d417f66 --- /dev/null +++ b/t/sha512.t @@ -0,0 +1,26 @@ +use strict; +use Digest::SHA qw(sha512_hex); + +my @vecs = map { eval } ; + +my $numtests = scalar(@vecs) / 2; +print "1..$numtests\n"; + +my $skip = sha512_hex("") ? 0 : 1; + +for (1 .. $numtests) { + my $data = shift @vecs; + my $digest = shift @vecs; + unless ($skip) { + print "not " unless sha512_hex($data) eq $digest; + } + print "ok ", $_, $skip ? " # skip: no 64-bit" : "", "\n"; +} + +__DATA__ +"abc" +"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" +"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" +"a" x 1000000 +"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" diff --git a/t/state.t b/t/state.t new file mode 100644 index 0000000..ff622ba --- /dev/null +++ b/t/state.t @@ -0,0 +1,80 @@ +use strict; +use Digest::SHA qw(sha384_hex sha512_hex); + +my @sharsp = ( + "34aa973cd4c4daa4f61eeb2bdbad27316534016f", + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0", + "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985", + "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" +); + +my $numtests = scalar @sharsp; +print "1..$numtests\n"; + +my($state001, $state256, $state384, $state512) = ('', '', '', ''); +for (1 .. 8) { my $line = ; $state001 .= $line } +for (1 .. 8) { my $line = ; $state256 .= $line } +for (1 .. 8) { my $line = ; $state384 .= $line } +for (1 .. 8) { my $line = ; $state512 .= $line } +my @states = ($state001, $state256, $state384, $state512); + +my @alg = (1, 256, 384, 512); +my $data = "a" x 990000; + +my $testnum = 1; +while (@sharsp) { + my $skip = 0; + my $alg = shift @alg; + my $rsp = shift @sharsp; + if ($alg == 384) { $skip = sha384_hex("") ? 0 : 1 } + if ($alg == 512) { $skip = sha512_hex("") ? 0 : 1 } + if ($skip) { + print "ok ", $testnum++, " # skip: no 64-bit\n"; + next; + } + my $digest; + my $state; + unless ($state = Digest::SHA->putstate(shift @states)) { + print "not ok ", $testnum++, "\n"; + next; + } + my $statestr = $state->add_bits($data, 79984)->getstate; + $state->putstate($statestr)->add_bits($data, 16); + $digest = $state->hexdigest; + print "not " unless $digest eq $rsp; + print "ok ", $testnum++, "\n"; +} + +__DATA__ +alg:1 +H:9d6f7d2f:65e21307:c6f41af6:7c7fd3a9:8dec6058:00000000:00000000:00000000 +block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 +blockcnt:384 +lenhh:0 +lenhl:0 +lenlh:0 +lenll:7920000 +alg:256 +H:2d6c0def:4244ade7:fc8c121c:108f4493:ec3fbec2:91425a6e:b8d30d2a:9db24273 +block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 +blockcnt:384 +lenhh:0 +lenhl:0 +lenlh:0 +lenll:7920000 +alg:384 +H:598147f4583a61f7:8d194a4d7c9008cb:39725c96557d600f:d7f2079ce8251f19:bd735d446f9a3c7c:234de90b9060898d:a5b481b9d635d190:81c6e74ee4556125 +block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 +blockcnt:384 +lenhh:0 +lenhl:0 +lenlh:0 +lenll:7920000 +alg:512 +H:0442fe29a02b8c30:13553e6dbedc2aa0:8f891a0cb2ac3107:6fa1762b40ac04dd:dcbf420d729eea79:34703e9672dcf145:7bf9aaa14d400433:2aa65f044825466d +block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 +blockcnt:384 +lenhh:0 +lenhl:0 +lenlh:0 +lenll:7920000 diff --git a/t/unicode.t b/t/unicode.t new file mode 100644 index 0000000..9f0107a --- /dev/null +++ b/t/unicode.t @@ -0,0 +1,29 @@ +use strict; +use Digest::SHA qw(sha1_hex); + +my $skip = $] < 5.006 ? 1 : 0; + +my $TEMPLATE = $] >= 5.006 ? 'U*' : 'C*'; +my $empty_unicode = pack($TEMPLATE, ()); +my $ok_unicode = pack($TEMPLATE, (0..255)); +my $wide_unicode = pack($TEMPLATE, (0..256)); + +print "1..3\n"; + +unless ($skip) { + print "not " unless sha1_hex($empty_unicode."abc") eq + "a9993e364706816aba3e25717850c26c9cd0d89d"; +} +print "ok 1", $skip ? " # skip: no Unicode" : "", "\n"; + +unless ($skip) { + print "not " unless sha1_hex($ok_unicode) eq + "4916d6bdb7f78e6803698cab32d1586ea457dfc8"; +} +print "ok 2", $skip ? " # skip: no Unicode" : "", "\n"; + +unless ($skip) { + eval { sha1_hex($wide_unicode) }; + print "not " unless $@ =~ /Wide character/; +} +print "ok 3", $skip ? " # skip: no Unicode" : "", "\n"; diff --git a/t/woodbury.t b/t/woodbury.t new file mode 100644 index 0000000..9552700 --- /dev/null +++ b/t/woodbury.t @@ -0,0 +1,129 @@ +# Test Vectors for HMAC-SHA-256/384/512 +# +# Vectors and initial script courtesy of Adam Woodbury, The MITRE Corporation + +use strict; +use Digest::SHA qw(hmac_sha256 hmac_sha384 hmac_sha512); + +my @plex = map { eval } ; + +my $numtests = scalar(@plex) / 3; +print "1..$numtests\n"; + +# Use RFC 2202 data/key values for 512-bit blocks + +my @data_bs512 = splice(@plex, 0, 7); +my @keys_bs512 = splice(@plex, 0, 7); +my @hmac256rsp = splice(@plex, 0, 7); + +# Lengthen final RFC 2202 data/key values for 1024-bit blocks + +my @data_bs1024 = splice(@plex, 0, 7); +my @keys_bs1024 = splice(@plex, 0, 7); +my @hmac384rsp = splice(@plex, 0, 7); + +my @dat2_bs1024 = splice(@plex, 0, 7); +my @key2_bs1024 = splice(@plex, 0, 7); +my @hmac512rsp = splice(@plex, 0, 7); + +my $testnum = 1; + +while (@data_bs512) { + print "not " unless + hmac_sha256(shift @data_bs512, shift @keys_bs512) + eq pack("H*", shift @hmac256rsp); + print "ok ", $testnum++, "\n"; +} + +my $skip = hmac_sha384("", "") ? 0 : 1; + +while (@data_bs1024) { + if ($skip) { + print "ok ", $testnum++, + $skip ? " # skip: no 64-bit" : "", "\n"; + shift @data_bs1024; + next; + } + print "not " unless + hmac_sha384(shift @data_bs1024, shift @keys_bs1024) + eq pack("H*", shift @hmac384rsp); + print "ok ", $testnum++, "\n"; +} + +while (@dat2_bs1024) { + if ($skip) { + print "ok ", $testnum++, + $skip ? " # skip: no 64-bit" : "", "\n"; + shift @dat2_bs1024; + next; + } + print "not " unless + hmac_sha512(shift @dat2_bs1024, shift @key2_bs1024) + eq pack("H*", shift @hmac512rsp); + print "ok ", $testnum++, "\n"; +} + +__DATA__ +"Hi There" +"what do ya want for nothing?" +chr(0xdd) x 50 +chr(0xcd) x 50 +"Test With Truncation" +"Test Using Larger Than Block-Size Key - Hash Key First" +"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" +chr(0x0b) x 20 +"Jefe" +chr(0xaa) x 20 +join("", map { chr } (1 .. 25)) +chr(0x0c) x 20 +chr(0xaa) x 80 +chr(0xaa) x 80 +"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7" +"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" +"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe" +"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b" +"a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5" +"6953025ed96f0c09f80a96f78e6538dbe2e7b820e3dd970e7ddd39091b32352f" +"6355ac22e890d0a3c8481a5ca4825bc884d3e7a1ff98a2fc2ac7d8e064c3b2e6" +"Hi There" +"what do ya want for nothing?" +chr(0xdd) x 50 +chr(0xcd) x 50 +"Test With Truncation" +"Test Using Larger Than Block-Size Key - Hash Key First" +"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data. The Larger Block-Sizes Make For Much Longer Test Vectors" +chr(0x0b) x 20 +"Jefe" +chr(0xaa) x 20 +join("", map { chr } (1 .. 25)) +chr(0x0c) x 20 +chr(0xaa) x 200 +chr(0xaa) x 200 +"afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6" +"af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649" +"88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27" +"3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb" +"3abf34c3503b2a23a46efc619baef897f4c8e42c934ce55ccbae9740fcbc1af4ca62269e2a37cd88ba926341efe4aeea" +"ec629fe0dc1fab504fc1c89572d6573cf15c3a4b5b69d53f0c13849561a6c13e153af48d2538ce056a3fe10d69da16c3" +"07109d2c6c2fdcac39c3a8b5f36fc9a69e029d3d8647cc3e4ddb77888418c5c09d807942e5f96d17ee9fd46aed64b7f2" +"Hi There" +"what do ya want for nothing?" +chr(0xdd) x 50 +chr(0xcd) x 50 +"Test With Truncation" +"Test Using Larger Than Block-Size Key - Hash Key First" +"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data. The Larger Block-Sizes Make For Much Longer Test Vectors" +chr(0x0b) x 20 +"Jefe" +chr(0xaa) x 20 +join("", map { chr } (1 .. 25)) +chr(0x0c) x 20 +chr(0xaa) x 200 +chr(0xaa) x 200 +"87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854" +"164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737" +"fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb" +"b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd" +"415fad6271580a531d4179bc891d87a650188707922a4fbb36663a1eb16da008711c5b50ddd0fc235084eb9d3364a1454fb2ef67cd1d29fe6773068ea266e96b" +"9dc6330f4c966b62b735d565343cb77413deccdf42a92d9ef5e4e2ae33f6c924bbc8e34c47111bc069482d4dbcfee148419a6547f2d01500e8160b39cc2e4ae8" +"396ed3a17cef82cddbd987ea66a5dd1f38b68167df31f049463b85fa10b531d0e90d1052f8c9c7cda263468ec3f980a8fec06213c2944c92a0ac95a2d8ade76d" diff --git a/typemap b/typemap new file mode 100644 index 0000000..8a47499 --- /dev/null +++ b/typemap @@ -0,0 +1,7 @@ +TYPEMAP +SHA * T_SHA +PerlIO * T_IN + +INPUT +T_SHA + $var = getSHA(aTHX_ $arg)