summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorausiv4 <ausiv4@eb105b4a-77de-11de-a249-6bf219df57d5>2009-07-25 15:33:37 +0000
committerausiv4 <ausiv4@eb105b4a-77de-11de-a249-6bf219df57d5>2009-07-25 15:33:37 +0000
commitebfe7e1cfc90e392112b831a1999ec8569b0354f (patch)
treeb2c8acc6328b0d8ea2e40f2b2bebd6ca5e0a1113
parent24bea39a0932c2123ead106ab7b72e871ace8e25 (diff)
This commit makes major revisions to srp.js. The SRP library now works
as a class. It is instantiated by: var srp = new SRP(username, password, server_type, base_url); Then it is run by calling: srp.register() to register a new user, and srp.identify() to authenticate an existing user. By default, a successful identification pops up an alert reading "Authentication Successful." To change this, set srp.success to a function. For example, srp.success = function() { alert("We win!"); } The same is true for error messages. By default, the SRP library sends the message to the user as an alert box, but web designers can replace the srp.error_message function to handle the error messages differently. The most significant part of making the SRP library into a class is that it cleans up the namespace. Instead of having tons of srp_Variables, we only add the SRP() function to the namespace, and all other variables are either private, public, or protected members of that class. A few minor edits were made to views.py to support logging in with the modified library. I haven't made the modifications to register yet, so it won't work for this revision. Oops.
-rw-r--r--django/srpproject/srp/views.py17
-rw-r--r--javascript/srp.js419
2 files changed, 181 insertions, 255 deletions
diff --git a/django/srpproject/srp/views.py b/django/srpproject/srp/views.py
index 834bce0..7df7ee6 100644
--- a/django/srpproject/srp/views.py
+++ b/django/srpproject/srp/views.py
@@ -36,14 +36,23 @@ def login_page(request):
<script src="http://%s/srp-test/javascript/jsbn2.js"></script>
<script src="http://%s/srp-test/javascript/srp.js"></script>
<script type="text/javascript">
- function srp_success()
+ function login()
+ {
+ var username = document.getElementById("srp_username").value;
+ var password = document.getElementById("srp_password").value;
+ var url = window.location.protocol+"//"+window.location.host+"/srp/";
+ srp = new SRP(username, password, "django", url);
+ srp.success = function()
{
- alert("Authentication successful.");
- }
+ alert("We win");
+ };
+ srp.identify();
+ return false;
+ }
</script>
</head>
<body>
- <form action="." onsubmit="return srp_identify()">
+ <form action="." onsubmit="return login()">
<table>
<tr><td>Username:</td><td><input type="text" id="srp_username" /></td></tr>
<tr><td>Password:</td><td><input type="password" id="srp_password" /></td></tr>
diff --git a/javascript/srp.js b/javascript/srp.js
index 4fcc1c9..d998ad4 100644
--- a/javascript/srp.js
+++ b/javascript/srp.js
@@ -1,264 +1,181 @@
-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()
+function SRP(username, password, ser, base_url)
{
- 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
+ var Nstr = "115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3";
+ var N = new BigInteger(Nstr, 16);
+ var g = new BigInteger("2");
+ var k = new BigInteger("c46d46600d87fef149bd79b81119842f3c20241fda67d06ef412d8f6d9479c58", 16);
+ var rng = new SecureRandom();
+ var a = new BigInteger(32, rng);
+ var A = g.modPow(a, N);
+ var Astr = A.toString(16);
+ var B = null;
+ var Bstr = null;
+ var I = username;
+ var u = null;
+ var p = password;
+ var x = null;
+ var S = null;
+ var K = null;
+ var M = null;
+ var M2 = null;
+ var xhr = null;
+ var url = base_url;
+ var server = ser;
+ var that = this;
+
+ function paths(str)
{
- 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);
+ // For now, str will be the django path
+ // This function will translate for other backends.
+ if(server == "django")
+ {
+ return str;
+ }
}
- else
+ function ajaxRequest(full_url, params, callback)
{
- 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){}
+ if(!xhr)
+ {
+ if( window.XMLHttpRequest)
+ xhr = new XMLHttpRequest();
+ else if (window.ActiveXObject){
+ try{
+ xhr = new ActiveXObject("Microsoft.XMLHTTP");
+ }catch (e){}
+ }
+ else
+ {
+ that.error_message("Ajax not supported.");
+ return;
+ }
+ }
+ if(xhr){
+ xhr.onreadystatechange = callback;
+ xhr.open("POST", full_url, true);
+ xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ xhr.setRequestHeader("Content-length", params.length);
+ xhr.setRequestHeader("Connection", "close");
+
+ xhr.send(params);
+ }
+ else
+ {
+ that.error_message("Ajax failed.");
+ }
}
- else
+
+ this.register = function()
{
- 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
+ var handshake_url = url + paths("register/salt/");
+ var params = "I="+I;
+ ajaxRequest(handshake_url, params, register_receive_salt);
+ };
+ function register_receive_salt()
{
- 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();
+ if(xhr.readyState == 4 && xhr.status == 200) {
+ if(xhr.responseXML.getElementsByTagName("salt").length > 0)
+ {
+ var s = innerxml(xhr.responseXML.getElementsByTagName("salt")[0]);
+ x = new BigInteger(SHA256(s + SHA256(I + ":" + p)), 16);
+ var v = g.modPow(x, N);
+ register_send_verifier(v.toString(16));
+ }
+ else if(xhr.responseXML.getElementsByTagName("error").length > 0)
+ {
+ that.error_message(innerxml(xhr.responseXML.getElementsByTagName("error")[0]));
+ }
}
- }
-};
-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
+ };
+ function register_send_verifier(v)
{
- 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
+ var params = "v="+v;
+ var auth_url = url + paths("register/user/");
+ ajaxRequest(auth_url, params, register_user);
+ };
+ function register_user()
{
- 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
+ if(xhr.readyState == 4 && xhr.status == 200) {
+ if(xhr.responseXML.getElementsByTagName("ok").length > 0)
+ {
+ this.identify();
+ }
+ }
+ };
+
+ function innerxml (node)
{
- 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
+ return node.firstChild.nodeValue;
+ };
+ this.identify = function()
{
- 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);
+ var handshake_url = url + paths("handshake/");
+ var params = "I="+I+"&A="+Astr;
+ ajaxRequest(handshake_url, params, receive_salts);
+ };
+ function receive_salts()
+ {
+ if(xhr.readyState == 4 && xhr.status == 200) {
+ if(xhr.responseXML.getElementsByTagName("r").length > 0)
+ {
+ var response = xhr.responseXML.getElementsByTagName("r")[0];
+ 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.
+ this.identify();
+ }
+ }
+ };
+ function calculations(s, ephemeral)
+ {
+ //S -> C: s | B
+ B = new BigInteger(ephemeral, 16);
+ Bstr = ephemeral;
+ // u = H(A,B)
+ u = new BigInteger(SHA256(Astr + Bstr), 16);
+ // x = H(s, H(I:p))
+ x = new BigInteger(SHA256(s + SHA256(I + ":" + p)), 16);
+ //S = (B - kg^x) ^ (a + ux)
+ var kgx = k.multiply(g.modPow(x, N));
+ var aux = a.add(u.multiply(x));
+ S = B.subtract(kgx).modPow(aux, N);
+ // M = H(H(N) xor H(g), H(I), s, A, B, K)
+ var Mstr = A.toString(16) + B.toString(16) + S.toString(16);
+ M = SHA256(Mstr);
+ send_hash(M);
+ //M2 = H(A, M, K)
+ M2 = SHA256(A.toString(16) + M + S.toString(16));
+ };
+ function send_hash(M)
+ {
+ var params = "M="+M;
+ var auth_url = url+paths("authenticate/");
+ ajaxRequest(auth_url, params, confirm_authentication);
+ };
+ function confirm_authentication()
+ {
+ if(xhr.readyState == 4 && xhr.status == 200) {
+ if(xhr.responseXML.getElementsByTagName("M").length > 0)
+ {
+ if(innerxml(xhr.responseXML.getElementsByTagName("M")[0]) == M2)
+ that.success();
+ else
+ that.error_message("Server key does not match");
+ }
+ else if (xhr.responseXML.getElementsByTagName("error").length > 0)
+ {
+ that.error_message(innerxml(xhr.responseXML.getElementsByTagName("error")[0]));
+ }
+ }
+ };
+ this.success = function()
+ {
+ alert("Authentication successful.");
+ };
+ this.error_message = function(t)
+ {
+ alert(t);
+ };
};