diff options
Diffstat (limited to 'proper-random/javascript/srp.js')
-rw-r--r-- | proper-random/javascript/srp.js | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/proper-random/javascript/srp.js b/proper-random/javascript/srp.js new file mode 100644 index 0000000..4fcc1c9 --- /dev/null +++ b/proper-random/javascript/srp.js @@ -0,0 +1,264 @@ +var srp_N = null; +var srp_Nstr = "115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3"; +var srp_g = null; +var srp_k = null; +var srp_a = null; +var srp_A = null; +var srp_Astr = null; +var srp_b = null; +var srp_B = null; +var srp_Bstr = null; +var srp_I = null; +var srp_u = null; +var srp_p = null; +var srp_x = null; +var srp_S = null; +var srp_K = null; +var srp_M = null; +var srp_M2 = null; +var xhr; +var rng; + +var srp_url = window.location.protocol+"//"+window.location.host+"/srp/"; +function srp_register() +{ + srp_N = new BigInteger(srp_Nstr, 16); + srp_g = new BigInteger("2"); + srp_k = new BigInteger("c46d46600d87fef149bd79b81119842f3c20241fda67d06ef412d8f6d9479c58", 16); + srp_I = document.getElementById("srp_username").value; + srp_register_salt(srp_I); + return false; +}; +function srp_register_salt(I) +{ + if( window.XMLHttpRequest) + xhr = new XMLHttpRequest(); + else if (window.ActiveXObject){ + try{ + xhr = new ActiveXObject("Microsoft.XMLHTTP"); + }catch (e){} + } + else + { + srp_error_message("Ajax not supported."); + return; + } + if(xhr){ + var srp_handshake_url = srp_url + "register/salt/"; + var srp_params = "I="+I; + xhr.onreadystatechange = srp_register_receive_salt; + xhr.open("POST", srp_handshake_url, true); + xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + xhr.setRequestHeader("Content-length", srp_params.length); + xhr.setRequestHeader("Connection", "close"); + + xhr.send(srp_params); + } + else + { + srp_error_message("Ajax failed."); + } +}; +function srp_register_receive_salt() +{ + if(xhr.readyState == 4 && xhr.status == 200) { + if(xhr.responseXML.getElementsByTagName("salt").length > 0) + { + s = innerxml(xhr.responseXML.getElementsByTagName("salt")[0]); + srp_x = srp_calculate_x(s); + v = srp_g.modPow(srp_x, srp_N); + srp_register_send_verifier(v.toString(16)); + } + else if(xhr.responseXML.getElementsByTagName("error").length > 0) + { + srp_error_message(innerxml(xhr.responseXML.getElementsByTagName("error")[0])); + } + } +}; +function srp_register_send_verifier(v) +{ + if( window.XMLHttpRequest) + xhr = new XMLHttpRequest(); + else if (window.ActiveXObject){ + try{ + xhr = new ActiveXObject("Microsoft.XMLHTTP"); + }catch (e){} + } + else + { + srp_error_message("Ajax not supported."); + return; + } + if(xhr){ + var srp_params = "v="+v; + var srp_auth_url = srp_url+ "register/user/"; + + xhr.onreadystatechange = srp_register_user; + xhr.open("POST", srp_auth_url, true); + xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + xhr.setRequestHeader("Content-length", srp_params.length); + xhr.setRequestHeader("Connection", "close"); + + xhr.send(srp_params); + } + else + { + srp_error_message("Ajax failed."); + } +}; +function srp_register_user() +{ + if(xhr.readyState == 4 && xhr.status == 200) { + if(xhr.responseXML.getElementsByTagName("ok").length > 0) + { + srp_identify(); + } + } +}; +function srp_identify() +{ + srp_N = new BigInteger(srp_Nstr, 16); + srp_g = new BigInteger("2"); + srp_k = new BigInteger("c46d46600d87fef149bd79b81119842f3c20241fda67d06ef412d8f6d9479c58", 16); + rng = new SecureRandom(); + srp_a = new BigInteger(32, rng); + // A = g**a % N + srp_A = srp_g.modPow(srp_a, srp_N); + srp_I = document.getElementById("srp_username").value; + + srp_Astr = srp_A.toString(16); + // C -> S: A | I + srp_send_identity(srp_Astr, srp_I); + return false; +}; +function srp_send_identity(Astr, I) +{ + if( window.XMLHttpRequest) + xhr = new XMLHttpRequest(); + else if (window.ActiveXObject){ + try{ + xhr = new ActiveXObject("Microsoft.XMLHTTP"); + }catch (e){} + } + else + { + srp_error_message("Ajax not supported."); + return; + } + if(xhr){ + var srp_handshake_url = srp_url + "handshake/"; + var srp_params = "I="+I+"&A="+Astr; + xhr.onreadystatechange = srp_receive_salts; + xhr.open("POST", srp_handshake_url, true); + xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + xhr.setRequestHeader("Content-length", srp_params.length); + xhr.setRequestHeader("Connection", "close"); + + xhr.send(srp_params); + } + else + { + srp_error_message("Ajax failed."); + } +}; +function srp_receive_salts() +{ + if(xhr.readyState == 4 && xhr.status == 200) { + if(xhr.responseXML.getElementsByTagName("r").length > 0) + { + response = xhr.responseXML.getElementsByTagName("r")[0]; + srp_calculations(response.getAttribute("s"), response.getAttribute("B")); + } + else if(xhr.responseXML.getElementsByTagName("error").length > 0) + { + // This probably means A % N == 0, which means we need to generate + // a new A and reidentify. + srp_identify(); + } + } +}; + +function srp_calculate_x(s) +{ + var p = document.getElementById("srp_password").value; + return new BigInteger(SHA256(s + SHA256(srp_I + ":" + p)), 16); +}; + +function srp_calculations(s, B) +{ + //S -> C: s | B + srp_B = new BigInteger(B, 16); + srp_Bstr = B; + // u = H(A,B) + srp_u = new BigInteger(SHA256(srp_Astr + srp_Bstr), 16); + // x = H(s, H(I:p)) + srp_x = srp_calculate_x(s); + //S = (B - kg^x) ^ (a + ux) + var kgx = srp_k.multiply(srp_g.modPow(srp_x, srp_N)); + var aux = srp_a.add(srp_u.multiply(srp_x)); + srp_S = srp_B.subtract(kgx).modPow(aux, srp_N); + // M = H(H(N) xor H(g), H(I), s, A, B, K) + var Mstr = srp_A.toString(16) + srp_B.toString(16) + srp_S.toString(16); + srp_M = SHA256(Mstr); + srp_send_hash(srp_M); + //M2 = H(A, M, K) + srp_M2 = SHA256(srp_A.toString(16) + srp_M + srp_S.toString(16)); +}; + + +function srp_send_hash(M) +{ + if( window.XMLHttpRequest) + xhr = new XMLHttpRequest(); + else if (window.ActiveXObject){ + try{ + xhr = new ActiveXObject("Microsoft.XMLHTTP"); + }catch (e){} + } + else + { + srp_error_message("Ajax not supported."); + return; + } + if(xhr){ + var srp_params = "M="+M; + var srp_auth_url = srp_url+ "authenticate/"; + + xhr.onreadystatechange = srp_confirm_authentication; + xhr.open("POST", srp_auth_url, true); + xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + xhr.setRequestHeader("Content-length", srp_params.length); + xhr.setRequestHeader("Connection", "close"); + + xhr.send(srp_params); + } + else + { + srp_error_message("Ajax failed."); + } +}; + +function srp_confirm_authentication() +{ + if(xhr.readyState == 4 && xhr.status == 200) { + if(xhr.responseXML.getElementsByTagName("M").length > 0) + { + if(innerxml(xhr.responseXML.getElementsByTagName("M")[0]) == srp_M2) + srp_success(); + else + srp_error_message("Server key does not match"); + } + else if (xhr.responseXML.getElementsByTagName("error").length > 0) + { + srp_error_message(innerxml(xhr.responseXML.getElementsByTagName("error")[0])); + } + } +}; +function innerxml (node) +{ + return node.firstChild.nodeValue; +}; +function srp_error_message(t) +{ + alert(t); +}; |