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 | } | ||
