4 <SCRIPT TYPE=
"text/ssperl" CGI=
"$REMOTE_ADDR">
5 # Create Session Ticket
6 open(URANDOM, 'dd count=
1 if=/dev/urandom
2>/dev/null |shasum-
5.12 -b|cut -f
1 -d
" "|') ||
8 $SESSIONTICKET =
<URANDOM>;
10 chomp($SESSIONTICKET);
13 open(URANDOM, 'dd count=
1 if=/dev/urandom
2>/dev/null |shasum-
5.12 -b|cut -f
1 -d
" "|') ||
15 $LOGINTICKET=
<URANDOM>;
19 # Create Random Hash Salt
20 open(URANDOM, 'dd count=
1 if=/dev/urandom
2>/dev/null |shasum-
5.12 -b|cut -f
1 -d
" "|') ||
22 $RANDOMSALT=
<URANDOM>;
27 open(SALTFILE,
"<~/Private/.Passwords/SALT") || die
"~/Private/.Passwords/SALT: $!\n";
32 # Create login session ticket
33 open(LOGINTICKET,
">~/Private/.Sessions/$LOGINTICKET") || die
"~/Private/.Sessions/$LOGINTICKET: $!\n";
34 print LOGINTICKET <<
"ENDOFLOGINTICKET";
36 IPaddress: $REMOTE_ADDR
38 Session: $SESSIONTICKET
39 Randomsalt: $RANDOMSALT
45 <SCRIPT LANGUAGE=
"JavaScript">
46 function createCookie(name,value,days,path) {
48 var date = new Date();
49 date.setTime(date.getTime()+(days*
24*
60*
60*
1000));
50 var expires =
"; expires="+date.toGMTString();
52 else var expires =
"";
53 document.cookie = name+
"="+value+expires+
"; path=/"+path;
56 function readCookie(name) {
57 var nameEQ = name +
"=";
58 var ca = document.cookie.split(';');
59 for(var i=
0;i < ca.length;i++) {
61 while (c.charAt(
0)==' ') c = c.substring(
1,c.length);
62 if (c.indexOf(nameEQ) ==
0) return c.substring(nameEQ.length,c.length);
67 function eraseCookie(name) {
68 createCookie(name,
"",-
1);
71 <script type=
"text/javascript">
72 // Combine the password with the site SALT and hash it
73 // Combine this Hash iwth the extra SALT, and hash them
74 function HashPassword(extsalt
) {
77 var passwordvalue
= document
.getElementById('password');
78 var saltvalue
= document
.getElementById('salt');
79 hash1
= hex_sha1(saltvalue
.value
+passwordvalue
.value
);
81 hash2
= hex_sha1(extsalt
+hash1
);
84 passwordvalue
.value
= hash2
;
89 <script type
="text/javascript">
91 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
93 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
94 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
95 * Distributed under the BSD License
96 * See http://pajhome.org.uk/crypt/md5 for details.
100 * Configurable variables. You may need to tweak these to be compatible with
101 * the server-side, but the defaults work in most cases.
103 var hexcase
= 0; /* hex output format. 0 - lowercase; 1 - uppercase */
104 var b64pad
= ""; /* base-64 pad character. "=" for strict RFC compliance */
107 * These are the functions you'll usually want to call
108 * They take string arguments and return either hex or base-64 encoded strings
110 function hex_sha1(s
) { return rstr2hex(rstr_sha1(str2rstr_utf8(s
))); }
111 function b64_sha1(s
) { return rstr2b64(rstr_sha1(str2rstr_utf8(s
))); }
112 function any_sha1(s
, e
) { return rstr2any(rstr_sha1(str2rstr_utf8(s
)), e
); }
113 function hex_hmac_sha1(k
, d
)
114 { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
))); }
115 function b64_hmac_sha1(k
, d
)
116 { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
))); }
117 function any_hmac_sha1(k
, d
, e
)
118 { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
)), e
); }
121 * Perform a simple self-test to see if the VM is working
123 function sha1_vm_test()
125 return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
129 * Calculate the SHA1 of a raw string
131 function rstr_sha1(s
)
133 return binb2rstr(binb_sha1(rstr2binb(s
), s
.length
* 8));
137 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
139 function rstr_hmac_sha1(key
, data
)
141 var bkey
= rstr2binb(key
);
142 if(bkey
.length
> 16) bkey
= binb_sha1(bkey
, key
.length
* 8);
144 var ipad
= Array(16), opad
= Array(16);
145 for(var i
= 0; i
< 16; i
++)
147 ipad
[i
] = bkey
[i
] ^ 0x36363636;
148 opad
[i
] = bkey
[i
] ^ 0x5C5C5C5C;
151 var hash
= binb_sha1(ipad
.concat(rstr2binb(data
)), 512 + data
.length
* 8);
152 return binb2rstr(binb_sha1(opad
.concat(hash
), 512 + 160));
156 * Convert a raw string to a hex string
158 function rstr2hex(input
)
160 try { hexcase
} catch(e
) { hexcase
=0; }
161 var hex_tab
= hexcase
? "0123456789ABCDEF" : "0123456789abcdef";
164 for(var i
= 0; i
< input
.length
; i
++)
166 x
= input
.charCodeAt(i
);
167 output
+= hex_tab
.charAt((x
>>> 4) & 0x0F)
168 + hex_tab
.charAt( x
& 0x0F);
174 * Convert a raw string to a base-64 string
176 function rstr2b64(input
)
178 try { b64pad
} catch(e
) { b64pad
=''; }
179 var tab
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
181 var len
= input
.length
;
182 for(var i
= 0; i
< len
; i
+= 3)
184 var triplet
= (input
.charCodeAt(i
) << 16)
185 | (i
+ 1 < len
? input
.charCodeAt(i
+1) << 8 : 0)
186 | (i
+ 2 < len
? input
.charCodeAt(i
+2) : 0);
187 for(var j
= 0; j
< 4; j
++)
189 if(i
* 8 + j
* 6 > input
.length
* 8) output
+= b64pad
;
190 else output
+= tab
.charAt((triplet
>>> 6*(3-j
)) & 0x3F);
197 * Convert a raw string to an arbitrary string encoding
199 function rstr2any(input
, encoding
)
201 var divisor
= encoding
.length
;
202 var remainders
= Array();
203 var i
, q
, x
, quotient
;
205 /* Convert to an array of 16-bit big-endian values, forming the dividend */
206 var dividend
= Array(Math
.ceil(input
.length
/ 2));
207 for(i
= 0; i
< dividend
.length
; i
++)
209 dividend
[i
] = (input
.charCodeAt(i
* 2) << 8) | input
.charCodeAt(i
* 2 + 1);
213 * Repeatedly perform a long division. The binary array forms the dividend,
214 * the length of the encoding is the divisor. Once computed, the quotient
215 * forms the dividend for the next step. We stop when the dividend is zero.
216 * All remainders are stored for later use.
218 while(dividend
.length
> 0)
222 for(i
= 0; i
< dividend
.length
; i
++)
224 x
= (x
<< 16) + dividend
[i
];
225 q
= Math
.floor(x
/ divisor
);
227 if(quotient
.length
> 0 || q
> 0)
228 quotient
[quotient
.length
] = q
;
230 remainders
[remainders
.length
] = x
;
234 /* Convert the remainders to the output string */
236 for(i
= remainders
.length
- 1; i
>= 0; i
--)
237 output
+= encoding
.charAt(remainders
[i
]);
239 /* Append leading zero equivalents */
240 var full_length
= Math
.ceil(input
.length
* 8 /
241 (Math
.log(encoding
.length
) / Math
.log(2)))
242 for(i
= output
.length
; i
< full_length
; i
++)
243 output
= encoding
[0] + output
;
249 * Encode a string as utf-8.
250 * For efficiency, this assumes the input is valid utf-16.
252 function str2rstr_utf8(input
)
258 while(++i
< input
.length
)
260 /* Decode utf-16 surrogate pairs */
261 x
= input
.charCodeAt(i
);
262 y
= i
+ 1 < input
.length
? input
.charCodeAt(i
+ 1) : 0;
263 if(0xD800 <= x
&& x
<= 0xDBFF && 0xDC00 <= y
&& y
<= 0xDFFF)
265 x
= 0x10000 + ((x
& 0x03FF) << 10) + (y
& 0x03FF);
269 /* Encode output as utf-8 */
271 output
+= String
.fromCharCode(x
);
273 output
+= String
.fromCharCode(0xC0 | ((x
>>> 6 ) & 0x1F),
276 output
+= String
.fromCharCode(0xE0 | ((x
>>> 12) & 0x0F),
277 0x80 | ((x
>>> 6 ) & 0x3F),
279 else if(x
<= 0x1FFFFF)
280 output
+= String
.fromCharCode(0xF0 | ((x
>>> 18) & 0x07),
281 0x80 | ((x
>>> 12) & 0x3F),
282 0x80 | ((x
>>> 6 ) & 0x3F),
289 * Encode a string as utf-16
291 function str2rstr_utf16le(input
)
294 for(var i
= 0; i
< input
.length
; i
++)
295 output
+= String
.fromCharCode( input
.charCodeAt(i
) & 0xFF,
296 (input
.charCodeAt(i
) >>> 8) & 0xFF);
300 function str2rstr_utf16be(input
)
303 for(var i
= 0; i
< input
.length
; i
++)
304 output
+= String
.fromCharCode((input
.charCodeAt(i
) >>> 8) & 0xFF,
305 input
.charCodeAt(i
) & 0xFF);
310 * Convert a raw string to an array of big-endian words
311 * Characters >255 have their high-byte silently ignored.
313 function rstr2binb(input
)
315 var output
= Array(input
.length
>> 2);
316 for(var i
= 0; i
< output
.length
; i
++)
318 for(var i
= 0; i
< input
.length
* 8; i
+= 8)
319 output
[i
>>5] |= (input
.charCodeAt(i
/ 8) & 0xFF) << (24 - i
% 32);
324 * Convert an array of big-endian words to a string
326 function binb2rstr(input
)
329 for(var i
= 0; i
< input
.length
* 32; i
+= 8)
330 output
+= String
.fromCharCode((input
[i
>>5] >>> (24 - i
% 32)) & 0xFF);
335 * Calculate the SHA-1 of an array of big-endian words, and a bit length
337 function binb_sha1(x
, len
)
340 x
[len
>> 5] |= 0x80 << (24 - len
% 32);
341 x
[((len
+ 64 >> 9) << 4) + 15] = len
;
350 for(var i
= 0; i
< x
.length
; i
+= 16)
358 for(var j
= 0; j
< 80; j
++)
360 if(j
< 16) w
[j
] = x
[i
+ j
];
361 else w
[j
] = bit_rol(w
[j
-3] ^ w
[j
-8] ^ w
[j
-14] ^ w
[j
-16], 1);
362 var t
= safe_add(safe_add(bit_rol(a
, 5), sha1_ft(j
, b
, c
, d
)),
363 safe_add(safe_add(e
, w
[j
]), sha1_kt(j
)));
371 a
= safe_add(a
, olda
);
372 b
= safe_add(b
, oldb
);
373 c
= safe_add(c
, oldc
);
374 d
= safe_add(d
, oldd
);
375 e
= safe_add(e
, olde
);
377 return Array(a
, b
, c
, d
, e
);
382 * Perform the appropriate triplet combination function for the current
385 function sha1_ft(t
, b
, c
, d
)
387 if(t
< 20) return (b
& c
) | ((~b
) & d
);
388 if(t
< 40) return b
^ c
^ d
;
389 if(t
< 60) return (b
& c
) | (b
& d
) | (c
& d
);
394 * Determine the appropriate additive constant for the current iteration
398 return (t
< 20) ? 1518500249 : (t
< 40) ? 1859775393 :
399 (t
< 60) ? -1894007588 : -899497514;
403 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
404 * to work around bugs in some JS interpreters.
406 function safe_add(x
, y
)
408 var lsw
= (x
& 0xFFFF) + (y
& 0xFFFF);
409 var msw
= (x
>> 16) + (y
>> 16) + (lsw
>> 16);
410 return (msw
<< 16) | (lsw
& 0xFFFF);
414 * Bitwise rotate a 32-bit number to the left.
416 function bit_rol(num
, cnt
)
418 return (num
<< cnt
) | (num
>>> (32 - cnt
));
424 <h1 align=CENTER
>Example of Login procedure
</h1>
426 Simple and very unsafe example login page for CGIscriptor.pl. The password is first hashed with the
427 site specific salt (as it is used to store the password on-site). Then it is hashed with a random,
428 one-time salt. Effectively, creating a one-time password. Only the last value is send to the server.
429 The server has both salt values stored. It will ignore anything except the username, hashed password, and
433 The Session Ticket is stored in a cookie with the name
<em>CGIscriptor
</em>.
436 <form method=
"POST" action=
"" id=
"LoginForm"
437 onSubmit='HashPassword(
"<SCRIPT TYPE="text/ssperl
">
438 $RANDOMSALT</SCRIPT>");createCookie(
"CGIscriptor",
"<SCRIPT TYPE="text/ssperl
">$SESSIONTICKET</SCRIPT>",
1,
"Private/");true'
>
439 <div style=
"margin-left: 30%; margin-right: 30%; text-align: left">
440 Username:
<input type=
"text" name=
"username" size=
"20" /><br />
441 Password:
<input type=
"password" name=
"password" id=
"password" size=
"20" /><br />
442 <input type=
"hidden" name=
"salt" id=
"salt" value=
"<SCRIPT TYPE="text/ssperl
">$SALT</SCRIPT>" /><br />
443 <input type=
"hidden" name=
"LOGINTICKET" value=
"<SCRIPT TYPE="text/ssperl
">$LOGINTICKET</SCRIPT>" /><br />
446 <p><input type=
"submit" value=
"Login" /></p>
450 The Salt and Ticket values are all created using SHA1 on
512 Byte of output from
<em>/dev/urandom
</em> in HEX.
452 <FONT STYLE=
"font-size:small">
453 <p> Example Login page for CGIscriptor.pl
<br />
454 Copyright
© 2012 R.J.J.H. van Son
<br />
455 This program is free software: you can redistribute it and/or modify
456 it under the terms of the GNU General Public License as published by
457 the Free Software Foundation, either version
3 of the License, or
458 (at your option) any later version.
459 This program is distributed in the hope that it will be useful,
460 but WITHOUT ANY WARRANTY; without even the implied warranty of
461 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
462 GNU General Public License for more details.
<br />
463 You should have received a copy of the GNU General Public License
464 along with this program. If not, see
<a href=
"http://www.gnu.org/licenses/">http://www.gnu.org/licenses/
</a>.
</p>
465 <p> JavaScript implementation of the Secure Hash Algorithm, SHA-
1, as defined in FIPS
180-
1<br />
466 Copyright
© 2000 -
2009 Paul Johnston, Version
2.2<br />
467 Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
<br />
468 Distributed under the BSD License
<br />
469 See
<a href=
"http://pajhome.org.uk/crypt/md5">http://pajhome.org.uk/crypt/md5
</a> for details.