summaryrefslogtreecommitdiffstats
path: root/3rd_party/libsrp6a-sha512/srp6a_sha512_client.c
diff options
context:
space:
mode:
Diffstat (limited to '3rd_party/libsrp6a-sha512/srp6a_sha512_client.c')
-rw-r--r--3rd_party/libsrp6a-sha512/srp6a_sha512_client.c363
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 @@
+/*
+ * Copyright (c) 1997-2007 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice.
+ */
+#include "t_defines.h"
+#include "srp.h"
+#include "t_sha.h"
+
+/*
+ * SRP-6/6a has two minor refinements relative to SRP-3/RFC2945:
+ * 1. The "g^x" value is multipled by three in the client's
+ * calculation of its session key.
+ * SRP-6a: The "g^x" value is multiplied by the hash of
+ * N and g in the client's session key calculation.
+ * 2. The value of u is taken as the hash of A and B,
+ * instead of the top 32 bits of the hash of B.
+ * This eliminates the old restriction where the
+ * server had to receive A before it could send B.
+ */
+
+/****************************/
+#define SHA512_DIGESTSIZE 64
+#define SRP6_SHA512_KEY_LEN 64
+
+/*
+ * The client keeps track of the running hash
+ * state via SHA512_CTX structures pointed to by the
+ * meth_data pointer. The "hash" member is the hash value that
+ * will be sent to the other side; the "ckhash" member is the
+ * hash value expected from the other side.
+ */
+struct sha512_client_meth_st {
+ SHA512_CTX hash;
+ SHA512_CTX ckhash;
+ unsigned char k[SRP6_SHA512_KEY_LEN];
+};
+
+#define SHA512_CLIENT_CTXP(srp) ((struct sha512_client_meth_st *)(srp)->meth_data)
+
+static SRP_RESULT
+srp6a_sha512_client_init(SRP * srp)
+{
+ srp->magic = SRP_MAGIC_CLIENT;
+ srp->flags = SRP_FLAG_MOD_ACCEL | SRP_FLAG_LEFT_PAD;
+ srp->meth_data = malloc(sizeof(struct sha512_client_meth_st));
+ SHA512Init(&SHA512_CLIENT_CTXP(srp)->hash);
+ SHA512Init(&SHA512_CLIENT_CTXP(srp)->ckhash);
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_finish(SRP * srp)
+{
+ if(srp->meth_data) {
+ memset(srp->meth_data, 0, sizeof(struct sha512_client_meth_st));
+ free(srp->meth_data);
+ }
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_params(SRP * srp, const unsigned char * modulus, int modlen,
+ const unsigned char * generator, int genlen,
+ const unsigned char * salt, int saltlen)
+{
+ int i;
+ unsigned char buf1[SHA512_DIGESTSIZE], buf2[SHA512_DIGESTSIZE];
+ SHA512_CTX ctxt;
+
+ /* Fields set by SRP_set_params */
+
+ /* Update hash state */
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, modulus, modlen);
+ SHA512Final(buf1, &ctxt); /* buf1 = H(modulus) */
+
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, generator, genlen);
+ SHA512Final(buf2, &ctxt); /* buf2 = H(generator) */
+
+ for(i = 0; i < sizeof(buf1); ++i)
+ buf1[i] ^= buf2[i]; /* buf1 = H(modulus) xor H(generator) */
+
+ /* hash: H(N) xor H(g) */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, buf1, sizeof(buf1));
+
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, srp->username->data, srp->username->length);
+ SHA512Final(buf1, &ctxt); /* buf1 = H(user) */
+
+ /* hash: (H(N) xor H(g)) | H(U) */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, buf1, sizeof(buf1));
+
+ /* hash: (H(N) xor H(g)) | H(U) | s */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, salt, saltlen);
+
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_auth(SRP * srp, const unsigned char * a, int alen)
+{
+ /* On the client, the authenticator is the raw password-derived hash */
+ srp->password = BigIntegerFromBytes(a, alen);
+
+ /* verifier = g^x mod N */
+ srp->verifier = BigIntegerFromInt(0);
+ BigIntegerModExp(srp->verifier, srp->generator, srp->password, srp->modulus, srp->bctx, srp->accel);
+
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_passwd(SRP * srp, const unsigned char * p, int plen)
+{
+ SHA512_CTX ctxt;
+ unsigned char dig[SHA512_DIGESTSIZE];
+ int r;
+
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, srp->username->data, srp->username->length);
+ SHA512Update(&ctxt, ":", 1);
+ SHA512Update(&ctxt, p, plen);
+ SHA512Final(dig, &ctxt); /* dig = H(U | ":" | P) */
+
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, srp->salt->data, srp->salt->length);
+ SHA512Update(&ctxt, dig, sizeof(dig));
+ SHA512Final(dig, &ctxt); /* dig = H(s | H(U | ":" | P)) */
+ memset(&ctxt, 0, sizeof(ctxt));
+
+ r = SRP_set_authenticator(srp, dig, sizeof(dig));
+ memset(dig, 0, sizeof(dig));
+
+ return r;
+}
+
+static SRP_RESULT
+srp6_sha512_client_genpub(SRP * srp, cstr ** result)
+{
+ cstr * astr;
+ int slen = (SRP_get_secret_bits(BigIntegerBitLen(srp->modulus)) + 7) / 8;
+
+ if(result == NULL)
+ astr = cstr_new();
+ else {
+ if(*result == NULL)
+ *result = cstr_new();
+ astr = *result;
+ }
+
+ cstr_set_length(astr, BigIntegerByteLen(srp->modulus));
+ t_random((unsigned char*)astr->data, slen);
+ srp->secret = BigIntegerFromBytes((const unsigned char*)astr->data, slen);
+ /* Force g^a mod n to "wrap around" by adding log[2](n) to "a". */
+ BigIntegerAddInt(srp->secret, srp->secret, BigIntegerBitLen(srp->modulus));
+ /* A = g^a mod n */
+ srp->pubkey = BigIntegerFromInt(0);
+ BigIntegerModExp(srp->pubkey, srp->generator, srp->secret, srp->modulus, srp->bctx, srp->accel);
+ BigIntegerToCstr(srp->pubkey, astr);
+
+ /* hash: (H(N) xor H(g)) | H(U) | s | A */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, astr->data, astr->length);
+ /* ckhash: A */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, astr->data, astr->length);
+
+ if(result == NULL) /* astr was a temporary */
+ cstr_clear_free(astr);
+
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6_sha512_client_key_ex(SRP * srp, cstr ** result,
+ const unsigned char * pubkey, int pubkeylen, BigInteger k)
+{
+ SHA512_CTX ctxt;
+ unsigned char dig[SHA512_DIGESTSIZE];
+ BigInteger gb, e;
+ cstr * s;
+ int modlen;
+
+ modlen = BigIntegerByteLen(srp->modulus);
+ if(pubkeylen > modlen)
+ return SRP_ERROR;
+
+ /* Compute u from client's and server's values */
+ SHA512Init(&ctxt);
+ /* Use s as a temporary to store client's value */
+ s = cstr_new();
+ if(srp->flags & SRP_FLAG_LEFT_PAD) {
+ BigIntegerToCstrEx(srp->pubkey, s, modlen);
+ SHA512Update(&ctxt, s->data, s->length);
+ if(pubkeylen < modlen) {
+ memcpy(s->data + (modlen - pubkeylen), pubkey, pubkeylen);
+ memset(s->data, 0, modlen - pubkeylen);
+ SHA512Update(&ctxt, s->data, modlen);
+ }
+ else
+ SHA512Update(&ctxt, pubkey, pubkeylen);
+ }
+ else {
+ BigIntegerToCstr(srp->pubkey, s);
+ SHA512Update(&ctxt, s->data, s->length);
+ SHA512Update(&ctxt, pubkey, pubkeylen);
+ }
+ SHA512Final(dig, &ctxt);
+ srp->u = BigIntegerFromBytes(dig, SHA512_DIGESTSIZE);
+
+ /* hash: (H(N) xor H(g)) | H(U) | s | A | B */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, pubkey, pubkeylen);
+
+ gb = BigIntegerFromBytes(pubkey, pubkeylen);
+ /* reject B == 0, B >= modulus */
+ if(BigIntegerCmp(gb, srp->modulus) >= 0 || BigIntegerCmpInt(gb, 0) == 0) {
+ BigIntegerFree(gb);
+ cstr_clear_free(s);
+ return SRP_ERROR;
+ }
+ e = BigIntegerFromInt(0);
+ srp->key = BigIntegerFromInt(0);
+ /* unblind g^b (mod N) */
+ BigIntegerSub(srp->key, srp->modulus, srp->verifier);
+ /* use e as temporary, e == -k*v (mod N) */
+ BigIntegerMul(e, k, srp->key, srp->bctx);
+ BigIntegerAdd(e, e, gb);
+ BigIntegerMod(gb, e, srp->modulus, srp->bctx);
+
+ /* compute gb^(a + ux) (mod N) */
+ BigIntegerMul(e, srp->password, srp->u, srp->bctx);
+ BigIntegerAdd(e, e, srp->secret); /* e = a + ux */
+
+ BigIntegerModExp(srp->key, gb, e, srp->modulus, srp->bctx, srp->accel);
+ BigIntegerClearFree(e);
+ BigIntegerClearFree(gb);
+
+ /* convert srp->key into a session key, update hash states */
+ BigIntegerToCstr(srp->key, s);
+ SHA512Init(&ctxt);
+ SHA512Update(&ctxt, s->data, s->length);
+ SHA512Final((unsigned char*)&SHA512_CLIENT_CTXP(srp)->k, &ctxt);
+ cstr_clear_free(s);
+
+ /* hash: (H(N) xor H(g)) | H(U) | s | A | B | K */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash, SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN);
+ /* hash: (H(N) xor H(g)) | H(U) | s | A | B | K | ex_data */
+ if(srp->ex_data->length > 0)
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->hash,
+ srp->ex_data->data, srp->ex_data->length);
+ if(result) {
+ if(*result == NULL)
+ *result = cstr_new();
+ cstr_setn(*result, (const char*)SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN);
+ }
+
+ return SRP_SUCCESS;
+}
+
+static SRP_RESULT
+srp6a_sha512_client_key(SRP * srp, cstr ** result,
+ const unsigned char * pubkey, int pubkeylen)
+{
+ SRP_RESULT ret;
+ BigInteger k;
+ cstr * s;
+ SHA512_CTX ctxt;
+ unsigned char dig[SHA512_DIGESTSIZE];
+
+ SHA512Init(&ctxt);
+ s = cstr_new();
+ BigIntegerToCstr(srp->modulus, s);
+ SHA512Update(&ctxt, s->data, s->length);
+ if(srp->flags & SRP_FLAG_LEFT_PAD)
+ BigIntegerToCstrEx(srp->generator, s, s->length);
+ else
+ BigIntegerToCstr(srp->generator, s);
+ SHA512Update(&ctxt, s->data, s->length);
+ SHA512Final(dig, &ctxt);
+ cstr_free(s);
+
+ k = BigIntegerFromBytes(dig, SHA512_DIGESTSIZE);
+ if(BigIntegerCmpInt(k, 0) == 0)
+ ret = SRP_ERROR;
+ else
+ ret = srp6_sha512_client_key_ex(srp, result, pubkey, pubkeylen, k);
+ BigIntegerClearFree(k);
+ return ret;
+}
+
+static SRP_RESULT
+srp6_sha512_client_verify(SRP * srp, const unsigned char * proof, int prooflen)
+{
+ unsigned char expected[SHA512_DIGESTSIZE];
+
+ SHA512Final(expected, &SHA512_CLIENT_CTXP(srp)->ckhash);
+ if(prooflen == SHA512_DIGESTSIZE && memcmp(expected, proof, prooflen) == 0)
+ return SRP_SUCCESS;
+ else
+ return SRP_ERROR;
+}
+
+static SRP_RESULT
+srp6_sha512_client_respond(SRP * srp, cstr ** proof)
+{
+ if(proof == NULL)
+ return SRP_ERROR;
+
+ if(*proof == NULL)
+ *proof = cstr_new();
+
+ /* proof contains client's response */
+ cstr_set_length(*proof, SHA512_DIGESTSIZE);
+ SHA512Final((unsigned char*)(*proof)->data, &SHA512_CLIENT_CTXP(srp)->hash);
+
+ /* ckhash: A | M | K */
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, (*proof)->data, (*proof)->length);
+ SHA512Update(&SHA512_CLIENT_CTXP(srp)->ckhash, SHA512_CLIENT_CTXP(srp)->k, SRP6_SHA512_KEY_LEN);
+ return SRP_SUCCESS;
+}
+
+static SRP_METHOD srp6a_sha512_client_meth = {
+ "SRP-6a sha512 client (tjw)",
+ srp6a_sha512_client_init,
+ srp6_sha512_client_finish,
+ srp6_sha512_client_params,
+ srp6_sha512_client_auth,
+ srp6_sha512_client_passwd,
+ srp6_sha512_client_genpub,
+ srp6a_sha512_client_key,
+ srp6_sha512_client_verify,
+ srp6_sha512_client_respond,
+ NULL
+};
+
+_TYPE( SRP_METHOD * )
+SRP6a_sha512_client_method()
+{
+ return &srp6a_sha512_client_meth;
+}