# Create your views here.
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.models import User
###
### General methods
###
# We need randomly generated salts. This is about 100 bits of entropy.
def generate_salt():
import string, random
randomgen = random.SystemRandom()
salt_chars = "./" + string.ascii_letters + string.digits
return "".join([randomgen.choice(salt_chars) for i in range(0,16)])
# We want to avoid information leakage. For users that don't exist, we need salts to be consistent.
# These "fake" salts are seeded with the username and the django secret_key. They're not as random
# as true salts should be, but they should be indistinguishable to a hacker who isn't sure whether
# or not an account exists.
def generate_fake_salt(I):
import string, random, settings, hashlib
random.seed("%s:%s" % (I, settings.SECRET_KEY))
salt_chars = "./" + string.ascii_letters + string.digits
salt = "".join([random.choice(salt_chars) for i in range(0,16)])
return salt, int(hashlib.sha256("%s:%s" % (salt, settings.SECRET_KEY)).hexdigest(), 16)
# In upgrades, we'll need to decrypt some AES data
def decrypt(c, key, plen):
from srp import aes
import base64
moo = aes.AESModeOfOperation()
cypherkey = map(ord, key.decode("hex"))
ciphertext = base64.b64decode(c.replace("_", "+"))
iv = map(ord, ciphertext[:16])
ciphertext= map(ord, ciphertext[16:])
return moo.decrypt(ciphertext, 0, moo.modeOfOperation["CFB"], cypherkey, len(cypherkey), iv)[:plen]
def generate_verifier(salt, username, password):
import hashlib
x = int(hashlib.sha256(salt + hashlib.sha256("%s:%s" % (username, password)).hexdigest()).hexdigest(), 16)
return hex(pow(2, x, 125617018995153554710546479714086468244499594888726646874671447258204721048803))[2:-1]
def login_page(request):
from django.shortcuts import render_to_response
return render_to_response('login.html', \
{'error': "Invalid username or password" if request.GET["error"] == '1' and not request.user.is_authenticated() else "",\
'static_files': "http://%s/srp-test/javascript" % request.get_host(), \
'srp_url': "http://%s/srp/" % request.get_host()})
def register_page(request):
from django.shortcuts import render_to_response
return render_to_response('register.html',\
{'static_files': "http://%s/srp-test/javascript" % request.get_host(),\
'srp_url': "http://%s/srp/" % request.get_host()})
###
### User Registration
###
# 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 User.objects.filter(username=request.POST["I"]).count() > 0:
return HttpResponse("Username already in use", mimetype="text/xml")
request.session["srp_name"] = request.POST["I"]
request.session["srp_salt"] = generate_salt()
return HttpResponse("%s" % request.session["srp_salt"], mimetype="text/xml")
# 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
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("", mimetype="text/xml");
# Step 3: The client initiates the login process.
###
### User Login
###
# Step 1: The user sends an identifier and public ephemeral key, A
# 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)
request.session["srp_A"] = request.POST["A"]
g = 2
N = 125617018995153554710546479714086468244499594888726646874671447258204721048803
k = 88846390364205216646376352624313659232912717719075174937149043299744712465496
upgrade = False
if A % N == 0:
return HttpResponse("Invalid ephemeral key.", mimetype="text/xml")
else:
try:
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
v = generate_verifier(salt, user.username, hashpass)
# We don't want to leak that the username doesn't exist. Make up a fake salt and verifier.
except User.DoesNotExist:
salt, x = generate_fake_salt(request.POST["I"])
v = pow(g, x, N)
# Ensure that B%N != 0
while True:
b = randomgen.getrandbits(32)
B = k*v + pow(g,b,N)
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
# 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])
request.session["srp_M"] = hashlib.sha256(Mstr).hexdigest()
response = "" % (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
user = authenticate(username=request.session["srp_I"], M=(request.POST["M"], request.session["srp_M"]))
if user:
response = "%s" % hashlib.sha256("%s%s%s" % (request.session["srp_A"], request.session["srp_M"], request.session["srp_S"])).hexdigest()
login(request, user)
else:
response = "Invalid username or password."
try:
del request.session["srp_I"]
del request.session["srp_M"]
del request.session["srp_S"]
del request.session["srp_A"]
except KeyError:
pass
return HttpResponse(response, mimetype="text/xml")
# Check that the user has generated the correct M
def upgrade_auth(request):
import hashlib
if request.POST["M"] == request.session["srp_M"]:
response = "%s" % 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 = "Invalid username or password."
return HttpResponse(response, mimetype="text/xml")
# Receive the encrypted password, create the verifier, save the user, and notify the client
def upgrade_add_verifier(request):
from srp.models import SRPUser
from django.contrib.auth.models import User
import hashlib
salt = generate_salt()
key = hashlib.sha256(request.session["srp_S"]).hexdigest()
user = User.objects.get(username=request.session["srp_I"])
srpuser = SRPUser()
srpuser.__dict__.update(user.__dict__)
srpuser.verifier = generate_verifier(salt, request.session["srp_I"], decrypt(request.POST["p"], key, int(request.POST["l"])))
srpuser.salt = salt
srpuser.password = ""
srpuser.save()
return HttpResponse("", mimetype="text/xml")
# If a user has posted their username and password, we'll go ahead and authenticate them
def no_javascript(request):
from django.contrib.auth.models import User
from srp.models import SRPUser
from django.contrib.auth import login, authenticate
try:
user = User.objects.get(username=request.POST["srp_username"])
try:
v = generate_verifier(user.srpuser.salt, request.POST["srp_username"], request.POST["srp_password"])
user = authenticate(username=request.POST["srp_username"], M=(user.srpuser.verifier, v))
if user:
login(request, user)
if not request.POST["srp_forward"].startswith("#"):
return HttpResponseRedirect(request.POST["srp_forward"])
else:
return HttpResponseRedirect("%s%s" % (request.META["HTTP_REFERER"], request.POST["srp_forward"]))
except SRPUser.DoesNotExist:
if user.check_password(request.POST["srp_password"]):
srpuser = SRPUser()
srpuser.__dict__.update(user.__dict__)
srpuser.salt = generate_salt()
srpuser.verifier = generate_verifier(srpuser.salt, request.POST["srp_username"], request.POST["srp_password"])
srpuser.password = ""
srpuser.save()
if not request.POST["srp_forward"].startswith("#"):
return HttpResponseRedirect(request.POST["srp_forward"])
else:
return HttpResponseRedirect("%s%s" % (request.META["HTTP_REFERER"], request.POST["srp_forward"]))
except User.DoesNotExist:
pass
if "?" in request.META["HTTP_REFERER"]:
if "error=1" in request.META["HTTP_REFERER"]:
return HttpResponseRedirect("%s" % request.META["HTTP_REFERER"])
else:
return HttpResponseRedirect("%s&error=1" % request.META["HTTP_REFERER"])
else:
return HttpResponseRedirect("%s?error=1" % request.META["HTTP_REFERER"])