from urllib.parse import urlencode, parse_qs
import requests
from Cryptodome.Cipher import AES
-from Cryptodome.Hash import SHA
+from Cryptodome.Hash import SHA256
from Cryptodome import Random
import time
s = "t=%s&%s" % (int(time.time()), urlencode({'r': request.GET['next']}))
# Now encrypt it
r = Random.new()
- iv = r.read(16)
- encryptor = AES.new(SHA.new(settings.SECRET_KEY.encode('ascii')).digest()[:16], AES.MODE_CBC, iv)
- cipher = encryptor.encrypt(s.encode('ascii') + b' ' * (16 - (len(s) % 16))) # pad to 16 bytes
-
- return HttpResponseRedirect("%s?d=%s$%s" % (
- settings.PGAUTH_REDIRECT,
- base64.b64encode(iv, b"-_").decode('utf8'),
- base64.b64encode(cipher, b"-_").decode('utf8'),
- ))
+ nonce = r.read(16)
+ encryptor = AES.new(
+ SHA256.new(settings.SECRET_KEY.encode('ascii')).digest()[:32], AES.MODE_SIV, nonce=nonce
+ )
+ cipher, tag = encryptor.encrypt_and_digest(s.encode('ascii'))
+
+ return HttpResponseRedirect("%s?%s" % (settings.PGAUTH_REDIRECT, urlencode({
+ 'd': '$'.join((
+ base64.urlsafe_b64encode(nonce).decode('utf8'),
+ base64.urlsafe_b64encode(cipher).decode('utf8'),
+ base64.urlsafe_b64encode(tag).decode('utf8'),
+ )),
+ })))
else:
return HttpResponseRedirect(settings.PGAUTH_REDIRECT)
# This was a logout request
return HttpResponseRedirect('/')
- if 'i' not in request.GET:
- return HttpResponse("Missing IV in url!", status=400)
+ if 'n' not in request.GET:
+ return HttpResponse("Missing nonce in url!", status=400)
if 'd' not in request.GET:
return HttpResponse("Missing data in url!", status=400)
+ if 't' not in request.GET:
+ return HttpResponse("Missing tag in url!", status=400)
# Set up an AES object and decrypt the data we received
try:
- decryptor = AES.new(base64.b64decode(settings.PGAUTH_KEY),
- AES.MODE_CBC,
- base64.b64decode(str(request.GET['i']), "-_"))
- s = decryptor.decrypt(base64.b64decode(str(request.GET['d']), "-_")).rstrip(b' ').decode('utf8')
+ decryptor = AES.new(
+ base64.b64decode(settings.PGAUTH_KEY),
+ AES.MODE_SIV,
+ nonce=base64.urlsafe_b64decode(str(request.GET['n'])),
+ )
+ s = decryptor.decrypt_and_verify(
+ base64.urlsafe_b64decode(str(request.GET['d'])),
+ base64.urlsafe_b64decode(str(request.GET['t'])),
+ ).rstrip(b' ').decode('utf8')
except UnicodeDecodeError:
return HttpResponse("Badly encoded data found", 400)
except Exception:
# Finally, check of we have a data package that tells us where to
# redirect the user.
if 'd' in data:
- (ivs, datas) = data['d'][0].split('$')
- decryptor = AES.new(SHA.new(settings.SECRET_KEY.encode('ascii')).digest()[:16],
- AES.MODE_CBC,
- base64.b64decode(ivs, b"-_"))
- s = decryptor.decrypt(base64.b64decode(datas, "-_")).rstrip(b' ').decode('utf8')
+ (nonces, datas, tags) = data['d'][0].split('$')
+ decryptor = AES.new(
+ SHA256.new(settings.SECRET_KEY.encode('ascii')).digest()[:32],
+ AES.MODE_SIV,
+ nonce=base64.urlsafe_b64decode(nonces),
+ )
+ s = decryptor.decrypt_and_verify(
+ base64.urlsafe_b64decode(datas),
+ base64.urlsafe_b64decode(tags),
+ ).rstrip(b' ').decode('utf8')
try:
rdata = parse_qs(s, strict_parsing=True)
except ValueError:
r = requests.get(
'{0}search/'.format(settings.PGAUTH_REDIRECT),
params=q,
+ timeout=10,
)
if r.status_code != 200:
return []
- (ivs, datas) = r.text.encode('utf8').split(b'&')
+ (nonces, datas, tags) = r.text.encode('utf8').split(b'&')
# Decryption time
- decryptor = AES.new(base64.b64decode(settings.PGAUTH_KEY),
- AES.MODE_CBC,
- base64.b64decode(ivs, "-_"))
- s = decryptor.decrypt(base64.b64decode(datas, "-_")).rstrip(b' ').decode('utf8')
+ decryptor = AES.new(
+ base64.b64decode(settings.PGAUTH_KEY),
+ AES.MODE_SIV,
+ nonce=base64.urlsafe_b64decode(nonces)
+ )
+ s = decryptor.decrypt_and_verify(
+ base64.urlsafe_b64decode(datas),
+ base64.urlsafe_b64decode(tags),
+ ).rstrip(b' ').decode('utf8')
+
j = json.loads(s)
return j