41
41
from urllib .parse import urlencode , parse_qs
42
42
import requests
43
43
from Cryptodome .Cipher import AES
44
- from Cryptodome .Hash import SHA
44
+ from Cryptodome .Hash import SHA256
45
45
from Cryptodome import Random
46
46
import time
47
47
@@ -75,15 +75,19 @@ def login(request):
75
75
s = "t=%s&%s" % (int (time .time ()), urlencode ({'r' : request .GET ['next' ]}))
76
76
# Now encrypt it
77
77
r = Random .new ()
78
- iv = r .read (16 )
79
- encryptor = AES .new (SHA .new (settings .SECRET_KEY .encode ('ascii' )).digest ()[:16 ], AES .MODE_CBC , iv )
80
- cipher = encryptor .encrypt (s .encode ('ascii' ) + b' ' * (16 - (len (s ) % 16 ))) # pad to 16 bytes
81
-
82
- return HttpResponseRedirect ("%s?d=%s$%s" % (
83
- settings .PGAUTH_REDIRECT ,
84
- base64 .b64encode (iv , b"-_" ).decode ('utf8' ),
85
- base64 .b64encode (cipher , b"-_" ).decode ('utf8' ),
86
- ))
78
+ nonce = r .read (16 )
79
+ encryptor = AES .new (
80
+ SHA256 .new (settings .SECRET_KEY .encode ('ascii' )).digest ()[:32 ], AES .MODE_SIV , nonce = nonce
81
+ )
82
+ cipher , tag = encryptor .encrypt_and_digest (s .encode ('ascii' ))
83
+
84
+ return HttpResponseRedirect ("%s?%s" % (settings .PGAUTH_REDIRECT , urlencode ({
85
+ 'd' : '$' .join ((
86
+ base64 .urlsafe_b64encode (nonce ).decode ('utf8' ),
87
+ base64 .urlsafe_b64encode (cipher ).decode ('utf8' ),
88
+ base64 .urlsafe_b64encode (tag ).decode ('utf8' ),
89
+ )),
90
+ })))
87
91
else :
88
92
return HttpResponseRedirect (settings .PGAUTH_REDIRECT )
89
93
@@ -103,17 +107,24 @@ def auth_receive(request):
103
107
# This was a logout request
104
108
return HttpResponseRedirect ('/' )
105
109
106
- if 'i ' not in request .GET :
107
- return HttpResponse ("Missing IV in url!" , status = 400 )
110
+ if 'n ' not in request .GET :
111
+ return HttpResponse ("Missing nonce in url!" , status = 400 )
108
112
if 'd' not in request .GET :
109
113
return HttpResponse ("Missing data in url!" , status = 400 )
114
+ if 't' not in request .GET :
115
+ return HttpResponse ("Missing tag in url!" , status = 400 )
110
116
111
117
# Set up an AES object and decrypt the data we received
112
118
try :
113
- decryptor = AES .new (base64 .b64decode (settings .PGAUTH_KEY ),
114
- AES .MODE_CBC ,
115
- base64 .b64decode (str (request .GET ['i' ]), "-_" ))
116
- s = decryptor .decrypt (base64 .b64decode (str (request .GET ['d' ]), "-_" )).rstrip (b' ' ).decode ('utf8' )
119
+ decryptor = AES .new (
120
+ base64 .b64decode (settings .PGAUTH_KEY ),
121
+ AES .MODE_SIV ,
122
+ nonce = base64 .urlsafe_b64decode (str (request .GET ['n' ])),
123
+ )
124
+ s = decryptor .decrypt_and_verify (
125
+ base64 .urlsafe_b64decode (str (request .GET ['d' ])),
126
+ base64 .urlsafe_b64decode (str (request .GET ['t' ])),
127
+ ).rstrip (b' ' ).decode ('utf8' )
117
128
except UnicodeDecodeError :
118
129
return HttpResponse ("Badly encoded data found" , 400 )
119
130
except Exception :
@@ -200,11 +211,16 @@ def auth_receive(request):
200
211
# Finally, check of we have a data package that tells us where to
201
212
# redirect the user.
202
213
if 'd' in data :
203
- (ivs , datas ) = data ['d' ][0 ].split ('$' )
204
- decryptor = AES .new (SHA .new (settings .SECRET_KEY .encode ('ascii' )).digest ()[:16 ],
205
- AES .MODE_CBC ,
206
- base64 .b64decode (ivs , b"-_" ))
207
- s = decryptor .decrypt (base64 .b64decode (datas , "-_" )).rstrip (b' ' ).decode ('utf8' )
214
+ (nonces , datas , tags ) = data ['d' ][0 ].split ('$' )
215
+ decryptor = AES .new (
216
+ SHA256 .new (settings .SECRET_KEY .encode ('ascii' )).digest ()[:32 ],
217
+ AES .MODE_SIV ,
218
+ nonce = base64 .urlsafe_b64decode (nonces ),
219
+ )
220
+ s = decryptor .decrypt_and_verify (
221
+ base64 .urlsafe_b64decode (datas ),
222
+ base64 .urlsafe_b64decode (tags ),
223
+ ).rstrip (b' ' ).decode ('utf8' )
208
224
try :
209
225
rdata = parse_qs (s , strict_parsing = True )
210
226
except ValueError :
@@ -304,17 +320,24 @@ def user_search(searchterm=None, userid=None):
304
320
r = requests .get (
305
321
'{0}search/' .format (settings .PGAUTH_REDIRECT ),
306
322
params = q ,
323
+ timeout = 10 ,
307
324
)
308
325
if r .status_code != 200 :
309
326
return []
310
327
311
- (ivs , datas ) = r .text .encode ('utf8' ).split (b'&' )
328
+ (nonces , datas , tags ) = r .text .encode ('utf8' ).split (b'&' )
312
329
313
330
# Decryption time
314
- decryptor = AES .new (base64 .b64decode (settings .PGAUTH_KEY ),
315
- AES .MODE_CBC ,
316
- base64 .b64decode (ivs , "-_" ))
317
- s = decryptor .decrypt (base64 .b64decode (datas , "-_" )).rstrip (b' ' ).decode ('utf8' )
331
+ decryptor = AES .new (
332
+ base64 .b64decode (settings .PGAUTH_KEY ),
333
+ AES .MODE_SIV ,
334
+ nonce = base64 .urlsafe_b64decode (nonces )
335
+ )
336
+ s = decryptor .decrypt_and_verify (
337
+ base64 .urlsafe_b64decode (datas ),
338
+ base64 .urlsafe_b64decode (tags ),
339
+ ).rstrip (b' ' ).decode ('utf8' )
340
+
318
341
j = json .loads (s )
319
342
320
343
return j
0 commit comments