diff options
Diffstat (limited to '3rd_party/libsrp6a-sha512/srp6a_sha512_client.c')
-rw-r--r-- | 3rd_party/libsrp6a-sha512/srp6a_sha512_client.c | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/3rd_party/libsrp6a-sha512/srp6a_sha512_client.c b/3rd_party/libsrp6a-sha512/srp6a_sha512_client.c new file mode 100644 index 0000000..db59fe8 --- /dev/null +++ b/3rd_party/libsrp6a-sha512/srp6a_sha512_client.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1997-2007 The Stanford SRP Authentication Project | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining | ||
6 | * a copy of this software and associated documentation files (the | ||
7 | * "Software"), to deal in the Software without restriction, including | ||
8 | * without limitation the rights to use, copy, modify, merge, publish, | ||
9 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
10 | * permit persons to whom the Software is furnished to do so, subject to | ||
11 | * the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be | ||
14 | * included in all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, | ||
17 | * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY | ||
18 | * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | ||
19 | * | ||
20 | * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, | ||
21 | * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER | ||
22 | * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF | ||
23 | * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT | ||
24 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
25 | * | ||
26 | * Redistributions in source or binary form must retain an intact copy | ||
27 | * of this copyright notice. | ||
28 | */ | ||
29 | #include "t_defines.h" | ||
30 | #include "srp.h" | ||
31 | #include "t_sha.h" | ||
32 | |||
33 | /* | ||
34 | * SRP-6/6a has two minor refinements relative to SRP-3/RFC2945: | ||
35 | * 1. The "g^x" value is multipled by three in the client's | ||
36 | * calculation of its session key. | ||
37 | * SRP-6a: The "g^x" value is multiplied by the hash of | ||
38 | * N and g in the client's session key calculation. | ||
39 | * 2. The value of u is taken as the hash of A and B, | ||
40 | * instead of the top 32 bits of the hash of B. | ||
41 | * This eliminates the old restriction where the | ||
42 | * server had to receive A before it could send B. | ||
43 | */ | ||
44 | |||
45 | /****************************/ | ||
46 | #define SHA512_DIGESTSIZE 64 | ||
47 | #define SRP6_SHA512_KEY_LEN 64 | ||
48 | |||
49 | /* | ||
50 | * The client keeps track of the running hash | ||
51 | * state via SHA512_CTX structures pointed to by the | ||
52 | * meth_data pointer. The "hash" member is the hash value that | ||
53 | * will be sent to the other side; the "ckhash" member is the | ||
54 | * hash value expected from the other side. | ||
55 | */ | ||
56 | struct sha512_client_meth_st { | ||
57 | SHA512_CTX hash; | ||
58 | SHA512_CTX ckhash; | ||
59 | unsigned char k[SRP6_SHA512_KEY_LEN]; | ||
60 | }; | ||
61 | |||
62 | #define SHA512_CLIENT_CTXP(srp) ((struct sha512_client_meth_st *)(srp)->meth_data) | ||
63 | |||
64 | static SRP_RESULT | ||
65 | srp6a_sha512_client_init(SRP * srp) | ||
66 | { | ||
67 | srp->magic = SRP_MAGIC_CLIENT; | ||
68 | srp->flags = SRP_FLAG_MOD_ACCEL | SRP_FLAG_LEFT_PAD; | ||
69 | srp->meth_data = malloc(sizeof(struct sha512_client_meth_st)); | ||
70 | SHA512Init(&SHA512_CLIENT_CTXP(srp)->hash); | ||
71 | SHA512Init(&SHA512_CLIENT_CTXP(srp)->ckhash); | ||
72 | return SRP_SUCCESS; | ||
73 | } | ||
74 | |||
75 | static SRP_RESULT | ||
76 | srp6_sha512_client_finish(SRP * srp) | ||
77 | { | ||
78 | if(srp->meth_data) { | ||
79 | memset(srp->meth_data, 0, sizeof(struct sha512_client_meth_st)); | ||
80 | free(srp->meth_data); | ||
81 | } | ||
82 | return SRP_SUCCESS; | ||
83 | } | ||
84 | |||
85 | static SRP_RESULT | ||
86 | srp6_sha512_client_params(SRP * srp, const unsigned char * modulus, int modlen, | ||
87 | const unsigned char * generator, int genlen, | ||
88 | const unsigned char * salt, int saltlen) | ||
89 | { | ||
90 | int i; | ||
91 | unsigned char buf1[SHA512_DIGESTSIZE], buf2[SHA512_DIGESTSIZE]; | ||
92 | SHA512_CTX ctxt; | ||
93 | |||
94 | /* Fields set by SRP_set_params */ | ||
95 | |||
96 | /* Update hash state */ | ||
97 | SHA512Init(&ctxt); | ||
98 | SHA512Update(&ctxt, modulus, modlen); | ||
99 | SHA512Final(buf1, &ctxt); /* buf1 = H(modulus) */ | ||
100 | |||
101 | SHA512Init(&ctxt); | ||
102 | SHA512Update(&ctxt, generator, genlen); | ||
103 | SHA512Final(buf2, &ctxt); /* buf2 = H(generator) */ | ||
104 | |||
105 | for(i = 0; i < sizeof(buf1); ++i) | ||
106 | buf1[i] ^= buf2[i]; /* buf1 = H(modulus) xor H(generator) */ | ||
107 | |||
108 | /* hash: H(N) xor H(g) */ | ||
109 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, buf1, sizeof(buf1)); | ||
110 | |||
111 | SHA512Init(&ctxt); | ||
112 | SHA512Update(&ctxt, srp->username->data, srp->username->length); | ||
113 | SHA512Final(buf1, &ctxt); /* buf1 = H(user) */ | ||
114 | |||
115 | /* hash: (H(N) xor H(g)) | H(U) */ | ||
116 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, buf1, sizeof(buf1)); | ||
117 | |||
118 | /* hash: (H(N) xor H(g)) | H(U) | s */ | ||
119 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, salt, saltlen); | ||
120 | |||
121 | return SRP_SUCCESS; | ||
122 | } | ||
123 | |||
124 | static SRP_RESULT | ||
125 | srp6_sha512_client_auth(SRP * srp, const unsigned char * a, int alen) | ||
126 | { | ||
127 | /* On the client, the authenticator is the raw password-derived hash */ | ||
128 | srp->password = BigIntegerFromBytes(a, alen); | ||
129 | |||
130 | /* verifier = g^x mod N */ | ||
131 | srp->verifier = BigIntegerFromInt(0); | ||
132 | BigIntegerModExp(srp->verifier, srp->generator, srp->password, srp->modulus, srp->bctx, srp->accel); | ||
133 | |||
134 | return SRP_SUCCESS; | ||
135 | } | ||
136 | |||
137 | static SRP_RESULT | ||
138 | srp6_sha512_client_passwd(SRP * srp, const unsigned char * p, int plen) | ||
139 | { | ||
140 | SHA512_CTX ctxt; | ||
141 | unsigned char dig[SHA512_DIGESTSIZE]; | ||
142 | int r; | ||
143 | |||
144 | SHA512Init(&ctxt); | ||
145 | SHA512Update(&ctxt, srp->username->data, srp->username->length); | ||
146 | SHA512Update(&ctxt, ":", 1); | ||
147 | SHA512Update(&ctxt, p, plen); | ||
148 | SHA512Final(dig, &ctxt); /* dig = H(U | ":" | P) */ | ||
149 | |||
150 | SHA512Init(&ctxt); | ||
151 | SHA512Update(&ctxt, srp->salt->data, srp->salt->length); | ||
152 | SHA512Update(&ctxt, dig, sizeof(dig)); | ||
153 | SHA512Final(dig, &ctxt); /* dig = H(s | H(U | ":" | P)) */ | ||
154 | memset(&ctxt, 0, sizeof(ctxt)); | ||
155 | |||
156 | r = SRP_set_authenticator(srp, dig, sizeof(dig)); | ||
157 | memset(dig, 0, sizeof(dig)); | ||
158 | |||
159 | return r; | ||
160 | } | ||
161 | |||
162 | static SRP_RESULT | ||
163 | srp6_sha512_client_genpub(SRP * srp, cstr ** result) | ||
164 | { | ||
165 | cstr * astr; | ||
166 | int slen = (SRP_get_secret_bits(BigIntegerBitLen(srp->modulus)) + 7) / 8; | ||
167 | |||
168 | if(result == NULL) | ||
169 | astr = cstr_new(); | ||
170 | else { | ||
171 | if(*result == NULL) | ||
172 | *result = cstr_new(); | ||
173 | astr = *result; | ||
174 | } | ||
175 | |||
176 | cstr_set_length(astr, BigIntegerByteLen(srp->modulus)); | ||
177 | t_random((unsigned char*)astr->data, slen); | ||
178 | srp->secret = BigIntegerFromBytes((const unsigned char*)astr->data, slen); | ||
179 | /* Force g^a mod n to "wrap around" by adding log[2](n) to "a". */ | ||
180 | BigIntegerAddInt(srp->secret, srp->secret, BigIntegerBitLen(srp->modulus)); | ||
181 | /* A = g^a mod n */ | ||
182 | srp->pubkey = BigIntegerFromInt(0); | ||
183 | BigIntegerModExp(srp->pubkey, srp->generator, srp->secret, srp->modulus, srp->bctx, srp->accel); | ||
184 | BigIntegerToCstr(srp->pubkey, astr); | ||
185 | |||
186 | /* hash: (H(N) xor H(g)) | H(U) | s | A */ | ||
187 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, astr->data, astr->length); | ||
188 | /* ckhash: A */ | ||
189 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, astr->data, astr->length); | ||
190 | |||
191 | if(result == NULL) /* astr was a temporary */ | ||
192 | cstr_clear_free(astr); | ||
193 | |||
194 | return SRP_SUCCESS; | ||
195 | } | ||
196 | |||
197 | static SRP_RESULT | ||
198 | srp6_sha512_client_key_ex(SRP * srp, cstr ** result, | ||
199 | const unsigned char * pubkey, int pubkeylen, BigInteger k) | ||
200 | { | ||
201 | SHA512_CTX ctxt; | ||
202 | unsigned char dig[SHA512_DIGESTSIZE]; | ||
203 | BigInteger gb, e; | ||
204 | cstr * s; | ||
205 | int modlen; | ||
206 | |||
207 | modlen = BigIntegerByteLen(srp->modulus); | ||
208 | if(pubkeylen > modlen) | ||
209 | return SRP_ERROR; | ||
210 | |||
211 | /* Compute u from client's and server's values */ | ||
212 | SHA512Init(&ctxt); | ||
213 | /* Use s as a temporary to store client's value */ | ||
214 | s = cstr_new(); | ||
215 | if(srp->flags & SRP_FLAG_LEFT_PAD) { | ||
216 | BigIntegerToCstrEx(srp->pubkey, s, modlen); | ||
217 | SHA512Update(&ctxt, s->data, s->length); | ||
218 | if(pubkeylen < modlen) { | ||
219 | memcpy(s->data + (modlen - pubkeylen), pubkey, pubkeylen); | ||
220 | memset(s->data, 0, modlen - pubkeylen); | ||
221 | SHA512Update(&ctxt, s->data, modlen); | ||
222 | } | ||
223 | else | ||
224 | SHA512Update(&ctxt, pubkey, pubkeylen); | ||
225 | } | ||
226 | else { | ||
227 | BigIntegerToCstr(srp->pubkey, s); | ||
228 | SHA512Update(&ctxt, s->data, s->length); | ||
229 | SHA512Update(&ctxt, pubkey, pubkeylen); | ||
230 | } | ||
231 | SHA512Final(dig, &ctxt); | ||
232 | srp->u = BigIntegerFromBytes(dig, SHA512_DIGESTSIZE); | ||
233 | |||
234 | /* hash: (H(N) xor H(g)) | H(U) | s | A | B */ | ||
235 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, pubkey, pubkeylen); | ||
236 | |||
237 | gb = BigIntegerFromBytes(pubkey, pubkeylen); | ||
238 | /* reject B == 0, B >= modulus */ | ||
239 | if(BigIntegerCmp(gb, srp->modulus) >= 0 || BigIntegerCmpInt(gb, 0) == 0) { | ||
240 | BigIntegerFree(gb); | ||
241 | cstr_clear_free(s); | ||
242 | return SRP_ERROR; | ||
243 | } | ||
244 | e = BigIntegerFromInt(0); | ||
245 | srp->key = BigIntegerFromInt(0); | ||
246 | /* unblind g^b (mod N) */ | ||
247 | BigIntegerSub(srp->key, srp->modulus, srp->verifier); | ||
248 | /* use e as temporary, e == -k*v (mod N) */ | ||
249 | BigIntegerMul(e, k, srp->key, srp->bctx); | ||
250 | BigIntegerAdd(e, e, gb); | ||
251 | BigIntegerMod(gb, e, srp->modulus, srp->bctx); | ||
252 | |||
253 | /* compute gb^(a + ux) (mod N) */ | ||
254 | BigIntegerMul(e, srp->password, srp->u, srp->bctx); | ||
255 | BigIntegerAdd(e, e, srp->secret); /* e = a + ux */ | ||
256 | |||
257 | BigIntegerModExp(srp->key, gb, e, srp->modulus, srp->bctx, srp->accel); | ||
258 | BigIntegerClearFree(e); | ||
259 | BigIntegerClearFree(gb); | ||
260 | |||
261 | /* convert srp->key into a session key, update hash states */ | ||
262 | BigIntegerToCstr(srp->key, s); | ||
263 | SHA512Init(&ctxt); | ||
264 | SHA512Update(&ctxt, s->data, s->length); | ||
265 | SHA512Final((unsigned char*)&SHA512_CLIENT_CTXP(srp)->k, &ctxt); | ||
266 | cstr_clear_free(s); | ||
267 | |||
268 | /* hash: (H(N) xor H(g)) | H(U) | s | A | B | K */ | ||
269 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN); | ||
270 | /* hash: (H(N) xor H(g)) | H(U) | s | A | B | K | ex_data */ | ||
271 | if(srp->ex_data->length > 0) | ||
272 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, | ||
273 | srp->ex_data->data, srp->ex_data->length); | ||
274 | if(result) { | ||
275 | if(*result == NULL) | ||
276 | *result = cstr_new(); | ||
277 | cstr_setn(*result, (const char*)SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN); | ||
278 | } | ||
279 | |||
280 | return SRP_SUCCESS; | ||
281 | } | ||
282 | |||
283 | static SRP_RESULT | ||
284 | srp6a_sha512_client_key(SRP * srp, cstr ** result, | ||
285 | const unsigned char * pubkey, int pubkeylen) | ||
286 | { | ||
287 | SRP_RESULT ret; | ||
288 | BigInteger k; | ||
289 | cstr * s; | ||
290 | SHA512_CTX ctxt; | ||
291 | unsigned char dig[SHA512_DIGESTSIZE]; | ||
292 | |||
293 | SHA512Init(&ctxt); | ||
294 | s = cstr_new(); | ||
295 | BigIntegerToCstr(srp->modulus, s); | ||
296 | SHA512Update(&ctxt, s->data, s->length); | ||
297 | if(srp->flags & SRP_FLAG_LEFT_PAD) | ||
298 | BigIntegerToCstrEx(srp->generator, s, s->length); | ||
299 | else | ||
300 | BigIntegerToCstr(srp->generator, s); | ||
301 | SHA512Update(&ctxt, s->data, s->length); | ||
302 | SHA512Final(dig, &ctxt); | ||
303 | cstr_free(s); | ||
304 | |||
305 | k = BigIntegerFromBytes(dig, SHA512_DIGESTSIZE); | ||
306 | if(BigIntegerCmpInt(k, 0) == 0) | ||
307 | ret = SRP_ERROR; | ||
308 | else | ||
309 | ret = srp6_sha512_client_key_ex(srp, result, pubkey, pubkeylen, k); | ||
310 | BigIntegerClearFree(k); | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | static SRP_RESULT | ||
315 | srp6_sha512_client_verify(SRP * srp, const unsigned char * proof, int prooflen) | ||
316 | { | ||
317 | unsigned char expected[SHA512_DIGESTSIZE]; | ||
318 | |||
319 | SHA512Final(expected, &SHA512_CLIENT_CTXP(srp)->ckhash); | ||
320 | if(prooflen == SHA512_DIGESTSIZE && memcmp(expected, proof, prooflen) == 0) | ||
321 | return SRP_SUCCESS; | ||
322 | else | ||
323 | return SRP_ERROR; | ||
324 | } | ||
325 | |||
326 | static SRP_RESULT | ||
327 | srp6_sha512_client_respond(SRP * srp, cstr ** proof) | ||
328 | { | ||
329 | if(proof == NULL) | ||
330 | return SRP_ERROR; | ||
331 | |||
332 | if(*proof == NULL) | ||
333 | *proof = cstr_new(); | ||
334 | |||
335 | /* proof contains client's response */ | ||
336 | cstr_set_length(*proof, SHA512_DIGESTSIZE); | ||
337 | SHA512Final((unsigned char*)(*proof)->data, &SHA512_CLIENT_CTXP(srp)->hash); | ||
338 | |||
339 | /* ckhash: A | M | K */ | ||
340 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, (*proof)->data, (*proof)->length); | ||
341 | SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN); | ||
342 | return SRP_SUCCESS; | ||
343 | } | ||
344 | |||
345 | static SRP_METHOD srp6a_sha512_client_meth = { | ||
346 | "SRP-6a sha512 client (tjw)", | ||
347 | srp6a_sha512_client_init, | ||
348 | srp6_sha512_client_finish, | ||
349 | srp6_sha512_client_params, | ||
350 | srp6_sha512_client_auth, | ||
351 | srp6_sha512_client_passwd, | ||
352 | srp6_sha512_client_genpub, | ||
353 | srp6a_sha512_client_key, | ||
354 | srp6_sha512_client_verify, | ||
355 | srp6_sha512_client_respond, | ||
356 | NULL | ||
357 | }; | ||
358 | |||
359 | _TYPE( SRP_METHOD * ) | ||
360 | SRP6a_sha512_client_method() | ||
361 | { | ||
362 | return &srp6a_sha512_client_meth; | ||
363 | } | ||