4 <META CONTENT=
"text/ssperl; CGI='$SERVERSALT $LOGINTICKET $RANDOMSALT $REMOTE_ADDR'">
5 <SCRIPT type=
"text/javascript" LANGUAGE=
"JavaScript">
6 function createCookie(name,value,days,path) {
10 date.setTime(date.getTime()+(days*
24*
60*
60*
1000));
11 expires = ';expires='+date.toGMTString();
13 document.cookie = name+'='+value+expires+';path=/'+path+'';
16 function readCookie(name) {
17 var nameEQ = name +
"=";
18 var ca = document.cookie.split(';');
19 for(var i=
0;i < ca.length;i++) {
21 while (c.charAt(
0)==' ') c = c.substring(
1,c.length);
22 if (c.indexOf(nameEQ) ==
0) return c.substring(nameEQ.length,c.length);
27 function eraseCookie(name) {
28 createCookie(name,
"",-
1);
31 <script type=
"text/javascript">
32 // Combine the PASSWORD with the site SALT and hash it
33 // Combine this Hash with the extra SALT, and hash them
34 function HashPassword(extsalt
) {
35 var hash
= HashSessionSeed(extsalt
);
36 var password
= document
.getElementById('PASSWORD');
38 password
.value
= hash
;
40 alert("NO PASSWORD IN FORM");
46 // REMEMBER: Set the session cookie BEFORE you hash the password!!!
47 function SetSessionCookie() {
48 var seed
= '<SCRIPT TYPE="text/ssperl">$LOGINTICKET</SCRIPT>';
49 var hash
= HashSessionSeed(seed
);
50 localStorage
.setItem("CGIscriptorPRIVATE", hash
)
54 function HashSessionSeed(sessionseed
) {
57 var passwordvalue
= document
.getElementById('PASSWORD');
58 var saltvalue
= document
.getElementById('SALT');
59 hash1
= hex_sha1(saltvalue
.value
+passwordvalue
.value
);
61 hash2
= hex_sha1(sessionseed
+hash1
);
67 function remove_cgiparam(elem
, attr
, parameter
) {
68 var elems
= document
.getElementsByTagName(elem
);
69 for (var i
= 0; i
< elems
.length
; i
++)
71 var n
=elems
[i
][attr
].indexOf("&"+parameter
);
73 elems
[i
][attr
] = elems
[i
][attr
].replace("&"+param
, "");
74 var n
=elems
[i
][attr
].indexOf(parameter
);
76 elems
[i
][attr
] = elems
[i
][attr
].replace(param
, "");
80 function check_username_password ( ) {
81 var username
= document
.getElementById('USERNAME');
82 var password
= document
.getElementById('PASSWORD');
83 if(username
.value
.match(/[a-zA-Z0-9]/) && password
.value
.match(/[a-zA-Z0-9]/))
85 alert("Please enter a user name and password");
89 // Remove EVERYTHING from Login window
90 window
.onload = function() {
91 if(window
.location
.search
)window
.location
.search
= "";
95 <script type
="text/javascript">
97 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
99 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
100 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
101 * Distributed under the BSD License
102 * See http://pajhome.org.uk/crypt/md5 for details.
106 * Configurable variables. You may need to tweak these to be compatible with
107 * the server-side, but the defaults work in most cases.
109 var hexcase
= 0; /* hex output format. 0 - lowercase; 1 - uppercase */
110 var b64pad
= ""; /* base-64 pad character. "=" for strict RFC compliance */
113 * These are the functions you'll usually want to call
114 * They take string arguments and return either hex or base-64 encoded strings
116 function hex_sha1(s
) { return rstr2hex(rstr_sha1(str2rstr_utf8(s
))); }
117 function b64_sha1(s
) { return rstr2b64(rstr_sha1(str2rstr_utf8(s
))); }
118 function any_sha1(s
, e
) { return rstr2any(rstr_sha1(str2rstr_utf8(s
)), e
); }
119 function hex_hmac_sha1(k
, d
)
120 { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
))); }
121 function b64_hmac_sha1(k
, d
)
122 { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
))); }
123 function any_hmac_sha1(k
, d
, e
)
124 { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k
), str2rstr_utf8(d
)), e
); }
127 * Perform a simple self-test to see if the VM is working
129 function sha1_vm_test()
131 return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
135 * Calculate the SHA1 of a raw string
137 function rstr_sha1(s
)
139 return binb2rstr(binb_sha1(rstr2binb(s
), s
.length
* 8));
143 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
145 function rstr_hmac_sha1(key
, data
)
147 var bkey
= rstr2binb(key
);
148 if(bkey
.length
> 16) bkey
= binb_sha1(bkey
, key
.length
* 8);
150 var ipad
= Array(16), opad
= Array(16);
151 for(var i
= 0; i
< 16; i
++)
153 ipad
[i
] = bkey
[i
] ^ 0x36363636;
154 opad
[i
] = bkey
[i
] ^ 0x5C5C5C5C;
157 var hash
= binb_sha1(ipad
.concat(rstr2binb(data
)), 512 + data
.length
* 8);
158 return binb2rstr(binb_sha1(opad
.concat(hash
), 512 + 160));
162 * Convert a raw string to a hex string
164 function rstr2hex(input
)
166 try { hexcase
} catch(e
) { hexcase
=0; }
167 var hex_tab
= hexcase
? "0123456789ABCDEF" : "0123456789abcdef";
170 for(var i
= 0; i
< input
.length
; i
++)
172 x
= input
.charCodeAt(i
);
173 output
+= hex_tab
.charAt((x
>>> 4) & 0x0F)
174 + hex_tab
.charAt( x
& 0x0F);
180 * Convert a raw string to a base-64 string
182 function rstr2b64(input
)
184 try { b64pad
} catch(e
) { b64pad
=''; }
185 var tab
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
187 var len
= input
.length
;
188 for(var i
= 0; i
< len
; i
+= 3)
190 var triplet
= (input
.charCodeAt(i
) << 16)
191 | (i
+ 1 < len
? input
.charCodeAt(i
+1) << 8 : 0)
192 | (i
+ 2 < len
? input
.charCodeAt(i
+2) : 0);
193 for(var j
= 0; j
< 4; j
++)
195 if(i
* 8 + j
* 6 > input
.length
* 8) output
+= b64pad
;
196 else output
+= tab
.charAt((triplet
>>> 6*(3-j
)) & 0x3F);
203 * Convert a raw string to an arbitrary string encoding
205 function rstr2any(input
, encoding
)
207 var divisor
= encoding
.length
;
208 var remainders
= Array();
209 var i
, q
, x
, quotient
;
211 /* Convert to an array of 16-bit big-endian values, forming the dividend */
212 var dividend
= Array(Math
.ceil(input
.length
/ 2));
213 for(i
= 0; i
< dividend
.length
; i
++)
215 dividend
[i
] = (input
.charCodeAt(i
* 2) << 8) | input
.charCodeAt(i
* 2 + 1);
219 * Repeatedly perform a long division. The binary array forms the dividend,
220 * the length of the encoding is the divisor. Once computed, the quotient
221 * forms the dividend for the next step. We stop when the dividend is zero.
222 * All remainders are stored for later use.
224 while(dividend
.length
> 0)
228 for(i
= 0; i
< dividend
.length
; i
++)
230 x
= (x
<< 16) + dividend
[i
];
231 q
= Math
.floor(x
/ divisor
);
233 if(quotient
.length
> 0 || q
> 0)
234 quotient
[quotient
.length
] = q
;
236 remainders
[remainders
.length
] = x
;
240 /* Convert the remainders to the output string */
242 for(i
= remainders
.length
- 1; i
>= 0; i
--)
243 output
+= encoding
.charAt(remainders
[i
]);
245 /* Append leading zero equivalents */
246 var full_length
= Math
.ceil(input
.length
* 8 /
247 (Math
.log(encoding
.length
) / Math
.log(2)))
248 for(i
= output
.length
; i
< full_length
; i
++)
249 output
= encoding
[0] + output
;
255 * Encode a string as utf-8.
256 * For efficiency, this assumes the input is valid utf-16.
258 function str2rstr_utf8(input
)
264 while(++i
< input
.length
)
266 /* Decode utf-16 surrogate pairs */
267 x
= input
.charCodeAt(i
);
268 y
= i
+ 1 < input
.length
? input
.charCodeAt(i
+ 1) : 0;
269 if(0xD800 <= x
&& x
<= 0xDBFF && 0xDC00 <= y
&& y
<= 0xDFFF)
271 x
= 0x10000 + ((x
& 0x03FF) << 10) + (y
& 0x03FF);
275 /* Encode output as utf-8 */
277 output
+= String
.fromCharCode(x
);
279 output
+= String
.fromCharCode(0xC0 | ((x
>>> 6 ) & 0x1F),
282 output
+= String
.fromCharCode(0xE0 | ((x
>>> 12) & 0x0F),
283 0x80 | ((x
>>> 6 ) & 0x3F),
285 else if(x
<= 0x1FFFFF)
286 output
+= String
.fromCharCode(0xF0 | ((x
>>> 18) & 0x07),
287 0x80 | ((x
>>> 12) & 0x3F),
288 0x80 | ((x
>>> 6 ) & 0x3F),
295 * Encode a string as utf-16
297 function str2rstr_utf16le(input
)
300 for(var i
= 0; i
< input
.length
; i
++)
301 output
+= String
.fromCharCode( input
.charCodeAt(i
) & 0xFF,
302 (input
.charCodeAt(i
) >>> 8) & 0xFF);
306 function str2rstr_utf16be(input
)
309 for(var i
= 0; i
< input
.length
; i
++)
310 output
+= String
.fromCharCode((input
.charCodeAt(i
) >>> 8) & 0xFF,
311 input
.charCodeAt(i
) & 0xFF);
316 * Convert a raw string to an array of big-endian words
317 * Characters >255 have their high-byte silently ignored.
319 function rstr2binb(input
)
321 var output
= Array(input
.length
>> 2);
322 for(var i
= 0; i
< output
.length
; i
++)
324 for(var i
= 0; i
< input
.length
* 8; i
+= 8)
325 output
[i
>>5] |= (input
.charCodeAt(i
/ 8) & 0xFF) << (24 - i
% 32);
330 * Convert an array of big-endian words to a string
332 function binb2rstr(input
)
335 for(var i
= 0; i
< input
.length
* 32; i
+= 8)
336 output
+= String
.fromCharCode((input
[i
>>5] >>> (24 - i
% 32)) & 0xFF);
341 * Calculate the SHA-1 of an array of big-endian words, and a bit length
343 function binb_sha1(x
, len
)
346 x
[len
>> 5] |= 0x80 << (24 - len
% 32);
347 x
[((len
+ 64 >> 9) << 4) + 15] = len
;
356 for(var i
= 0; i
< x
.length
; i
+= 16)
364 for(var j
= 0; j
< 80; j
++)
366 if(j
< 16) w
[j
] = x
[i
+ j
];
367 else w
[j
] = bit_rol(w
[j
-3] ^ w
[j
-8] ^ w
[j
-14] ^ w
[j
-16], 1);
368 var t
= safe_add(safe_add(bit_rol(a
, 5), sha1_ft(j
, b
, c
, d
)),
369 safe_add(safe_add(e
, w
[j
]), sha1_kt(j
)));
377 a
= safe_add(a
, olda
);
378 b
= safe_add(b
, oldb
);
379 c
= safe_add(c
, oldc
);
380 d
= safe_add(d
, oldd
);
381 e
= safe_add(e
, olde
);
383 return Array(a
, b
, c
, d
, e
);
388 * Perform the appropriate triplet combination function for the current
391 function sha1_ft(t
, b
, c
, d
)
393 if(t
< 20) return (b
& c
) | ((~b
) & d
);
394 if(t
< 40) return b
^ c
^ d
;
395 if(t
< 60) return (b
& c
) | (b
& d
) | (c
& d
);
400 * Determine the appropriate additive constant for the current iteration
404 return (t
< 20) ? 1518500249 : (t
< 40) ? 1859775393 :
405 (t
< 60) ? -1894007588 : -899497514;
409 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
410 * to work around bugs in some JS interpreters.
412 function safe_add(x
, y
)
414 var lsw
= (x
& 0xFFFF) + (y
& 0xFFFF);
415 var msw
= (x
>> 16) + (y
>> 16) + (lsw
>> 16);
416 return (msw
<< 16) | (lsw
& 0xFFFF);
420 * Bitwise rotate a 32-bit number to the left.
422 function bit_rol(num
, cnt
)
424 return (num
<< cnt
) | (num
>>> (32 - cnt
));
430 <h1 align=CENTER
>Example of Login procedure
</h1>
432 Simple and very unsafe example login page for CGIscriptor.pl. The password is first hashed with the
433 site specific salt (as it is used to store the password on-site). Then it is hashed with a random,
434 one-time salt. Effectively, creating a one-time password. Only the last value is send to the server.
435 The server has both salt values stored. It will ignore anything except the username, hashed password, and
439 The Session Ticket is stored in a cookie with the name
<em>CGIscriptor
</em>.
442 <form method=
"POST" action=
"" id=
"LoginForm"
443 onSubmit='var success=check_username_password();SetSessionCookie();HashPassword(
"<SCRIPT TYPE="text/ssperl
">
444 $RANDOMSALT</SCRIPT>");success'
>
445 <div style=
"margin-left: 30%; margin-right: 30%; text-align: left">
446 Username:
<input type=
"text" name=
"USERNAME" id=
"USERNAME" size=
"20" /><br />
447 Password:
<input type=
"PASSWORD" name=
"PASSWORD" id=
"PASSWORD" size=
"20" /><br />
448 <input type=
"hidden" name=
"SALT" id=
"SALT" value=
"<SCRIPT TYPE="text/ssperl
">$SERVERSALT</SCRIPT>" /><br />
449 <input type=
"hidden" name=
"LOGINTICKET" value=
"<SCRIPT TYPE="text/ssperl
">$LOGINTICKET</SCRIPT>" /><br />
452 <p><input type=
"submit" value=
"Login" /></p>
456 The Salt and Ticket values are all created using SHA1 on
512 Byte of output from
<em>/dev/urandom
</em> in HEX.
458 <FONT STYLE=
"font-size:small">
459 <p> Example Login page for CGIscriptor.pl
<br />
460 Copyright
© 2012 R.J.J.H. van Son
<br />
461 This program is free software: you can redistribute it and/or modify
462 it under the terms of the GNU General Public License as published by
463 the Free Software Foundation, either version
3 of the License, or
464 (at your option) any later version.
465 This program is distributed in the hope that it will be useful,
466 but WITHOUT ANY WARRANTY; without even the implied warranty of
467 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
468 GNU General Public License for more details.
<br />
469 You should have received a copy of the GNU General Public License
470 along with this program. If not, see
<a href=
"http://www.gnu.org/licenses/">http://www.gnu.org/licenses/
</a>.
</p>
471 <p> JavaScript implementation of the Secure Hash Algorithm, SHA-
1, as defined in FIPS
180-
1<br />
472 Copyright
© 2000 -
2009 Paul Johnston, Version
2.2<br />
473 Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
<br />
474 Distributed under the BSD License
<br />
475 See
<a href=
"http://pajhome.org.uk/crypt/md5">http://pajhome.org.uk/crypt/md5
</a> for details.