1238384Sjkim/* crypto/srp/srp_lib.c */
2280304Sjkim/*
3280304Sjkim * Written by Christophe Renou (christophe.renou@edelweb.fr) with the
4280304Sjkim * precious help of Peter Sylvester (peter.sylvester@edelweb.fr) for the
5280304Sjkim * EdelKey project and contributed to the OpenSSL project 2004.
6238384Sjkim */
7238384Sjkim/* ====================================================================
8238384Sjkim * Copyright (c) 2004 The OpenSSL Project.  All rights reserved.
9238384Sjkim *
10238384Sjkim * Redistribution and use in source and binary forms, with or without
11238384Sjkim * modification, are permitted provided that the following conditions
12238384Sjkim * are met:
13238384Sjkim *
14238384Sjkim * 1. Redistributions of source code must retain the above copyright
15280304Sjkim *    notice, this list of conditions and the following disclaimer.
16238384Sjkim *
17238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright
18238384Sjkim *    notice, this list of conditions and the following disclaimer in
19238384Sjkim *    the documentation and/or other materials provided with the
20238384Sjkim *    distribution.
21238384Sjkim *
22238384Sjkim * 3. All advertising materials mentioning features or use of this
23238384Sjkim *    software must display the following acknowledgment:
24238384Sjkim *    "This product includes software developed by the OpenSSL Project
25238384Sjkim *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
26238384Sjkim *
27238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
28238384Sjkim *    endorse or promote products derived from this software without
29238384Sjkim *    prior written permission. For written permission, please contact
30238384Sjkim *    licensing@OpenSSL.org.
31238384Sjkim *
32238384Sjkim * 5. Products derived from this software may not be called "OpenSSL"
33238384Sjkim *    nor may "OpenSSL" appear in their names without prior written
34238384Sjkim *    permission of the OpenSSL Project.
35238384Sjkim *
36238384Sjkim * 6. Redistributions of any form whatsoever must retain the following
37238384Sjkim *    acknowledgment:
38238384Sjkim *    "This product includes software developed by the OpenSSL Project
39238384Sjkim *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
40238384Sjkim *
41238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
42238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44238384Sjkim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
45238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE.
53238384Sjkim * ====================================================================
54238384Sjkim *
55238384Sjkim * This product includes cryptographic software written by Eric Young
56238384Sjkim * (eay@cryptsoft.com).  This product includes software written by Tim
57238384Sjkim * Hudson (tjh@cryptsoft.com).
58238384Sjkim *
59238384Sjkim */
60238384Sjkim#ifndef OPENSSL_NO_SRP
61280304Sjkim# include "cryptlib.h"
62280304Sjkim# include "srp_lcl.h"
63280304Sjkim# include <openssl/srp.h>
64280304Sjkim# include <openssl/evp.h>
65238384Sjkim
66280304Sjkim# if (BN_BYTES == 8)
67280304Sjkim#  if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
68280304Sjkim#   define bn_pack4(a1,a2,a3,a4) ((a1##UI64<<48)|(a2##UI64<<32)|(a3##UI64<<16)|a4##UI64)
69280304Sjkim#  elif defined(__arch64__)
70280304Sjkim#   define bn_pack4(a1,a2,a3,a4) ((a1##UL<<48)|(a2##UL<<32)|(a3##UL<<16)|a4##UL)
71280304Sjkim#  else
72280304Sjkim#   define bn_pack4(a1,a2,a3,a4) ((a1##ULL<<48)|(a2##ULL<<32)|(a3##ULL<<16)|a4##ULL)
73280304Sjkim#  endif
74280304Sjkim# elif (BN_BYTES == 4)
75280304Sjkim#  define bn_pack4(a1,a2,a3,a4)  ((a3##UL<<16)|a4##UL), ((a1##UL<<16)|a2##UL)
76264331Sjkim# else
77280304Sjkim#  error "unsupported BN_BYTES"
78264331Sjkim# endif
79238384Sjkim
80280304Sjkim# include "srp_grps.h"
81238384Sjkim
82238384Sjkimstatic BIGNUM *srp_Calc_k(BIGNUM *N, BIGNUM *g)
83280304Sjkim{
84280304Sjkim    /* k = SHA1(N | PAD(g)) -- tls-srp draft 8 */
85238384Sjkim
86280304Sjkim    unsigned char digest[SHA_DIGEST_LENGTH];
87280304Sjkim    unsigned char *tmp;
88280304Sjkim    EVP_MD_CTX ctxt;
89280304Sjkim    int longg;
90280304Sjkim    int longN = BN_num_bytes(N);
91238384Sjkim
92280304Sjkim    if (BN_ucmp(g, N) >= 0)
93280304Sjkim        return NULL;
94269686Sjkim
95280304Sjkim    if ((tmp = OPENSSL_malloc(longN)) == NULL)
96280304Sjkim        return NULL;
97280304Sjkim    BN_bn2bin(N, tmp);
98238384Sjkim
99280304Sjkim    EVP_MD_CTX_init(&ctxt);
100280304Sjkim    EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL);
101280304Sjkim    EVP_DigestUpdate(&ctxt, tmp, longN);
102238384Sjkim
103280304Sjkim    memset(tmp, 0, longN);
104280304Sjkim    longg = BN_bn2bin(g, tmp);
105280304Sjkim    /* use the zeros behind to pad on left */
106280304Sjkim    EVP_DigestUpdate(&ctxt, tmp + longg, longN - longg);
107280304Sjkim    EVP_DigestUpdate(&ctxt, tmp, longg);
108280304Sjkim    OPENSSL_free(tmp);
109238384Sjkim
110280304Sjkim    EVP_DigestFinal_ex(&ctxt, digest, NULL);
111280304Sjkim    EVP_MD_CTX_cleanup(&ctxt);
112280304Sjkim    return BN_bin2bn(digest, sizeof(digest), NULL);
113280304Sjkim}
114238384Sjkim
115238384SjkimBIGNUM *SRP_Calc_u(BIGNUM *A, BIGNUM *B, BIGNUM *N)
116280304Sjkim{
117280304Sjkim    /* k = SHA1(PAD(A) || PAD(B) ) -- tls-srp draft 8 */
118238384Sjkim
119280304Sjkim    BIGNUM *u;
120280304Sjkim    unsigned char cu[SHA_DIGEST_LENGTH];
121280304Sjkim    unsigned char *cAB;
122280304Sjkim    EVP_MD_CTX ctxt;
123280304Sjkim    int longN;
124280304Sjkim    if ((A == NULL) || (B == NULL) || (N == NULL))
125280304Sjkim        return NULL;
126238384Sjkim
127280304Sjkim    if (BN_ucmp(A, N) >= 0 || BN_ucmp(B, N) >= 0)
128280304Sjkim        return NULL;
129269686Sjkim
130280304Sjkim    longN = BN_num_bytes(N);
131238384Sjkim
132280304Sjkim    if ((cAB = OPENSSL_malloc(2 * longN)) == NULL)
133280304Sjkim        return NULL;
134238384Sjkim
135280304Sjkim    memset(cAB, 0, longN);
136238384Sjkim
137280304Sjkim    EVP_MD_CTX_init(&ctxt);
138280304Sjkim    EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL);
139280304Sjkim    EVP_DigestUpdate(&ctxt, cAB + BN_bn2bin(A, cAB + longN), longN);
140280304Sjkim    EVP_DigestUpdate(&ctxt, cAB + BN_bn2bin(B, cAB + longN), longN);
141280304Sjkim    OPENSSL_free(cAB);
142280304Sjkim    EVP_DigestFinal_ex(&ctxt, cu, NULL);
143280304Sjkim    EVP_MD_CTX_cleanup(&ctxt);
144238384Sjkim
145280304Sjkim    if (!(u = BN_bin2bn(cu, sizeof(cu), NULL)))
146280304Sjkim        return NULL;
147280304Sjkim    if (!BN_is_zero(u))
148280304Sjkim        return u;
149280304Sjkim    BN_free(u);
150280304Sjkim    return NULL;
151238384Sjkim}
152238384Sjkim
153280304SjkimBIGNUM *SRP_Calc_server_key(BIGNUM *A, BIGNUM *v, BIGNUM *u, BIGNUM *b,
154280304Sjkim                            BIGNUM *N)
155280304Sjkim{
156280304Sjkim    BIGNUM *tmp = NULL, *S = NULL;
157280304Sjkim    BN_CTX *bn_ctx;
158238384Sjkim
159280304Sjkim    if (u == NULL || A == NULL || v == NULL || b == NULL || N == NULL)
160280304Sjkim        return NULL;
161238384Sjkim
162280304Sjkim    if ((bn_ctx = BN_CTX_new()) == NULL ||
163280304Sjkim        (tmp = BN_new()) == NULL || (S = BN_new()) == NULL)
164280304Sjkim        goto err;
165238384Sjkim
166280304Sjkim    /* S = (A*v**u) ** b */
167238384Sjkim
168280304Sjkim    if (!BN_mod_exp(tmp, v, u, N, bn_ctx))
169280304Sjkim        goto err;
170280304Sjkim    if (!BN_mod_mul(tmp, A, tmp, N, bn_ctx))
171280304Sjkim        goto err;
172280304Sjkim    if (!BN_mod_exp(S, tmp, b, N, bn_ctx))
173280304Sjkim        goto err;
174280304Sjkim err:
175280304Sjkim    BN_CTX_free(bn_ctx);
176280304Sjkim    BN_clear_free(tmp);
177280304Sjkim    return S;
178280304Sjkim}
179280304Sjkim
180238384SjkimBIGNUM *SRP_Calc_B(BIGNUM *b, BIGNUM *N, BIGNUM *g, BIGNUM *v)
181280304Sjkim{
182280304Sjkim    BIGNUM *kv = NULL, *gb = NULL;
183280304Sjkim    BIGNUM *B = NULL, *k = NULL;
184280304Sjkim    BN_CTX *bn_ctx;
185238384Sjkim
186280304Sjkim    if (b == NULL || N == NULL || g == NULL || v == NULL ||
187280304Sjkim        (bn_ctx = BN_CTX_new()) == NULL)
188280304Sjkim        return NULL;
189238384Sjkim
190280304Sjkim    if ((kv = BN_new()) == NULL ||
191280304Sjkim        (gb = BN_new()) == NULL || (B = BN_new()) == NULL)
192280304Sjkim        goto err;
193238384Sjkim
194280304Sjkim    /* B = g**b + k*v */
195238384Sjkim
196280304Sjkim    if (!BN_mod_exp(gb, g, b, N, bn_ctx) ||
197280304Sjkim        !(k = srp_Calc_k(N, g)) ||
198280304Sjkim        !BN_mod_mul(kv, v, k, N, bn_ctx) ||
199280304Sjkim        !BN_mod_add(B, gb, kv, N, bn_ctx)) {
200280304Sjkim        BN_free(B);
201280304Sjkim        B = NULL;
202280304Sjkim    }
203280304Sjkim err:
204280304Sjkim    BN_CTX_free(bn_ctx);
205280304Sjkim    BN_clear_free(kv);
206280304Sjkim    BN_clear_free(gb);
207280304Sjkim    BN_free(k);
208280304Sjkim    return B;
209280304Sjkim}
210238384Sjkim
211238384SjkimBIGNUM *SRP_Calc_x(BIGNUM *s, const char *user, const char *pass)
212280304Sjkim{
213280304Sjkim    unsigned char dig[SHA_DIGEST_LENGTH];
214280304Sjkim    EVP_MD_CTX ctxt;
215280304Sjkim    unsigned char *cs;
216238384Sjkim
217280304Sjkim    if ((s == NULL) || (user == NULL) || (pass == NULL))
218280304Sjkim        return NULL;
219238384Sjkim
220280304Sjkim    if ((cs = OPENSSL_malloc(BN_num_bytes(s))) == NULL)
221280304Sjkim        return NULL;
222238384Sjkim
223280304Sjkim    EVP_MD_CTX_init(&ctxt);
224280304Sjkim    EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL);
225280304Sjkim    EVP_DigestUpdate(&ctxt, user, strlen(user));
226280304Sjkim    EVP_DigestUpdate(&ctxt, ":", 1);
227280304Sjkim    EVP_DigestUpdate(&ctxt, pass, strlen(pass));
228280304Sjkim    EVP_DigestFinal_ex(&ctxt, dig, NULL);
229238384Sjkim
230280304Sjkim    EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL);
231280304Sjkim    BN_bn2bin(s, cs);
232280304Sjkim    EVP_DigestUpdate(&ctxt, cs, BN_num_bytes(s));
233280304Sjkim    OPENSSL_free(cs);
234280304Sjkim    EVP_DigestUpdate(&ctxt, dig, sizeof(dig));
235280304Sjkim    EVP_DigestFinal_ex(&ctxt, dig, NULL);
236280304Sjkim    EVP_MD_CTX_cleanup(&ctxt);
237238384Sjkim
238280304Sjkim    return BN_bin2bn(dig, sizeof(dig), NULL);
239280304Sjkim}
240238384Sjkim
241238384SjkimBIGNUM *SRP_Calc_A(BIGNUM *a, BIGNUM *N, BIGNUM *g)
242280304Sjkim{
243280304Sjkim    BN_CTX *bn_ctx;
244280304Sjkim    BIGNUM *A = NULL;
245238384Sjkim
246280304Sjkim    if (a == NULL || N == NULL || g == NULL ||
247280304Sjkim        (bn_ctx = BN_CTX_new()) == NULL)
248280304Sjkim        return NULL;
249238384Sjkim
250280304Sjkim    if ((A = BN_new()) != NULL && !BN_mod_exp(A, g, a, N, bn_ctx)) {
251280304Sjkim        BN_free(A);
252280304Sjkim        A = NULL;
253280304Sjkim    }
254280304Sjkim    BN_CTX_free(bn_ctx);
255280304Sjkim    return A;
256280304Sjkim}
257238384Sjkim
258280304SjkimBIGNUM *SRP_Calc_client_key(BIGNUM *N, BIGNUM *B, BIGNUM *g, BIGNUM *x,
259280304Sjkim                            BIGNUM *a, BIGNUM *u)
260280304Sjkim{
261280304Sjkim    BIGNUM *tmp = NULL, *tmp2 = NULL, *tmp3 = NULL, *k = NULL, *K = NULL;
262280304Sjkim    BN_CTX *bn_ctx;
263238384Sjkim
264280304Sjkim    if (u == NULL || B == NULL || N == NULL || g == NULL || x == NULL
265280304Sjkim        || a == NULL || (bn_ctx = BN_CTX_new()) == NULL)
266280304Sjkim        return NULL;
267238384Sjkim
268280304Sjkim    if ((tmp = BN_new()) == NULL ||
269280304Sjkim        (tmp2 = BN_new()) == NULL ||
270280304Sjkim        (tmp3 = BN_new()) == NULL || (K = BN_new()) == NULL)
271280304Sjkim        goto err;
272238384Sjkim
273280304Sjkim    if (!BN_mod_exp(tmp, g, x, N, bn_ctx))
274280304Sjkim        goto err;
275280304Sjkim    if (!(k = srp_Calc_k(N, g)))
276280304Sjkim        goto err;
277280304Sjkim    if (!BN_mod_mul(tmp2, tmp, k, N, bn_ctx))
278280304Sjkim        goto err;
279280304Sjkim    if (!BN_mod_sub(tmp, B, tmp2, N, bn_ctx))
280280304Sjkim        goto err;
281238384Sjkim
282280304Sjkim    if (!BN_mod_mul(tmp3, u, x, N, bn_ctx))
283280304Sjkim        goto err;
284280304Sjkim    if (!BN_mod_add(tmp2, a, tmp3, N, bn_ctx))
285280304Sjkim        goto err;
286280304Sjkim    if (!BN_mod_exp(K, tmp, tmp2, N, bn_ctx))
287280304Sjkim        goto err;
288238384Sjkim
289280304Sjkim err:
290280304Sjkim    BN_CTX_free(bn_ctx);
291280304Sjkim    BN_clear_free(tmp);
292280304Sjkim    BN_clear_free(tmp2);
293280304Sjkim    BN_clear_free(tmp3);
294280304Sjkim    BN_free(k);
295280304Sjkim    return K;
296280304Sjkim}
297238384Sjkim
298238384Sjkimint SRP_Verify_B_mod_N(BIGNUM *B, BIGNUM *N)
299280304Sjkim{
300280304Sjkim    BIGNUM *r;
301280304Sjkim    BN_CTX *bn_ctx;
302280304Sjkim    int ret = 0;
303238384Sjkim
304280304Sjkim    if (B == NULL || N == NULL || (bn_ctx = BN_CTX_new()) == NULL)
305280304Sjkim        return 0;
306238384Sjkim
307280304Sjkim    if ((r = BN_new()) == NULL)
308280304Sjkim        goto err;
309280304Sjkim    /* Checks if B % N == 0 */
310280304Sjkim    if (!BN_nnmod(r, B, N, bn_ctx))
311280304Sjkim        goto err;
312280304Sjkim    ret = !BN_is_zero(r);
313280304Sjkim err:
314280304Sjkim    BN_CTX_free(bn_ctx);
315280304Sjkim    BN_free(r);
316280304Sjkim    return ret;
317280304Sjkim}
318238384Sjkim
319238384Sjkimint SRP_Verify_A_mod_N(BIGNUM *A, BIGNUM *N)
320280304Sjkim{
321280304Sjkim    /* Checks if A % N == 0 */
322280304Sjkim    return SRP_Verify_B_mod_N(A, N);
323280304Sjkim}
324238384Sjkim
325280304Sjkim/*
326280304Sjkim * Check if G and N are kwown parameters. The values have been generated
327280304Sjkim * from the ietf-tls-srp draft version 8
328280304Sjkim */
329238384Sjkimchar *SRP_check_known_gN_param(BIGNUM *g, BIGNUM *N)
330280304Sjkim{
331280304Sjkim    size_t i;
332280304Sjkim    if ((g == NULL) || (N == NULL))
333280304Sjkim        return 0;
334238384Sjkim
335280304Sjkim    srp_bn_print(g);
336280304Sjkim    srp_bn_print(N);
337238384Sjkim
338280304Sjkim    for (i = 0; i < KNOWN_GN_NUMBER; i++) {
339280304Sjkim        if (BN_cmp(knowngN[i].g, g) == 0 && BN_cmp(knowngN[i].N, N) == 0)
340280304Sjkim            return knowngN[i].id;
341280304Sjkim    }
342280304Sjkim    return NULL;
343280304Sjkim}
344238384Sjkim
345238384SjkimSRP_gN *SRP_get_default_gN(const char *id)
346280304Sjkim{
347280304Sjkim    size_t i;
348238384Sjkim
349280304Sjkim    if (id == NULL)
350280304Sjkim        return knowngN;
351280304Sjkim    for (i = 0; i < KNOWN_GN_NUMBER; i++) {
352280304Sjkim        if (strcmp(knowngN[i].id, id) == 0)
353280304Sjkim            return knowngN + i;
354280304Sjkim    }
355280304Sjkim    return NULL;
356280304Sjkim}
357238384Sjkim#endif
358