2 * Secure Remote Password 6a implementation
3 * https://github.com/est31/csrp-gmp
5 * The MIT License (MIT)
7 * Copyright (c) 2010, 2013 Tom Cocagne, 2015 est31 <MTest31@outlook.com>
9 * Permission is hereby granted, free of charge, to any person obtaining a copy of
10 * this software and associated documentation files (the "Software"), to deal in
11 * the Software without restriction, including without limitation the rights to
12 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
13 * of the Software, and to permit persons to whom the Software is furnished to do
14 * so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in all
17 * copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
55 #include <util/sha2.h>
58 //#define CSRP_USE_SHA1
59 #define CSRP_USE_SHA256
61 #define srp_dbg_data(data, datalen, prevtext) ;
62 /*void srp_dbg_data(unsigned char * data, size_t datalen, char * prevtext)
66 for (i = 0; i < datalen; i++)
68 printf("%02X", data[i]);
73 static int g_initialized
= 0;
75 #define RAND_BUFF_MAX 128
76 static unsigned int g_rand_idx
;
77 static unsigned char g_rand_buff
[RAND_BUFF_MAX
];
79 void *(*srp_alloc
)(size_t) = &malloc
;
80 void *(*srp_realloc
)(void *, size_t) = &realloc
;
81 void (*srp_free
)(void *) = &free
;
84 void srp_set_memory_functions(
85 void *(*new_srp_alloc
)(size_t),
86 void *(*new_srp_realloc
)(void *, size_t),
87 void (*new_srp_free
)(void *))
89 srp_alloc
= new_srp_alloc
;
90 srp_realloc
= new_srp_realloc
;
91 srp_free
= new_srp_free
;
105 /* All constants here were pulled from Appendix A of RFC 5054 */
106 static struct NGHex global_Ng_constants
[] = {
108 "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
109 "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
110 "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
111 "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
112 "FD5138FE8376435B9FC61D2FC0EB06E3",
115 "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294"
116 "3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D"
117 "CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB"
118 "D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74"
119 "7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A"
120 "436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D"
121 "5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73"
122 "03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6"
123 "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F"
127 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
128 "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
129 "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
130 "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
131 "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
132 "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
133 "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
134 "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
135 "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
136 "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
137 "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
138 "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
139 "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
140 "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
141 "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
142 "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
143 "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
144 "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
148 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
149 "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
150 "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
151 "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
152 "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
153 "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
154 "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
155 "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
156 "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
157 "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
158 "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
159 "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
160 "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
161 "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
162 "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
163 "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
164 "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
165 "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
166 "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
167 "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
168 "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
169 "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
170 "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
171 "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
172 "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
173 "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
174 "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
175 "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA"
176 "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C"
177 "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
178 "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886"
179 "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6"
180 "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5"
181 "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268"
182 "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6"
183 "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
184 "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
186 {0, 0} /* null sentinel */
189 static void delete_ng(NGConstant
*ng
)
198 static NGConstant
*new_ng(SRP_NGType ng_type
, const char *n_hex
, const char *g_hex
)
200 NGConstant
*ng
= (NGConstant
*)srp_alloc(sizeof(NGConstant
));
207 if (ng_type
!= SRP_NG_CUSTOM
) {
208 n_hex
= global_Ng_constants
[ng_type
].n_hex
;
209 g_hex
= global_Ng_constants
[ng_type
].g_hex
;
213 rv
= mpz_set_str(ng
->N
, n_hex
, 16);
214 rv
= rv
| mpz_set_str(ng
->g
, g_hex
, 16);
227 // SHA512_CTX sha512;
231 SRP_HashAlgorithm hash_alg
;
235 unsigned char *bytes_B
;
238 unsigned char M
[SHA512_DIGEST_LENGTH
];
239 unsigned char H_AMK
[SHA512_DIGEST_LENGTH
];
240 unsigned char session_key
[SHA512_DIGEST_LENGTH
];
244 SRP_HashAlgorithm hash_alg
;
251 unsigned char *bytes_A
;
255 char *username_verifier
;
256 unsigned char *password
;
259 unsigned char M
[SHA512_DIGEST_LENGTH
];
260 unsigned char H_AMK
[SHA512_DIGEST_LENGTH
];
261 unsigned char session_key
[SHA512_DIGEST_LENGTH
];
265 static int hash_init(SRP_HashAlgorithm alg
, HashCTX
*c
)
269 case SRP_SHA1
: return SHA1_Init(&c
->sha
);
272 case SRP_SHA224: return SHA224_Init(&c->sha256);
274 #ifdef CSRP_USE_SHA256
275 case SRP_SHA256
: return SHA256_Init(&c
->sha256
);
278 case SRP_SHA384: return SHA384_Init(&c->sha512);
279 case SRP_SHA512: return SHA512_Init(&c->sha512);
284 static int hash_update( SRP_HashAlgorithm alg
, HashCTX
*c
, const void *data
, size_t len
)
288 case SRP_SHA1
: return SHA1_Update(&c
->sha
, data
, len
);
291 case SRP_SHA224: return SHA224_Update(&c->sha256, data, len);
293 #ifdef CSRP_USE_SHA256
294 case SRP_SHA256
: return SHA256_Update(&c
->sha256
, data
, len
);
297 case SRP_SHA384: return SHA384_Update(&c->sha512, data, len);
298 case SRP_SHA512: return SHA512_Update(&c->sha512, data, len);
303 static int hash_final( SRP_HashAlgorithm alg
, HashCTX
*c
, unsigned char *md
)
307 case SRP_SHA1
: return SHA1_Final(md
, &c
->sha
);
310 case SRP_SHA224: return SHA224_Final(md, &c->sha256);
312 #ifdef CSRP_USE_SHA256
313 case SRP_SHA256
: return SHA256_Final(md
, &c
->sha256
);
316 case SRP_SHA384: return SHA384_Final(md, &c->sha512);
317 case SRP_SHA512: return SHA512_Final(md, &c->sha512);
322 static unsigned char *hash(SRP_HashAlgorithm alg
, const unsigned char *d
, size_t n
, unsigned char *md
)
326 case SRP_SHA1
: return SHA1(d
, n
, md
);
329 case SRP_SHA224: return SHA224( d, n, md );
331 #ifdef CSRP_USE_SHA256
332 case SRP_SHA256
: return SHA256(d
, n
, md
);
335 case SRP_SHA384: return SHA384( d, n, md );
336 case SRP_SHA512: return SHA512( d, n, md );
341 static size_t hash_length(SRP_HashAlgorithm alg
)
345 case SRP_SHA1
: return SHA_DIGEST_LENGTH
;
348 case SRP_SHA224: return SHA224_DIGEST_LENGTH;
350 #ifdef CSRP_USE_SHA256
351 case SRP_SHA256
: return SHA256_DIGEST_LENGTH
;
354 case SRP_SHA384: return SHA384_DIGEST_LENGTH;
355 case SRP_SHA512: return SHA512_DIGEST_LENGTH;
362 inline static int mpz_num_bytes(const mpz_t op
)
364 return (mpz_sizeinbase(op
, 2) + 7) / 8;
367 inline static void mpz_to_bin(const mpz_t op
, unsigned char *to
)
369 mpz_export(to
, NULL
, 1, 1, 1, 0, op
);
372 inline static void mpz_from_bin(const unsigned char *s
, size_t len
, mpz_t ret
)
374 mpz_import(ret
, len
, 1, 1, 1, 0, s
);
377 // set op to (op1 * op2) mod d, using tmp for the calculation
378 inline static void mpz_mulm(
379 mpz_t op
, const mpz_t op1
, const mpz_t op2
, const mpz_t d
, mpz_t tmp
)
381 mpz_mul(tmp
, op1
, op2
);
385 // set op to (op1 + op2) mod d, using tmp for the calculation
386 inline static void mpz_addm(
387 mpz_t op
, const mpz_t op1
, const mpz_t op2
, const mpz_t d
, mpz_t tmp
)
389 mpz_add(tmp
, op1
, op2
);
393 // set op to (op1 - op2) mod d, using tmp for the calculation
394 inline static void mpz_subm(
395 mpz_t op
, const mpz_t op1
, const mpz_t op2
, const mpz_t d
, mpz_t tmp
)
397 mpz_sub(tmp
, op1
, op2
);
401 static SRP_Result
H_nn(
402 mpz_t result
, SRP_HashAlgorithm alg
, const mpz_t N
, const mpz_t n1
, const mpz_t n2
)
404 unsigned char buff
[SHA512_DIGEST_LENGTH
];
405 size_t len_N
= mpz_num_bytes(N
);
406 size_t len_n1
= mpz_num_bytes(n1
);
407 size_t len_n2
= mpz_num_bytes(n2
);
408 size_t nbytes
= len_N
+ len_N
;
409 unsigned char *bin
= (unsigned char *)srp_alloc(nbytes
);
410 if (!bin
) return SRP_ERR
;
411 if (len_n1
> len_N
|| len_n2
> len_N
) {
415 memset(bin
, 0, nbytes
);
416 mpz_to_bin(n1
, bin
+ (len_N
- len_n1
));
417 mpz_to_bin(n2
, bin
+ (len_N
+ len_N
- len_n2
));
418 hash(alg
, bin
, nbytes
, buff
);
420 mpz_from_bin(buff
, hash_length(alg
), result
);
424 static SRP_Result
H_ns(mpz_t result
, SRP_HashAlgorithm alg
, const unsigned char *n
,
425 size_t len_n
, const unsigned char *bytes
, uint32_t len_bytes
)
427 unsigned char buff
[SHA512_DIGEST_LENGTH
];
428 size_t nbytes
= len_n
+ len_bytes
;
429 unsigned char *bin
= (unsigned char *)srp_alloc(nbytes
);
430 if (!bin
) return SRP_ERR
;
431 memcpy(bin
, n
, len_n
);
432 memcpy(bin
+ len_n
, bytes
, len_bytes
);
433 hash(alg
, bin
, nbytes
, buff
);
435 mpz_from_bin(buff
, hash_length(alg
), result
);
439 static int calculate_x(mpz_t result
, SRP_HashAlgorithm alg
, const unsigned char *salt
,
440 size_t salt_len
, const char *username
, const unsigned char *password
,
443 unsigned char ucp_hash
[SHA512_DIGEST_LENGTH
];
445 hash_init(alg
, &ctx
);
447 srp_dbg_data((char *)username
, strlen(username
), "Username for x: ");
448 srp_dbg_data((char *)password
, password_len
, "Password for x: ");
449 hash_update(alg
, &ctx
, username
, strlen(username
));
450 hash_update(alg
, &ctx
, ":", 1);
451 hash_update(alg
, &ctx
, password
, password_len
);
453 hash_final(alg
, &ctx
, ucp_hash
);
455 return H_ns(result
, alg
, salt
, salt_len
, ucp_hash
, hash_length(alg
));
458 static SRP_Result
update_hash_n(SRP_HashAlgorithm alg
, HashCTX
*ctx
, const mpz_t n
)
460 size_t len
= mpz_num_bytes(n
);
461 unsigned char *n_bytes
= (unsigned char *)srp_alloc(len
);
462 if (!n_bytes
) return SRP_ERR
;
463 mpz_to_bin(n
, n_bytes
);
464 hash_update(alg
, ctx
, n_bytes
, len
);
469 static SRP_Result
hash_num(SRP_HashAlgorithm alg
, const mpz_t n
, unsigned char *dest
)
471 int nbytes
= mpz_num_bytes(n
);
472 unsigned char *bin
= (unsigned char *)srp_alloc(nbytes
);
473 if (!bin
) return SRP_ERR
;
475 hash(alg
, bin
, nbytes
, dest
);
480 static SRP_Result
calculate_M(SRP_HashAlgorithm alg
, NGConstant
*ng
, unsigned char *dest
,
481 const char *I
, const unsigned char *s_bytes
, size_t s_len
, const mpz_t A
,
482 const mpz_t B
, const unsigned char *K
)
484 unsigned char H_N
[SHA512_DIGEST_LENGTH
];
485 unsigned char H_g
[SHA512_DIGEST_LENGTH
];
486 unsigned char H_I
[SHA512_DIGEST_LENGTH
];
487 unsigned char H_xor
[SHA512_DIGEST_LENGTH
];
490 size_t hash_len
= hash_length(alg
);
492 if (!hash_num(alg
, ng
->N
, H_N
)) return SRP_ERR
;
493 if (!hash_num(alg
, ng
->g
, H_g
)) return SRP_ERR
;
495 hash(alg
, (const unsigned char *)I
, strlen(I
), H_I
);
497 for (i
= 0; i
< hash_len
; i
++)
498 H_xor
[i
] = H_N
[i
] ^ H_g
[i
];
500 hash_init(alg
, &ctx
);
502 hash_update(alg
, &ctx
, H_xor
, hash_len
);
503 hash_update(alg
, &ctx
, H_I
, hash_len
);
504 hash_update(alg
, &ctx
, s_bytes
, s_len
);
505 if (!update_hash_n(alg
, &ctx
, A
)) return SRP_ERR
;
506 if (!update_hash_n(alg
, &ctx
, B
)) return SRP_ERR
;
507 hash_update(alg
, &ctx
, K
, hash_len
);
509 hash_final(alg
, &ctx
, dest
);
513 static SRP_Result
calculate_H_AMK(SRP_HashAlgorithm alg
, unsigned char *dest
,
514 const mpz_t A
, const unsigned char *M
, const unsigned char *K
)
518 hash_init(alg
, &ctx
);
520 if (!update_hash_n(alg
, &ctx
, A
)) return SRP_ERR
;
521 hash_update(alg
, &ctx
, M
, hash_length(alg
));
522 hash_update(alg
, &ctx
, K
, hash_length(alg
));
524 hash_final(alg
, &ctx
, dest
);
528 static SRP_Result
fill_buff()
540 if (!CryptAcquireContext(&wctx
, NULL
, NULL
, PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
))
542 if (!CryptGenRandom(wctx
, sizeof(g_rand_buff
), (BYTE
*)g_rand_buff
)) return SRP_ERR
;
543 if (!CryptReleaseContext(wctx
, 0)) return SRP_ERR
;
546 fp
= fopen("/dev/urandom", "r");
548 if (!fp
) return SRP_ERR
;
550 if (fread(g_rand_buff
, sizeof(g_rand_buff
), 1, fp
) != 1) { fclose(fp
); return SRP_ERR
; }
551 if (fclose(fp
)) return SRP_ERR
;
556 static SRP_Result
mpz_fill_random(mpz_t num
)
558 // was call: BN_rand(num, 256, -1, 0);
559 if (RAND_BUFF_MAX
- g_rand_idx
< 32)
560 if (fill_buff() != SRP_OK
) return SRP_ERR
;
561 mpz_from_bin((const unsigned char *)(&g_rand_buff
[g_rand_idx
]), 32, num
);
566 static SRP_Result
init_random()
568 if (g_initialized
) return SRP_OK
;
569 SRP_Result ret
= fill_buff();
570 g_initialized
= (ret
== SRP_OK
);
574 #define srp_dbg_num(num, text) ;
575 /*void srp_dbg_num(mpz_t num, char * prevtext)
577 int len_num = mpz_num_bytes(num);
578 char *bytes_num = (char*) srp_alloc(len_num);
579 mpz_to_bin(num, (unsigned char *) bytes_num);
580 srp_dbg_data(bytes_num, len_num, prevtext);
585 /***********************************************************************************************************
589 ***********************************************************************************************************/
592 SRP_Result
srp_create_salted_verification_key( SRP_HashAlgorithm alg
,
593 SRP_NGType ng_type
, const char *username_for_verifier
,
594 const unsigned char *password
, size_t len_password
,
595 unsigned char **bytes_s
, size_t *len_s
,
596 unsigned char **bytes_v
, size_t *len_v
,
597 const char *n_hex
, const char *g_hex
)
599 SRP_Result ret
= SRP_OK
;
601 mpz_t v
; mpz_init(v
);
602 mpz_t x
; mpz_init(x
);
605 NGConstant
*ng
= new_ng(ng_type
, n_hex
, g_hex
);
607 if (!ng
) goto error_and_exit
;
609 if (init_random() != SRP_OK
) /* Only happens once */
612 if (*bytes_s
== NULL
) {
613 size_t size_to_fill
= 16;
614 *len_s
= size_to_fill
;
615 if (RAND_BUFF_MAX
- g_rand_idx
< size_to_fill
)
616 if (fill_buff() != SRP_OK
) goto error_and_exit
;
617 *bytes_s
= (unsigned char *)srp_alloc(size_to_fill
);
618 if (!*bytes_s
) goto error_and_exit
;
619 memcpy(*bytes_s
, &g_rand_buff
[g_rand_idx
], size_to_fill
);
620 g_rand_idx
+= size_to_fill
;
624 x
, alg
, *bytes_s
, *len_s
, username_for_verifier
, password
, len_password
))
627 srp_dbg_num(x
, "Server calculated x: ");
629 mpz_powm(v
, ng
->g
, x
, ng
->N
);
631 *len_v
= mpz_num_bytes(v
);
633 *bytes_v
= (unsigned char *)srp_alloc(*len_v
);
635 if (!*bytes_v
) goto error_and_exit
;
637 mpz_to_bin(v
, *bytes_v
);
646 goto cleanup_and_exit
;
651 /* Out: bytes_B, len_B.
653 * On failure, bytes_B will be set to NULL and len_B will be set to 0
655 struct SRPVerifier
*srp_verifier_new(SRP_HashAlgorithm alg
,
656 SRP_NGType ng_type
, const char *username
,
657 const unsigned char *bytes_s
, size_t len_s
,
658 const unsigned char *bytes_v
, size_t len_v
,
659 const unsigned char *bytes_A
, size_t len_A
,
660 const unsigned char *bytes_b
, size_t len_b
,
661 unsigned char **bytes_B
, size_t *len_B
,
662 const char *n_hex
, const char *g_hex
)
664 mpz_t v
; mpz_init(v
); mpz_from_bin(bytes_v
, len_v
, v
);
665 mpz_t A
; mpz_init(A
); mpz_from_bin(bytes_A
, len_A
, A
);
666 mpz_t u
; mpz_init(u
);
667 mpz_t B
; mpz_init(B
);
668 mpz_t S
; mpz_init(S
);
669 mpz_t b
; mpz_init(b
);
670 mpz_t k
; mpz_init(k
);
671 mpz_t tmp1
; mpz_init(tmp1
);
672 mpz_t tmp2
; mpz_init(tmp2
);
673 mpz_t tmp3
; mpz_init(tmp3
);
675 size_t ulen
= strlen(username
) + 1;
676 NGConstant
*ng
= new_ng(ng_type
, n_hex
, g_hex
);
677 struct SRPVerifier
*ver
= 0;
682 if (!ng
) goto cleanup_and_exit
;
684 ver
= (struct SRPVerifier
*)srp_alloc(sizeof(struct SRPVerifier
));
686 if (!ver
) goto cleanup_and_exit
;
688 if (init_random() != SRP_OK
) { /* Only happens once */
691 goto cleanup_and_exit
;
694 ver
->username
= (char *)srp_alloc(ulen
);
698 if (!ver
->username
) {
701 goto cleanup_and_exit
;
704 memcpy(ver
->username
, username
, ulen
);
706 ver
->authenticated
= 0;
708 /* SRP-6a safety check */
709 mpz_mod(tmp1
, A
, ng
->N
);
710 if (mpz_sgn(tmp1
) != 0) {
712 mpz_from_bin(bytes_b
, len_b
, b
);
714 if (!mpz_fill_random(b
)) goto ver_cleanup_and_exit
;
717 if (!H_nn(k
, alg
, ng
->N
, ng
->N
, ng
->g
)) goto ver_cleanup_and_exit
;
720 mpz_mulm(tmp1
, k
, v
, ng
->N
, tmp3
);
721 mpz_powm(tmp2
, ng
->g
, b
, ng
->N
);
722 mpz_addm(B
, tmp1
, tmp2
, ng
->N
, tmp3
);
724 if (!H_nn(u
, alg
, ng
->N
, A
, B
)) goto ver_cleanup_and_exit
;
726 srp_dbg_num(u
, "Server calculated u: ");
728 /* S = (A *(v^u)) ^ b */
729 mpz_powm(tmp1
, v
, u
, ng
->N
);
730 mpz_mulm(tmp2
, A
, tmp1
, ng
->N
, tmp3
);
731 mpz_powm(S
, tmp2
, b
, ng
->N
);
733 if (!hash_num(alg
, S
, ver
->session_key
)) goto ver_cleanup_and_exit
;
736 alg
, ng
, ver
->M
, username
, bytes_s
, len_s
, A
, B
, ver
->session_key
)) {
737 goto ver_cleanup_and_exit
;
739 if (!calculate_H_AMK(alg
, ver
->H_AMK
, A
, ver
->M
, ver
->session_key
)) {
740 goto ver_cleanup_and_exit
;
743 *len_B
= mpz_num_bytes(B
);
744 *bytes_B
= (unsigned char *)srp_alloc(*len_B
);
748 goto ver_cleanup_and_exit
;
751 mpz_to_bin(B
, *bytes_B
);
753 ver
->bytes_B
= *bytes_B
;
771 ver_cleanup_and_exit
:
772 srp_free(ver
->username
);
775 goto cleanup_and_exit
;
778 void srp_verifier_delete(struct SRPVerifier
*ver
)
782 srp_free(ver
->username
);
783 srp_free(ver
->bytes_B
);
784 memset(ver
, 0, sizeof(*ver
));
789 int srp_verifier_is_authenticated(struct SRPVerifier
*ver
)
791 return ver
->authenticated
;
794 const char *srp_verifier_get_username(struct SRPVerifier
*ver
)
796 return ver
->username
;
799 const unsigned char *srp_verifier_get_session_key(
800 struct SRPVerifier
*ver
, size_t *key_length
)
802 if (key_length
) *key_length
= hash_length(ver
->hash_alg
);
803 return ver
->session_key
;
806 size_t srp_verifier_get_session_key_length(struct SRPVerifier
*ver
)
808 return hash_length(ver
->hash_alg
);
811 /* user_M must be exactly SHA512_DIGEST_LENGTH bytes in size */
812 void srp_verifier_verify_session(
813 struct SRPVerifier
*ver
, const unsigned char *user_M
, unsigned char **bytes_HAMK
)
815 if (memcmp(ver
->M
, user_M
, hash_length(ver
->hash_alg
)) == 0) {
816 ver
->authenticated
= 1;
817 *bytes_HAMK
= ver
->H_AMK
;
822 /*******************************************************************************/
824 struct SRPUser
*srp_user_new(SRP_HashAlgorithm alg
, SRP_NGType ng_type
,
825 const char *username
, const char *username_for_verifier
,
826 const unsigned char *bytes_password
, size_t len_password
, const char *n_hex
,
829 struct SRPUser
*usr
= (struct SRPUser
*)srp_alloc(sizeof(struct SRPUser
));
830 size_t ulen
= strlen(username
) + 1;
831 size_t uvlen
= strlen(username_for_verifier
) + 1;
833 if (!usr
) goto err_exit
;
835 if (init_random() != SRP_OK
) /* Only happens once */
839 usr
->ng
= new_ng(ng_type
, n_hex
, g_hex
);
845 if (!usr
->ng
) goto err_exit
;
847 usr
->username
= (char *)srp_alloc(ulen
);
848 usr
->username_verifier
= (char *)srp_alloc(uvlen
);
849 usr
->password
= (unsigned char *)srp_alloc(len_password
);
850 usr
->password_len
= len_password
;
852 if (!usr
->username
|| !usr
->password
|| !usr
->username_verifier
) goto err_exit
;
854 memcpy(usr
->username
, username
, ulen
);
855 memcpy(usr
->username_verifier
, username_for_verifier
, uvlen
);
856 memcpy(usr
->password
, bytes_password
, len_password
);
858 usr
->authenticated
= 0;
870 srp_free(usr
->username
);
871 srp_free(usr
->username_verifier
);
873 memset(usr
->password
, 0, usr
->password_len
);
874 srp_free(usr
->password
);
882 void srp_user_delete(struct SRPUser
*usr
)
891 memset(usr
->password
, 0, usr
->password_len
);
893 srp_free(usr
->username
);
894 srp_free(usr
->username_verifier
);
895 srp_free(usr
->password
);
897 if (usr
->bytes_A
) srp_free(usr
->bytes_A
);
899 memset(usr
, 0, sizeof(*usr
));
904 int srp_user_is_authenticated(struct SRPUser
*usr
)
906 return usr
->authenticated
;
909 const char *srp_user_get_username(struct SRPUser
*usr
)
911 return usr
->username
;
914 const unsigned char *srp_user_get_session_key(struct SRPUser
*usr
, size_t *key_length
)
916 if (key_length
) *key_length
= hash_length(usr
->hash_alg
);
917 return usr
->session_key
;
920 size_t srp_user_get_session_key_length(struct SRPUser
*usr
)
922 return hash_length(usr
->hash_alg
);
926 /* Output: username, bytes_A, len_A */
927 SRP_Result
srp_user_start_authentication(struct SRPUser
*usr
, char **username
,
928 const unsigned char *bytes_a
, size_t len_a
,
929 unsigned char **bytes_A
, size_t *len_A
)
933 mpz_from_bin(bytes_a
, len_a
, usr
->a
);
935 if (!mpz_fill_random(usr
->a
)) goto error_and_exit
;
938 mpz_powm(usr
->A
, usr
->ng
->g
, usr
->a
, usr
->ng
->N
);
940 *len_A
= mpz_num_bytes(usr
->A
);
941 *bytes_A
= (unsigned char *)srp_alloc(*len_A
);
943 if (!*bytes_A
) goto error_and_exit
;
945 mpz_to_bin(usr
->A
, *bytes_A
);
947 usr
->bytes_A
= *bytes_A
;
948 if (username
) *username
= usr
->username
;
960 /* Output: bytes_M. Buffer length is SHA512_DIGEST_LENGTH */
961 void srp_user_process_challenge(struct SRPUser
*usr
,
962 const unsigned char *bytes_s
, size_t len_s
,
963 const unsigned char *bytes_B
, size_t len_B
,
964 unsigned char **bytes_M
, size_t *len_M
)
966 mpz_t B
; mpz_init(B
); mpz_from_bin(bytes_B
, len_B
, B
);
967 mpz_t u
; mpz_init(u
);
968 mpz_t x
; mpz_init(x
);
969 mpz_t k
; mpz_init(k
);
970 mpz_t v
; mpz_init(v
);
971 mpz_t tmp1
; mpz_init(tmp1
);
972 mpz_t tmp2
; mpz_init(tmp2
);
973 mpz_t tmp3
; mpz_init(tmp3
);
974 mpz_t tmp4
; mpz_init(tmp4
);
980 if (!H_nn(u
, usr
->hash_alg
, usr
->ng
->N
, usr
->A
, B
)) goto cleanup_and_exit
;
982 srp_dbg_num(u
, "Client calculated u: ");
984 if (!calculate_x(x
, usr
->hash_alg
, bytes_s
, len_s
, usr
->username_verifier
,
985 usr
->password
, usr
->password_len
))
986 goto cleanup_and_exit
;
988 srp_dbg_num(x
, "Client calculated x: ");
990 if (!H_nn(k
, usr
->hash_alg
, usr
->ng
->N
, usr
->ng
->N
, usr
->ng
->g
))
991 goto cleanup_and_exit
;
993 /* SRP-6a safety check */
994 if (mpz_sgn(B
) != 0 && mpz_sgn(u
) != 0) {
995 mpz_powm(v
, usr
->ng
->g
, x
, usr
->ng
->N
);
997 srp_dbg_num(v
, "Client calculated v: ");
1000 /* S = (B - k*(g^x)) ^ (a + ux) */
1001 mpz_mul(tmp1
, u
, x
);
1002 mpz_add(tmp2
, usr
->a
, tmp1
); /* tmp2 = (a + ux) */
1003 mpz_powm(tmp1
, usr
->ng
->g
, x
, usr
->ng
->N
); /* tmp1 = g^x */
1004 mpz_mulm(tmp3
, k
, tmp1
, usr
->ng
->N
, tmp4
); /* tmp3 = k*(g^x) */
1005 mpz_subm(tmp1
, B
, tmp3
, usr
->ng
->N
, tmp4
); /* tmp1 = (B - K*(g^x)) */
1006 mpz_powm(usr
->S
, tmp1
, tmp2
, usr
->ng
->N
);
1009 if (!hash_num(usr
->hash_alg
, usr
->S
, usr
->session_key
)) goto cleanup_and_exit
;
1011 if (!calculate_M(usr
->hash_alg
, usr
->ng
, usr
->M
, usr
->username
, bytes_s
, len_s
,
1012 usr
->A
, B
, usr
->session_key
))
1013 goto cleanup_and_exit
;
1014 if (!calculate_H_AMK(usr
->hash_alg
, usr
->H_AMK
, usr
->A
, usr
->M
, usr
->session_key
))
1015 goto cleanup_and_exit
;
1018 if (len_M
) *len_M
= hash_length(usr
->hash_alg
);
1021 if (len_M
) *len_M
= 0;
1036 void srp_user_verify_session(struct SRPUser
*usr
, const unsigned char *bytes_HAMK
)
1038 if (memcmp(usr
->H_AMK
, bytes_HAMK
, hash_length(usr
->hash_alg
)) == 0)
1039 usr
->authenticated
= 1;