diff --git a/wolfcrypt/src/srp.c b/wolfcrypt/src/srp.c index 48219d49b..03345ac21 100644 --- a/wolfcrypt/src/srp.c +++ b/wolfcrypt/src/srp.c @@ -150,6 +150,7 @@ int wc_SrpInit(Srp* srp, byte type, byte side) int r; /* validating params */ + if (!srp) return BAD_FUNC_ARG; @@ -160,61 +161,46 @@ int wc_SrpInit(Srp* srp, byte type, byte side) type != SRP_TYPE_SHA384 && type != SRP_TYPE_SHA512) return BAD_FUNC_ARG; - /* initializing common data */ + /* initializing variables */ + + if ((r = SrpHashInit(&srp->client_proof, type)) != 0) + return r; + + if ((r = SrpHashInit(&srp->server_proof, type)) != 0) + return r; + + if ((r = mp_init_multi(&srp->N, &srp->g, &srp->s, &srp->u, 0, 0)) != 0) + return r; + + if ((r = mp_init_multi(&srp->auth, &srp->peer, &srp->priv, &srp->pub, + 0, 0)) != 0) { + /* undo previous initializations on error */ + mp_clear(&srp->N); mp_clear(&srp->g); + mp_clear(&srp->s); mp_clear(&srp->u); + + return r; + } + srp->side = side; srp->type = type; srp->salt = NULL; srp->saltSz = 0; srp->user = NULL; srp->userSz = 0; - if (mp_init_multi(&srp->N, &srp->g, &srp->s, &srp->u, 0, 0) != MP_OKAY) - return MP_INIT_E; - - r = SrpHashInit(&srp->client_proof, type); - if (!r) r = SrpHashInit(&srp->server_proof, type); - - /* initializing client specific data */ - if (!r && srp->side == SRP_CLIENT_SIDE) - r = mp_init_multi(&srp->specific.client.a, &srp->specific.client.A, - &srp->specific.client.B, &srp->specific.client.x,0,0); - - /* initializing server specific data */ - if (!r && srp->side == SRP_SERVER_SIDE) - r = mp_init_multi(&srp->specific.server.b, &srp->specific.server.B, - &srp->specific.server.A, &srp->specific.server.v,0,0); - - /* undo initializations on error */ - if (r != 0) { - mp_clear(&srp->N); mp_clear(&srp->g); - mp_clear(&srp->s); mp_clear(&srp->u); - } - - return r; + return 0; } void wc_SrpTerm(Srp* srp) { if (srp) { - mp_clear(&srp->N); mp_clear(&srp->g); - mp_clear(&srp->s); mp_clear(&srp->u); + mp_clear(&srp->N); mp_clear(&srp->g); + mp_clear(&srp->s); mp_clear(&srp->u); + mp_clear(&srp->auth); mp_clear(&srp->peer); + mp_clear(&srp->priv); mp_clear(&srp->pub); XMEMSET(srp->salt, 0, srp->saltSz); XFREE(srp->salt, NULL, DYNAMIC_TYPE_SRP); XMEMSET(srp->user, 0, srp->userSz); XFREE(srp->user, NULL, DYNAMIC_TYPE_SRP); - if (srp->side == SRP_CLIENT_SIDE) { - mp_clear(&srp->specific.client.a); - mp_clear(&srp->specific.client.A); - mp_clear(&srp->specific.client.B); - mp_clear(&srp->specific.client.x); - } - - if (srp->side == SRP_SERVER_SIDE) { - mp_clear(&srp->specific.server.b); - mp_clear(&srp->specific.server.B); - mp_clear(&srp->specific.server.A); - mp_clear(&srp->specific.server.v); - } - XMEMSET(srp, 0, sizeof(Srp)); } } @@ -233,6 +219,7 @@ int wc_SrpSetUsername(Srp* srp, const byte* username, word32 size) return 0; } + int wc_SrpSetParams(Srp* srp, const byte* N, word32 nSz, const byte* g, word32 gSz, const byte* salt, word32 saltSz) @@ -311,6 +298,7 @@ int wc_SrpSetPassword(Srp* srp, const byte* password, word32 size) { SrpHash hash; byte digest[SRP_MAX_DIGEST_SIZE]; + word32 digestSz; int r; if (!srp || !password || srp->side != SRP_CLIENT_SIDE) @@ -319,6 +307,8 @@ int wc_SrpSetPassword(Srp* srp, const byte* password, word32 size) if (!srp->salt) return SRP_CALL_ORDER_E; + digestSz = SrpHashSize(srp->type); + /* digest = H(username | ':' | password) */ r = SrpHashInit(&hash, srp->type); if (!r) r = SrpHashUpdate(&hash, srp->user, srp->userSz); @@ -329,13 +319,11 @@ int wc_SrpSetPassword(Srp* srp, const byte* password, word32 size) /* digest = H(salt | H(username | ':' | password)) */ if (!r) r = SrpHashInit(&hash, srp->type); if (!r) r = SrpHashUpdate(&hash, srp->salt, srp->saltSz); - if (!r) r = SrpHashUpdate(&hash, digest, SrpHashSize(srp->type)); + if (!r) r = SrpHashUpdate(&hash, digest, digestSz); if (!r) r = SrpHashFinal(&hash, digest); /* Set x (private key) */ - if (!r && mp_read_unsigned_bin(&srp->specific.client.x, digest, - SrpHashSize(srp->type)) != MP_OKAY) - r = MP_READ_E; + if (!r) r = mp_read_unsigned_bin(&srp->auth, digest, digestSz); XMEMSET(digest, 0, SRP_MAX_DIGEST_SIZE); @@ -350,13 +338,13 @@ int wc_SrpGetVerifier(Srp* srp, byte* verifier, word32* size) if (!srp || !verifier || !size || srp->side != SRP_CLIENT_SIDE) return BAD_FUNC_ARG; - if (mp_iszero(&srp->specific.client.x)) + if (mp_iszero(&srp->auth)) return SRP_CALL_ORDER_E; r = mp_init(&v); /* v = g ^ x % N */ - if (!r) r = mp_exptmod(&srp->g, &srp->specific.client.x, &srp->N, &v); + if (!r) r = mp_exptmod(&srp->g, &srp->auth, &srp->N, &v); if (!r) r = *size < (word32)mp_unsigned_bin_size(&v) ? BUFFER_E : MP_OKAY; if (!r) r = mp_to_unsigned_bin(&v, verifier); if (!r) *size = mp_unsigned_bin_size(&v); @@ -371,23 +359,19 @@ int wc_SrpSetVerifier(Srp* srp, const byte* verifier, word32 size) if (!srp || !verifier || srp->side != SRP_SERVER_SIDE) return BAD_FUNC_ARG; - if (mp_read_unsigned_bin(&srp->specific.server.v, verifier, size) - != MP_OKAY) - return MP_READ_E; - - return 0; + return mp_read_unsigned_bin(&srp->auth, verifier, size); } -int wc_SrpSetPrivate(Srp* srp, const byte* private, word32 size) { +int wc_SrpSetPrivate(Srp* srp, const byte* private, word32 size) +{ if (!srp || !private || !size) return BAD_FUNC_ARG; - return mp_read_unsigned_bin(srp->type == SRP_CLIENT_SIDE - ? &srp->specific.client.a - : &srp->specific.server.b, private, size); + return mp_read_unsigned_bin(&srp->priv, private, size); } -static int wc_SrpGenPrivate(Srp* srp, byte* private, word32 size) { +static int wc_SrpGenPrivate(Srp* srp, byte* private, word32 size) +{ RNG rng; int r = wc_InitRng(&rng); @@ -407,11 +391,10 @@ int wc_SrpGenPublic(Srp* srp, byte* public, word32* size) if (!srp || (!public && size) || (public && !size)) return BAD_FUNC_ARG; - if (srp->side == SRP_CLIENT_SIDE && mp_iszero(&srp->N)) + if (mp_iszero(&srp->N)) return SRP_CALL_ORDER_E; - if (srp->side == SRP_SERVER_SIDE && (mp_iszero(&srp->N) || - mp_iszero(&srp->specific.server.v))) + if (srp->side == SRP_SERVER_SIDE && mp_iszero(&srp->auth)) return SRP_CALL_ORDER_E; len = mp_unsigned_bin_size(&srp->N); @@ -422,55 +405,44 @@ int wc_SrpGenPublic(Srp* srp, byte* public, word32* size) if (!buf) return MEMORY_E; + /* priv = random() */ + if (mp_iszero(&srp->priv)) + r = wc_SrpGenPrivate(srp, buf, len); + + /* client side: A = g ^ a % N */ if (srp->side == SRP_CLIENT_SIDE) { - /* a = random() */ - if (mp_iszero(&srp->specific.client.a)) - r = wc_SrpGenPrivate(srp, buf, len); - /* A = g ^ a % N */ - if (!r) r = mp_exptmod(&srp->g, &srp->specific.client.a, - &srp->N, &srp->specific.client.A); + if (!r) r = mp_exptmod(&srp->g, &srp->priv, + &srp->N, &srp->pub); - /* extract public key to buffer */ - XMEMSET(buf, 0, len); - if (!r) r = mp_to_unsigned_bin(&srp->specific.client.A, buf); - if (!r) len = mp_unsigned_bin_size(&srp->specific.client.A); + /* server side: B = (k * v + (g ^ b % N)) % N */ + } else { + mp_int i, j; + if (mp_init_multi(&i, &j, 0, 0, 0, 0) == MP_OKAY) { + if (!r) r = mp_read_unsigned_bin(&i, srp->k,SrpHashSize(srp->type)); + if (!r) r = mp_exptmod(&srp->g, &srp->priv, + &srp->N, &srp->pub); + if (!r) r = mp_mulmod(&i, &srp->auth, &srp->N, &j); + if (!r) r = mp_add(&j, &srp->pub, &i); + if (!r) r = mp_mod(&i, &srp->N, &srp->pub); + + mp_clear(&i); mp_clear(&j); + } + } + + /* extract public key to buffer */ + XMEMSET(buf, 0, len); + if (!r) r = mp_to_unsigned_bin(&srp->pub, buf); + if (!r) len = mp_unsigned_bin_size(&srp->pub); + + /* update proofs */ + if (srp->side == SRP_CLIENT_SIDE) { /* Client proof = H( H(N) ^ H(g) | H(user) | salt | A) */ if (!r) r = SrpHashUpdate(&srp->client_proof, buf, len); /* Server proof = H(A) */ if (!r) r = SrpHashUpdate(&srp->server_proof, buf, len); - - } else { - mp_int i, j; - - if (mp_init_multi(&i, &j, 0, 0, 0, 0) == MP_OKAY) { - /* b = random() */ - if (mp_iszero(&srp->specific.server.b)) - r = wc_SrpGenPrivate(srp, buf, len); - - /* B = (k * v + (g ^ b % N)) % N */ - if (!r) r = mp_read_unsigned_bin(&i, srp->k,SrpHashSize(srp->type)); - if (!r) r = mp_exptmod(&srp->g, &srp->specific.server.b, - &srp->N, &srp->specific.server.B); - if (!r) r = mp_mul(&i, &srp->specific.server.v, &j); - if (!r) r = mp_add(&j, &srp->specific.server.B, &i); - if (!r) r = mp_mod(&i, &srp->N, &srp->specific.server.B); - - /* extract public key to buffer */ - XMEMSET(buf, 0, len); - if (!r) r = mp_to_unsigned_bin(&srp->specific.server.B, buf); - if (!r) len = mp_unsigned_bin_size(&srp->specific.server.B); - - /* Client proof = H( H(N) ^ H(g) | H(user) | salt | A) */ - if (!r) r = SrpHashUpdate(&srp->client_proof, buf, len); - - /* Server proof = H(A) */ - if (!r) r = SrpHashUpdate(&srp->server_proof, buf, len); - - mp_clear(&i); mp_clear(&j); - } } if (public) @@ -481,4 +453,112 @@ int wc_SrpGenPublic(Srp* srp, byte* public, word32* size) return r; } +static int wc_SrpSetU(Srp* srp, byte* peersKey, word32 peersKeySz) +{ + SrpHash hash; + byte digest[SRP_MAX_DIGEST_SIZE]; + byte* public = NULL; + word32 publicSz = 0; + word32 modulusSz = mp_unsigned_bin_size(&srp->N); + byte pad = 0; + word32 i; + int r = SrpHashInit(&hash, srp->type); + + if (!r && srp->side == SRP_CLIENT_SIDE) { + publicSz = mp_unsigned_bin_size(&srp->pub); + public = (byte*)XMALLOC(publicSz, NULL, DYNAMIC_TYPE_SRP); + + if (public == NULL) + r = MEMORY_E; + + /* H(A) */ + if (!r) r = mp_to_unsigned_bin(&srp->pub, public); + for (i = 0; i < modulusSz - publicSz; i++) + SrpHashUpdate(&hash, &pad, 1); + if (!r) r = SrpHashUpdate(&hash, public, publicSz); + + /* H(A | B) */ + if (!r) r = mp_read_unsigned_bin(&srp->peer, + peersKey, peersKeySz); + for (i = 0; i < modulusSz - peersKeySz; i++) + SrpHashUpdate(&hash, &pad, 1); + if (!r) r = SrpHashUpdate(&hash, peersKey, peersKeySz); + + /* Client proof = H( H(N) ^ H(g) | H(user) | salt | A | B) */ + if (!r) r = SrpHashUpdate(&srp->client_proof, peersKey, peersKeySz); + + } else if (!r && srp->side == SRP_SERVER_SIDE) { + publicSz = mp_unsigned_bin_size(&srp->pub); + public = (byte*)XMALLOC(publicSz, NULL, DYNAMIC_TYPE_SRP); + + if (public == NULL) + r = MEMORY_E; + + /* H(A) */ + if (!r) r = mp_read_unsigned_bin(&srp->peer, + peersKey, peersKeySz); + for (i = 0; i < modulusSz - peersKeySz; i++) + SrpHashUpdate(&hash, &pad, 1); + if (!r) r = SrpHashUpdate(&hash, peersKey, peersKeySz); + + /* H(A | B) */ + if (!r) r = mp_to_unsigned_bin(&srp->pub, public); + for (i = 0; i < modulusSz - publicSz; i++) + SrpHashUpdate(&hash, &pad, 1); + if (!r) r = SrpHashUpdate(&hash, public, publicSz); + } + + if (!r) r = SrpHashFinal(&hash, digest); + if (!r) r = mp_read_unsigned_bin(&srp->u, digest, SrpHashSize(srp->type)); + + XFREE(public, NULL, DYNAMIC_TYPE_SRP); + + return r; +} + +WOLFSSL_API int wc_SrpComputeKey(Srp* srp, byte* peersKey, word32 peersKeySz) +{ + mp_int i, j; + int r; + + if (!srp || !peersKey || peersKeySz == 0) + return BAD_FUNC_ARG; + + if ((r = mp_init_multi(&i, &j, 0, 0, 0, 0)) != MP_OKAY) + return r; + + r = wc_SrpSetU(srp, peersKey, peersKeySz); + + if (!r && srp->side == SRP_CLIENT_SIDE) { + r = mp_read_unsigned_bin(&i, srp->k, SrpHashSize(srp->type)); + + /* i = B - k * v */ + if (!r) r = mp_exptmod(&srp->g, &srp->auth, &srp->N, &j); + if (!r) r = mp_mulmod(&i, &j, &srp->N, &srp->s); + if (!r) r = mp_sub(&srp->peer, &srp->s, &i); + + /* j = a + u * x */ + if (!r) r = mp_mulmod(&srp->u, &srp->auth, &srp->N, &srp->s); + if (!r) r = mp_add(&srp->priv, &srp->s, &j); + + /* s = i ^ j % N */ + if (!r) r = mp_exptmod(&i, &j, &srp->N, &srp->s); + + } else if (!r && srp->side == SRP_SERVER_SIDE) { + /* i = v ^ u % N */ + if (!r) r = mp_exptmod(&srp->auth, &srp->u, &srp->N, &i); + + /* j = A * i % N */ + if (!r) r = mp_mulmod(&srp->peer, &i, &srp->N, &j); + + /* s = j * b % N */ + if (!r) r = mp_exptmod(&j, &srp->priv, &srp->N, &srp->s); + } + + mp_clear(&i); + mp_clear(&j); + + return r; +} + #endif /* WOLFCRYPT_HAVE_SRP */ diff --git a/wolfssl/wolfcrypt/srp.h b/wolfssl/wolfcrypt/srp.h index 8f6f9c081..7b19a4025 100644 --- a/wolfssl/wolfcrypt/srp.h +++ b/wolfssl/wolfcrypt/srp.h @@ -83,40 +83,27 @@ typedef struct { } SrpHash; typedef struct { - mp_int a; /**< Private ephemeral value. Random. */ - mp_int A; /**< Public ephemeral value. pow(g, a, N) */ - mp_int B; /**< Server's public ephemeral value. */ - mp_int x; /**< Priv key. H(salt, H(user, ":", pswd)) */ -} SrpClient; - -typedef struct { - mp_int b; /**< Private ephemeral value. */ - mp_int B; /**< Public ephemeral value. */ - mp_int A; /**< Client's public ephemeral value. */ - mp_int v; /**< Verifier. v = pow(g, x, N) */ -} SrpServer; - -typedef struct { - byte side; /**< Client or Server side. */ - byte type; /**< Hash type, SHA[1:256:384:512] */ - mp_int N; /**< Modulus. N = 2q+1, [q, N] are primes. */ - mp_int g; /**< Generator. A generator modulo N. */ - mp_int s; /**< Session key. */ - byte k[SRP_MAX_DIGEST_SIZE]; /**< Multiplier parameeter. H(N, g) */ - mp_int u; /**< Random scrambling parameeter. */ + byte side; /**< SRP_CLIENT_SIDE or SRP_SERVER_SIDE */ + byte type; /**< Hash type, one of SRP_TYPE_SHA[|256|384|512] */ byte* user; /**< Username, login. */ word32 userSz; /**< Username length. */ byte* salt; /**< Small salt. */ word32 saltSz; /**< Salt length. */ + mp_int N; /**< Modulus. N = 2q+1, [q, N] are primes. */ + mp_int g; /**< Generator. A generator modulo N. */ + byte k[SRP_MAX_DIGEST_SIZE]; /**< Multiplier parameeter. H(N, g) */ + mp_int auth; /**< Priv key. H(salt, H(user, ":", pswd)) */ + mp_int priv; /**< Private ephemeral value. */ + mp_int pub; /**< Public ephemeral value. */ + mp_int peer; /**< Peer's public ephemeral value. */ + mp_int u; /**< Random scrambling parameeter. */ SrpHash client_proof; /**< Client proof. Sent to Server. */ SrpHash server_proof; /**< Server proof. Sent to Client. */ - union { - SrpClient client; - SrpServer server; - } specific; + mp_int s; /**< Session key. */ } Srp; WOLFSSL_API int wc_SrpInit(Srp* srp, byte type, byte side); + WOLFSSL_API void wc_SrpTerm(Srp* srp); WOLFSSL_API int wc_SrpSetUsername(Srp* srp, const byte* username, word32 size); @@ -135,6 +122,8 @@ WOLFSSL_API int wc_SrpSetPrivate(Srp* srp, const byte* private, word32 size); WOLFSSL_API int wc_SrpGenPublic(Srp* srp, byte* public, word32* size); +WOLFSSL_API int wc_SrpComputeKey(Srp* srp, byte* peersKey, word32 peersKeySz); + #ifdef __cplusplus } /* extern "C" */ #endif