1 |
dashley |
35 |
<?php
|
2 |
|
|
//$Header: /hl/cvsroots/gpl01/gpl01/webprojs/fboprime/sw/phplib/passwd.inc,v 1.4 2006/07/08 21:07:50 dashley Exp $
|
3 |
|
|
//********************************************************************************
|
4 |
|
|
//Copyright (C) 2006 David T. Ashley
|
5 |
|
|
//********************************************************************************
|
6 |
|
|
//This program or source file is free software; you can redistribute it and/or
|
7 |
|
|
//modify it under the terms of the GNU General Public License as published by
|
8 |
|
|
//the Free Software Foundation; either version 2 of the License, or (at your
|
9 |
|
|
//option) any later version.
|
10 |
|
|
//
|
11 |
|
|
//This program or source file is distributed in the hope that it will
|
12 |
|
|
//be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
|
|
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
|
|
//GNU General Public License for more details.
|
15 |
|
|
//
|
16 |
|
|
//You may have received a copy of the GNU General Public License
|
17 |
|
|
//along with this program; if not, write to the Free Software
|
18 |
|
|
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19 |
|
|
//********************************************************************************
|
20 |
|
|
//Dave Ashley, 04/06
|
21 |
|
|
//
|
22 |
|
|
//This source file provides the code to deal with the manipulation of
|
23 |
|
|
//passwords.
|
24 |
|
|
//
|
25 |
|
|
require_once("sguid.inc"); //Necesssary to generate SGUIDs.
|
26 |
|
|
require_once("crhsh.inc");
|
27 |
|
|
//
|
28 |
|
|
//
|
29 |
|
|
//Characters allowed in a password.
|
30 |
|
|
define("PASSWD_ALLOWED_CHARS", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-");
|
31 |
|
|
//
|
32 |
|
|
//Characters that will be used when generating an automatic replacement password.
|
33 |
|
|
define("PASSWD_AUTOGEN_CHARS", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
|
34 |
|
|
//
|
35 |
|
|
//Minimum and maximum lengths for a password.
|
36 |
|
|
define("PASSWD_LEN_MIN", 4);
|
37 |
|
|
define("PASSWD_LEN_MAX", 22);
|
38 |
|
|
//
|
39 |
|
|
//
|
40 |
|
|
//--------------------------------------------------------------------------------
|
41 |
|
|
//Returns a random password suitable for use when e-mailing a user a replacement
|
42 |
|
|
//for a lost password.
|
43 |
|
|
//
|
44 |
|
|
//Unit-tested 20060408.
|
45 |
|
|
//
|
46 |
|
|
function PASSWD_random_password_gen()
|
47 |
|
|
{
|
48 |
|
|
//Assuming 12 chars, this will be about 62^10 = 3.2E21 possibilities.
|
49 |
|
|
//This will be adequate, although it is substantially less information
|
50 |
|
|
//than an MD5 (2^128 = 3.4E38). Strictly speaking, this appears to be
|
51 |
|
|
//the weak link. However, even guessing 1,000 passwords per second,
|
52 |
|
|
//expected value of solution time is 102 billion years.
|
53 |
|
|
//
|
54 |
|
|
$len = 12; //PASSWD_LEN_MAX;
|
55 |
|
|
$pwd = "";
|
56 |
|
|
|
57 |
|
|
for ($i=0; $i<$len; $i++)
|
58 |
|
|
{
|
59 |
|
|
$pos = rand(0, strlen(PASSWD_AUTOGEN_CHARS)-1);
|
60 |
|
|
$c = SubStr(PASSWD_AUTOGEN_CHARS, $pos, 1);
|
61 |
|
|
$pwd .= $c;
|
62 |
|
|
}
|
63 |
|
|
|
64 |
|
|
return($pwd);
|
65 |
|
|
}
|
66 |
|
|
//
|
67 |
|
|
//
|
68 |
|
|
//--------------------------------------------------------------------------------
|
69 |
|
|
//Given a password, returns the salt and the hash that should be stored in
|
70 |
|
|
//the database. The salt is an SGUID (32 characters), and the hash proper
|
71 |
|
|
//will be another 32 characters, giving a total of 64 characters.
|
72 |
|
|
//
|
73 |
|
|
//The password used isn't checked--that should have been done before
|
74 |
|
|
//this function is used.
|
75 |
|
|
//
|
76 |
|
|
//Unit-tested 20060408.
|
77 |
|
|
//
|
78 |
|
|
function PASSWD_stored_hash_gen($passwd)
|
79 |
|
|
{
|
80 |
|
|
$salt = SGUID_sguid();
|
81 |
|
|
$hash = CRHSH_hashva($salt, $passwd);
|
82 |
|
|
return(StrToUpper($salt . $hash));
|
83 |
|
|
}
|
84 |
|
|
//
|
85 |
|
|
//
|
86 |
|
|
//--------------------------------------------------------------------------------
|
87 |
|
|
//Authenticates a password against a 64-character stored salt/hash.
|
88 |
|
|
//Returns 0 for authentication failure or 1 for authentication success.
|
89 |
|
|
//
|
90 |
|
|
//Unit-tested 20060408.
|
91 |
|
|
//
|
92 |
|
|
function PASSWD_pwd_hash_auth($stored_hash, $passwd)
|
93 |
|
|
{
|
94 |
|
|
//We can only accept strings. Failure to provide
|
95 |
|
|
//two strings is authentication failure.
|
96 |
|
|
if ((! is_string($stored_hash)) || (! is_string($passwd)))
|
97 |
|
|
return(0);
|
98 |
|
|
|
99 |
|
|
//Stored hash must be of the right length.
|
100 |
|
|
if (strlen($stored_hash) != 64)
|
101 |
|
|
return(0);
|
102 |
|
|
|
103 |
|
|
//Extract the salt from the stored hash.
|
104 |
|
|
$salt = SubStr($stored_hash, 0, 32);
|
105 |
|
|
|
106 |
|
|
//The salt should be a properly formed SGUID. If not, failure.
|
107 |
|
|
if (! SGUID_is_syntactically_valid($salt))
|
108 |
|
|
return(0);
|
109 |
|
|
|
110 |
|
|
//The comparison hash is formed from the stored salt and the password.
|
111 |
|
|
$comparison_hash = StrToUpper(CRHSH_hashva($salt, $passwd));
|
112 |
|
|
|
113 |
|
|
//The full value that should be stored and that we compare against is
|
114 |
|
|
//the concatenation of the salt and the hash with upper-case letters.
|
115 |
|
|
$comparison_stored_hash = $salt . $comparison_hash;
|
116 |
|
|
|
117 |
|
|
//If the strings don't match, authentication failure.
|
118 |
|
|
if ($stored_hash != $comparison_stored_hash)
|
119 |
|
|
return(0);
|
120 |
|
|
|
121 |
|
|
//If we're here, authentication success.
|
122 |
|
|
return(1);
|
123 |
|
|
}
|
124 |
|
|
//
|
125 |
|
|
//
|
126 |
|
|
//--------------------------------------------------------------------------------
|
127 |
|
|
//Accepts as input a password that was either entered by a user either
|
128 |
|
|
//to authenticate or change passwords. Checks the password
|
129 |
|
|
//against design rules for passwords. Returns TRUE if the password
|
130 |
|
|
//is acceptable, or returns an array of complaints with HTML markup if not.
|
131 |
|
|
//
|
132 |
|
|
//Unit-tested 20060408.
|
133 |
|
|
//
|
134 |
|
|
function PASSWD_passwd_rules_check($passwd)
|
135 |
|
|
{
|
136 |
|
|
//Index into the complaints.
|
137 |
|
|
$i = 0;
|
138 |
|
|
|
139 |
|
|
//If we have been passed a non-string type, that is the ultimate complaint.
|
140 |
|
|
if (! is_string($passwd))
|
141 |
|
|
{
|
142 |
|
|
$complaints[0] = "A non-string password was supplied to software internals.";
|
143 |
|
|
return($complaints);
|
144 |
|
|
}
|
145 |
|
|
|
146 |
|
|
//Can't be too short.
|
147 |
|
|
if (strlen($passwd) < PASSWD_LEN_MIN)
|
148 |
|
|
{
|
149 |
|
|
$complaints[$i] = "The password supplied is too short. Passwords must be at least 4 characters long.";
|
150 |
|
|
$i++;
|
151 |
|
|
}
|
152 |
|
|
|
153 |
|
|
//Can't be too long.
|
154 |
|
|
if (strlen($passwd) > PASSWD_LEN_MAX)
|
155 |
|
|
{
|
156 |
|
|
$complaints[$i] = "The password supplied is too long. Passwords can be no longer than 20 characters.";
|
157 |
|
|
$i++;
|
158 |
|
|
}
|
159 |
|
|
|
160 |
|
|
//Can't contain illegal characters."
|
161 |
|
|
if (! STRFUNC_is_char_subset($passwd, PASSWD_ALLOWED_CHARS))
|
162 |
|
|
{
|
163 |
|
|
$complaints[$i] = "The password supplied contains illegal characters. Passwords may contain only " .
|
164 |
|
|
"characters from the set "" . PASSWD_ALLOWED_CHARS . "".";
|
165 |
|
|
$i++;
|
166 |
|
|
}
|
167 |
|
|
|
168 |
|
|
//If we've registered no complaints, return TRUE, else return the complaints.
|
169 |
|
|
if ($i)
|
170 |
|
|
{
|
171 |
|
|
return($complaints);
|
172 |
|
|
}
|
173 |
|
|
else
|
174 |
|
|
{
|
175 |
|
|
return(TRUE);
|
176 |
|
|
}
|
177 |
|
|
}
|
178 |
|
|
//--------------------------------------------------------------------------------
|
179 |
|
|
?>
|