4 <SCRIPT TYPE=
"text/ssperl" CGI=
"$REMOTE_ADDR $RANDOMHASHCMD">
5 # Create Session Ticket
6 open(URANDOM,
"$RANDOMHASHCMD |") || die
"URANDOM; $RANDOMHASHCMD | $!\n";
7 $SESSIONTICKET =
<URANDOM>;
12 open(URANDOM,
"$RANDOMHASHCMD |") || die
"URANDOM; $!\n";
13 $LOGINTICKET=
<URANDOM>;
17 # Create Random Hash Salt
18 open(URANDOM,
"$RANDOMHASHCMD |") || die
"URANDOM; $RANDOMHASHCMD | $!\n";
19 $RANDOMSALT=
<URANDOM>;
24 open(SALTFILE,
"<~/Private/.Passwords/SALT") || die
"~/Private/.Passwords/SALT: $!\n";
29 # Create login session ticket
30 open(LOGINTICKET,
">~/Private/.Sessions/$LOGINTICKET") || die
"~/Private/.Sessions/$LOGINTICKET: $!\n";
31 print LOGINTICKET <<
"ENDOFLOGINTICKET";
33 IPaddress: $REMOTE_ADDR
35 Session: $SESSIONTICKET
36 Randomsalt: $RANDOMSALT
42 <SCRIPT LANGUAGE=
"JavaScript">
43 function createCookie(name,value,days,path) {
45 var date = new Date();
46 date.setTime(date.getTime()+(days*
24*
60*
60*
1000));
47 var expires =
"; expires="+date.toGMTString();
49 else var expires =
"";
50 document.cookie = name+
"="+value+expires+
"; path=/"+path;
53 function readCookie(name) {
54 var nameEQ = name +
"=";
55 var ca = document.cookie.split(';');
56 for(var i=
0;i < ca.length;i++) {
58 while (c.charAt(
0)==' ') c = c.substring(
1,c.length);
59 if (c.indexOf(nameEQ) ==
0) return c.substring(nameEQ.length,c.length);
64 function eraseCookie(name) {
65 createCookie(name,
"",-
1);
68 <script type=
"text/javascript">
69 // Combine the password with the site SALT and hash it
70 // Combine this Hash iwth the extra SALT, and hash them
71 function HashPassword(extsalt
) {
74 var passwordvalue
= document
.getElementById('password');
75 var saltvalue
= document
.getElementById('salt');
76 hash1
= hex_sha1(saltvalue
.value
+passwordvalue
.value
);
78 hash2
= hex_sha1(extsalt
+hash1
);
81 passwordvalue
.value
= hash2
;
86 <script type
="text/javascript">
88 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
90 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
91 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
92 * Distributed under the BSD License
93 * See http://pajhome.org.uk/crypt/md5 for details.
97 * Configurable variables. You may need to tweak these to be compatible with
98 * the server-side, but the defaults work in most cases.
100 var hexcase
= 0; /* hex output format. 0 - lowercase; 1 - uppercase */
101 var b64pad
= ""; /* base-64 pad character. "=" for strict RFC compliance */
104 * These are the functions you'll usually want to call
105 * They take string arguments and return either hex or base-64 encoded strings
107 function hex_sha1(s
) { return rstr2hex(rstr_sha1(str2rstr_utf8(s
))); }
108 function b64_sha1(s
) { return rstr2b64(rstr_sha1(str2rstr_utf8(s
))); }
109 function any_sha1(s
, e
) { return rstr2any(rstr_sha1(str2rstr_utf8(s
)), e
); }
110 function hex_hmac_sha1(k
, d
)
111 { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
))); }
112 function b64_hmac_sha1(k
, d
)
113 { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
))); }
114 function any_hmac_sha1(k
, d
, e
)
115 { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
)), e
); }
118 * Perform a simple self-test to see if the VM is working
120 function sha1_vm_test()
122 return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
126 * Calculate the SHA1 of a raw string
128 function rstr_sha1(s
)
130 return binb2rstr(binb_sha1(rstr2binb(s
), s
.length
* 8));
134 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
136 function rstr_hmac_sha1(key
, data
)
138 var bkey
= rstr2binb(key
);
139 if(bkey
.length
> 16) bkey
= binb_sha1(bkey
, key
.length
* 8);
141 var ipad
= Array(16), opad
= Array(16);
142 for(var i
= 0; i
< 16; i
++)
144 ipad
[i
] = bkey
[i
] ^ 0x36363636;
145 opad
[i
] = bkey
[i
] ^ 0x5C5C5C5C;
148 var hash
= binb_sha1(ipad
.concat(rstr2binb(data
)), 512 + data
.length
* 8);
149 return binb2rstr(binb_sha1(opad
.concat(hash
), 512 + 160));
153 * Convert a raw string to a hex string
155 function rstr2hex(input
)
157 try { hexcase
} catch(e
) { hexcase
=0; }
158 var hex_tab
= hexcase
? "0123456789ABCDEF" : "0123456789abcdef";
161 for(var i
= 0; i
< input
.length
; i
++)
163 x
= input
.charCodeAt(i
);
164 output
+= hex_tab
.charAt((x
>>> 4) & 0x0F)
165 + hex_tab
.charAt( x
& 0x0F);
171 * Convert a raw string to a base-64 string
173 function rstr2b64(input
)
175 try { b64pad
} catch(e
) { b64pad
=''; }
176 var tab
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
178 var len
= input
.length
;
179 for(var i
= 0; i
< len
; i
+= 3)
181 var triplet
= (input
.charCodeAt(i
) << 16)
182 | (i
+ 1 < len
? input
.charCodeAt(i
+1) << 8 : 0)
183 | (i
+ 2 < len
? input
.charCodeAt(i
+2) : 0);
184 for(var j
= 0; j
< 4; j
++)
186 if(i
* 8 + j
* 6 > input
.length
* 8) output
+= b64pad
;
187 else output
+= tab
.charAt((triplet
>>> 6*(3-j
)) & 0x3F);
194 * Convert a raw string to an arbitrary string encoding
196 function rstr2any(input
, encoding
)
198 var divisor
= encoding
.length
;
199 var remainders
= Array();
200 var i
, q
, x
, quotient
;
202 /* Convert to an array of 16-bit big-endian values, forming the dividend */
203 var dividend
= Array(Math
.ceil(input
.length
/ 2));
204 for(i
= 0; i
< dividend
.length
; i
++)
206 dividend
[i
] = (input
.charCodeAt(i
* 2) << 8) | input
.charCodeAt(i
* 2 + 1);
210 * Repeatedly perform a long division. The binary array forms the dividend,
211 * the length of the encoding is the divisor. Once computed, the quotient
212 * forms the dividend for the next step. We stop when the dividend is zero.
213 * All remainders are stored for later use.
215 while(dividend
.length
> 0)
219 for(i
= 0; i
< dividend
.length
; i
++)
221 x
= (x
<< 16) + dividend
[i
];
222 q
= Math
.floor(x
/ divisor
);
224 if(quotient
.length
> 0 || q
> 0)
225 quotient
[quotient
.length
] = q
;
227 remainders
[remainders
.length
] = x
;
231 /* Convert the remainders to the output string */
233 for(i
= remainders
.length
- 1; i
>= 0; i
--)
234 output
+= encoding
.charAt(remainders
[i
]);
236 /* Append leading zero equivalents */
237 var full_length
= Math
.ceil(input
.length
* 8 /
238 (Math
.log(encoding
.length
) / Math
.log(2)))
239 for(i
= output
.length
; i
< full_length
; i
++)
240 output
= encoding
[0] + output
;
246 * Encode a string as utf-8.
247 * For efficiency, this assumes the input is valid utf-16.
249 function str2rstr_utf8(input
)
255 while(++i
< input
.length
)
257 /* Decode utf-16 surrogate pairs */
258 x
= input
.charCodeAt(i
);
259 y
= i
+ 1 < input
.length
? input
.charCodeAt(i
+ 1) : 0;
260 if(0xD800 <= x
&& x
<= 0xDBFF && 0xDC00 <= y
&& y
<= 0xDFFF)
262 x
= 0x10000 + ((x
& 0x03FF) << 10) + (y
& 0x03FF);
266 /* Encode output as utf-8 */
268 output
+= String
.fromCharCode(x
);
270 output
+= String
.fromCharCode(0xC0 | ((x
>>> 6 ) & 0x1F),
273 output
+= String
.fromCharCode(0xE0 | ((x
>>> 12) & 0x0F),
274 0x80 | ((x
>>> 6 ) & 0x3F),
276 else if(x
<= 0x1FFFFF)
277 output
+= String
.fromCharCode(0xF0 | ((x
>>> 18) & 0x07),
278 0x80 | ((x
>>> 12) & 0x3F),
279 0x80 | ((x
>>> 6 ) & 0x3F),
286 * Encode a string as utf-16
288 function str2rstr_utf16le(input
)
291 for(var i
= 0; i
< input
.length
; i
++)
292 output
+= String
.fromCharCode( input
.charCodeAt(i
) & 0xFF,
293 (input
.charCodeAt(i
) >>> 8) & 0xFF);
297 function str2rstr_utf16be(input
)
300 for(var i
= 0; i
< input
.length
; i
++)
301 output
+= String
.fromCharCode((input
.charCodeAt(i
) >>> 8) & 0xFF,
302 input
.charCodeAt(i
) & 0xFF);
307 * Convert a raw string to an array of big-endian words
308 * Characters >255 have their high-byte silently ignored.
310 function rstr2binb(input
)
312 var output
= Array(input
.length
>> 2);
313 for(var i
= 0; i
< output
.length
; i
++)
315 for(var i
= 0; i
< input
.length
* 8; i
+= 8)
316 output
[i
>>5] |= (input
.charCodeAt(i
/ 8) & 0xFF) << (24 - i
% 32);
321 * Convert an array of big-endian words to a string
323 function binb2rstr(input
)
326 for(var i
= 0; i
< input
.length
* 32; i
+= 8)
327 output
+= String
.fromCharCode((input
[i
>>5] >>> (24 - i
% 32)) & 0xFF);
332 * Calculate the SHA-1 of an array of big-endian words, and a bit length
334 function binb_sha1(x
, len
)
337 x
[len
>> 5] |= 0x80 << (24 - len
% 32);
338 x
[((len
+ 64 >> 9) << 4) + 15] = len
;
347 for(var i
= 0; i
< x
.length
; i
+= 16)
355 for(var j
= 0; j
< 80; j
++)
357 if(j
< 16) w
[j
] = x
[i
+ j
];
358 else w
[j
] = bit_rol(w
[j
-3] ^ w
[j
-8] ^ w
[j
-14] ^ w
[j
-16], 1);
359 var t
= safe_add(safe_add(bit_rol(a
, 5), sha1_ft(j
, b
, c
, d
)),
360 safe_add(safe_add(e
, w
[j
]), sha1_kt(j
)));
368 a
= safe_add(a
, olda
);
369 b
= safe_add(b
, oldb
);
370 c
= safe_add(c
, oldc
);
371 d
= safe_add(d
, oldd
);
372 e
= safe_add(e
, olde
);
374 return Array(a
, b
, c
, d
, e
);
379 * Perform the appropriate triplet combination function for the current
382 function sha1_ft(t
, b
, c
, d
)
384 if(t
< 20) return (b
& c
) | ((~b
) & d
);
385 if(t
< 40) return b
^ c
^ d
;
386 if(t
< 60) return (b
& c
) | (b
& d
) | (c
& d
);
391 * Determine the appropriate additive constant for the current iteration
395 return (t
< 20) ? 1518500249 : (t
< 40) ? 1859775393 :
396 (t
< 60) ? -1894007588 : -899497514;
400 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
401 * to work around bugs in some JS interpreters.
403 function safe_add(x
, y
)
405 var lsw
= (x
& 0xFFFF) + (y
& 0xFFFF);
406 var msw
= (x
>> 16) + (y
>> 16) + (lsw
>> 16);
407 return (msw
<< 16) | (lsw
& 0xFFFF);
411 * Bitwise rotate a 32-bit number to the left.
413 function bit_rol(num
, cnt
)
415 return (num
<< cnt
) | (num
>>> (32 - cnt
));
421 <h1 align=CENTER
>Example of Login procedure
</h1>
423 Simple and very unsafe example login page for CGIscriptor.pl. The password is first hashed with the
424 site specific salt (as it is used to store the password on-site). Then it is hashed with a random,
425 one-time salt. Effectively, creating a one-time password. Only the last value is send to the server.
426 The server has both salt values stored. It will ignore anything except the username, hashed password, and
430 The Session Ticket is stored in a cookie with the name
<em>CGIscriptor
</em>.
433 <form method=
"POST" action=
"" id=
"LoginForm"
434 onSubmit='HashPassword(
"<SCRIPT TYPE="text/ssperl
">
435 $RANDOMSALT</SCRIPT>");createCookie(
"CGIscriptor",
"<SCRIPT TYPE="text/ssperl
">$SESSIONTICKET</SCRIPT>",
1,
"Private/");true'
>
436 <div style=
"margin-left: 30%; margin-right: 30%; text-align: left">
437 Username:
<input type=
"text" name=
"username" size=
"20" /><br />
438 Password:
<input type=
"password" name=
"password" id=
"password" size=
"20" /><br />
439 <input type=
"hidden" name=
"salt" id=
"salt" value=
"<SCRIPT TYPE="text/ssperl
">$SALT</SCRIPT>" /><br />
440 <input type=
"hidden" name=
"LOGINTICKET" value=
"<SCRIPT TYPE="text/ssperl
">$LOGINTICKET</SCRIPT>" /><br />
443 <p><input type=
"submit" value=
"Login" /></p>
447 The Salt and Ticket values are all created using SHA1 on
512 Byte of output from
<em>/dev/urandom
</em> in HEX.
449 <FONT STYLE=
"font-size:small">
450 <p> Example Login page for CGIscriptor.pl
<br />
451 Copyright
© 2012 R.J.J.H. van Son
<br />
452 This program is free software: you can redistribute it and/or modify
453 it under the terms of the GNU General Public License as published by
454 the Free Software Foundation, either version
3 of the License, or
455 (at your option) any later version.
456 This program is distributed in the hope that it will be useful,
457 but WITHOUT ANY WARRANTY; without even the implied warranty of
458 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
459 GNU General Public License for more details.
<br />
460 You should have received a copy of the GNU General Public License
461 along with this program. If not, see
<a href=
"http://www.gnu.org/licenses/">http://www.gnu.org/licenses/
</a>.
</p>
462 <p> JavaScript implementation of the Secure Hash Algorithm, SHA-
1, as defined in FIPS
180-
1<br />
463 Copyright
© 2000 -
2009 Paul Johnston, Version
2.2<br />
464 Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
<br />
465 Distributed under the BSD License
<br />
466 See
<a href=
"http://pajhome.org.uk/crypt/md5">http://pajhome.org.uk/crypt/md5
</a> for details.