| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
''' |
|---|
| 9 |
Following document was copied from <http://srp.stanford.edu/design.html>. |
|---|
| 10 |
----- |
|---|
| 11 |
SRP Protocol Design |
|---|
| 12 |
|
|---|
| 13 |
SRP is the newest addition to a new class of strong authentication protocols that resist all the well-known passive and active attacks over the network. SRP borrows some elements from other key-exchange and identification protcols and adds some subtle modifications and refinements. The result is a protocol that preserves the strength and efficiency of the EKE family protocols while fixing some of their shortcomings. |
|---|
| 14 |
|
|---|
| 15 |
The following is a description of SRP-6 and 6a, the latest versions of SRP: |
|---|
| 16 |
|
|---|
| 17 |
N A large safe prime (N = 2q+1, where q is prime) |
|---|
| 18 |
All arithmetic is done modulo N. |
|---|
| 19 |
g A generator modulo N |
|---|
| 20 |
k Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6) |
|---|
| 21 |
s User's salt |
|---|
| 22 |
I Username |
|---|
| 23 |
p Cleartext Password |
|---|
| 24 |
H() One-way hash function |
|---|
| 25 |
^ (Modular) Exponentiation |
|---|
| 26 |
u Random scrambling parameter |
|---|
| 27 |
a,b Secret ephemeral values |
|---|
| 28 |
A,B Public ephemeral values |
|---|
| 29 |
x Private key (derived from p and s) |
|---|
| 30 |
v Password verifier |
|---|
| 31 |
|
|---|
| 32 |
The host stores passwords using the following formula: |
|---|
| 33 |
|
|---|
| 34 |
x = H(s, p) (s is chosen randomly) |
|---|
| 35 |
v = g^x (computes password verifier) |
|---|
| 36 |
|
|---|
| 37 |
The host then keeps {I, s, v} in its password database. The authentication protocol itself goes as follows: |
|---|
| 38 |
|
|---|
| 39 |
User -> Host: I, A = g^a (identifies self, a = random number) |
|---|
| 40 |
Host -> User: s, B = kv + g^b (sends salt, b = random number) |
|---|
| 41 |
|
|---|
| 42 |
Both: u = H(A, B) |
|---|
| 43 |
|
|---|
| 44 |
User: x = H(s, p) (user enters password) |
|---|
| 45 |
User: S = (B - kg^x) ^ (a + ux) (computes session key) |
|---|
| 46 |
User: K = H(S) |
|---|
| 47 |
|
|---|
| 48 |
Host: S = (Av^u) ^ b (computes session key) |
|---|
| 49 |
Host: K = H(S) |
|---|
| 50 |
|
|---|
| 51 |
Now the two parties have a shared, strong session key K. To complete authentication, they need to prove to each other that their keys match. One possible way: |
|---|
| 52 |
|
|---|
| 53 |
User -> Host: M = H(H(N) xor H(g), H(I), s, A, B, K) |
|---|
| 54 |
Host -> User: H(A, M, K) |
|---|
| 55 |
|
|---|
| 56 |
The two parties also employ the following safeguards: |
|---|
| 57 |
|
|---|
| 58 |
1. The user will abort if he receives B == 0 (mod N) or u == 0. |
|---|
| 59 |
2. The host will abort if it detects that A == 0 (mod N). |
|---|
| 60 |
3. The user must show his proof of K first. If the server detects that the user's proof is incorrect, it must abort without showing its own proof of K. |
|---|
| 61 |
|
|---|
| 62 |
See http://srp.stanford.edu/ for more information. |
|---|
| 63 |
|
|---|
| 64 |
----- |
|---|
| 65 |
>>> user = 'user' |
|---|
| 66 |
>>> passphrase = 'passphrase' |
|---|
| 67 |
>>> (salt, verifier, bits) = newVerifier(user, passphrase, 1024) |
|---|
| 68 |
>>> cl = Client(user, passphrase, bits) |
|---|
| 69 |
>>> sv = Server(user, salt, verifier, bits) |
|---|
| 70 |
>>> A = cl.seed() |
|---|
| 71 |
>>> B = sv.seed() |
|---|
| 72 |
>>> clientProof = cl.proof(salt, B) |
|---|
| 73 |
>>> serverProof = sv.proof(A, clientProof) |
|---|
| 74 |
>>> clientKey = cl.key(serverProof) |
|---|
| 75 |
>>> serverKey = sv.key() |
|---|
| 76 |
>>> clientKey == serverKey |
|---|
| 77 |
True |
|---|
| 78 |
''' |
|---|
| 79 |
|
|---|
| 80 |
import sha |
|---|
| 81 |
import hmac |
|---|
| 82 |
import random |
|---|
| 83 |
|
|---|
| 84 |
__all__ = [ |
|---|
| 85 |
'newVerifier', |
|---|
| 86 |
'primeID', |
|---|
| 87 |
'primeID_size', |
|---|
| 88 |
'Client', |
|---|
| 89 |
'Server', |
|---|
| 90 |
'Error', |
|---|
| 91 |
'NotSupported', |
|---|
| 92 |
'ImproperKeyValue', |
|---|
| 93 |
'AuthFailure' |
|---|
| 94 |
] |
|---|
| 95 |
|
|---|
| 96 |
|
|---|
| 97 |
saltlen = 16 |
|---|
| 98 |
ablen = 256 |
|---|
| 99 |
|
|---|
| 100 |
|
|---|
| 101 |
class Error(Exception): |
|---|
| 102 |
'Exception base class for this module.' |
|---|
| 103 |
class NotSupported(Error): |
|---|
| 104 |
'Given parameter is not supported.' |
|---|
| 105 |
class ImproperKeyValue(Error): |
|---|
| 106 |
'Exception indicates that the given key is improper.' |
|---|
| 107 |
class AuthFailure(Error): |
|---|
| 108 |
'Exception indicates authentication failure.' |
|---|
| 109 |
|
|---|
| 110 |
|
|---|
| 111 |
def newVerifier(user, passphrase, bits=1024): |
|---|
| 112 |
return SRP(bits).newVerifier(user, passphrase) + (bits,) |
|---|
| 113 |
|
|---|
| 114 |
def primeID(bits=1024): |
|---|
| 115 |
return SRP(bits).primeID() |
|---|
| 116 |
|
|---|
| 117 |
primeID_size = sha.digest_size |
|---|
| 118 |
|
|---|
| 119 |
|
|---|
| 120 |
|
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 |
pflist = { |
|---|
| 124 |
1024 : (2L, 0xEEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3), |
|---|
| 125 |
1536 : (2L, 0x9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB), |
|---|
| 126 |
2048 : (2L, 0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73), |
|---|
| 127 |
3072 : (2L, 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF), |
|---|
| 128 |
4096 : (5L, 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF), |
|---|
| 129 |
6144 : (5L, 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF), |
|---|
| 130 |
8192 : (5L, 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF) |
|---|
| 131 |
} |
|---|
| 132 |
|
|---|
| 133 |
|
|---|
| 134 |
|
|---|
| 135 |
|
|---|
| 136 |
class SRP: |
|---|
| 137 |
|
|---|
| 138 |
|
|---|
| 139 |
|
|---|
| 140 |
|
|---|
| 141 |
def __init__(self, bits=1024): |
|---|
| 142 |
try: |
|---|
| 143 |
(self.g, self.N) = pflist[bits] |
|---|
| 144 |
except KeyError: |
|---|
| 145 |
raise NotSupported, '%d bits not available' % bits |
|---|
| 146 |
n = self.N |
|---|
| 147 |
self.scale = 0 |
|---|
| 148 |
while n > 0: |
|---|
| 149 |
self.scale += 1 |
|---|
| 150 |
n >>= 8 |
|---|
| 151 |
self.kid_ = self.SHA(self.pad(self.N), self.pad(self.g)) |
|---|
| 152 |
self.k = self.__b2n(self.kid_) |
|---|
| 153 |
|
|---|
| 154 |
def newVerifier(self, user, passphrase): |
|---|
| 155 |
salt = ''.join([chr(random.randrange(0, 256)) for x in range(saltlen)]) |
|---|
| 156 |
return (salt, self.pow(self.g, SRP.makeX(salt, user, passphrase))) |
|---|
| 157 |
|
|---|
| 158 |
def primeID(self): |
|---|
| 159 |
return self.kid_ |
|---|
| 160 |
|
|---|
| 161 |
def makeU(self, A, B): |
|---|
| 162 |
return SRP.__b2n(SRP.SHA(self.pad(A), self.pad(B))) |
|---|
| 163 |
|
|---|
| 164 |
def pow(self, a, b): |
|---|
| 165 |
return pow(a, b, self.N) |
|---|
| 166 |
|
|---|
| 167 |
def pad(self, n): |
|---|
| 168 |
s = [] |
|---|
| 169 |
for x in range(self.scale): |
|---|
| 170 |
s.insert(0, chr(n & 255)) |
|---|
| 171 |
n >>= 8 |
|---|
| 172 |
return ''.join(s) |
|---|
| 173 |
|
|---|
| 174 |
def __n2b(n): |
|---|
| 175 |
s = [] |
|---|
| 176 |
while n > 0: |
|---|
| 177 |
s.insert(0, chr(n & 255)) |
|---|
| 178 |
n >>= 8 |
|---|
| 179 |
return ''.join(s) |
|---|
| 180 |
__n2b = staticmethod(__n2b) |
|---|
| 181 |
|
|---|
| 182 |
def __b2n(s): |
|---|
| 183 |
r = 0L |
|---|
| 184 |
for c in s: |
|---|
| 185 |
r <<= 8 |
|---|
| 186 |
r += ord(c) |
|---|
| 187 |
return r |
|---|
| 188 |
__b2n = staticmethod(__b2n) |
|---|
| 189 |
|
|---|
| 190 |
def SHA(*args): |
|---|
| 191 |
m = sha.new() |
|---|
| 192 |
for s in args: |
|---|
| 193 |
if type(s) == long: |
|---|
| 194 |
s = SRP.__n2b(s) |
|---|
| 195 |
m.update(s) |
|---|
| 196 |
return m.digest() |
|---|
| 197 |
SHA = staticmethod(SHA) |
|---|
| 198 |
|
|---|
| 199 |
def hmacSHA(key, *args): |
|---|
| 200 |
m = hmac.new(key, None, sha) |
|---|
| 201 |
for s in args: |
|---|
| 202 |
if type(s) == long: |
|---|
| 203 |
s = SRP.__n2b(s) |
|---|
| 204 |
m.update(s) |
|---|
| 205 |
return m.digest() |
|---|
| 206 |
hmacSHA = staticmethod(hmacSHA) |
|---|
| 207 |
|
|---|
| 208 |
def makeX(salt, user, passphrase): |
|---|
| 209 |
return SRP.__b2n( |
|---|
| 210 |
SRP.SHA(salt, SRP.SHA(user, ':', passphrase))) |
|---|
| 211 |
makeX = staticmethod(makeX) |
|---|
| 212 |
|
|---|
| 213 |
|
|---|
| 214 |
class Client(SRP): |
|---|
| 215 |
def __init__(self, user, passphrase, bits=1024): |
|---|
| 216 |
'''bits: 1024, 1536, 2048, 3072, 4096, 6144 or 8192''' |
|---|
| 217 |
SRP.__init__(self, bits) |
|---|
| 218 |
self.user = user |
|---|
| 219 |
self.passphrase = passphrase |
|---|
| 220 |
while 1: |
|---|
| 221 |
self.a = random.randrange(0, 1L << ablen) |
|---|
| 222 |
self.A = self.pow(self.g, self.a) |
|---|
| 223 |
if self.A != 0: |
|---|
| 224 |
break |
|---|
| 225 |
|
|---|
| 226 |
def seed(self): |
|---|
| 227 |
return self.A |
|---|
| 228 |
|
|---|
| 229 |
def proof(self, salt, B): |
|---|
| 230 |
if not 0 < B < self.N: |
|---|
| 231 |
raise ImproperKeyValue |
|---|
| 232 |
|
|---|
| 233 |
u = self.makeU(self.A, B) |
|---|
| 234 |
if u == 0: |
|---|
| 235 |
raise ImproperKeyValue |
|---|
| 236 |
|
|---|
| 237 |
x = SRP.makeX(salt, self.user, self.passphrase) |
|---|
| 238 |
v = self.pow(self.g, x) |
|---|
| 239 |
S = self.pow((B - self.k * v) % self.N, self.a + u * x) |
|---|
| 240 |
self.K = SRP.SHA(S) |
|---|
| 241 |
self.M = SRP.hmacSHA(self.K, |
|---|
| 242 |
SRP.SHA(self.N), SRP.SHA(self.g), |
|---|
| 243 |
SRP.SHA(self.user), salt, self.A, B) |
|---|
| 244 |
del self.user, self.passphrase |
|---|
| 245 |
return self.M |
|---|
| 246 |
|
|---|
| 247 |
def key(self, serverProof): |
|---|
| 248 |
if serverProof != SRP.hmacSHA(self.K, self.A, self.M): |
|---|
| 249 |
raise AuthFailure, 'Server not authenticated.' |
|---|
| 250 |
return self.K |
|---|
| 251 |
|
|---|
| 252 |
|
|---|
| 253 |
class Server(SRP): |
|---|
| 254 |
def __init__(self, user, salt, verifier, bits=1024): |
|---|
| 255 |
'''bits: 1024, 1536, 2048, 3072, 4096, 6144 or 8192''' |
|---|
| 256 |
SRP.__init__(self, bits) |
|---|
| 257 |
self.user = user |
|---|
| 258 |
self.salt = salt |
|---|
| 259 |
self.v = verifier |
|---|
| 260 |
while 1: |
|---|
| 261 |
self.b = random.randrange(0, 1L << ablen) |
|---|
| 262 |
self.B = (self.pow(self.g, self.b) + self.k * verifier) % self.N |
|---|
| 263 |
if self.B != 0: |
|---|
| 264 |
break |
|---|
| 265 |
|
|---|
| 266 |
def seed(self): |
|---|
| 267 |
return self.B |
|---|
| 268 |
|
|---|
| 269 |
def proof(self, A, clientProof): |
|---|
| 270 |
if not 0 < A < self.N: |
|---|
| 271 |
raise ImproperKeyValue |
|---|
| 272 |
|
|---|
| 273 |
u = self.makeU(A, self.B) |
|---|
| 274 |
S = pow((A * pow(self.v, u, self.N)) % self.N, self.b, self.N) |
|---|
| 275 |
self.K = SRP.SHA(S) |
|---|
| 276 |
self.M = SRP.hmacSHA(self.K, |
|---|
| 277 |
SRP.SHA(self.N), SRP.SHA(self.g), |
|---|
| 278 |
SRP.SHA(self.user), self.salt, A, self.B) |
|---|
| 279 |
if clientProof != self.M: |
|---|
| 280 |
raise AuthFailure, 'Client not authenticated.' |
|---|
| 281 |
return SRP.hmacSHA(self.K, A, self.M) |
|---|
| 282 |
|
|---|
| 283 |
def key(self): |
|---|
| 284 |
return self.K |
|---|
| 285 |
|
|---|
| 286 |
|
|---|
| 287 |
def _test(): |
|---|
| 288 |
import doctest |
|---|
| 289 |
doctest.testmod() |
|---|
| 290 |
|
|---|
| 291 |
if __name__ == '__main__': |
|---|
| 292 |
_test() |
|---|