var READY_STATE_COMPLETE = 4;

var ARROW_CLASS = 'prepend-10 span-4 append-10';
var SERVER_CLASS = 'prepend-14 span-10';
var CLIENT_CLASS = 'span-10 append-14';

var http_request = null;
var fname = null;
var p = null;
var no_key_len = null;
var p_1 = null;
var u1 = null;
var q1 = null;
var steps_div = null;

var href = location.href;
var url = href.replace(/^((http[s]?):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$/,"$2://$3$4");
var nokey_url = url + "nokey.php";

var pass;
var client_num = 0;
var server_num = 0;
var arrow_num = 0;

// Function that clear all the content of steps div
function clear_steps(){
	var steps_div = document.getElementById('steps');
	steps_div.innerHTML = "";
}

function create_div(type, text){
	var class_div1;
	var class_div2;
	var id_div2;
	switch(type){
		case 'client':
			client_num++;
		        class_div1 = CLIENT_CLASS;
			class_div2 = 'client';
			id_div2 = class_div2 + '-' + client_num;
			break;
		case 'server':
			server_num++;
			class_div1 = SERVER_CLASS;
			class_div2 = 'server';
			id_div2 = class_div2 + '-' + server_num;
			break;
		case 'arrow':
			arrow_num++;
			class_div1 = ARROW_CLASS;
			class_div2 = 'arrow';
			id_div2 = class_div2 + '-' + arrow_num;
			break;
	}
	var newdiv1 = document.createElement('div');
	newdiv1.setAttribute('class', class_div1);
	var newdiv2 = document.createElement('div');
	newdiv2.setAttribute('class', class_div2);
	newdiv2.setAttribute('id', id_div2);
	newdiv2.innerHTML = text;
	newdiv1.appendChild(newdiv2);

	return newdiv1;
}

function login(){
	clear_steps();

	// Show the top header
	document.getElementById('topsteps').style.visibility="visible";

	// Get password value
	pass = document.getElementById("user_pass").value;

	// Get steps_div
	var steps_div = document.getElementById('steps');

	// client-1 div
	var text_client_1 = "<ul><li>The browser sends the password to the server.</li></ul>";
	var client_div = create_div('client',text_client_1);
	steps_div.appendChild(client_div);

	// arrow-1 div
	var text_arrow_1 = "<img src='images/l_arrow-1.jpg' alt='--- sends the password in plain text' />";
	var arrow1_div = create_div('arrow',text_arrow_1);
	steps_div.appendChild(arrow1_div);

	// server-1 div
	var text_server_1 = "<ul><li>The server receives the password <i>'" + pass + "'</i> in plain text</li>"
		+ "<li>User authentication</li></ul>";
	var server_div = create_div('server', text_server_1);
	steps_div.appendChild(server_div); 
}

// Function that converts a string to hexadecimal
function str2hex(str){
    var r="";
    var e=str.length;
    var c=0;
    var h;
    while(c<e){
        h=str.charCodeAt(c++).toString(16);
        while(h.length<2) h="0"+h;
        r+=h;
    }
    return r;
}

// Function that creates a XMLHttpRequest object
function init_xhr() {
    if(window.XMLHttpRequest) {
	return new XMLHttpRequest();
    }
    else if(window.ActiveXObject) {
	return new ActiveXObject("Microsoft.XMLHTTP");
    }
}

// Function that implements the client-side of Shamir's No Key protocol
function safe_login() {
	clear_steps();

	// Show the top header
	document.getElementById('topsteps').style.visibility="visible";

	// Get steps_div
	steps_div = document.getElementById('steps');

	// client-1 div
        var client1_text = "<ul><li>The browser requests the <i>modulus <strong>p</strong></i></li></ul>";
	var client1_div = create_div('client',client1_text);
        steps_div.appendChild(client1_div);

        // arrow-1 div
	var text_arrow1 = "<img src='images/sl_arrow-1.jpg' alt='--- requests p --->' />";
	var arrow1_div = create_div('arrow', text_arrow1);
        steps_div.appendChild(arrow1_div);
	
	
	// Init XMLHttpRequest
	http_request = init_xhr();
	if(http_request) {
		http_request.onreadystatechange = step_1;
		http_request.open("POST", nokey_url, true);
		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		var query_string = "step=1&nocache=" + Math.random(); // the 'nocache' param is used to avoid 
								      // the browser cache and to force it
								      // to request to the server
	http_request.send(query_string);
	} else {
		alert("XMLHttpRequest Error");
	}
}

// Function that chooses a random number 'u1', which is a unit modulo 'p-1' and
// computes 'q1 = k^u1 mod(p)'. Then sends 'q1' to the server.
function step_1() {
    if(http_request.readyState == READY_STATE_COMPLETE) {
	if(http_request.status == 200) {
	    // The server provides the tmpdir and the modulus 'p'
	    var json_response = http_request.responseText;
	    var json_object = eval("("+json_response+")");
	    fname = json_object.tmpdir;
	    p = json_object.p;
	    no_key_len = p.length * 4; // p bit-length
	    p = new BigInteger(p,16);
	    var p_str = p.toString(16).toUpperCase();

	    // server1 div
	    var text_server1 = "<ul><li>The server generates the prime <strong>p</strong> (or reads it from a config file)"
		+ "<br/><span class='formula'><strong>p</strong>=" + p_str + "</span></li></ul>";
	    var server1_div = create_div('server', text_server1);
	    steps_div.appendChild(server1_div);

	    // arrow-2 div
	    var text_arrow2 = "<img src='images/sl_arrow-2.jpg' alt='<--- responses p ---' />";
	    var arrow2_div = create_div('arrow', text_arrow2);
	    steps_div.appendChild(arrow2_div);

	    // u1: random number between 0 and p-1
	    var rng = new SecureRandom();
	    var no_key_len_bytes = no_key_len/8;
	    var x = new Array(no_key_len_bytes);
	    rng.nextBytes(x);
	    u1 = new BigInteger(x);
	    p_1 = p.subtract(BigInteger.ONE);
 	    u1 = u1.mod(p_1);

 	    // u1 y p-1 (relative primes)
 	    var gcd = u1.gcd(p_1);
	    var gcds = gcd.toString(16);
 	    while (gcds != "1"){
 	    	u1 = u1.add(BigInteger.ONE);
 	    	gcd = u1.gcd(p_1);
		gcds = gcd.toString(16);
 	    }

 	    // Converts the 'plain-key' to hex
	    pass = document.getElementById("user_pass").value;
 	    var pass_hex = str2hex(pass);
 	    var K = new BigInteger(pass_hex,16);

 	    // q1 = K^u1 mod(p)
	    q1 = K.modPow(u1,p);
	   
	    // client-2 div
	    var text_client2 = "<ul><li>Chooses <span class='formula'>0&lt;=u1&lt;p</span><br/>"
		+ "<span class='formula'><strong>u1</strong>=" + u1.toString(16).toUpperCase() + "</span><br/></li>"
		+ "<li>Converts the password '<i>" + pass + "</i>' to hex <br/>"
		+ "<span class='formula'><strong>k</strong>=" + pass_hex.toUpperCase() + "</span><br/></li>"
		+ "<li>Computes <span class='formula'>q1=k^u1 mod(p)</span><br/>"
		+ "<span class='formula'><strong>q1</strong>=" + q1.toString(16).toUpperCase() + "</span><br/></li></ul>"; 
	    var client2_div = create_div('client', text_client2);
	    steps_div.appendChild(client2_div);

	    // arrow-3
	    var text_arrow3 = "<img src='images/sl_arrow-3.jpg' alt='--- sends q1 --->' />"
	    var arrow3_div = create_div('arrow', text_arrow3);
	    steps_div.appendChild(arrow3_div);

	    // Go to step_2
	    http_request = init_xhr();
 	    if(http_request) {
 		http_request.onreadystatechange = step_2;
 		http_request.open("POST", nokey_url, true);
 		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 		var query_string = "step=2&tmpdir=" + fname + "&q1=" + q1.toString(16) + "&nocache=" + Math.random();
 		http_request.send(query_string);
 	    } else {
 		alert("XMLHttpRequest Error");
 	    }

	}
    }
}

// Function that computes 'v1 = 1/u1 mod(p-1)' and sends 'q3 = q2^v1 mod(p)'
// to the server
function step_2(){
    if(http_request.readyState == READY_STATE_COMPLETE) {
	if(http_request.status == 200) {
	    // Receives tmpdir y q2
	    var json_response = http_request.responseText;
	    var json_object = eval("("+json_response+")");
	    fname = json_object.tmpdir;
	    var q2 = json_object.q2;
	    q2 = new BigInteger(q2,16);
	    var q2_str = q2.toString(16).toUpperCase();

            // server-2
            var text_server2 = "<ul><li>Chooses <span class='formula'>0&lt;=u2&lt;p</span></li>"
		+ "<li>Computes <span class='formula'>q2=q1^u2 mod(p)</span><br/> "
		+ "<span class='formula'><strong>q1</strong></i>=" + q2_str + "</span></li></ul>";
	    var server2_div = create_div('server', text_server2);
	    steps_div.appendChild(server2_div);

	    // arrow-4
            var text_arrow4 = "<img src='images/sl_arrow-4.jpg' alt='<--- sends q2 ---' />";
	    var arrow4_div = create_div('arrow', text_arrow4);
            steps_div.appendChild(arrow4_div);

            // Computes v1 and send q3
	    var v1 = u1.modInverse(p_1);
	    var q3 = q2.modPow(v1,p);

	    // client-3
	    var text_client3 = "<ul><li>Computes <span class='formula'>v1=1/u1 mod(p-1)</span><br/>"
		+ "<span class='formula'><strong>v1</strong></i>=" + v1.toString(16).toUpperCase() + "</span></li>"
		+ "<li>Computes <span class='formula'>q3=q2^v1 mod(p)</span><br/>" 
		+ "<span class='formula'><strong>q3</strong></i>=" + q3.toString(16).toUpperCase() + "</span></li></ul>";
	    var client3_div = create_div('client', text_client3);
	    steps_div.appendChild(client3_div);

	    // get username
	    var user = document.getElementById("user_login").value;

	    // Go to step_3
	    http_request = init_xhr();
 	    if(http_request) {
 		http_request.onreadystatechange = step_3;
 		http_request.open("POST", nokey_url, true);
 		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 		var query_string = "step=3&user=" + user + "&tmpdir=" + fname + "&q3=" + q3.toString(16) + "&end=1&nocache=" + Math.random();
 		http_request.send(query_string);
 	   } else {
 		alert("XMLHttpRequest Error");
 	    }
	}
    }
}

// Function that receives if the user and password are valid and redirects to
// the index page (valid) or show a error message (invalid)
function step_3(){
    if(http_request.readyState == READY_STATE_COMPLETE) {
	if(http_request.status == 200) {

            // Receive user authentication
            var json_response = http_request.responseText;
            var json_object = eval("("+json_response+")");
            var valid_user = json_object.valid_user;

	    // arrow-5
            var text_arrow5 = "<img src='images/sl_arrow-5.jpg' alt='--- sends q3 --->' />";
	    var arrow5_div = create_div('arrow', text_arrow5);
            steps_div.appendChild(arrow5_div);


	    // server-3 div
	    var text_server3 = "<ul><li>Computes <span class='formula'>v2=1/u2 mod(p-1)</span></li>"
		+ "<li>Computes <span class='formula'>q4=q3^v2 mod(p)</span></li>"
		+ "<li>By Fermat's little theorem, <span class='formula'>q4=k mod(p)</span></li>"
		+ "<li>User authentication: ";
	    if(valid_user == 1){
		var text_server3 = text_server3 + "Login OK</li></ul>";
            } else {
		var text_server3 = text_server3 + "Wrong username/password</li></ul>";
	    }

	    var server3_div = create_div('server', text_server3);
	    steps_div.appendChild(server3_div);

	    // arrow-6 div
	    var text_arrow6 = "<img src='images/sl_arrow-6.jpg' alt='<--------------' />";
	    var arrow6_div = create_div('arrow', text_arrow6);
	    steps_div.appendChild(arrow6_div);

	    // client-4 div
	    if(valid_user == 1){
		var text_client4 = "<ul><li>Main page</li></ul>";
	    } else {
		var text_client4 = "<ul><li>Login page</li></ul>";
	    }
	    var client4_div = create_div ('client', text_client4);
	    steps_div.appendChild(client4_div);

	}
    }
}


