summaryrefslogtreecommitdiff
path: root/django/srpproject/srp/views.py
diff options
context:
space:
mode:
authorausiv4 <ausiv4@eb105b4a-77de-11de-a249-6bf219df57d5>2009-08-08 20:50:53 +0000
committerausiv4 <ausiv4@eb105b4a-77de-11de-a249-6bf219df57d5>2009-08-08 20:50:53 +0000
commit48c6ab56a73b830c6fcddd32f44636e8b399be85 (patch)
tree0f522e92f9ce0ac810f210f6388246626dd3a8d2 /django/srpproject/srp/views.py
parent29e50956daeadaa6786b7cf34ab96387e5295bb6 (diff)
This adds upgrade functionality so that existing django apps can switch to SRP.
If a user exists in the auth table but not the srp table, the server sends back the algorithm and salt needed to hash the password. The hashed password is used to authenticate the user. After the server authenticates the user and the user verifies the identity of the server, the user sends the password in plaintext. The server uses the plaintext password to calculate the verifier and stores. Finally, the client reinitiates the login process.
Diffstat (limited to 'django/srpproject/srp/views.py')
-rw-r--r--django/srpproject/srp/views.py72
1 files changed, 53 insertions, 19 deletions
diff --git a/django/srpproject/srp/views.py b/django/srpproject/srp/views.py
index 38d5503..8529fa9 100644
--- a/django/srpproject/srp/views.py
+++ b/django/srpproject/srp/views.py
@@ -2,7 +2,7 @@
from django.http import HttpResponse
-from srp import models
+from django.contrib.auth.models import User
###
### General methods
@@ -41,7 +41,7 @@ def register_page(request):
# Step 1. A client submits a username. If the username is available, we generate a salt, store it, and return it.
# Otherwise, we return an error.
def register_salt(request):
- if models.SRPUser.objects.filter(username=request.POST["I"]).count() > 0:
+ if User.objects.filter(username=request.POST["I"]).count() > 0:
return HttpResponse("<error>Username already in use</error>", mimetype="text/xml")
request.session["srp_name"] = request.POST["I"]
request.session["srp_salt"] = generate_salt()
@@ -50,7 +50,8 @@ def register_salt(request):
# Step 2. The client creates the password verifier and sends it to the server, along with a username.
def register_user(request):
from django.contrib import auth
- models.SRPUser(salt=request.session["srp_salt"], username=request.session["srp_name"], verifier=request.POST["v"]).save()
+ from srp.models import SRPUser
+ SRPUser(salt=request.session["srp_salt"], username=request.session["srp_name"], verifier=request.POST["v"]).save()
del request.session["srp_salt"]
del request.session["srp_name"]
return HttpResponse("<ok/>", mimetype="text/xml");
@@ -65,6 +66,7 @@ def register_user(request):
# The server responds with the salt and public ephemeral key, B
def handshake(request):
import random, hashlib
+ from srp.models import SRPUser
randomgen = random.SystemRandom()
request.session["srp_I"] = request.POST["I"]
A = int(request.POST["A"], 16)
@@ -72,15 +74,28 @@ def handshake(request):
g = 2
N = 125617018995153554710546479714086468244499594888726646874671447258204721048803
k = 88846390364205216646376352624313659232912717719075174937149043299744712465496
+ upgrade = False
if A % N == 0:
return HttpResponse("<error>Invalid ephemeral key.</error>", mimetype="text/xml")
else:
try:
- user = models.SRPUser.objects.get(username=request.session["srp_I"])
- salt = user.salt
- v = int(user.verifier, 16)
+ user = User.objects.get(username=request.session["srp_I"])
+ try:
+ user = user.srpuser
+ salt = user.salt
+ v = int(user.verifier, 16)
+ # The auth.User exists, but the SRPUser does not
+ # We need to create an SRPUser to correspond to that auth.User
+ # Initially, the verifier will be based on the known hash of the password
+ except SRPUser.DoesNotExist:
+ salt = generate_salt()
+ algo, dsalt, hashpass = user.password.split("$")
+ upgrade = True
+ x = int(hashlib.sha256(salt + hashlib.sha256(user.username + ":" + hashpass).hexdigest()).hexdigest(), 16)
+ v = pow(2, x, N)
+
# We don't want to leak that the username doesn't exist. Make up a fake salt and verifier.
- except models.SRPUser.DoesNotExist:
+ except User.DoesNotExist:
salt, x = generate_fake_salt(request.POST["I"])
v = pow(g, x, N)
@@ -91,31 +106,26 @@ def handshake(request):
u = int(hashlib.sha256("%s%s" % (hex(A)[2:-1],hex(B)[2:-1])).hexdigest(), 16)
if B % N != 0 and u % N != 0: break
- response = "<r s='%s' B='%s' />" % (salt, hex(B)[2:-1])
# Ideally, we could return this response and then calculate M concurrently with the user
# Unfortunately, django isn't designed to do computations after responding.
# Maybe someone will find a way.
S = pow(A*pow(v,u,N), b, N)
request.session["srp_S"] = hex(S)[2:-1]
Mstr = "%s%s%s" % (hex(A)[2:-1],hex(B)[2:-1],hex(S)[2:-1])
- response = "<r s='%s' B='%s' />" % (salt, hex(B)[2:-1])
request.session["srp_M"] = hashlib.sha256(Mstr).hexdigest()
+ response = "<r s='%s' B='%s'%s />" % (salt, hex(B)[2:-1], " a='%s' d='%s'" % (algo, dsalt) if upgrade else "")
return HttpResponse(response, mimetype="text/xml")
# Step 2: The client sends its proof of S. The server confirms, and sends its proof of S.
def verify(request):
import hashlib
from django.contrib.auth import login, authenticate
- try:
- user = authenticate(username=request.session["srp_I"], M=(request.POST["M"], request.session["srp_M"]))
- if user:
- response = "<M>%s</M>" % hashlib.sha256("%s%s%s" % (request.session["srp_A"], request.session["srp_M"], request.session["srp_S"])).hexdigest()
- login(request, user)
- else:
- response = "<error>Invalid username or password.</error>"
- except models.SRPUser.DoesNotExist:
- # This should only happen when authentication is successful with SRP, but the user isn't in the auth table.
- response = "<error>Authentication failed. This is likely a server problem.</error>"
+ user = authenticate(username=request.session["srp_I"], M=(request.POST["M"], request.session["srp_M"]))
+ if user:
+ response = "<M>%s</M>" % hashlib.sha256("%s%s%s" % (request.session["srp_A"], request.session["srp_M"], request.session["srp_S"])).hexdigest()
+ login(request, user)
+ else:
+ response = "<error>Invalid username or password.</error>"
try:
del request.session["srp_I"]
@@ -125,3 +135,27 @@ def verify(request):
except KeyError:
pass
return HttpResponse(response, mimetype="text/xml")
+
+def upgrade_auth(request):
+ import hashlib
+ if request.POST["M"] == request.session["srp_M"]:
+ response = "<M>%s</M>" % hashlib.sha256("%s%s%s" % (request.session["srp_A"], request.session["srp_M"], request.session["srp_S"])).hexdigest()
+ request.session["srp_preauth"] = True
+ else:
+ response = "<error>Invalid username or password.</error>"
+ return HttpResponse(response, mimetype="text/xml")
+
+def upgrade_add_verifier(request):
+ from srp.models import SRPUser
+ from django.contrib.auth.models import User
+ import hashlib
+ salt = generate_salt()
+ x = int(hashlib.sha256(salt + hashlib.sha256("%s:%s" % (request.session["srp_I"], request.POST["p"])).hexdigest()).hexdigest(), 16)
+ user = User.objects.get(username=request.session["srp_I"])
+ srpuser = SRPUser()
+ srpuser.__dict__.update(user.__dict__)
+ srpuser.verifier = hex(pow(2, x, 125617018995153554710546479714086468244499594888726646874671447258204721048803))[2:-1]
+ srpuser.salt = salt
+ srpuser.password = ""
+ srpuser.save()
+ return HttpResponse("<ok/>", mimetype="text/xml")