summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/md5crypt
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
commitea28451286d3ea4a772fa174483f9a7a66bb1ab3 (patch)
tree6ee9d8a7848333a7ceeee3b13d492e40225f8b86 /tcllib/modules/md5crypt
parentb5ca09bae0d6a1edce939eea03594dd56383f2c8 (diff)
parent7c621da28f07e449ad90c387344f07a453927569 (diff)
downloadblt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.zip
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.gz
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.bz2
Merge commit '7c621da28f07e449ad90c387344f07a453927569' as 'tcllib'
Diffstat (limited to 'tcllib/modules/md5crypt')
-rw-r--r--tcllib/modules/md5crypt/ChangeLog130
-rw-r--r--tcllib/modules/md5crypt/md5crypt.bench46
-rw-r--r--tcllib/modules/md5crypt/md5crypt.man85
-rw-r--r--tcllib/modules/md5crypt/md5crypt.tcl152
-rw-r--r--tcllib/modules/md5crypt/md5crypt.test152
-rw-r--r--tcllib/modules/md5crypt/md5cryptc.tcl174
-rw-r--r--tcllib/modules/md5crypt/pkgIndex.tcl3
7 files changed, 742 insertions, 0 deletions
diff --git a/tcllib/modules/md5crypt/ChangeLog b/tcllib/modules/md5crypt/ChangeLog
new file mode 100644
index 0000000..ea070bd
--- /dev/null
+++ b/tcllib/modules/md5crypt/ChangeLog
@@ -0,0 +1,130 @@
+2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.15 ========================
+ *
+
+2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.14 ========================
+ *
+
+2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.13 ========================
+ *
+
+2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.12 ========================
+ *
+
+2009-05-07 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * md5cryptc.tcl: Fixed poor idiom setting interp result.
+
+2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11.1 ========================
+ *
+
+2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11 ========================
+ *
+
+2008-01-26 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * md5crypt.tcl: Implemented FR #1824212 from Aaron Faupell to
+ * md5crypt.man: provide a salt command for use when generating
+ * pkgIndex.tcl: passwords.
+
+2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.10 ========================
+ *
+
+2007-03-21 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * md5crypt.man: Fixed all warnings due to use of now deprecated
+ commands. Added a section about how to give feedback.
+
+2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.9 ========================
+ *
+
+2006-09-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * md5crypt.test: The critcl implementation of md5crypt generates
+ different error messages when called with the wrong number of
+ arguments. Updated the tests to take this into account.
+
+2006-01-23 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * md5crypt.test: More boilerplate simplified via use of test support.
+
+2006-01-19 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * md5crypt.test: Hooked into the new common test support code.
+
+2005-10-24 Andreas Kupries <andreask@activestate.com>
+
+ * md5crypt.bench: New file. Basic benchmarks for MD5 password
+ hashes.
+
+2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.8 ========================
+ *
+
+2005-10-05 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * md5cryptc.tcl: Fix for building with msvc.
+
+2004-10-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.7 ========================
+ *
+
+2004-05-23 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.6.1 ========================
+ *
+
+2004-02-15 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.6 ========================
+ *
+
+2004-02-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * md5crypt.test: Testsuite fixed. Had to account that error
+ messages can dependent on the version of the Tcl core.
+
+2003-07-26 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * md5crypt.tcl: Provided implementation of the Apache
+ * md5cryptc.tcl: variation of md5crypt - as used in the
+ * md5crypt.test: Apache2 htpasswd program.
+
+ * md5crypt.man: Added a manual page.
+
+2003-07-26 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * md5crypt.tcl: Initial version of a pure-Tcl and
+ * md5crypt.test: critcl-enhanced implementation of
+ * md5cryptc.tcl: the BSD MD5-crypt algorithm.
+ * pkgIndex.tcl:
+ * ChangeLog:
diff --git a/tcllib/modules/md5crypt/md5crypt.bench b/tcllib/modules/md5crypt/md5crypt.bench
new file mode 100644
index 0000000..6135395
--- /dev/null
+++ b/tcllib/modules/md5crypt/md5crypt.bench
@@ -0,0 +1,46 @@
+# -*- tcl -*-
+# Tcl Benchmark File
+#
+# This file contains a number of benchmarks for the 'md5' module.
+# This allow developers to monitor/gauge/track package performance.
+#
+# (c) 2005 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+# We need at least version 8.2 for the package and thus the
+# benchmarks.
+
+if {![package vsatisfies [package provide Tcl] 8.2]} {
+ return
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Setting up the environment ...
+
+set moddir [file dirname [file dirname [info script]]]
+lappend auto_path $moddir
+
+package forget md5
+catch {namespace delete ::md5}
+source [file join [file dirname [file dirname [info script]]] md5 md5x.tcl]
+
+package forget md5crypt
+catch {namespace delete ::md5crypt}
+source [file join [file dirname [info script]] md5crypt.tcl]
+
+set key aaaaaaaaa
+
+# ### ### ### ######### ######### ######### ###########################
+## Benchmarks.
+
+foreach n {1 10 100 1000 10000} {
+ # Extremely expensive. Limit #iterations to keep total runtime acceptable.
+
+ bench -desc "MD5Crypt $n" -pre {
+ set str [string repeat " " $n]
+ } -body {
+ md5crypt::md5crypt $key $str
+ } -iters 10
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Complete
diff --git a/tcllib/modules/md5crypt/md5crypt.man b/tcllib/modules/md5crypt/md5crypt.man
new file mode 100644
index 0000000..c7b46f9
--- /dev/null
+++ b/tcllib/modules/md5crypt/md5crypt.man
@@ -0,0 +1,85 @@
+[manpage_begin md5crypt n 1.1.0]
+[see_also md5]
+[keywords hashing]
+[keywords md5]
+[keywords md5crypt]
+[keywords message-digest]
+[keywords security]
+[moddesc {MD5-based password encryption}]
+[copyright {2003, Pat Thoyts <patthoyts@users.sourceforge.net>}]
+[titledesc {MD5-based password encryption}]
+[category {Hashes, checksums, and encryption}]
+[require Tcl 8.2]
+[require md5 2.0]
+[require md5crypt [opt 1.1.0]]
+[description]
+[para]
+
+This package provides an implementation of the MD5-crypt password
+encryption algorithm as pioneered by FreeBSD and currently in use as a
+replacement for the unix crypt(3) function in many modern
+systems. An implementation of the closely related Apache MD5-crypt is
+also available.
+
+The output of these commands are compatible with the BSD and OpenSSL
+implementation of md5crypt and the Apache 2 htpasswd program.
+
+[section {COMMANDS}]
+
+[list_begin definitions]
+
+[call [cmd "::md5crypt::md5crypt"] \
+ [arg "password"] \
+ [arg "salt"]]
+
+Generate a BSD compatible md5-encoded password hash from the plaintext
+password and a random salt (see SALT).
+
+[call [cmd "::md5crypt::aprcrypt"] \
+ [arg "password"] \
+ [arg "salt"]]
+
+Generate an Apache compatible md5-encoded password hash from the plaintext
+password and a random salt (see SALT).
+
+[call [cmd "::md5crypt::salt"] [opt [arg "length"]]]
+
+Generate a random salt string suitable for use with the [cmd md5crypt] and
+[cmd aprcrypt] commands.
+
+[list_end]
+
+[section {SALT}]
+
+The salt passed to either of the encryption schemes implemented here
+is checked to see if it begins with the encryption scheme magic string
+(either "$1$" for MD5-crypt or "$apr1$" for Apache crypt). If so, this
+is removed. The remaining characters up to the next $ and up to a
+maximum of 8 characters are then used as the salt. The salt text
+should probably be restricted the set of ASCII alphanumeric characters
+plus "./" (dot and forward-slash) - this is to preserve maximum
+compatability with the unix password file format.
+[para]
+If a password is being generated rather than checked from a password
+file then the [cmd salt] command may be used to generate a random salt.
+
+[section {EXAMPLES}]
+
+[example {
+% md5crypt::md5crypt password 01234567
+$1$01234567$b5lh2mHyD2PdJjFfALlEz1
+}]
+
+[example {
+% md5crypt::aprcrypt password 01234567
+$apr1$01234567$IXBaQywhAhc0d75ZbaSDp/
+}]
+
+[example {
+% md5crypt::md5crypt password [md5crypt::salt]
+$1$dFmvyRmO$T.V3OmzqeEf3hqJp2WFcb.
+}]
+
+[vset CATEGORY md5crypt]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/md5crypt/md5crypt.tcl b/tcllib/modules/md5crypt/md5crypt.tcl
new file mode 100644
index 0000000..47d9a0a
--- /dev/null
+++ b/tcllib/modules/md5crypt/md5crypt.tcl
@@ -0,0 +1,152 @@
+# md5crypt.tcl - Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# This file provides a pure tcl implementation of the BSD MD5 crypt algorithm.
+# The implementation is based upon the OpenBSD code which is in turn based upon
+# the original code by Poul-Henning Kamp.
+#
+# -------------------------------------------------------------------------
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# -------------------------------------------------------------------------
+# @mdgen EXCLUDE: md5cryptc.tcl
+
+package require Tcl 8.2; # tcl minimum version
+package require md5 2; # tcllib 1.5
+
+# Try and load a compiled extension to help.
+if {[catch {package require tcllibc}]} {
+ catch {package require md5cryptc}
+}
+
+namespace eval md5crypt {
+ variable itoa64 \
+ {./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz}
+
+ namespace import -force ::md5::MD5Init ::md5::MD5Update ::md5::MD5Final
+ namespace export md5crypt
+}
+
+proc ::md5crypt::to64_tcl {v n} {
+ variable itoa64
+ for {} {$n > 0} {incr n -1} {
+ set i [expr {$v & 0x3f}]
+ append s [string index $itoa64 $i]
+ set v [expr {($v >> 6) & 0x3FFFFFFF}]
+ }
+ return $s
+}
+
+# ::md5crypt::salt --
+# Generate a salt string suitable for use with the md5crypt command.
+proc ::md5crypt::salt {{len 8}} {
+ variable itoa64
+ set salt ""
+ for {set n 0} {$n < $len} {incr n} {
+ append salt [string index $itoa64 [expr {int(rand() * 64)}]]
+ }
+ return $salt
+}
+
+proc ::md5crypt::md5crypt_tcl {magic pw salt} {
+ set sp 0
+
+ set start 0
+ if {[string match "${magic}*" $salt]} {
+ set start [string length $magic]
+ }
+ set end [string first $ $salt $start]
+ if {$end < 0} {set end [string length $salt]} else {incr end -1}
+ if {$end - $start > 7} {set end [expr {$start + 7}]}
+ set salt [string range $salt $start $end]
+
+ set ctx [MD5Init]
+ MD5Update $ctx $pw
+ MD5Update $ctx $magic
+ MD5Update $ctx $salt
+
+ set ctx2 [MD5Init]
+ MD5Update $ctx2 $pw
+ MD5Update $ctx2 $salt
+ MD5Update $ctx2 $pw
+ set H2 [MD5Final $ctx2]
+
+ for {set pl [string length $pw]} {$pl > 0} {incr pl -16} {
+ set tl [expr {($pl > 16 ? 16 : $pl) - 1}]
+ MD5Update $ctx [string range $H2 0 $tl]
+ }
+
+ for {set i [string length $pw]} {$i != 0} {set i [expr {$i >> 1}]} {
+ if {$i & 1} {
+ set c \0
+ } else {
+ set c [string index $pw 0]
+ }
+ MD5Update $ctx $c
+ }
+
+ set result "${magic}${salt}\$"
+
+ set H [MD5Final $ctx]
+
+ for {set i 0} {$i < 1000} {incr i} {
+ set ctx [MD5Init]
+ if {$i & 1} {
+ MD5Update $ctx $pw
+ } else {
+ MD5Update $ctx $H
+ }
+ if {$i % 3} {
+ MD5Update $ctx $salt
+ }
+ if {$i % 7} {
+ MD5Update $ctx $pw
+ }
+ if {$i & 1} {
+ MD5Update $ctx $H
+ } else {
+ MD5Update $ctx $pw
+ }
+ set H [MD5Final $ctx]
+ }
+
+ binary scan $H c* Vs
+ foreach v $Vs {lappend V [expr {$v & 0xFF}]}
+ set l [expr {([lindex $V 0] << 16) | ([lindex $V 6] << 8) | [lindex $V 12]}]
+ append result [to64 $l 4]
+ set l [expr {([lindex $V 1] << 16) | ([lindex $V 7] << 8) | [lindex $V 13]}]
+ append result [to64 $l 4]
+ set l [expr {([lindex $V 2] << 16) | ([lindex $V 8] << 8) | [lindex $V 14]}]
+ append result [to64 $l 4]
+ set l [expr {([lindex $V 3] << 16) | ([lindex $V 9] << 8) | [lindex $V 15]}]
+ append result [to64 $l 4]
+ set l [expr {([lindex $V 4] << 16) | ([lindex $V 10] << 8) | [lindex $V 5]}]
+ append result [to64 $l 4]
+ set l [expr {[lindex $V 11]}]
+ append result [to64 $l 2]
+
+ return $result
+}
+
+if {[info commands ::md5crypt::to64_c] == {}} {
+ interp alias {} ::md5crypt::to64 {} ::md5crypt::to64_tcl
+} else {
+ interp alias {} ::md5crypt::to64 {} ::md5crypt::to64_c
+}
+
+if {[info commands ::md5crypt::md5crypt_c] == {}} {
+ interp alias {} ::md5crypt::md5crypt {} ::md5crypt::md5crypt_tcl {$1$}
+ interp alias {} ::md5crypt::aprcrypt {} ::md5crypt::md5crypt_tcl {$apr1$}
+} else {
+ interp alias {} ::md5crypt::md5crypt {} ::md5crypt::md5crypt_c {$1$}
+ interp alias {} ::md5crypt::aprcrypt {} ::md5crypt::md5crypt_c {$apr1$}
+}
+
+# -------------------------------------------------------------------------
+
+package provide md5crypt 1.1.0
+
+# -------------------------------------------------------------------------
+# Local Variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End:
diff --git a/tcllib/modules/md5crypt/md5crypt.test b/tcllib/modules/md5crypt/md5crypt.test
new file mode 100644
index 0000000..5ae8aca
--- /dev/null
+++ b/tcllib/modules/md5crypt/md5crypt.test
@@ -0,0 +1,152 @@
+# -*- tcl -*-
+# md5crypt.test: tests for the md5crypt commands
+#
+# This file contains a collection of tests for one or more of the Tcllib
+# commands. Sourcing this file into Tcl runs the tests and generates
+# output for errors. No output means no errors were found.
+#
+# Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# RCS: @(#) $Id: md5crypt.test,v 1.9 2006/10/09 21:41:41 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.2
+testsNeedTcltest 1.0
+
+testing {
+ useLocal md5crypt.tcl md5crypt
+}
+
+# -------------------------------------------------------------------------
+# Setup any constraints
+
+# Set this true if we have the critcl version.
+
+::tcltest::testConstraint md5crypt_c \
+ [llength [info commands ::md5crypt::md5crypt_c]]
+
+# -------------------------------------------------------------------------
+
+if {[llength [info commands ::md5crypt::md5crypt_c]]} {
+ puts "> critcl based"
+ set impl critcl
+} else {
+ puts "> pure Tcl"
+ set impl tcl
+}
+
+# -------------------------------------------------------------------------
+# Now the package specific tests....
+# -------------------------------------------------------------------------
+# A procedure and a C command generate different error messages.
+
+test md5crypt-1.0 {md5crypt basic usage} {
+ catch {::md5crypt::md5crypt} result
+ if {$impl == "critcl"} {
+ set expected {wrong # args: should be "::md5crypt::md5crypt_c magic pw salt"}
+ } else {
+ set expected [tcltest::wrongNumArgs {*} {pw salt} 0]
+ }
+ string match $expected $result
+} 1
+
+test md5crypt-1.1 {md5crypt basic usage} {
+ catch {::md5crypt::md5crypt pw} result
+ if {$impl == "critcl"} {
+ set expected {wrong # args: should be "::md5crypt::md5crypt_c magic pw salt"}
+ } else {
+ set expected [tcltest::wrongNumArgs {*} {pw salt} 1]
+ }
+ string match $expected $result
+} 1
+
+test md5crypt-1.2 {md5crypt basic usage} {
+ catch {::md5crypt::md5crypt pw salt other} result
+ if {$impl == "critcl"} {
+ set expected {wrong # args: should be "::md5crypt::md5crypt_c magic pw salt"}
+ } else {
+ set expected [tcltest::tooManyArgs {*} {pw salt}]
+ }
+ string match $expected $result
+} 1
+
+# -------------------------------------------------------------------------
+
+foreach {n salt passwd expected} {
+ 1 {} a {$1$$Ij31LCAysPM23KuPlm1wA/}
+ 2 {a} a {$1$a$44cUw6Nm5bX0muHWNIwub0}
+ 3 {aa} a {$1$aa$aM/8fu5RTEKSCJWsk9qH.0}
+ 4 {aaa} a {$1$aaa$SCk4CXyogLtcfwl2VqfSF0}
+ 5 {aaaa} a {$1$aaaa$tjZedp/Ch2UpwkJdEKLPm.}
+ 6 {aaaaa} a {$1$aaaaa$iVkHUcCwuXWk4NaYTbyUa/}
+ 7 {aaaaaa} a {$1$aaaaaa$MUMWPbGfzrHFCNm7ZHg31.}
+ 8 {aaaaaaa} a {$1$aaaaaaa$4OzJTk7W1gmppy.1Lu4nr.}
+ 9 {aaaaaaaa} a {$1$aaaaaaaa$S270EsVIz5M8Y9/k4SSEf.}
+ 10 {aaaaaaaaa} a {$1$aaaaaaaa$S270EsVIz5M8Y9/k4SSEf.}
+ 12 {a$aaaaaaa} a {$1$a$44cUw6Nm5bX0muHWNIwub0}
+ 13 {$1$a$junk} a {$1$a$44cUw6Nm5bX0muHWNIwub0}
+} {
+ test md5passwd-2.${n} [list md5crypt salt check \"$salt\"] {
+ ::md5crypt::md5crypt $passwd $salt
+ } $expected
+
+ # If the C code is loaded, then we have tested that so now check the
+ # pure-tcl implementation as well.
+ test md5passwd-3.${n}_tcl [list md5crypt salt check \"$salt\"] \
+ {md5crypt_c} {
+ ::md5crypt::md5crypt_tcl {$1$} $passwd $salt
+ } $expected
+}
+
+# -------------------------------------------------------------------------
+
+foreach {n salt passwd expected} [list \
+ 1 {a} {} {$1$a$8CfZSfErbeskipdhZHtvu.} \
+ 2 {a} {a} {$1$a$44cUw6Nm5bX0muHWNIwub0} \
+ 3 {a} [string repeat a 100] {$1$a$vTAcWEblAgdUlX6KBz0NM.} \
+ 4 {a} [string repeat a 200] {$1$a$kC.K4D6mvUznpkjWJK8Tm0} \
+ 5 {a} [string repeat a 400] {$1$a$nBvNVTsAryOnHlW7L/gzf/} \
+ 6 {a} [string repeat a 1000] {$1$a$yhNnTV4IKHbl8oEB/eJaj0} \
+] {
+ test md5passwd-4.${n} {md5crypt check passwd} {
+ ::md5crypt::md5crypt $passwd $salt
+ } $expected
+
+ # If the C code is loaded, then we have tested that so now check the
+ # pure-tcl implementation as well.
+ test md5passwd-5.${n}_tcl {md5crypt (pure-Tcl) check passwd} {md5crypt_c} {
+ ::md5crypt::md5crypt_tcl {$1$} $passwd $salt
+ } $expected
+}
+
+# -------------------------------------------------------------------------
+
+foreach {n salt passwd expected} [list \
+ 1 {883.....} {a} {$apr1$883.....$wCU4E7Fv9tHAzFEm5D.mp/} \
+ 2 {XA3.....} {a} {$apr1$XA3.....$kp5j/oX/OCrpKdKhmUqTu1} \
+] {
+ test md5passwd-6.${n} {aprcrypt check passwd} {
+ ::md5crypt::aprcrypt $passwd $salt
+ } $expected
+
+ # If the C code is loaded, then we have tested that so now check the
+ # pure-tcl implementation as well.
+ test md5passwd-7.${n}_tcl {aprcrypt (pure-Tcl) check passwd} {md5crypt_c} {
+ ::md5crypt::md5crypt_tcl {$apr1$} $passwd $salt
+ } $expected
+}
+
+# -------------------------------------------------------------------------
+
+testsuiteCleanup
+
+# -------------------------------------------------------------------------
+# Local variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End: \ No newline at end of file
diff --git a/tcllib/modules/md5crypt/md5cryptc.tcl b/tcllib/modules/md5crypt/md5cryptc.tcl
new file mode 100644
index 0000000..e1facd8
--- /dev/null
+++ b/tcllib/modules/md5crypt/md5cryptc.tcl
@@ -0,0 +1,174 @@
+# md5cryptc.tcl - Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# This is a critcl-based wrapper to provide a Tcl implementation of the md5crypt
+# function. The C code here is based upon the OpenBSD source, which is in turn
+# derived from the original implementation by Poul-Henning Kamp
+#
+# The original C source license reads:
+#/*
+# * ----------------------------------------------------------------------------
+# * "THE BEER-WARE LICENSE" (Revision 42):
+# * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+# * can do whatever you want with this stuff. If we meet some day, and you think
+# * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+# * ----------------------------------------------------------------------------
+# */
+#
+# -------------------------------------------------------------------------
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# -------------------------------------------------------------------------
+
+
+package require critcl
+# @sak notprovided md5cryptc
+package provide md5cryptc 1.0
+
+critcl::cheaders ../md5/md5.h
+#critcl::csources ../md5/md5.c
+
+namespace eval ::md5crypt {
+ critcl::ccode {
+#include <string.h>
+#include "md5.h"
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+ static unsigned char itoa64[] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ static void to64(char *s, unsigned int v, int n)
+ {
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+ }
+
+ static void dump(const char *s, unsigned int len)
+ {
+ unsigned int i;
+ for (i = 0; i < len; i++)
+ printf("%02X", s[i]&0xFF);
+ putchar('\n');
+ }
+
+ static char * md5crypt(const char *pw,
+ const char *salt,
+ const char *magic)
+ {
+ static char passwd[120], *p;
+ static const unsigned char *sp,*ep;
+ unsigned char final[16];
+ int sl,pl,i;
+ MD5_CTX ctx,ctx1;
+ unsigned long l;
+
+ /* Refine the Salt first */
+ sp = (const unsigned char *)salt;
+
+ /* If it starts with the magic string, then skip that */
+ if(!strncmp((const char *)sp,(const char *)magic,strlen((const char *)magic)))
+ sp += strlen((const char *)magic);
+
+ /* It stops at the first '$', max 8 chars */
+ for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
+ continue;
+
+ /* get the length of the true salt */
+ sl = ep - sp;
+
+ MD5Init(&ctx);
+
+ /* The password first, since that is what is most unknown */
+ MD5Update(&ctx,(unsigned char *)pw,strlen(pw));
+
+ /* Then our magic string */
+ MD5Update(&ctx,(unsigned char *)magic,strlen((const char *)magic));
+
+ /* Then the raw salt */
+ MD5Update(&ctx,(unsigned char*)sp,sl);
+
+ /* Then just as many characters of the MD5(pw,salt,pw) */
+ MD5Init(&ctx1);
+ MD5Update(&ctx1,(unsigned char *)pw,strlen(pw));
+ MD5Update(&ctx1,(unsigned char *)sp,sl);
+ MD5Update(&ctx1,(unsigned char *)pw,strlen(pw));
+ MD5Final(final,&ctx1);
+
+ for(pl = strlen(pw); pl > 0; pl -= 16) {
+ int tl = pl > 16 ? 16 : pl;
+ MD5Update(&ctx,final,pl>16 ? 16 : pl);
+ }
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final,0,sizeof final);
+
+ /* Then something really weird... */
+ for (i = strlen(pw); i ; i >>= 1) {
+ if(i&1)
+ MD5Update(&ctx, final, 1);
+ else
+ MD5Update(&ctx, (unsigned char *)pw, 1);
+ }
+
+ /* Now make the output string */
+ snprintf(passwd, sizeof(passwd), "%s%.*s$", (char *)magic,
+ sl, (const char *)sp);
+
+ MD5Final(final,&ctx);
+
+ /*
+ * and now, just to make sure things don't run too fast
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for(i=0;i<1000;i++) {
+ MD5Init(&ctx1);
+ if(i & 1)
+ MD5Update(&ctx1,(unsigned char *)pw,strlen(pw));
+ else
+ MD5Update(&ctx1,final,16);
+
+ if(i % 3)
+ MD5Update(&ctx1,(unsigned char *)sp,sl);
+
+ if(i % 7)
+ MD5Update(&ctx1,(unsigned char *)pw,strlen(pw));
+
+ if(i & 1)
+ MD5Update(&ctx1,final,16);
+ else
+ MD5Update(&ctx1,(unsigned char *)pw,strlen(pw));
+ MD5Final(final,&ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
+ l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
+ l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
+ l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
+ l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
+ l = final[11] ; to64(p,l,2); p += 2;
+ *p = '\0';
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final,0,sizeof final);
+
+ return passwd;
+ }
+ }
+ critcl::cproc to64_c {Tcl_Interp* interp int v int n} ok {
+ char s[5];
+ to64(s, (unsigned int)v, n);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(s, n));
+ return TCL_OK;
+ }
+
+ critcl::cproc md5crypt_c {Tcl_Interp* interp char* magic char* pw char* salt} ok {
+ char* s = md5crypt(pw, salt, magic);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(s, strlen(s)));
+ return TCL_OK;
+ }
+}
diff --git a/tcllib/modules/md5crypt/pkgIndex.tcl b/tcllib/modules/md5crypt/pkgIndex.tcl
new file mode 100644
index 0000000..487ff9d
--- /dev/null
+++ b/tcllib/modules/md5crypt/pkgIndex.tcl
@@ -0,0 +1,3 @@
+# package index for md5crypt
+if {![package vsatisfies [package provide Tcl] 8.2]} {return}
+package ifneeded md5crypt 1.1.0 [list source [file join $dir md5crypt.tcl]]