static unsigned int g_rand_idx;
static unsigned char g_rand_buff[RAND_BUFF_MAX];
+void *(*srp_alloc) (size_t) = &malloc;
+void *(*srp_realloc) (void *, size_t) = &realloc;
+void (*srp_free) (void *) = &free;
+
+void srp_set_memory_functions(
+ void *(*new_srp_alloc) (size_t),
+ void *(*new_srp_realloc) (void *, size_t),
+ void (*new_srp_free) (void *)) {
+ srp_alloc = new_srp_alloc;
+ srp_realloc = new_srp_realloc;
+ srp_free = new_srp_free;
+}
+
typedef struct
{
mpz_t N;
if (ng) {
mpz_clear(ng->N);
mpz_clear(ng->g);
- free(ng);
+ srp_free(ng);
}
}
static NGConstant *new_ng( SRP_NGType ng_type, const char *n_hex, const char *g_hex )
{
- NGConstant *ng = (NGConstant *) malloc(sizeof(NGConstant));
+ NGConstant *ng = (NGConstant *) srp_alloc(sizeof(NGConstant));
mpz_init(ng->N);
mpz_init(ng->g);
size_t len_n1 = mpz_num_bytes(n1);
size_t len_n2 = mpz_num_bytes(n2);
size_t nbytes = len_N + len_N;
- unsigned char *bin = (unsigned char *) malloc(nbytes);
+ unsigned char *bin = (unsigned char *) srp_alloc(nbytes);
if (!bin)
return 0;
if (len_n1 > len_N || len_n2 > len_N) {
- free(bin);
+ srp_free(bin);
return 0;
}
memset(bin, 0, nbytes);
mpz_to_bin(n1, bin + (len_N - len_n1));
mpz_to_bin(n2, bin + (len_N + len_N - len_n2));
hash( alg, bin, nbytes, buff );
- free(bin);
+ srp_free(bin);
mpz_from_bin(buff, hash_length(alg), result);
return 1;
}
{
unsigned char buff[SHA512_DIGEST_LENGTH];
size_t nbytes = len_n + len_bytes;
- unsigned char *bin = (unsigned char *) malloc(nbytes);
+ unsigned char *bin = (unsigned char *) srp_alloc(nbytes);
if (!bin)
return 0;
memcpy(bin, n, len_n);
memcpy(bin + len_n, bytes, len_bytes);
hash(alg, bin, nbytes, buff);
- free(bin);
+ srp_free(bin);
mpz_from_bin(buff, hash_length(alg), result);
return 1;
}
static void update_hash_n(SRP_HashAlgorithm alg, HashCTX *ctx, const mpz_t n)
{
size_t len = mpz_num_bytes(n);
- unsigned char* n_bytes = (unsigned char *) malloc(len);
+ unsigned char* n_bytes = (unsigned char *) srp_alloc(len);
if (!n_bytes)
return;
mpz_to_bin(n, n_bytes);
hash_update(alg, ctx, n_bytes, len);
- free(n_bytes);
+ srp_free(n_bytes);
}
static void hash_num( SRP_HashAlgorithm alg, const mpz_t n, unsigned char *dest )
{
int nbytes = mpz_num_bytes(n);
- unsigned char *bin = (unsigned char *) malloc(nbytes);
+ unsigned char *bin = (unsigned char *) srp_alloc(nbytes);
if(!bin)
return;
mpz_to_bin(n, bin);
hash(alg, bin, nbytes, dest);
- free(bin);
+ srp_free(bin);
}
static void calculate_M(SRP_HashAlgorithm alg, NGConstant *ng, unsigned char *dest,
}
-static int fill_buff()
+static SRP_Result fill_buff()
{
g_rand_idx = 0;
CryptGenRandom(wctx, sizeof(g_rand_buff), (BYTE*) g_rand_buff);
CryptReleaseContext(wctx, 0);
- return 1;
+ return SRP_OK;
#else
fp = fopen("/dev/urandom", "r");
fread(g_rand_buff, sizeof(g_rand_buff), 1, fp);
fclose(fp);
} else {
- srp_pcgrandom *r = (srp_pcgrandom *) malloc(sizeof(srp_pcgrandom));
+ srp_pcgrandom *r = (srp_pcgrandom *) srp_alloc(sizeof(srp_pcgrandom));
+ if (!r)
+ return SRP_ERR;
srp_pcgrandom_seed(r, time(NULL) ^ clock(), 0xda3e39cb94b95bdbULL);
size_t i = 0;
for (i = 0; i < RAND_BUFF_MAX; i++) {
g_rand_buff[i] = srp_pcgrandom_next(r);
}
+ srp_free(r);
}
#endif
- return 1;
+ return SRP_OK;
}
-static void mpz_fill_random(mpz_t num)
+static SRP_Result mpz_fill_random(mpz_t num)
{
// was call: BN_rand(num, 256, -1, 0);
if (RAND_BUFF_MAX - g_rand_idx < 32)
- fill_buff();
+ if (fill_buff() != SRP_OK)
+ return SRP_ERR;
mpz_from_bin((const unsigned char *) (&g_rand_buff[g_rand_idx]), 32, num);
g_rand_idx += 32;
+ return SRP_OK;
}
-static void init_random()
+static SRP_Result init_random()
{
if (g_initialized)
- return;
- g_initialized = fill_buff();
+ return SRP_OK;
+ SRP_Result ret = fill_buff();
+ g_initialized = (ret == SRP_OK);
+ return ret;
}
#define srp_dbg_num(num, text) ;
/*void srp_dbg_num(mpz_t num, char * prevtext)
{
int len_num = mpz_num_bytes(num);
- char *bytes_num = (char*) malloc(len_num);
+ char *bytes_num = (char*) srp_alloc(len_num);
mpz_to_bin(num, (unsigned char *) bytes_num);
srp_dbg_data(bytes_num, len_num, prevtext);
- free(bytes_num);
+ srp_free(bytes_num);
}*/
*
***********************************************************************************************************/
-void srp_create_salted_verification_key( SRP_HashAlgorithm alg,
+SRP_Result srp_create_salted_verification_key( SRP_HashAlgorithm alg,
SRP_NGType ng_type, const char *username_for_verifier,
const unsigned char *password, size_t len_password,
unsigned char **bytes_s, size_t *len_s,
unsigned char **bytes_v, size_t *len_v,
const char *n_hex, const char *g_hex )
{
+ SRP_Result ret = SRP_OK;
+
mpz_t v; mpz_init(v);
mpz_t x; mpz_init(x);
NGConstant *ng = new_ng(ng_type, n_hex, g_hex);
- if(!ng)
- goto cleanup_and_exit;
+ if (!ng)
+ goto error_and_exit;
- init_random(); /* Only happens once */
+ if (init_random() != SRP_OK) /* Only happens once */
+ goto error_and_exit;
if (*bytes_s == NULL) {
- *len_s = 16;
- if (RAND_BUFF_MAX - g_rand_idx < 16)
- fill_buff();
- *bytes_s = (unsigned char*)malloc(sizeof(char) * 16);
- memcpy(*bytes_s, &g_rand_buff + g_rand_idx, sizeof(char) * 16);
- g_rand_idx += 16;
+ size_t size_to_fill = 16;
+ *len_s = size_to_fill;
+ if (RAND_BUFF_MAX - g_rand_idx < size_to_fill)
+ if (fill_buff() != SRP_OK)
+ goto error_and_exit;
+ *bytes_s = (unsigned char*)srp_alloc(size_to_fill);
+ if (!*bytes_s)
+ goto error_and_exit;
+ memcpy(*bytes_s, &g_rand_buff + g_rand_idx, size_to_fill);
+ g_rand_idx += size_to_fill;
}
if (!calculate_x(x, alg, *bytes_s, *len_s, username_for_verifier,
password, len_password))
- goto cleanup_and_exit;
+ goto error_and_exit;
srp_dbg_num(x, "Server calculated x: ");
*len_v = mpz_num_bytes(v);
- *bytes_v = (unsigned char*)malloc(*len_v);
+ *bytes_v = (unsigned char*)srp_alloc(*len_v);
if (!bytes_v)
- goto cleanup_and_exit;
+ goto error_and_exit;
mpz_to_bin(v, *bytes_v);
delete_ng( ng );
mpz_clear(v);
mpz_clear(x);
+ return ret;
+error_and_exit:
+ ret = SRP_ERR;
+ goto cleanup_and_exit;
}
if (!ng)
goto cleanup_and_exit;
- ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) );
+ ver = (struct SRPVerifier *) srp_alloc( sizeof(struct SRPVerifier) );
if (!ver)
goto cleanup_and_exit;
- init_random(); /* Only happens once */
+ if (init_random() != SRP_OK) { /* Only happens once */
+ srp_free(ver);
+ ver = 0;
+ goto cleanup_and_exit;
+ }
- ver->username = (char *) malloc(ulen);
+ ver->username = (char *) srp_alloc(ulen);
ver->hash_alg = alg;
ver->ng = ng;
if (!ver->username) {
- free(ver);
+ srp_free(ver);
ver = 0;
goto cleanup_and_exit;
}
if (bytes_b) {
mpz_from_bin(bytes_b, len_b, b);
} else {
- mpz_fill_random(b);
+ if (mpz_fill_random(b) != SRP_OK) {
+ srp_free(ver);
+ ver = 0;
+ goto cleanup_and_exit;
+ }
}
if (!H_nn(k, alg, ng->N, ng->N, ng->g)) {
- free(ver);
+ srp_free(ver);
ver = 0;
goto cleanup_and_exit;
}
mpz_addm(B, tmp1, tmp2, ng->N, tmp3);
if (!H_nn(u, alg, ng->N, A, B)) {
- free(ver);
+ srp_free(ver);
ver = 0;
goto cleanup_and_exit;
}
calculate_H_AMK(alg, ver->H_AMK, A, ver->M, ver->session_key);
*len_B = mpz_num_bytes(B);
- *bytes_B = (unsigned char*)malloc(*len_B);
+ *bytes_B = (unsigned char*)srp_alloc(*len_B);
if (!*bytes_B) {
- free(ver->username);
- free(ver);
+ srp_free(ver->username);
+ srp_free(ver);
ver = 0;
*len_B = 0;
goto cleanup_and_exit;
ver->bytes_B = *bytes_B;
} else {
- free(ver);
+ srp_free(ver);
ver = 0;
}
{
if (ver) {
delete_ng(ver->ng);
- free(ver->username);
- free(ver->bytes_B);
+ srp_free(ver->username);
+ srp_free(ver->bytes_B);
memset(ver, 0, sizeof(*ver));
- free(ver);
+ srp_free(ver);
}
}
const unsigned char *bytes_password, size_t len_password,
const char *n_hex, const char *g_hex)
{
- struct SRPUser *usr = (struct SRPUser *) malloc(sizeof(struct SRPUser));
+ struct SRPUser *usr = (struct SRPUser *) srp_alloc(sizeof(struct SRPUser));
size_t ulen = strlen(username) + 1;
size_t uvlen = strlen(username_for_verifier) + 1;
if (!usr)
goto err_exit;
- init_random(); /* Only happens once */
+ if (init_random() != SRP_OK) /* Only happens once */
+ goto err_exit;
usr->hash_alg = alg;
usr->ng = new_ng(ng_type, n_hex, g_hex);
if (!usr->ng)
goto err_exit;
- usr->username = (char*)malloc(ulen);
- usr->username_verifier = (char*)malloc(uvlen);
- usr->password = (unsigned char*)malloc(len_password);
+ usr->username = (char*)srp_alloc(ulen);
+ usr->username_verifier = (char*)srp_alloc(uvlen);
+ usr->password = (unsigned char*)srp_alloc(len_password);
usr->password_len = len_password;
- if (!usr->username || !usr->password)
+ if (!usr->username || !usr->password || !usr->username_verifier)
goto err_exit;
memcpy(usr->username, username, ulen);
mpz_clear(usr->S);
if (usr->ng)
delete_ng(usr->ng);
- if (usr->username)
- free(usr->username);
- if (usr->username_verifier)
- free(usr->username_verifier);
+ srp_free(usr->username);
+ srp_free(usr->username_verifier);
if (usr->password) {
memset(usr->password, 0, usr->password_len);
- free(usr->password);
+ srp_free(usr->password);
}
- free(usr);
+ srp_free(usr);
}
return 0;
memset(usr->password, 0, usr->password_len);
- free(usr->username);
- free(usr->username_verifier);
- free(usr->password);
+ srp_free(usr->username);
+ srp_free(usr->username_verifier);
+ srp_free(usr->password);
if (usr->bytes_A)
- free(usr->bytes_A);
+ srp_free(usr->bytes_A);
memset(usr, 0, sizeof(*usr));
- free(usr);
+ srp_free(usr);
}
}
/* Output: username, bytes_A, len_A */
-void srp_user_start_authentication(struct SRPUser *usr, char **username,
+SRP_Result srp_user_start_authentication(struct SRPUser *usr, char **username,
const unsigned char *bytes_a, size_t len_a,
unsigned char **bytes_A, size_t *len_A)
{
if (bytes_a) {
mpz_from_bin(bytes_a, len_a, usr->a);
} else {
- mpz_fill_random(usr->a);
+ if (mpz_fill_random(usr->a) != SRP_OK)
+ goto error_and_exit;
}
mpz_powm(usr->A, usr->ng->g, usr->a, usr->ng->N);
*len_A = mpz_num_bytes(usr->A);
- *bytes_A = (unsigned char*)malloc(*len_A);
+ *bytes_A = (unsigned char*)srp_alloc(*len_A);
- if (!*bytes_A) {
- *len_A = 0;
- *bytes_A = 0;
- *username = 0;
- return;
- }
+ if (!*bytes_A)
+ goto error_and_exit;
mpz_to_bin(usr->A, *bytes_A);
usr->bytes_A = *bytes_A;
if (username)
*username = usr->username;
+
+ return SRP_OK;
+
+error_and_exit:
+ *len_A = 0;
+ *bytes_A = 0;
+ *username = 0;
+ return SRP_ERR;
}
SRP_SHA512*/
} SRP_HashAlgorithm;
+typedef enum
+{
+ SRP_OK,
+ SRP_ERR,
+} SRP_Result;
+
+/* Sets the memory functions used by srp.
+ * Note: this doesn't set the memory functions used by gmp,
+ * but it is supported to have different functions for srp and gmp.
+ * Don't call this after you have already allocated srp structures.
+ */
+void srp_set_memory_functions(
+ void *(*new_srp_alloc) (size_t),
+ void *(*new_srp_realloc) (void *, size_t),
+ void (*new_srp_free) (void *));
+
/* Out: bytes_v, len_v
*
* The caller is responsible for freeing the memory allocated for bytes_v
* If provided, they must contain ASCII text of the hexidecimal notation.
*
* If bytes_s == NULL, it is filled with random data. The caller is responsible for freeing.
+ *
+ * Returns SRP_OK on success, and SRP_ERR on error.
+ * bytes_s might be in this case invalid, don't free it.
*/
-void srp_create_salted_verification_key( SRP_HashAlgorithm alg,
+SRP_Result srp_create_salted_verification_key( SRP_HashAlgorithm alg,
SRP_NGType ng_type, const char *username_for_verifier,
const unsigned char *password, size_t len_password,
unsigned char **bytes_s, size_t *len_s,
* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type
*
* If bytes_b == NULL, random data is used for b.
+ *
+ * Returns pointer to SRPVerifier on success, and NULL on error.
*/
struct SRPVerifier* srp_verifier_new(SRP_HashAlgorithm alg, SRP_NGType ng_type,
const char *username,
void srp_verifier_delete( struct SRPVerifier* ver );
-
+// srp_verifier_verify_session must have been called before
int srp_verifier_is_authenticated( struct SRPVerifier* ver );
size_t srp_verifier_get_session_key_length(struct SRPVerifier* ver);
-/* user_M must be exactly srp_verifier_get_session_key_length() bytes in size */
+/* Verifies session, on success, it writes bytes_HAMK.
+ * user_M must be exactly srp_verifier_get_session_key_length() bytes in size
+ */
void srp_verifier_verify_session( struct SRPVerifier* ver,
const unsigned char* user_M, unsigned char** bytes_HAMK );
/* Output: username, bytes_A, len_A. If you don't want it get written, set username to NULL.
* If bytes_a == NULL, random data is used for a. */
-void srp_user_start_authentication(struct SRPUser* usr, char** username,
+SRP_Result srp_user_start_authentication(struct SRPUser* usr, char** username,
const unsigned char* bytes_a, size_t len_a,
unsigned char** bytes_A, size_t* len_A);