diff --git a/contrib/mbedtls/meson.build b/contrib/mbedtls/meson.build
index 6819bab11bf9f33af4fcc9ca361698499f571132..06929f90b88dc71a7e3a23463b2a33bf9a989b25 100644
--- a/contrib/mbedtls/meson.build
+++ b/contrib/mbedtls/meson.build
@@ -12,6 +12,11 @@ if not builtin_mbedtls
     endif
     if mbedcrypto_lib.found()
         mbedcrypto_lib_found = true
+		mpi_random_test = '''
+#include <mbedtls/bignum.h>
+void test_has_func() { mbedtls_mpi_random(NULL, 0, NULL, NULL, NULL); }
+'''
+		cdata.set10('MBEDTLS_HAS_MPI_RANDOM', cc.compiles(mpi_random_test, name: 'MbedTLS has mbedtls_mpi_random()', dependencies: mbedcrypto_lib))
     endif
 endif
 if builtin_mbedtls and not mbedcrypto_lib_found
@@ -93,13 +98,9 @@ if builtin_mbedtls and not mbedcrypto_lib_found
         )
     inc += mbedcrypto_lib_includes
     mbedcrypto_lib_found = true
+	cdata.set10('MBEDTLS_HAS_MPI_RANDOM', false)
     # We could compile libmbedcrypto.a using make on contrib/mbedtls and copy to the build folder instead
     #my_mbedcrypto_inc = mbedcrypto_lib_includes
     #my_mbedcrypto_lib = static_library('mbedcrypto')
     #mbedcrypto_lib = declare_dependency(link_with : my_mbedcrypto_lib, include_directories : my_mbedcrypto_inc)
 endif
-if mbedcrypto_lib_found
-    deps += mbedcrypto_lib
-    platform_files += 'contrib/srp.c'
-    platform_files += 'src/eap.c'
-endif
\ No newline at end of file
diff --git a/contrib/srp.c b/contrib/srp.c
deleted file mode 100644
index fab531b09fd0fc398c6d526e81d01b7dde6186ef..0000000000000000000000000000000000000000
--- a/contrib/srp.c
+++ /dev/null
@@ -1,1208 +0,0 @@
-/*
- * Secure Remote Password 6a implementation based on mbedtls.
- *
- * Copyright (c) 2017 Johannes Schriewer
- * https://github.com/dunkelstern/mbedtls-csrp
- *
- * Copyright (c) 2015 Dieter Wimberger
- * https://github.com/dwimberger/mbedtls-csrp
- *
- * Derived from:
- * Copyright (c) 2010 Tom Cocagne. All rights reserved.
- * https://github.com/cocagne/csrp
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Tom Cocagne, Dieter Wimberger
- *
- * 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", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <time.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "mbedtls/bignum.h"
-#include "mbedtls/entropy.h"
-#include "mbedtls/ctr_drbg.h"
-#include "mbedtls/sha1.h"
-#include "mbedtls/sha256.h"
-#include "mbedtls/sha512.h"
-
-#include "mbedtls/version.h"
-
-#if MBEDTLS_VERSION_NUMBER > 0x02070000
-#define USE_SHA_RET 1
-#else
-#define USE_SHA_RET 0
-#endif
-
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
-#include <mbedtls/compat-2.x.h>
-#endif
-
-
-#define DEBUG_EXTRACT_SRP_EXCHANGE 0
-
-#include "srp.h"
-
-static int g_initialized = 0;
-static mbedtls_entropy_context entropy_ctx;
-static mbedtls_ctr_drbg_context ctr_drbg_ctx;
-static mbedtls_mpi * RR;
-
-typedef struct
-{
-    BIGNUM     *N;
-    BIGNUM     *g;
-} NGConstant;
-
-struct NGHex
-{
-    const char * n_hex;
-    const char * g_hex;
-};
-
-/* All constants here were pulled from Appendix A of RFC 5054 */
-static struct NGHex global_Ng_constants[] = {
- { /* 512 */
-  "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B"
-  "1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3",
-  "2"
- },
- { /* 768 */
-   "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F402653BE7147F"
-   "00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF737D9BE9713CEF8D837ADA"
-   "6380B1093E94B6A529A8C6C2BE33E0867C60C3262B",
-   "2"
- },
- { /* 1024 */
-   "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496"
-   "EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E"
-   "F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA"
-   "9AFD5138FE8376435B9FC61D2FC0EB06E3",
-   "2"
- },
- { /* 2048 */
-   "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4"
-   "A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60"
-   "95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF"
-   "747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907"
-   "8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861"
-   "60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB"
-   "FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73",
-   "2"
- },
- { /* 4096 */
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
-   "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
-   "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
-   "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
-   "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
-   "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
-   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
-   "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
-   "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
-   "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
-   "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
-   "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
-   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
-   "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
-   "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
-   "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
-   "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
-   "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
-   "FFFFFFFFFFFFFFFF",
-   "5"
- },
- { /* 8192 */
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
-   "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
-   "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
-   "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
-   "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
-   "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
-   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
-   "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
-   "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
-   "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
-   "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
-   "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
-   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
-   "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
-   "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
-   "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
-   "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
-   "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
-   "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
-   "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
-   "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
-   "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
-   "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
-   "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
-   "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
-   "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
-   "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
-   "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA"
-   "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C"
-   "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
-   "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886"
-   "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6"
-   "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5"
-   "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268"
-   "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6"
-   "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
-   "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
-   "13"
- },
- {0,0} /* null sentinel */
-};
-
-
-static NGConstant * new_ng( SRP_NGType ng_type, const char * n_hex, const char * g_hex )
-{
-    NGConstant * ng   = (NGConstant *) malloc( sizeof(NGConstant) );
-    ng->N = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    ng->g = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(ng->N);
-    mbedtls_mpi_init(ng->g);
-
-    if( !ng || !ng->N || !ng->g )
-    {
-        if (ng->N)
-            mbedtls_mpi_free(ng->N);
-        if (ng->g)
-            mbedtls_mpi_free(ng->g);
-        free(ng);
-        return 0;
-    }
-
-    if ( ng_type != SRP_NG_CUSTOM )
-    {
-        n_hex = global_Ng_constants[ ng_type ].n_hex;
-        g_hex = global_Ng_constants[ ng_type ].g_hex;
-    }
-
-    mbedtls_mpi_read_string( ng->N, 16, n_hex);
-    mbedtls_mpi_read_string( ng->g, 16, g_hex);
-
-    return ng;
-}
-
-static void delete_ng( NGConstant * ng )
-{
-   if (ng)
-   {
-      mbedtls_mpi_free( ng->N );
-      mbedtls_mpi_free( ng->g );
-      free(ng->N);
-      free(ng->g);
-      free(ng);
-   }
-}
-
-
-typedef union
-{
-    mbedtls_sha1_context   sha;
-    mbedtls_sha256_context sha256;
-    mbedtls_sha512_context sha512;
-} HashCTX;
-
-struct SRPSession
-{
-    SRP_HashAlgorithm  hash_alg;
-    NGConstant        *ng;
-};
-
-struct SRPVerifier
-{
-    SRP_HashAlgorithm  hash_alg;
-    NGConstant        *ng;
-
-    const char          * username;
-    const unsigned char * bytes_B;
-    int                   authenticated;
-
-    unsigned char M           [SHA512_DIGEST_LENGTH];
-    unsigned char H_AMK       [SHA512_DIGEST_LENGTH];
-    unsigned char session_key [SHA512_DIGEST_LENGTH];
-};
-
-
-struct SRPUser
-{
-    SRP_HashAlgorithm  hash_alg;
-    NGConstant        *ng;
-
-    BIGNUM *a;
-    BIGNUM *A;
-    BIGNUM *S;
-
-    const unsigned char * bytes_A;
-    int                   authenticated;
-
-    const char *          username;
-    const unsigned char * password;
-    size_t                   password_len;
-
-    unsigned char M           [SHA512_DIGEST_LENGTH];
-    unsigned char H_AMK       [SHA512_DIGEST_LENGTH];
-    unsigned char session_key [SHA512_DIGEST_LENGTH];
-};
-
-
-static void hash_init( SRP_HashAlgorithm alg, HashCTX *c )
-{
-    switch (alg)
-    {
-      case SRP_SHA1  :
-	  		mbedtls_sha1_init( &c->sha );
-	  		break;
-      case SRP_SHA256:
-	  		mbedtls_sha256_init( &c->sha256 );
-	        break;
-      case SRP_SHA512:
-	  		mbedtls_sha512_init( &c->sha512 );
-	        break;
-      default:
-        return;
-    };
-}
-
-/*
-static void hash_start( SRP_HashAlgorithm alg, HashCTX *c )
-{
-    switch (alg)
-    {
-      case SRP_SHA1  : mbedtls_sha1_starts( &c->sha );
-      case SRP_SHA224: mbedtls_sha256_starts( &c->sha256, 1 );
-      case SRP_SHA256: mbedtls_sha256_starts( &c->sha256, 0 );
-      case SRP_SHA384: mbedtls_sha512_starts( &c->sha512, 1 );
-      case SRP_SHA512: mbedtls_sha512_starts( &c->sha512, 0 );
-      default:
-        return;
-    };
-}*/
-
-
-static int hash_update( SRP_HashAlgorithm alg, HashCTX *c, const void *data, size_t len )
-{
-#if !USE_SHA_RET
-    switch (alg)
-    {
-      case SRP_SHA1  : mbedtls_sha1_update( &c->sha, data, len ); break;
-      case SRP_SHA224: mbedtls_sha256_update( &c->sha256, data, len ); break;
-      case SRP_SHA256: mbedtls_sha256_update( &c->sha256, data, len ); break;
-      case SRP_SHA384: mbedtls_sha512_update( &c->sha512, data, len ); break;
-      case SRP_SHA512: mbedtls_sha512_update( &c->sha512, data, len ); break;
-      default:
-        return -1;
-    };
-    return 0;
-#else
-    switch (alg)
-    {
-    case SRP_SHA1:
-        return mbedtls_sha1_update_ret( &c->sha, data, len );
-    case SRP_SHA224:
-        return mbedtls_sha256_update_ret( &c->sha256, data, len );
-    case SRP_SHA256:
-        return mbedtls_sha256_update_ret( &c->sha256, data, len );
-    case SRP_SHA384:
-        return mbedtls_sha512_update_ret( &c->sha512, data, len );
-    case SRP_SHA512:
-        return mbedtls_sha512_update_ret( &c->sha512, data, len );
-    default:
-        return -1;
-    };
-#endif
-}
-static int hash_final( SRP_HashAlgorithm alg, HashCTX *c, unsigned char *md )
-{
-#if !USE_SHA_RET
-    switch (alg)
-    {
-      case SRP_SHA1  : mbedtls_sha1_finish( &c->sha, md ); break;
-      case SRP_SHA224: mbedtls_sha256_finish( &c->sha256, md ); break;
-      case SRP_SHA256: mbedtls_sha256_finish( &c->sha256, md ); break;
-      case SRP_SHA384: mbedtls_sha512_finish( &c->sha512, md ); break;
-      case SRP_SHA512: mbedtls_sha512_finish( &c->sha512, md ); break;
-      default:
-        return -1;
-    };
-    return 0;
-#else
-    switch (alg)
-    {
-    case SRP_SHA1  :
-        return mbedtls_sha1_finish_ret( &c->sha, md );
-    case SRP_SHA224:
-        return mbedtls_sha256_finish_ret( &c->sha256, md );
-    case SRP_SHA256:
-        return mbedtls_sha256_finish_ret( &c->sha256, md );
-    case SRP_SHA384:
-        return mbedtls_sha512_finish_ret( &c->sha512, md );
-    case SRP_SHA512:
-        return mbedtls_sha512_finish_ret( &c->sha512, md );
-      default:
-        return -1;
-    };
-#endif
-}
-static int hash( SRP_HashAlgorithm alg, const unsigned char *d, size_t n, unsigned char *md )
-{
-#if !USE_SHA_RET
-    switch (alg)
-    {
-      case SRP_SHA1  : mbedtls_sha1( d, n, md ); break;
-      case SRP_SHA224: mbedtls_sha256( d, n, md, 1); break;
-      case SRP_SHA256: mbedtls_sha256( d, n, md, 0); break;
-      case SRP_SHA384: mbedtls_sha512( d, n, md, 1 ); break;
-      case SRP_SHA512: mbedtls_sha512( d, n, md, 0 ); break;
-      default:
-        return -1;
-    };
-    return 0;
-#else
-    switch (alg)
-    {
-    case SRP_SHA1  :
-        return mbedtls_sha1_ret( d, n, md );
-    case SRP_SHA224:
-        return mbedtls_sha256_ret( d, n, md, 1);
-    case SRP_SHA256:
-        return mbedtls_sha256_ret( d, n, md, 0);
-    case SRP_SHA384:
-        return mbedtls_sha512_ret( d, n, md, 1 );
-    case SRP_SHA512:
-        return mbedtls_sha512_ret( d, n, md, 0 );
-    default:
-        return -1;
-    };
-#endif
-}
-static int hash_length( SRP_HashAlgorithm alg )
-{
-    switch (alg)
-    {
-      case SRP_SHA1  : return SHA1_DIGEST_LENGTH;
-      case SRP_SHA224: return SHA224_DIGEST_LENGTH;
-      case SRP_SHA256: return SHA256_DIGEST_LENGTH;
-      case SRP_SHA384: return SHA384_DIGEST_LENGTH;
-      case SRP_SHA512: return SHA512_DIGEST_LENGTH;
-      default:
-        return -1;
-    };
-}
-
-
-static BIGNUM * H_nn( SRP_HashAlgorithm alg, const BIGNUM * n1, const BIGNUM * n2 )
-{
-    unsigned char   buff[ SHA512_DIGEST_LENGTH ];
-    size_t             len_n1 = mbedtls_mpi_size(n1);
-    size_t             len_n2 = mbedtls_mpi_size(n2);
-    size_t             nbytes = len_n1 + len_n2;
-    unsigned char * bin    = (unsigned char *) malloc( nbytes );
-    if (!bin)
-       return 0;
-
-    mbedtls_mpi_write_binary( n1, bin, len_n1 );
-    mbedtls_mpi_write_binary( n2, bin+len_n1, len_n2 );
-    hash( alg, bin, nbytes, buff );
-    free(bin);
-    BIGNUM * bn;
-    bn = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(bn);
-    mbedtls_mpi_read_binary( bn, buff, hash_length(alg) );
-    return bn;
-}
-
-static BIGNUM * H_ns( SRP_HashAlgorithm alg, const BIGNUM * n, const unsigned char * bytes, size_t len_bytes )
-{
-    unsigned char   buff[ SHA512_DIGEST_LENGTH ];
-    size_t             len_n  = mbedtls_mpi_size(n);
-    size_t             nbytes = len_n + len_bytes;
-    unsigned char * bin    = (unsigned char *) malloc( nbytes );
-    if (!bin)
-       return 0;
-    mbedtls_mpi_write_binary( n, bin, len_n );
-    memcpy( bin + len_n, bytes, len_bytes );
-    hash( alg, bin, nbytes, buff );
-    free(bin);
-
-    BIGNUM * bn;
-    bn = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(bn);
-    mbedtls_mpi_read_binary( bn, buff, hash_length(alg) );
-    return bn;
-}
-
-static BIGNUM * calculate_x( SRP_HashAlgorithm alg, const BIGNUM * salt, const char * username, const unsigned char * password, size_t password_len )
-{
-    unsigned char ucp_hash[SHA512_DIGEST_LENGTH];
-    HashCTX       ctx;
-
-    hash_init( alg, &ctx );
-
-    if (hash_update( alg, &ctx, username, strlen(username) ) != 0)
-        return NULL;
-
-    if (hash_update( alg, &ctx, ":", 1 ) != 0)
-        return NULL;
-
-    if (hash_update( alg, &ctx, password, password_len ) != 0)
-        return NULL;
-
-    if (hash_final( alg, &ctx, ucp_hash ) != 0)
-        return NULL;
-
-    return H_ns( alg, salt, ucp_hash, hash_length(alg) );
-}
-
-static void update_hash_n( SRP_HashAlgorithm alg, HashCTX *ctx, const BIGNUM * n )
-{
-    unsigned long len = mbedtls_mpi_size(n);
-    unsigned char * n_bytes = (unsigned char *) malloc( len );
-    if (!n_bytes)
-       return;
-    mbedtls_mpi_write_binary( n, n_bytes, len );
-    hash_update(alg, ctx, n_bytes, len);
-    free(n_bytes);
-}
-
-static void hash_num( SRP_HashAlgorithm alg, const BIGNUM * n, unsigned char * dest )
-{
-    size_t             nbytes = mbedtls_mpi_size(n);
-    unsigned char * bin    = (unsigned char *) malloc( nbytes );
-    if(!bin)
-       return;
-    mbedtls_mpi_write_binary( n, bin, nbytes );
-    hash( alg, bin, nbytes, dest );
-    free(bin);
-}
-
-static void calculate_M( SRP_HashAlgorithm alg, NGConstant *ng, unsigned char * dest, const char * I, const BIGNUM * s,
-                         const BIGNUM * A, const BIGNUM * B, const unsigned char * K )
-{
-    unsigned char H_N[ SHA512_DIGEST_LENGTH ] = { '\0' };
-    unsigned char H_g[ SHA512_DIGEST_LENGTH ] = { '\0' };
-    unsigned char H_I[ SHA512_DIGEST_LENGTH ] = { '\0' };
-    unsigned char H_xor[ SHA512_DIGEST_LENGTH ] = { '\0' };
-    HashCTX       ctx;
-    int           i = 0;
-    int           hash_len = hash_length(alg);
-
-    hash_num( alg, ng->N, H_N );
-    hash_num( alg, ng->g, H_g );
-
-    hash(alg, (const unsigned char *)I, strlen(I), H_I);
-
-
-    for (i=0; i < hash_len; i++ )
-        H_xor[i] = H_N[i] ^ H_g[i];
-
-    hash_init( alg, &ctx );
-
-    hash_update( alg, &ctx, H_xor, hash_len );
-    hash_update( alg, &ctx, H_I,   hash_len );
-    update_hash_n( alg, &ctx, s );
-    update_hash_n( alg, &ctx, A );
-    update_hash_n( alg, &ctx, B );
-    hash_update( alg, &ctx, K, hash_len );
-
-    hash_final( alg, &ctx, dest );
-}
-
-static void calculate_H_AMK( SRP_HashAlgorithm alg, unsigned char *dest, const BIGNUM * A, const unsigned char * M, const unsigned char * K )
-{
-    HashCTX ctx;
-
-    hash_init( alg, &ctx );
-
-    update_hash_n( alg, &ctx, A );
-    hash_update( alg, &ctx, M, hash_length(alg) );
-    hash_update( alg, &ctx, K, hash_length(alg) );
-
-    hash_final( alg, &ctx, dest );
-}
-
-
-static void init_random()
-{
-    if (g_initialized)
-        return;
-
-     mbedtls_entropy_init( &entropy_ctx );
-     mbedtls_ctr_drbg_init( &ctr_drbg_ctx );
-
-     unsigned char hotBits[128] = {
-    82, 42, 71, 87, 124, 241, 30, 1, 54, 239, 240, 121, 89, 9, 151, 11, 60,
-    226, 142, 47, 115, 157, 100, 126, 242, 132, 46, 12, 56, 197, 194, 76,
-    198, 122, 90, 241, 255, 43, 120, 209, 69, 21, 195, 212, 100, 251, 18,
-    111, 30, 238, 24, 199, 238, 236, 138, 225, 45, 15, 42, 83, 114, 132,
-    165, 141, 32, 185, 167, 100, 131, 23, 236, 9, 11, 51, 130, 136, 97, 161,
-    36, 174, 129, 234, 2, 54, 119, 184, 70, 103, 118, 109, 122, 15, 24, 23,
-    166, 203, 102, 160, 77, 100, 17, 4, 132, 138, 215, 204, 109, 245, 122,
-    9, 184, 89, 70, 247, 125, 97, 213, 240, 85, 243, 91, 226, 127, 64, 136,
-    37, 154, 232
-};
-
-     mbedtls_ctr_drbg_seed(
-        &ctr_drbg_ctx,
-        mbedtls_entropy_func,
-        &entropy_ctx,
-        hotBits,
-        128
-    );
-
-    RR = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(RR);
-    g_initialized = 1;
-
-}
-
-
-/***********************************************************************************************************
- *
- *  Exported Functions
- *
- ***********************************************************************************************************/
-
-struct SRPSession * srp_session_new( SRP_HashAlgorithm alg,
-                                     SRP_NGType ng_type,
-                                     const char * n_hex, const char * g_hex)
-{
-    struct SRPSession * session;
-
-    session = (struct SRPSession *)malloc(sizeof(struct SRPSession));
-    memset(session, 0, sizeof(struct SRPSession));
-
-    session->hash_alg = alg;
-    session->ng  = new_ng( ng_type, n_hex, g_hex );
-
-    return session;
-}
-
-void srp_session_delete(struct SRPSession *session)
-{
-    delete_ng( session->ng );
-    free(session);
-}
-
-
-void srp_random_seed( const unsigned char * random_data, size_t data_length )
-{
-    g_initialized = 1;
-
-
-   if( mbedtls_ctr_drbg_seed( &ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx,
-                           (const unsigned char *) random_data,
-                           data_length )  != 0 )
-    {
-        return;
-    }
-
-}
-
-
-void srp_create_salted_verification_key( struct SRPSession *session,
-                                         const char * username,
-                                         const unsigned char * password, size_t len_password,
-                                         const unsigned char ** bytes_s, size_t * len_s,
-                                         const unsigned char ** bytes_v, size_t * len_v)
-{
-
-
-    BIGNUM     * s;
-    BIGNUM     * v;
-    BIGNUM     * x   = 0;
-
-    s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(s);
-    v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(v);
-
-    if( !session || !s || !v )
-       goto cleanup_and_exit;
-
-    init_random(); /* Only happens once */
-
-    mbedtls_mpi_fill_random( s, 32,
-                     &mbedtls_ctr_drbg_random,
-                     &ctr_drbg_ctx );
-
-    x = calculate_x( session->hash_alg, s, username, password, len_password );
-
-    if( !x )
-       goto cleanup_and_exit;
-
-    mbedtls_mpi_exp_mod(v, session->ng->g, x, session->ng->N, RR);
-
-    *len_s   = mbedtls_mpi_size(s);
-    *len_v   = mbedtls_mpi_size(v);
-
-    *bytes_s = (const unsigned char *) malloc( *len_s );
-    *bytes_v = (const unsigned char *) malloc( *len_v );
-
-    if (!bytes_s || !bytes_v)
-       goto cleanup_and_exit;
-#if DEBUG_EXTRACT_SRP_EXCHANGE
-	mbedtls_mpi_write_file("Salt:", s, 16, NULL);
-	mbedtls_mpi_write_file("Verifier:", v, 16, NULL);
-#endif
-    mbedtls_mpi_write_binary( s, (unsigned char *)*bytes_s, *len_s );
-    mbedtls_mpi_write_binary( v, (unsigned char *)*bytes_v, *len_v );
-
- cleanup_and_exit:
-    mbedtls_mpi_free(s);
-    free(s);
-    mbedtls_mpi_free(v);
-    free(v);
-    mbedtls_mpi_free(x);
-    free(x);
-    //TODO: BN_CTX_free(ctx);
-}
-
-
-
-/* Out: bytes_B, len_B.
- *
- * On failure, bytes_B will be set to NULL and len_B will be set to 0
- */
-struct SRPVerifier *  srp_verifier_new( struct SRPSession *session,
-                                        const char *username,
-                                        const unsigned char * bytes_s, size_t len_s,
-                                        const unsigned char * bytes_v, size_t len_v,
-                                        const unsigned char * bytes_A, size_t len_A,
-                                        const unsigned char ** bytes_B, size_t * len_B)
-{
-
-    BIGNUM *s;
-    s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(s);
-    mbedtls_mpi_read_binary(s, bytes_s, len_s);
-
-    BIGNUM *v;
-    v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(v);
-    mbedtls_mpi_read_binary(v, bytes_v, len_v);
-
-    BIGNUM *A;
-    A = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(A);
-    mbedtls_mpi_read_binary(A, bytes_A, len_A);
-
-    BIGNUM             *u    = 0;
-
-    BIGNUM             *B;
-    B = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(B);
-
-    BIGNUM             *S;
-    S = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(S);
-
-    BIGNUM             *b;
-    b = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(b);
-
-    BIGNUM             *k    = 0;
-
-    BIGNUM             *tmp1;
-    tmp1 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(tmp1);
-
-    BIGNUM             *tmp2;
-    tmp2 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(tmp2);
-
-    size_t                 ulen = strlen(username) + 1;
-
-    struct SRPVerifier *ver  = 0;
-    ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) );
-
-    *len_B   = 0;
-    *bytes_B = 0;
-
-    if( !session || !B || !S || !b || !tmp1 || !tmp2 || !ver ) {
-       goto cleanup_and_exit;
-    }
-
-    init_random(); /* Only happens once */
-
-    ver->hash_alg = session->hash_alg;
-    ver->ng       = session->ng;
-
-    ver->username = (char *) malloc( ulen ); // FIXME
-    if (!ver->username)
-    {
-       free(ver);
-       ver = 0;
-       goto cleanup_and_exit;
-    }
-    memcpy( (char*)ver->username, username, ulen );
-
-    ver->authenticated = 0;
-
-    /* SRP-6a safety check */
-    mbedtls_mpi_mod_mpi( tmp1, A, session->ng->N );
-    if ( mbedtls_mpi_cmp_int( tmp1, 0 )  != 0)
-    {
-        mbedtls_mpi_fill_random( b, 32,
-                     &mbedtls_ctr_drbg_random,
-                     &ctr_drbg_ctx );
-
-       k = H_nn(session->hash_alg, session->ng->N, session->ng->g);
-
-       /* B = kv + g^b */
-       mbedtls_mpi_mul_mpi( tmp1, k, v);
-       mbedtls_mpi_exp_mod( tmp2, session->ng->g, b, session->ng->N, RR );
-       mbedtls_mpi_add_mpi( tmp1, tmp1, tmp2 );
-       mbedtls_mpi_mod_mpi( B, tmp1, session->ng->N );
-
-       u = H_nn(session->hash_alg, A, B);
-
-       /* S = (A *(v^u)) ^ b */
-       mbedtls_mpi_exp_mod(tmp1, v, u, session->ng->N, RR);
-       mbedtls_mpi_mul_mpi(tmp2, A, tmp1);
-       mbedtls_mpi_exp_mod(S, tmp2, b, session->ng->N, RR);
-
-       hash_num(session->hash_alg, S, ver->session_key);
-
-       calculate_M( session->hash_alg, session->ng, ver->M, username, s, A, B, ver->session_key );
-       calculate_H_AMK( session->hash_alg, ver->H_AMK, A, ver->M, ver->session_key );
-
-#if DEBUG_EXTRACT_SRP_EXCHANGE
-	   mbedtls_mpi_write_file("Server k:", k, 16, NULL);
-	   mbedtls_mpi_write_file("Server b:", b, 16, NULL);
-	   mbedtls_mpi_write_file("Server B:", B, 16, NULL);
-	   mbedtls_mpi_write_file("Server u:", u, 16, NULL);
-	   mbedtls_mpi_write_file("Server S:", S, 16, NULL);
-	   fprintf(stderr, "Server K:");
-	   for (int i =0; i < SHA256_DIGEST_LENGTH; i++) {
-		   fprintf(stderr, "%02X", ver->session_key[i]);
-	   }
-	   fprintf(stderr, "\n");
-	   fprintf(stderr, "Server M1:");
-	   for (int i =0; i < SHA256_DIGEST_LENGTH; i++) {
-		   fprintf(stderr, "%02X", ver->M[i]);
-	   }
-	   fprintf(stderr, "\n");
-	   fprintf(stderr, "Server M2:");
-	   for (int i =0; i < SHA256_DIGEST_LENGTH; i++) {
-		   fprintf(stderr, "%02X", ver->H_AMK[i]);
-	   }
-	   fprintf(stderr, "\n");
-#endif
-
-       *len_B   = mbedtls_mpi_size(B);
-       *bytes_B = malloc( *len_B );
-
-       if( !*bytes_B )
-       {
-          free( (void*) ver->username );
-          free( ver );
-          ver = 0;
-          *len_B = 0;
-          goto cleanup_and_exit;
-       }
-
-       mbedtls_mpi_write_binary( B, (unsigned char *)*bytes_B, *len_B );
-       ver->bytes_B = *bytes_B;
-    }
-
- cleanup_and_exit:
-    mbedtls_mpi_free(s);
-    free(s);
-    mbedtls_mpi_free(v);
-    free(v);
-    mbedtls_mpi_free(A);
-    free(A);
-    if (u) {mbedtls_mpi_free(u); free(u);}
-    if (k) {mbedtls_mpi_free(k); free(k);}
-    mbedtls_mpi_free(B);
-    free(B);
-    mbedtls_mpi_free(S);
-    free(S);
-    mbedtls_mpi_free(b);
-    free(b);
-    mbedtls_mpi_free(tmp1);
-    free(tmp1);
-    mbedtls_mpi_free(tmp2);
-    free(tmp2);
-
-    return ver;
-}
-
-
-
-
-void srp_verifier_delete( struct SRPVerifier * ver )
-{
-   if (ver)
-   {
-      //delete_ng( ver->ng );
-      free( (char *) ver->username );
-      if(ver->bytes_B !=0) {
-        free( (unsigned char *) ver->bytes_B );
-      }
-      memset(ver, 0, sizeof(*ver));
-      free( ver );
-   }
-}
-
-
-
-int srp_verifier_is_authenticated( struct SRPVerifier * ver )
-{
-    return ver->authenticated;
-}
-
-
-const char * srp_verifier_get_username( struct SRPVerifier * ver )
-{
-    return ver->username;
-}
-
-
-const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, size_t * key_length )
-{
-    if (key_length)
-        *key_length = hash_length( ver->hash_alg );
-    return ver->session_key;
-}
-
-
-int srp_verifier_get_session_key_length( struct SRPVerifier * ver )
-{
-    return hash_length( ver->hash_alg );
-}
-
-
-/* user_M must be exactly SHA512_DIGEST_LENGTH bytes in size */
-void srp_verifier_verify_session( struct SRPVerifier * ver, const unsigned char * user_M, const unsigned char ** bytes_HAMK )
-{
-    if ( memcmp( ver->M, user_M, hash_length(ver->hash_alg) ) == 0 )
-    {
-        ver->authenticated = 1;
-        *bytes_HAMK = ver->H_AMK;
-    }
-    else
-        *bytes_HAMK = NULL;
-}
-
-/*******************************************************************************/
-
-struct SRPUser * srp_user_new( struct SRPSession *session, const char * username,
-                               const unsigned char * bytes_password, size_t len_password)
-{
-    struct SRPUser  *usr  = (struct SRPUser *) calloc(1, sizeof(struct SRPUser) );
-    size_t           ulen = strlen(username) + 1;
-
-    if (!usr)
-       goto err_exit;
-
-    init_random(); /* Only happens once */
-
-    usr->hash_alg = session->hash_alg;
-    usr->ng       = session->ng;
-
-    usr->a = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    usr->A = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    usr->S = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-
-    mbedtls_mpi_init(usr->a);
-    mbedtls_mpi_init(usr->A);
-    mbedtls_mpi_init(usr->S);
-
-    if (!usr->ng || !usr->a || !usr->A || !usr->S)
-       goto err_exit;
-
-    usr->username     = (const char *) malloc(ulen);
-    usr->password     = (const unsigned char *) malloc(len_password);
-    usr->password_len = len_password;
-
-    if (!usr->username || !usr->password)
-       goto err_exit;
-
-    memcpy((char *)usr->username, username,       ulen);
-    memcpy((char *)usr->password, bytes_password, len_password);
-
-    usr->authenticated = 0;
-
-    usr->bytes_A = 0;
-
-    return usr;
-
- err_exit:
-    if (usr)
-    {
-       mbedtls_mpi_free(usr->a);
-       mbedtls_mpi_free(usr->A);
-       mbedtls_mpi_free(usr->S);
-       if (usr->username)
-          free((void*)usr->username);
-       if (usr->password)
-       {
-          memset((void*)usr->password, 0, usr->password_len);
-          free((void*)usr->password);
-       }
-       free(usr);
-    }
-
-    return 0;
-}
-
-
-
-void srp_user_delete( struct SRPUser * usr )
-{
-   if( usr )
-   {
-      mbedtls_mpi_free( usr->a );
-      mbedtls_mpi_free( usr->A );
-      mbedtls_mpi_free( usr->S );
-      free(usr->a);
-      free(usr->A);
-      free(usr->S);
-
-      //delete_ng( usr->ng );
-
-      memset((void*)usr->password, 0, usr->password_len);
-
-      free((char *)usr->username);
-      free((char *)usr->password);
-
-      if (usr->bytes_A)
-         free( (char *)usr->bytes_A );
-
-      memset(usr, 0, sizeof(*usr));
-      free( usr );
-   }
-}
-
-
-
-int srp_user_is_authenticated( struct SRPUser * usr)
-{
-    return usr->authenticated;
-}
-
-
-const char * srp_user_get_username( struct SRPUser * usr )
-{
-    return usr->username;
-}
-
-
-
-const unsigned char * srp_user_get_session_key( struct SRPUser * usr, size_t * key_length )
-{
-    if (key_length)
-        *key_length = hash_length( usr->hash_alg );
-    return usr->session_key;
-}
-
-
-int srp_user_get_session_key_length( struct SRPUser * usr )
-{
-    return hash_length( usr->hash_alg );
-}
-
-
-
-/* Output: username, bytes_A, len_A */
-void  srp_user_start_authentication( struct SRPUser * usr, const char ** username,
-                                     const unsigned char ** bytes_A, size_t * len_A )
-{
-
-    mbedtls_mpi_fill_random( usr->a, 32, &mbedtls_ctr_drbg_random, &ctr_drbg_ctx);
-    mbedtls_mpi_exp_mod(usr->A, usr->ng->g, usr->a, usr->ng->N, RR);
-
-#if DEBUG_EXTRACT_SRP_EXCHANGE
-	mbedtls_mpi_write_file("User a:", usr->a, 16, NULL);
-	mbedtls_mpi_write_file("User A:", usr->A, 16, NULL);
-#endif
-
-    *len_A   = mbedtls_mpi_size(usr->A);
-    *bytes_A = malloc( *len_A );
-
-    if (!*bytes_A)
-    {
-       *len_A = 0;
-       *bytes_A = 0;
-       *username = 0;
-       return;
-    }
-
-    mbedtls_mpi_write_binary( usr->A, (unsigned char *) *bytes_A, *len_A );
-
-    usr->bytes_A = *bytes_A;
-    *username = usr->username;
-}
-
-
-/* Output: bytes_M. Buffer length is SHA512_DIGEST_LENGTH */
-void  srp_user_process_challenge( struct SRPUser * usr,
-                                  const unsigned char * bytes_s, size_t len_s,
-                                  const unsigned char * bytes_B, size_t len_B,
-                                  const unsigned char ** bytes_M, size_t * len_M )
-{
-    BIGNUM *u    = 0;
-    BIGNUM *x    = 0;
-    BIGNUM *k    = 0;
-
-    BIGNUM *s;
-    s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(s);
-    mbedtls_mpi_read_binary(s, bytes_s, len_s);
-
-    BIGNUM *B;
-    B = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(B);
-    mbedtls_mpi_read_binary(B, bytes_B, len_B);
-
-    BIGNUM *v;
-    v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(v);
-
-    BIGNUM *tmp1;
-    tmp1 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(tmp1);
-
-    BIGNUM *tmp2;
-    tmp2 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(tmp2);
-
-    BIGNUM *tmp3;
-    tmp3 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
-    mbedtls_mpi_init(tmp3);
-
-    *len_M = 0;
-    *bytes_M = 0;
-
-    if( !s || !B || !v || !tmp1 || !tmp2 || !tmp3 )
-       goto cleanup_and_exit;
-
-    u = H_nn(usr->hash_alg, usr->A, B);
-
-    if (!u)
-       goto cleanup_and_exit;
-
-    x = calculate_x( usr->hash_alg, s, usr->username, usr->password, usr->password_len );
-
-    if (!x)
-       goto cleanup_and_exit;
-
-    k = H_nn(usr->hash_alg, usr->ng->N, usr->ng->g);
-
-#if DEBUG_EXTRACT_SRP_EXCHANGE
-	mbedtls_mpi_write_file("User u:", u, 16, NULL);
-	mbedtls_mpi_write_file("User x:", x, 16, NULL);
-	mbedtls_mpi_write_file("User k:", k, 16, NULL);
-#endif
-
-    if (!k)
-       goto cleanup_and_exit;
-
-    /* SRP-6a safety check */
-    if( mbedtls_mpi_cmp_int( B, 0 ) != 0 && mbedtls_mpi_cmp_int( u, 0 ) !=0 )
-    {
-        mbedtls_mpi_exp_mod(v, usr->ng->g, x, usr->ng->N, RR);
-        /* S = (B - k*(g^x)) ^ (a + ux) */
-        mbedtls_mpi_mul_mpi( tmp1, u, x );
-        mbedtls_mpi_mod_mpi( tmp1, tmp1, usr->ng->N);
-        mbedtls_mpi_add_mpi( tmp2, usr->a, tmp1);
-        mbedtls_mpi_mod_mpi( tmp2, tmp2, usr->ng->N);
-        /* tmp2 = (a + ux)      */
-        mbedtls_mpi_exp_mod( tmp1, usr->ng->g, x, usr->ng->N, RR);
-        mbedtls_mpi_mul_mpi( tmp3, k, tmp1 );
-        mbedtls_mpi_mod_mpi( tmp3, tmp3, usr->ng->N);
-        /* tmp3 = k*(g^x)       */
-        mbedtls_mpi_sub_mpi(tmp1, B, tmp3);
-        /* tmp1 = (B - K*(g^x)) */
-        mbedtls_mpi_exp_mod( usr->S, tmp1, tmp2, usr->ng->N, RR);
-
-        hash_num(usr->hash_alg, usr->S, usr->session_key);
-
-        calculate_M( usr->hash_alg, usr->ng, usr->M, usr->username, s, usr->A, B, usr->session_key );
-        calculate_H_AMK( usr->hash_alg, usr->H_AMK, usr->A, usr->M, usr->session_key );
-
-#if DEBUG_EXTRACT_SRP_EXCHANGE
-		mbedtls_mpi_write_file("User S:", usr->S, 16, NULL);
-		fprintf(stderr, "User K:");
-	    for (int i =0; i < SHA256_DIGEST_LENGTH; i++) {
-		   fprintf(stderr, "%02X", usr->session_key[i]);
-	    }
-		fprintf(stderr, "\n");
-		fprintf(stderr, "User M1:");
-	    for (int i =0; i < SHA256_DIGEST_LENGTH; i++) {
-		   fprintf(stderr, "%02X", usr->M[i]);
-	    }
-		fprintf(stderr, "\n");
-		fprintf(stderr, "User M2:");
-	    for (int i =0; i < SHA256_DIGEST_LENGTH; i++) {
-		   fprintf(stderr, "%02X", usr->H_AMK[i]);
-	    }
-		fprintf(stderr, "\n");
-#endif
-
-        *bytes_M = usr->M;
-        if (len_M) {
-            *len_M = hash_length( usr->hash_alg );
-        }
-    }
-    else
-    {
-        *bytes_M = NULL;
-        if (len_M)
-            *len_M   = 0;
-    }
-
- cleanup_and_exit:
-
-    mbedtls_mpi_free(s);
-    mbedtls_mpi_free(B);
-    mbedtls_mpi_free(u);
-    mbedtls_mpi_free(x);
-    mbedtls_mpi_free(k);
-    mbedtls_mpi_free(v);
-    mbedtls_mpi_free(tmp1);
-    mbedtls_mpi_free(tmp2);
-    mbedtls_mpi_free(tmp3);
-    free(s);
-    free(B);
-    free(u);
-    free(x);
-    free(k);
-    free(v);
-    free(tmp1);
-    free(tmp2);
-    free(tmp3);
-}
-
-
-void srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK )
-{
-    if ( memcmp( usr->H_AMK, bytes_HAMK, hash_length(usr->hash_alg) ) == 0 )
-        usr->authenticated = 1;
-}
diff --git a/contrib/srp.h b/contrib/srp.h
deleted file mode 100644
index fcfc0b875b22425380df2fd391079e7997928dba..0000000000000000000000000000000000000000
--- a/contrib/srp.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Secure Remote Password 6a implementation based on mbedtls.
- *
- * Copyright (c) 2017 Johannes Schriewer
- * https://github.com/dunkelstern/mbedtls-csrp
- *
- * Copyright (c) 2015 Dieter Wimberger
- * https://github.com/dwimberger/mbedtls-csrp
- *
- * Derived from:
- * Copyright (c) 2010 Tom Cocagne. All rights reserved.
- * https://github.com/cocagne/csrp
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Tom Cocagne, Dieter Wimberger
- *
- * 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", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-/*
- *
- * Purpose:       This is a direct implementation of the Secure Remote Password
- *                Protocol version 6a as described by
- *                http://srp.stanford.edu/design.html
- *
- * Author:        tom.cocagne@gmail.com (Tom Cocagne), Dieter Wimberger
- *
- * Dependencies:  mbedtls
- *
- * Usage:         Refer to test_srp.c for a demonstration
- *
- * Notes:
- *    This library allows multiple combinations of hashing algorithms and
- *    prime number constants. For authentication to succeed, the hash and
- *    prime number constants must match between
- *    srp_create_salted_verification_key(), srp_user_new(),
- *    and srp_verifier_new(). A recommended approach is to determine the
- *    desired level of security for an application and globally define the
- *    hash and prime number constants to the predetermined values.
- *
- *    As one might suspect, more bits means more security. As one might also
- *    suspect, more bits also means more processing time. The test_srp.c
- *    program can be easily modified to profile various combinations of
- *    hash & prime number pairings.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include <stddef.h>
-
-#ifndef SRP_H
-#define SRP_H
-
-#define SHA1_DIGEST_LENGTH 20
-#define SHA224_DIGEST_LENGTH 28
-#define SHA256_DIGEST_LENGTH 32
-#define SHA384_DIGEST_LENGTH 48
-#define SHA512_DIGEST_LENGTH 64
-#define BIGNUM	mbedtls_mpi
-
-struct SRPSession;
-struct SRPVerifier;
-struct SRPUser;
-
-typedef enum
-{
-	SRP_NG_512,
-	SRP_NG_768,
-    SRP_NG_1024,
-    SRP_NG_2048,
-    SRP_NG_4096,
-    SRP_NG_8192,
-    SRP_NG_CUSTOM
-} SRP_NGType;
-
-typedef enum
-{
-    SRP_SHA1,
-    SRP_SHA224,
-    SRP_SHA256,
-    SRP_SHA384,
-    SRP_SHA512
-} SRP_HashAlgorithm;
-
-/* This library will automatically seed the mbedtls random number generator.
- *
- * The random data should include at least as many bits of entropy as the
- * largest hash function used by the application. So, for example, if a
- * 512-bit hash function is used, the random data requies at least 512
- * bits of entropy.
- *
- * Passing a null pointer to this function will cause this library to skip
- * seeding the random number generator.
- *
- * Notes:
- *    * This function is optional on Windows & Linux and mandatory on all
- *      other platforms.
- */
-void srp_random_seed( const unsigned char * random_data, size_t data_length );
-
-
-/*
- * The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type.
- * If provided, they must contain ASCII text of the hexidecimal notation.
- */
-struct SRPSession * srp_session_new( SRP_HashAlgorithm alg,
-                                     SRP_NGType ng_type,
-                                     const char * n_hex, const char * g_hex);
-
-void srp_session_delete(struct SRPSession *session);
-
-/* Out: bytes_s, len_s, bytes_v, len_v
- *
- * The caller is responsible for freeing the memory allocated for bytes_s and bytes_v
- */
-void srp_create_salted_verification_key( struct SRPSession * session,
-                                         const char * username,
-                                         const unsigned char * password, size_t len_password,
-                                         const unsigned char ** bytes_s, size_t * len_s,
-                                         const unsigned char ** bytes_v, size_t * len_v);
-
-
-/* Out: bytes_B, len_B.
- *
- * On failure, bytes_B will be set to NULL and len_B will be set to 0
- */
-struct SRPVerifier *  srp_verifier_new( struct SRPSession * session,
-                                        const char * username,
-                                        const unsigned char * bytes_s, size_t len_s,
-                                        const unsigned char * bytes_v, size_t len_v,
-                                        const unsigned char * bytes_A, size_t len_A,
-                                        const unsigned char ** bytes_B, size_t * len_B);
-
-
-void                  srp_verifier_delete( struct SRPVerifier * ver );
-
-
-int                   srp_verifier_is_authenticated( struct SRPVerifier * ver );
-
-
-const char *          srp_verifier_get_username( struct SRPVerifier * ver );
-
-/* key_length may be null */
-const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, size_t * key_length );
-
-
-int                   srp_verifier_get_session_key_length( struct SRPVerifier * ver );
-
-
-/* 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,
-                                                   const unsigned char ** bytes_HAMK );
-
-/*******************************************************************************/
-
-/* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type */
-struct SRPUser *      srp_user_new( struct SRPSession *session,
-                                    const char * username,
-                                    const unsigned char * bytes_password, size_t len_password);
-
-void                  srp_user_delete( struct SRPUser * usr );
-
-int                   srp_user_is_authenticated( struct SRPUser * usr);
-
-
-const char *          srp_user_get_username( struct SRPUser * usr );
-
-/* key_length may be null */
-const unsigned char * srp_user_get_session_key( struct SRPUser * usr, size_t * key_length );
-
-int                   srp_user_get_session_key_length( struct SRPUser * usr );
-
-/* Output: username, bytes_A, len_A */
-void                  srp_user_start_authentication( struct SRPUser * usr, const char ** username,
-                                                     const unsigned char ** bytes_A, size_t * len_A );
-
-/* Output: bytes_M, len_M  (len_M may be null and will always be
- *                          srp_user_get_session_key_length() bytes in size) */
-void                  srp_user_process_challenge( struct SRPUser * usr,
-                                                  const unsigned char * bytes_s, size_t len_s,
-                                                  const unsigned char * bytes_B, size_t len_B,
-                                                  const unsigned char ** bytes_M, size_t * len_M );
-
-/* bytes_HAMK must be exactly srp_user_get_session_key_length() bytes in size */
-void                  srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK );
-
-#endif /* Include Guard */
-#ifdef __cplusplus
-}
-#endif
diff --git a/include/librist/config.h.in b/include/librist/config.h.in
index 7a288f92244ae9671eca11123dd50d54eb4d989a..feb270a06396a76c17def06a1ff5b83cfaa4947a 100644
--- a/include/librist/config.h.in
+++ b/include/librist/config.h.in
@@ -8,8 +8,6 @@
 #ifndef LIBRIST_CONFIG_H
 #define LIBRIST_CONFIG_H
 
-#define HAVE_MBEDTLS @HAVE_MBEDTLS@
-
-#define HAVE_NETTLE @HAVE_NETTLE@
+#define HAVE_SRP_SUPPORT @HAVE_SRP_SUPPORT@
 
 #endif /* LIBRIST_CONFIG_H */
diff --git a/include/librist/librist_srp.h b/include/librist/librist_srp.h
index 49d015cb13524ba727602914de1f08e29c37604c..2091e83c410797c419194cd2f4872adf643c83ca 100644
--- a/include/librist/librist_srp.h
+++ b/include/librist/librist_srp.h
@@ -9,10 +9,11 @@
 #ifndef _LIBRIST_SRP_H_
 #define _LIBRIST_SRP_H_
 #include "librist_config.h"
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 #include "librist.h"
-#include <stddef.h>
 #include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -47,6 +48,56 @@ typedef void (*user_verifier_lookup_t)(char * username,
 									   char **generator_ascii,
 									   void *user_data);
 
+/**
+ * @brief SRP User lookup function
+ *
+ *  The SRP User lookup function is called inside the process of authentication
+ *  the calling application MUST implement this function if it desires to so run
+ *  as a RIST MAIN profile server with SRP authentication enabled.
+ *  Userlookup is assumed to have been successful if both verifier params and both salt
+ *  params are set by the lookup function.
+ *  If the verifier function sets a non-zero generation number libRIST will periodically
+ *  poll it to see if salt/verifier has changed, it will do this with verifier_len, verifier,
+ *  salt_len, etc. set to NULL. On changes it will request the client to re-authenticate
+ *  itself. If the libRIST supplied generation number is non-zero AND the generation number
+ *  is left unchanged NO data must be set on the other variables.
+ *  Leave generation number at 0 to keep the old behaviour of unconditionally periodically
+ *  reauthenticating clients.
+ *  libRIST will take ownership of all heap allocated data.
+ *
+ *  @bug Previous releases of libRIST had an error in combined hashing of multiple data
+	     sources. The error produced reproducable hashes that are not matching with
+		 correctly hashed data. This reflects in the SRP file and also results in
+		 incompatibilty with the newly created nettle+gmp crypto backend.
+		 To ensure compatibilty with previous libRIST releases it's recommended to have
+		 both old and new verifier/salt pairs availabe and in the lookup function return
+		 the maximum requested version. Where 0 is the legacy compatible version and 1
+		 is the new correct version.
+		 Compatibility with the broken hashing will be removed in a future release.
+ *
+ *  @param username IN the username attempting authentication
+ *  @param verifier_len OUT len in bytes of the verifier.
+ *  @param verifier OUT verifier bytes, MUST be heap allocated.
+ *  @param salt_len OUT salt len in bytes of the salt.
+ *  @param salt OUT salt bytes, MUST be heap allocated.
+ *  @param use_default_2048_bit_n_modulus OUT Use the default 2048 bit modulus, when true N Prime modulus & generator MUST be NULL.
+ *  @param n_modulus_ascii OUT N Prime modulus in hex as a zero terminated C string, MUST be heap allocated or NULL.
+ *  @param generator_ascii OUT Generator in hex as a zero terminated C string, MUST be heap allocated or NULL.
+ *  @param hashversion IN/OUT IN: the maximum supported hashversion that should be looked up. OUT: the hashversion of the found salt/verifier pair.
+ *  @param generation IN/OUT IN: generation number the library has cached for the requested user. OUT: generation number of the returned data.
+ *  @param user_data IN pointer to user data.
+ *
+ **/
+typedef void (*user_verifier_lookup_2_t)(char * username,
+									   size_t *verifier_len, char **verifier,
+									   size_t *salt_len, char **salt,
+									   bool *use_default_2048_bit_n_modulus,
+									   char **n_modulus_ascii,
+									   char **generator_ascii,
+									   int *hashversion,
+									   uint64_t *generation,
+									   void *user_data);
+
 /**
  * @brief Enable SRP authentication
  *
@@ -61,7 +112,8 @@ typedef void (*user_verifier_lookup_t)(char * username,
  * @param userdata IN optional user data to be supplied to lookup function.
  *
  **/
-RIST_API int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata);
+RIST_API RIST_DEPRECATED int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata);
+RIST_API int rist_enable_eap_srp_2(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_2_t lookup_func, void *userdata);
 
 #ifdef __cplusplus
 }
diff --git a/include/librist/meson.build b/include/librist/meson.build
index 159528280925a4b1aa96e2ca61c3e803844856b6..596c2e76bf915a3834d8d93e63dd41fb47bc291e 100644
--- a/include/librist/meson.build
+++ b/include/librist/meson.build
@@ -16,8 +16,7 @@ version_h_target = configure_file(input: 'version.h.in',
 								  configuration: version_h_data)
 
 config_h_data = configuration_data()
-config_h_data.set10('HAVE_MBEDTLS', mbedcrypto_lib_found)
-config_h_data.set10('HAVE_NETTLE', use_nettle)
+config_h_data.set10('HAVE_SRP_SUPPORT', mbedcrypto_lib_found or use_nettle)
 config_h_target = configure_file(input: 'config.h.in',
 								 output: 'librist_config.h',
 								 configuration: config_h_data)
diff --git a/meson.build b/meson.build
index a921e1f82a5fbc87736b7bd121b55250d67bb3a3..ed573ae6f843d41c2a89e3b9c2a4d4b6d8ac182d 100755
--- a/meson.build
+++ b/meson.build
@@ -37,7 +37,6 @@ librist_src_root = meson.current_source_dir()
 
 deps = []
 platform_files = []
-contrib_libs = []
 inc = []
 inc += include_directories('.', 'src', 'include/librist', 'include', 'contrib')
 
@@ -200,13 +199,28 @@ if get_option('use_tun')
 	endif
 endif
 
+crypto_deps = []
+
 mbedcrypto_lib_found = false
 if use_mbedtls
 	message('Building mbedtls')
 	subdir('contrib/mbedtls')
+
+	crypto_deps += mbedcrypto_lib
 elif use_nettle
-	deps += dependency('nettle')
+	crypto_deps = [dependency('nettle'), dependency('hogweed')]
+	test_mini_gmp = '''
+#include <nettle/bignum.h>
+#if !NETTLE_USE_MINI_GMP
+	#error "Need to link gmp"
+#endif
+'''
+	if not cc.compiles(test_mini_gmp, name: 'Nettle with mini-gmp?', dependencies: crypto_deps)
+		crypto_deps += dependency('gmp')
+	endif
+	crypto_deps += dependency('gnutls')#Just for random numbers at the moment :/
 endif
+deps += crypto_deps
 
 subdir('include')
 
@@ -234,6 +248,19 @@ if not mbedcrypto_lib_found and not use_nettle
 	]
 endif
 
+have_srp = mbedcrypto_lib_found or use_nettle
+
+if have_srp
+    platform_files += 'src/eap.c'
+	platform_files += 'src/crypto/srp_constants.c'
+	platform_files += 'src/crypto/srp.c'
+endif
+
+cdata.set10('HAVE_MBEDTLS', mbedcrypto_lib_found)
+cdata.set10('HAVE_NETTLE', use_nettle and not mbedcrypto_lib_found)
+# Generate config.h
+config_file = configure_file(output: 'config.h', configuration: cdata)
+
 librist = library('librist',
 	'src/crypto/crypto.c',
 	'src/crypto/psk.c',
@@ -251,6 +278,7 @@ librist = library('librist',
 	'contrib/stdio-shim.c',
 	'contrib/time-shim.c',
 	'contrib/pthread-shim.c',
+	config_file,
 	platform_files,
 	rev_target,
 	include_directories: inc,
@@ -310,9 +338,6 @@ endif
 
 librist_dep = declare_dependency(include_directories: inc, link_with : librist)
 
-# Generate config.h
-config_h_target = configure_file(output: 'config.h', configuration: cdata)
-
 if get_option('built_tools')
 	message('Building tools')
 	subdir('tools')
diff --git a/src/crypto/psk.c b/src/crypto/psk.c
index 97b994d35b563f9eac1b40524dd0c9461bcc0ecd..6443fbfd0196682d10f59391a062ff5d555bd768 100644
--- a/src/crypto/psk.c
+++ b/src/crypto/psk.c
@@ -5,9 +5,11 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include "config.h"
 #include "psk.h"
 #include "log-private.h"
 #include "crypto-private.h"
+#include <string.h>
 
 #if HAVE_MBEDTLS
 #include "mbedtls/aes.h"
@@ -215,3 +217,15 @@ void _librist_crypto_psk_encrypt(struct rist_key *key, uint32_t seq_nbe, uint8_t
     _librist_crypto_psk_aes_ctr(key, seq_nbe, gre_version, inbuf, outbuf, payload_len);
     return;
 }
+
+int _librist_crypto_psk_set_passphrase(struct rist_key *key, char *passsphrase, size_t passphrase_len) {
+	if (passphrase_len > sizeof(key->password) -1) {
+		return -1;
+	}
+	memcpy(key->password, passsphrase, passphrase_len);
+	do {
+		key->gre_nonce = prand_u32();
+	} while (!key->gre_nonce);
+	_librist_crypto_aes_key(key);
+	return 0;
+}
diff --git a/src/crypto/psk.h b/src/crypto/psk.h
index 0452cecc45f97e7a0aea80c23baeda4bbc2ba6b3..4aed1f3533814c1907339bc45923520aece2f7e7 100644
--- a/src/crypto/psk.h
+++ b/src/crypto/psk.h
@@ -8,6 +8,7 @@
 #ifndef RIST_CRYPTO_PSK_H
 #define RIST_CRYPTO_PSK_H
 
+#include "config.h"
 #include "common/attributes.h"
 #include "librist/librist_config.h"
 #if HAVE_MBEDTLS
@@ -46,6 +47,6 @@ RIST_PRIV int _librist_crypto_psk_rist_key_destroy(struct rist_key *key);
 RIST_PRIV int _librist_crypto_psk_rist_key_clone(struct rist_key *key_in, struct rist_key *key_out);
 RIST_PRIV void _librist_crypto_psk_decrypt(struct rist_key *key, uint32_t nonce, uint32_t seq_nbe, uint8_t gre_version,const uint8_t inbuf[], uint8_t outbuf[], size_t payload_len);
 RIST_PRIV void _librist_crypto_psk_encrypt(struct rist_key *key, uint32_t seq_nbe, uint8_t gre_version,const uint8_t inbuf[],uint8_t outbuf[], size_t payload_len);
-
+RIST_PRIV int _librist_crypto_psk_set_passphrase(struct rist_key *key, char *passsphrase, size_t passphrase_len);
 
 #endif
diff --git a/src/crypto/srp.c b/src/crypto/srp.c
new file mode 100644
index 0000000000000000000000000000000000000000..704ff0ba5acc4eb7d91522a6b6a550259543fde6
--- /dev/null
+++ b/src/crypto/srp.c
@@ -0,0 +1,992 @@
+#include "srp.h"
+
+#include "config.h"
+#include "crypto/srp_constants.h"
+#include "vcs_version.h"
+#include "pthread-shim.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define DEBUG_EXTRACT_SRP_EXCHANGE 0
+#ifndef DEBUG_USE_EXAMPLE_CONSTANTS
+#define DEBUG_USE_EXAMPLE_CONSTANTS 0
+#endif
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+static void print_hash(const uint8_t *buf, char *specifier) {
+	char outbuf[SHA256_DIGEST_LENGTH*2 +1];
+	size_t j;
+	for (j = 0; j < SHA256_DIGEST_LENGTH; j++) {
+		outbuf[2 * j] = (buf[j] >> 4) + 48;
+		outbuf[2 * j + 1] = (buf[j] & 15) + 48;
+		if (outbuf[2 * j] > 57)
+			outbuf[2 * j] += 7;
+		if (outbuf[2 * j + 1] > 57)
+			outbuf[2 * j + 1] += 7;
+	}
+	outbuf[2 * j] = '\0';
+
+	fprintf(stderr, "%s%s\n", specifier, outbuf);
+}
+#endif
+
+#if !defined(_WIN32) || HAVE_PTHREADS
+static pthread_once_t entropy_init_once = PTHREAD_ONCE_INIT;
+#endif
+#if defined(_WIN32) && !HAVE_PTHREADS
+static INIT_ONCE entropy_init_once = INIT_ONCE_STATIC_INIT;
+#endif
+
+#if HAVE_MBEDTLS
+#include <mbedtls/bignum.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/version.h>
+
+#if MBEDTLS_VERSION_NUMBER > 0x02070000
+#define USE_SHA_RET 1
+#else
+#define USE_SHA_RET 0
+#endif
+
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#include <mbedtls/compat-2.x.h>
+#endif
+
+#define BIGNUM mbedtls_mpi
+#define BIGNUM_INIT(num) mbedtls_mpi_init(num)
+#define BIGNUM_FREE(num) mbedtls_mpi_free(num)
+#define BIGNUM_GET_BINARY_SIZE(num) mbedtls_mpi_size(num)
+#define BIGNUM_FROM_ARRAY(num, array, size) ret = mbedtls_mpi_read_binary(num, array, size)
+#define BIGNUM_FROM_STRING(num, str) ret = mbedtls_mpi_read_string(num, 16, str)
+#if MBEDTLS_HAS_MPI_RANDOM
+#define BIGNUM_RANDOM(num, max) ret = mbedtls_mpi_random(num, 0, max, mbedtls_ctr_drbg_random, &ctr_drbg_ctx);
+#else
+#define BIGNUM_RANDOM(num, max) ret = mbedtls_mpi_fill_random(num, 32, mbedtls_ctr_drbg_random, &ctr_drbg_ctx);
+#endif
+#define BIGNUM_MOD_RED(out, a, b) ret = mbedtls_mpi_mod_mpi(out, a, b)
+#define BIGNUM_EXP_MOD(out, base, exp, mod) ret = mbedtls_mpi_exp_mod(out, base, exp, mod, NULL)
+#define BIGNUM_MULT_BIG(prod, a, b) ret = mbedtls_mpi_mul_mpi(prod, a, b)
+#define BIGNUM_ADD_BIG(prod, a, b) ret = mbedtls_mpi_add_mpi(prod, a, b)
+#define BIGNUM_SUB_BIG(prod, a, b) ret = mbedtls_mpi_sub_mpi(prod, a, b)
+#define BIGNUM_EQUALS(num, comp) (mbedtls_mpi_cmp_int(num, comp) == 0)
+#define BIGNUM_WRITE_BYTES(num, bytes, bytes_size) if (mbedtls_mpi_write_binary(num, bytes, bytes_size) != 0) {return -1; }
+#define BIGNUM_WRITE_BYTES_ALLOC(num, bytes_pp, len_p, lbl) do {\
+	*len_p = mbedtls_mpi_size(num); \
+	*bytes_pp = malloc(*len_p); \
+	if (!*bytes_pp) { goto lbl; } \
+	if (mbedtls_mpi_write_binary(num, *bytes_pp, *len_p) != 0) {goto lbl; } \
+} while(false)
+#define BIGNUM_PRINT(prefix, num) mbedtls_mpi_write_file(prefix, num, 16, stderr)
+#define HASH_CONTEXT mbedtls_sha256_context
+
+void librist_crypto_srp_mbedtls_hash_init(HASH_CONTEXT *ctx, bool correct_init) {
+    mbedtls_sha256_init(ctx);
+	if (correct_init) {
+#if USE_SHA_RET
+		mbedtls_sha256_starts_ret(ctx, 0);
+#else
+		mbedtls_sha256_starts(ctx, 0);
+#endif
+	}
+}
+
+#define HASH_CONTEXT_INIT(ctx, correct) librist_crypto_srp_mbedtls_hash_init(ctx, correct)
+#define HASH_CONTEXT_FREE(ctx) mbedtls_sha256_free(ctx)
+static mbedtls_entropy_context entropy_ctx;
+static mbedtls_ctr_drbg_context ctr_drbg_ctx;
+
+
+#elif HAVE_NETTLE
+#include <nettle/sha2.h>
+#include <nettle/bignum.h>
+#include <gnutls/crypto.h>
+#define BIGNUM MP_INT
+#define BIGNUM_INIT(num) mpz_init(num)
+#define BIGNUM_FREE(num) mpz_clear(num)
+#define BIGNUM_GET_BINARY_SIZE(num) ((mpz_sizeinbase(num, 2) +7) /8)
+#define BIGNUM_FROM_ARRAY(num, array, size) mpz_import(num, size, 1, 1, 0, 0, array)
+#define BIGNUM_FROM_STRING(num, str) ret = mpz_set_str(num, str, 16)
+#define BIGNUM_RANDOM(num, max) nettle_mpz_random(num, NULL, gnutls_random_wrapper, max);
+#define BIGNUM_MOD_RED(out, a, b) mpz_mod(out, a, b)
+#define BIGNUM_EXP_MOD(out, base, exp, mod) mpz_powm(out, base, exp, mod)
+#define BIGNUM_MULT_BIG(prod, a, b) mpz_mul(prod, a, b)
+#define BIGNUM_ADD_BIG(prod, a, b) mpz_add(prod, a, b)
+#define BIGNUM_SUB_BIG(prod, a, b) mpz_sub(prod, a, b)
+#define BIGNUM_EQUALS(num, comp) (mpz_cmp_ui(num, comp) == 0)
+#define BIGNUM_WRITE_BYTES(num, bytes, bytes_size) mpz_export(bytes, NULL, 1, 1, 0, 0, num)
+#define BIGNUM_WRITE_BYTES_ALLOC(num, bytes_pp, len_p, lbl) do {\
+	*bytes_pp = mpz_export(NULL, len_p, 1, 1, 0, 0, num); \
+	if (!*bytes_pp) { goto lbl; } \
+} while (false)
+#define BIGNUM_PRINT(prefix, num) do { \
+	fprintf(stderr, prefix); \
+	mpz_out_str(stderr, 16, num); \
+	fprintf(stderr, "\n"); \
+} while(false)
+#define HASH_CONTEXT struct sha256_ctx
+#define HASH_CONTEXT_INIT(ctx, correct) (void)(correct); nettle_sha256_init(ctx)
+#define HASH_CONTEXT_FREE(ctx)
+
+void gnutls_random_wrapper(void *ctx, size_t length, uint8_t *dst) {
+	(void)ctx;
+	int ret;
+	int i=0;
+	do {
+		ret = gnutls_rnd(GNUTLS_RND_NONCE, dst, length);//This call is thread-safe
+		i++;
+	} while (ret != 0 && i < 10);
+}
+#endif
+
+static int librist_crypto_srp_hash_update(HASH_CONTEXT *hash_ctx, const void *data, size_t len)
+{
+#if HAVE_MBEDTLS
+#if !USE_SHA_RET
+	mbedtls_sha256_update( hash_ctx, data, len );
+#else
+	return mbedtls_sha256_update_ret( hash_ctx, data, len );
+#endif
+#else
+	nettle_sha256_update( hash_ctx, len, data);
+	return 0;
+#endif
+}
+
+static int librist_crypto_srp_hash_update_bignum(HASH_CONTEXT *hash_ctx, const BIGNUM *num) {
+	uint8_t bytes[1024];
+	size_t size = BIGNUM_GET_BINARY_SIZE(num);
+	if (size > sizeof(bytes))
+		return -1;
+
+	BIGNUM_WRITE_BYTES(num, bytes, size);
+
+	return librist_crypto_srp_hash_update(hash_ctx, bytes, size);
+}
+
+static int librist_crypto_srp_hash_final(HASH_CONTEXT *hash_ctx, uint8_t *data)
+{
+#if HAVE_MBEDTLS
+#if !USE_SHA_RET
+	mbedtls_sha256_finish( hash_ctx, data);
+#else
+	return mbedtls_sha256_finish_ret( hash_ctx, data);
+#endif
+#else
+	nettle_sha256_digest( hash_ctx, SHA256_DIGEST_LENGTH, data);
+#endif
+	return 0;
+}
+
+static int librist_crypto_srp_hash(const uint8_t *indata, size_t inlen, uint8_t outdata[SHA256_DIGEST_LENGTH])
+{
+#if HAVE_MBEDTLS
+#if !USE_SHA_RET
+	mbedtls_sha256(hash_data, salt_len + SHA256_DIGEST_LENGTH, x_hash, 0)
+#else
+	return mbedtls_sha256_ret(indata, inlen, outdata, 0);
+#endif
+#else
+	HASH_CONTEXT hash_ctx;
+	HASH_CONTEXT_INIT(&hash_ctx, true);
+	librist_crypto_srp_hash_update(&hash_ctx, indata, inlen);
+	librist_crypto_srp_hash_final(&hash_ctx, outdata);
+#endif
+	return 0;
+}
+
+#if HAVE_PTHREADS
+static void librist_crypto_srp_init_random_func(void)
+#else
+static BOOL librist_crypto_srp_init_random_func(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
+#endif
+{
+#if HAVE_MBEDTLS
+	mbedtls_entropy_init(&entropy_ctx);
+	mbedtls_ctr_drbg_init(&ctr_drbg_ctx);
+	//ctr_drbg_ctx is threadsafe, so can be used by multiple threads freely, seeding isn't though.
+	const char user_custom[] = "libRIST librist_crypto_srp_init_random "LIBRIST_VERSION;
+	mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, (const unsigned char  *)user_custom, sizeof(user_custom));
+#endif
+}
+
+static inline void librist_crypto_srp_init_random(void) {
+#if HAVE_PTHREADS
+	pthread_once(&entropy_init_once, librist_crypto_srp_init_random_func);
+#else
+	InitOnceExecuteOnce(&entropy_init_once, librist_crypto_srp_init_random_func, NULL, NULL);
+#endif
+}
+
+//Calculates the value of x as follows: x = SHA256(s, SHA256(I | “:” | P))
+static int librist_crypto_srp_calc_x(BIGNUM *salt, const char * username, const char * password, size_t password_len, BIGNUM *x, bool correct)
+{
+	HASH_CONTEXT hash_ctx;
+	HASH_CONTEXT_INIT(&hash_ctx, correct);
+	int ret = 0;
+
+	if (librist_crypto_srp_hash_update(&hash_ctx, username, strlen(username)) != 0)
+		return -1;
+	if (librist_crypto_srp_hash_update(&hash_ctx, ":", 1) != 0)
+		return -1;
+	if (librist_crypto_srp_hash_update(&hash_ctx, password, password_len) != 0)
+		return -1;
+
+	size_t salt_len = BIGNUM_GET_BINARY_SIZE(salt);
+	uint8_t *hash_data = malloc(salt_len + SHA256_DIGEST_LENGTH);
+	if (!hash_data)
+		return -1;
+
+	if (librist_crypto_srp_hash_final(&hash_ctx, &hash_data[salt_len]) != 0)
+		goto failed;
+
+	BIGNUM_WRITE_BYTES(salt, hash_data, salt_len);
+	if (ret != 0)
+		goto failed;
+
+	HASH_CONTEXT_FREE(&hash_ctx);
+
+	uint8_t x_hash[SHA256_DIGEST_LENGTH];
+
+	if (librist_crypto_srp_hash( hash_data, salt_len + SHA256_DIGEST_LENGTH, x_hash) != 0)
+		goto failed;
+
+	BIGNUM_FROM_ARRAY(x, x_hash, SHA256_DIGEST_LENGTH);
+	if (ret != 0)
+		goto failed;
+
+	free(hash_data);
+	return 0;
+
+failed:
+	free(hash_data);
+	return -1;
+}
+
+static int librist_crypto_srp_hash_2_bignum(BIGNUM *A, BIGNUM *B, uint8_t hash_out[SHA256_DIGEST_LENGTH])
+{
+	size_t A_size = BIGNUM_GET_BINARY_SIZE(A);
+	size_t B_size = BIGNUM_GET_BINARY_SIZE(B);
+	uint8_t AB[2048];
+
+	if (A_size + B_size > sizeof(AB))
+		return -1;
+	BIGNUM_WRITE_BYTES(A, AB, A_size);
+	BIGNUM_WRITE_BYTES(B, &AB[A_size], B_size);
+
+	return librist_crypto_srp_hash(AB, A_size+B_size, hash_out);
+}
+
+static int librist_crypto_srp_hash_bignum(BIGNUM *in, uint8_t hash_out[SHA256_DIGEST_LENGTH])
+{
+	size_t size = BIGNUM_GET_BINARY_SIZE(in);
+	uint8_t in_bytes[1024];
+	if (size > sizeof(in_bytes))
+		return -1;
+	BIGNUM_WRITE_BYTES(in, in_bytes, size);
+	return librist_crypto_srp_hash(in_bytes, size, hash_out);
+}
+
+static int librist_crypto_srp_calculate_m(BIGNUM *N, BIGNUM *g, const char *I, BIGNUM *s, BIGNUM *A, BIGNUM *B, const uint8_t K[SHA256_DIGEST_LENGTH], uint8_t m1_out[SHA256_DIGEST_LENGTH], bool correct) {
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	fprintf(stderr, "\n\n%s\n", __func__);
+	fprintf(stderr, "DOING CORRECT? %d\n", correct);
+	BIGNUM_PRINT("N: ", N);
+	BIGNUM_PRINT("g: ", g);
+	fprintf(stderr, "I: %s\n", I);
+	BIGNUM_PRINT("s: ",s);
+	BIGNUM_PRINT("A: ", A);
+	BIGNUM_PRINT("B: ", B);
+	print_hash(K, "K: ");
+#endif
+	uint8_t hash_tmp[SHA256_DIGEST_LENGTH];
+	{
+		uint8_t hash_N[SHA256_DIGEST_LENGTH];
+		uint8_t hash_g[SHA256_DIGEST_LENGTH];
+
+		librist_crypto_srp_hash_bignum(N, hash_N);
+		librist_crypto_srp_hash_bignum(g, hash_g);
+
+		for (size_t i=0; i < sizeof(hash_tmp); i++)
+			hash_tmp[i] = hash_N[i] ^ hash_g[i];
+	}
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	print_hash(hash_tmp, "XOR: ");
+#endif
+
+
+	int ret = -1;
+	HASH_CONTEXT hash_ctx;
+	HASH_CONTEXT_INIT(&hash_ctx, correct);
+
+	if (librist_crypto_srp_hash_update(&hash_ctx, hash_tmp, sizeof(hash_tmp)) != 0)
+		goto out;
+
+	if (librist_crypto_srp_hash((const uint8_t *)I, strlen(I), hash_tmp) != 0)
+		goto out;
+
+	if (librist_crypto_srp_hash_update(&hash_ctx, hash_tmp, sizeof(hash_tmp)) != 0)
+		goto out;
+
+	if (librist_crypto_srp_hash_update_bignum(&hash_ctx, s) != 0)
+		goto out;
+
+	if (librist_crypto_srp_hash_update_bignum(&hash_ctx, A) != 0)
+		goto out;
+
+	if (librist_crypto_srp_hash_update_bignum(&hash_ctx, B) != 0)
+		goto out;
+
+	if (librist_crypto_srp_hash_update(&hash_ctx, K, SHA256_DIGEST_LENGTH) != 0)
+		goto out;
+
+	if (librist_crypto_srp_hash_final(&hash_ctx, m1_out) != 0)
+		goto out;
+
+	ret = 0;
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	print_hash(m1_out, "M1: ");
+	fprintf(stderr, "\n\n");
+#endif
+
+out:
+	HASH_CONTEXT_FREE(&hash_ctx);
+	return ret;
+}
+
+static int librist_crypto_srp_calculate_m2(const BIGNUM *A,const uint8_t M1[SHA256_DIGEST_LENGTH],const uint8_t K[SHA256_DIGEST_LENGTH], uint8_t M2_OUT[SHA256_DIGEST_LENGTH], bool correct) {
+	HASH_CONTEXT hash_ctx;
+	HASH_CONTEXT_INIT(&hash_ctx, correct);
+	int ret;
+	ret = librist_crypto_srp_hash_update_bignum(&hash_ctx, A);
+	if (ret != 0)
+		goto out;
+
+	ret = librist_crypto_srp_hash_update(&hash_ctx, M1, SHA256_DIGEST_LENGTH);
+	if (ret != 0)
+		goto out;
+
+	ret = librist_crypto_srp_hash_update(&hash_ctx, K, SHA256_DIGEST_LENGTH);
+	if (ret != 0)
+		goto out;
+
+	ret = librist_crypto_srp_hash_final(&hash_ctx, M2_OUT);
+
+out:
+	HASH_CONTEXT_FREE(&hash_ctx);
+
+	return ret;
+}
+
+
+struct librist_crypto_srp_authenticator_ctx {
+	//Static values once created
+	BIGNUM N;
+	BIGNUM g;
+	BIGNUM v;
+	BIGNUM s;
+
+	//Supplied by client
+	BIGNUM A;
+
+	//Random number in range 0, N-1
+	BIGNUM b;
+	BIGNUM k;
+	BIGNUM B;
+
+	//Session key
+	uint8_t key[SHA256_DIGEST_LENGTH];
+
+	uint8_t m2[SHA256_DIGEST_LENGTH];
+
+	bool correct_hashing_init;
+};
+
+struct librist_crypto_srp_authenticator_ctx *librist_crypto_srp_authenticator_ctx_create(const char* n_hex, const char *g_hex, const uint8_t *v_bytes, size_t v_len, const uint8_t *s_bytes, size_t s_len, bool correct) {
+	if (!v_bytes || !s_bytes || v_len == 0 || s_len == 0)
+		return NULL;
+	struct librist_crypto_srp_authenticator_ctx *ctx = calloc(1, sizeof(*ctx));
+	if (!ctx)
+		return NULL;
+
+	ctx->correct_hashing_init = correct;
+	BIGNUM_INIT(&ctx->N);
+	BIGNUM_INIT(&ctx->g);
+	BIGNUM_INIT(&ctx->v);
+	BIGNUM_INIT(&ctx->s);
+
+	int ret = 0;
+	BIGNUM_FROM_STRING(&ctx->N, n_hex);
+	if (ret != 0)
+		goto fail;
+
+	BIGNUM_FROM_STRING(&ctx->g, g_hex);
+	if (ret != 0)
+		goto fail;
+
+	BIGNUM_FROM_ARRAY(&ctx->v, v_bytes, v_len);
+	if (ret != 0)
+		goto fail;
+
+	BIGNUM_FROM_ARRAY(&ctx->s, s_bytes, s_len);
+	if (ret != 0)
+		goto fail;
+
+
+	BIGNUM_INIT(&ctx->A);
+	BIGNUM_INIT(&ctx->b);
+	return ctx;
+
+fail:
+	BIGNUM_FREE(&ctx->N);
+	BIGNUM_FREE(&ctx->g);
+	BIGNUM_FREE(&ctx->v);
+	BIGNUM_FREE(&ctx->s);
+	free(ctx);
+	return NULL;
+}
+
+void librist_crypto_srp_authenticator_ctx_free(struct librist_crypto_srp_authenticator_ctx *ctx) {
+	if (ctx == NULL)
+		return;
+	BIGNUM_FREE(&ctx->N);
+	BIGNUM_FREE(&ctx->g);
+	BIGNUM_FREE(&ctx->v);
+	BIGNUM_FREE(&ctx->s);
+
+	BIGNUM_FREE(&ctx->A);
+	BIGNUM_FREE(&ctx->b);
+	BIGNUM_FREE(&ctx->k);
+	BIGNUM_FREE(&ctx->B);
+
+	free(ctx);
+}
+
+int librist_crypto_srp_authenticator_write_g_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *g_buf, size_t g_buf_len) {
+	size_t size = BIGNUM_GET_BINARY_SIZE(&ctx->g);
+	if (g_buf_len < size)
+		return -1;
+
+	BIGNUM_WRITE_BYTES(&ctx->g, g_buf, size);
+	return (int)size;
+}
+
+int librist_crypto_srp_authenticator_write_n_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *n_buf, size_t n_buf_len) {
+	size_t size = BIGNUM_GET_BINARY_SIZE(&ctx->N);
+	if (n_buf_len < size)
+		return -1;
+
+	BIGNUM_WRITE_BYTES(&ctx->N, n_buf, size);
+	return (int)size;
+}
+
+int librist_crypto_srp_authenticator_write_B_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t* B_buf, size_t B_buf_len) {
+	size_t size = BIGNUM_GET_BINARY_SIZE(&ctx->B);
+	if (B_buf_len < size)
+		return -1;
+
+	BIGNUM_WRITE_BYTES(&ctx->B, B_buf, size);
+	return (int)size;
+}
+
+void librist_crypto_srp_authenticator_write_M2_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t* m2_buf) {
+	memcpy(m2_buf, ctx->m2, sizeof(ctx->m2));
+}
+
+//We received A, verify that it's secure, set b and then calculate:
+//k=SHA256(N,g)
+//B=(kv + g^b) % N
+int librist_crypto_srp_authenticator_handle_A(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *A_buf, size_t A_buf_len) {
+	int ret = 0;
+	BIGNUM_FROM_ARRAY(&ctx->A, A_buf, A_buf_len);
+	if (ret != 0)
+		return -1;
+
+	BIGNUM tmp;
+	BIGNUM_INIT(&tmp);
+	BIGNUM_MOD_RED(&tmp, &ctx->A, &ctx->N);
+	if (ret != 0)
+		goto out;
+
+	if (BIGNUM_EQUALS(&tmp, 0))
+		goto out;
+
+
+	librist_crypto_srp_init_random();
+	//Set b
+#if DEBUG_USE_EXAMPLE_CONSTANTS
+	const char b_hex[] = "ED0D58FF861A1FC75A0829BEA5F1392D2B13AB2B05CBCD6ED1E71AAAD761E856";
+	BIGNUM_FROM_STRING(&ctx->b, b_hex);
+#else
+	BIGNUM_RANDOM(&ctx->b, &ctx->N);
+	if (ret != 0)
+		goto out;
+#endif
+
+
+	//calc k
+	uint8_t k_hash[SHA256_DIGEST_LENGTH];
+	librist_crypto_srp_hash_2_bignum(&ctx->N, &ctx->g, k_hash);
+	BIGNUM_FROM_ARRAY(&ctx->k, k_hash, sizeof(k_hash));
+	if (ret != 0)
+		goto out;
+
+	BIGNUM tmp2;
+	BIGNUM_INIT(&tmp2);
+
+	//calc B
+	BIGNUM_MULT_BIG(&tmp, &ctx->k, &ctx->v);
+	if (ret != 0)
+		goto b_out;
+
+	BIGNUM_EXP_MOD(&tmp2, &ctx->g, &ctx->b, &ctx->N);
+	if (ret != 0)
+		goto b_out;
+
+	BIGNUM_ADD_BIG(&tmp, &tmp, &tmp2);
+	if (ret != 0)
+		goto b_out;
+
+	BIGNUM_MOD_RED(&ctx->B, &tmp, &ctx->N);
+	if (ret != 0)
+		goto b_out;
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	fprintf(stderr, "%s\n", __func__);
+	BIGNUM_PRINT("b: ", &ctx->b);
+	BIGNUM_PRINT("k: ", &ctx->k);
+	BIGNUM_PRINT("B: ", &ctx->B);
+#endif
+
+
+b_out:
+	BIGNUM_FREE(&tmp2);
+
+out:
+	BIGNUM_FREE(&tmp);
+	return ret;
+}
+
+//Calculate M1 & verify against client supplied M1 value
+//u = SHA256(A, B)
+//S = ((Av^u) ^ b) % N
+//K = SHA256(S)
+//M1 = SHA256(SHA256(N) xor SHA256(g), SHA256(I, s, A, B, K)
+//Verify that client supplied M1 matches our calculation
+//Then calculate M2:
+//M2 = SHA256(A, M1, K)
+int librist_crypto_srp_authenticator_verify_m1(struct librist_crypto_srp_authenticator_ctx *ctx, const char *username,  uint8_t *client_m1_buf) {
+	uint8_t u_hash[SHA256_DIGEST_LENGTH];
+	if (librist_crypto_srp_hash_2_bignum(&ctx->A, &ctx->B, u_hash) != 0) {
+		return -1;
+	}
+
+	int ret = 0;
+	BIGNUM u;
+	BIGNUM tmp1;
+	BIGNUM tmp2;
+	BIGNUM_INIT(&u);
+	BIGNUM_INIT(&tmp1);
+	BIGNUM_INIT(&tmp2);
+
+	BIGNUM_FROM_ARRAY(&u, u_hash, sizeof(u_hash));
+	if (ret != 0)
+		goto out;
+
+	BIGNUM_EXP_MOD(&tmp1, &ctx->v, &u, &ctx->N);
+	if (ret != 0)
+		goto out;
+
+	BIGNUM_MULT_BIG(&tmp2, &ctx->A, &tmp1);
+	if (ret != 0)
+		goto out;
+
+	//tmp1 -> S
+	BIGNUM_EXP_MOD(&tmp1, &tmp2, &ctx->b, &ctx->N);
+
+    librist_crypto_srp_hash_bignum(&tmp1, ctx->key);
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+    fprintf(stderr, "%s\n", __func__);
+    BIGNUM_PRINT("u: ", &u);
+    BIGNUM_PRINT("S: ", &tmp1);
+	print_hash(ctx->key, "K: ");
+#endif
+
+	uint8_t m1_buf[SHA256_DIGEST_LENGTH];
+	ret = librist_crypto_srp_calculate_m(&ctx->N, &ctx->g, username, &ctx->s, &ctx->A, &ctx->B, ctx->key, m1_buf, ctx->correct_hashing_init);
+	if (ret != 0)
+		goto out;
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	print_hash(m1_buf, "M1: ");
+#endif
+
+	ret = memcmp(m1_buf, client_m1_buf, sizeof(m1_buf));
+	if (ret != 0)
+		goto out;
+
+	ret = librist_crypto_srp_calculate_m2(&ctx->A, m1_buf, ctx->key, ctx->m2, ctx->correct_hashing_init);
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	print_hash(ctx->key, "M2: ");
+#endif
+out:
+	BIGNUM_FREE(&u);
+	BIGNUM_FREE(&tmp1);
+	BIGNUM_FREE(&tmp2);
+
+	return ret;
+}
+
+struct librist_crypto_srp_client_ctx {
+	//Static values once created
+	BIGNUM N;
+	BIGNUM g;
+	BIGNUM s;
+	BIGNUM a;
+	BIGNUM A;
+
+	//Supplied by server
+	BIGNUM B;
+
+	BIGNUM k;
+
+	//Session key
+	uint8_t key[SHA256_DIGEST_LENGTH];
+
+	uint8_t m1[SHA256_DIGEST_LENGTH];
+
+	bool correct_hashing_init;
+};
+
+int librist_crypto_srp_client_write_A_bytes(struct librist_crypto_srp_client_ctx *ctx, uint8_t *A_buf, size_t A_buf_len) {
+	size_t size = BIGNUM_GET_BINARY_SIZE(&ctx->A);
+	if (A_buf_len < size)
+		return -1;
+
+	BIGNUM_WRITE_BYTES(&ctx->A, A_buf, size);
+	return (int)size;
+}
+
+void librist_crypto_srp_client_write_M1_bytes(struct librist_crypto_srp_client_ctx *ctx, uint8_t M1_buf[SHA256_DIGEST_LENGTH]) {
+	memcpy(M1_buf, ctx->m1, sizeof(ctx->m1));
+}
+
+
+//We've received B from the server so now we compute:
+//x = SHA256(s, SHA256(I, “:”, P))
+//k = SHA256(N, g)
+//u = SHA256(A, B)
+//S = ((B – kg^x) ^ (a +ux)) % N
+//K = SHA256(S)
+//M1 = SHA256(SHA256(N) xor SHA256(g), SHA256(I, s, A, B, K))
+int librist_crypto_srp_client_handle_B(struct librist_crypto_srp_client_ctx *ctx, uint8_t *B_bytes, size_t B_len, const char *username, const char *password) {
+	int ret = 0;
+
+	BIGNUM_FROM_ARRAY(&ctx->B, B_bytes, B_len);
+	if (ret != 0)
+		return -1;
+
+	BIGNUM u;
+	BIGNUM x;
+	BIGNUM tmp1;
+	BIGNUM tmp2;
+	BIGNUM tmp3;
+	BIGNUM tmp4;
+
+	BIGNUM_INIT(&u);
+	BIGNUM_INIT(&x);
+	BIGNUM_INIT(&tmp1);
+	BIGNUM_INIT(&tmp2);
+	BIGNUM_INIT(&tmp3);
+	BIGNUM_INIT(&tmp4);
+
+	//Safety check: exit early if B mod N equals 0
+	BIGNUM_MOD_RED(&tmp1, &ctx->B, &ctx->N);
+	if (ret != 0)
+		goto out;
+
+	if (BIGNUM_EQUALS(&tmp1, 0))
+		goto out;
+
+	//Calculate u & execute safety check
+	{
+		uint8_t u_hash[SHA256_DIGEST_LENGTH];
+		ret =librist_crypto_srp_hash_2_bignum(&ctx->A, &ctx->B, u_hash);
+		if (ret != 0)
+			goto out;
+
+
+		BIGNUM_FROM_ARRAY(&u, u_hash, sizeof(u_hash));
+		//Safety check: exit early if u mod N equals 0
+		BIGNUM_MOD_RED(&tmp1, &u, &ctx->N);
+		if (ret != 0)
+			goto out;
+
+		if (BIGNUM_EQUALS(&tmp1, 0))
+			goto out;
+	}
+
+	//Calculate k
+	{
+		uint8_t k_hash[SHA256_DIGEST_LENGTH];
+		ret = librist_crypto_srp_hash_2_bignum(&ctx->N, &ctx->g, k_hash);
+		if (ret != 0)
+			goto out;
+
+		BIGNUM_FROM_ARRAY(&tmp4, k_hash, sizeof(k_hash));
+	}
+
+	ret = librist_crypto_srp_calc_x(&ctx->s, username, password, strlen(password), &x, ctx->correct_hashing_init);
+	if (ret != 0)
+		goto out;
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	fprintf(stderr, "%s\n", __func__);
+    BIGNUM_PRINT("u: ", &u);
+    BIGNUM_PRINT("k: ", &tmp4);
+    BIGNUM_PRINT("x: ", &x);
+#endif
+
+	//Calculate 'v' (g^x)
+	BIGNUM_EXP_MOD(&tmp2, &ctx->g, &x, &ctx->N);
+	if (ret != 0)
+		goto out;
+
+	// k (tmp4) * g^x (tmp2)
+	BIGNUM_MULT_BIG(&tmp3, &tmp4, &tmp2);
+	if (ret != 0)
+		goto out;
+
+	// B - kg^x (tmp3)
+	BIGNUM_SUB_BIG(&tmp1, &ctx->B, &tmp3);
+	if (ret != 0)
+		goto out;
+
+	//u * x
+	BIGNUM_MULT_BIG(&tmp3, &u, &x);
+	if (ret != 0)
+		goto out;
+
+	//a + ux (tmp3)
+	BIGNUM_ADD_BIG(&tmp2, &ctx->a, &tmp3);
+	if (ret != 0)
+		goto out;
+
+	//S = ((B – kg^x) (tmp1) ^ (a +ux)) (tmp2) % N
+	BIGNUM_EXP_MOD(&tmp3, &tmp1, &tmp2, &ctx->N);
+	if (ret != 0)
+		goto out;
+
+	ret = librist_crypto_srp_hash_bignum(&tmp3, ctx->key);
+	if (ret != 0)
+		goto out;
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+    BIGNUM_PRINT("S: ", &tmp3);
+    print_hash(ctx->key, "K: ");
+#endif
+
+	ret = librist_crypto_srp_calculate_m(&ctx->N, &ctx->g, username, &ctx->s, &ctx->A, &ctx->B, ctx->key, ctx->m1, ctx->correct_hashing_init);
+
+out:
+	BIGNUM_FREE(&u);
+	BIGNUM_FREE(&x);
+	BIGNUM_FREE(&tmp4);
+	BIGNUM_FREE(&tmp1);
+	BIGNUM_FREE(&tmp2);
+	BIGNUM_FREE(&tmp3);
+	return ret;
+}
+
+int librist_crypto_srp_client_verify_m2(struct librist_crypto_srp_client_ctx *ctx, uint8_t *m2) {
+	uint8_t calc_m2[SHA256_DIGEST_LENGTH];
+	int ret = librist_crypto_srp_calculate_m2(&ctx->A, ctx->m1, ctx->key, calc_m2, ctx->correct_hashing_init);
+	if (ret != 0)
+		return ret;
+
+	return memcmp(m2, calc_m2, sizeof(calc_m2));
+}
+
+struct librist_crypto_srp_client_ctx *librist_crypto_srp_client_ctx_create(bool default_ng, uint8_t *N_bytes, size_t N_len, uint8_t *g_bytes, size_t g_len, uint8_t *s_bytes, size_t s_len, bool correct) {
+	if (!s_bytes || s_len == 0 || (!default_ng && (!N_bytes || N_len == 0 || !g_bytes || g_len == 0)))
+		return NULL;
+
+	struct librist_crypto_srp_client_ctx *ctx = calloc(sizeof(*ctx), 1);
+	if (!ctx)
+		return NULL;
+
+	ctx->correct_hashing_init = correct;
+	BIGNUM_INIT(&ctx->N);
+	BIGNUM_INIT(&ctx->g);
+	BIGNUM_INIT(&ctx->s);
+	BIGNUM_INIT(&ctx->a);
+	BIGNUM_INIT(&ctx->A);
+	BIGNUM_INIT(&ctx->B);
+	BIGNUM_INIT(&ctx->k);
+
+	int ret = 0;
+	BIGNUM_FROM_ARRAY(&ctx->s, s_bytes, s_len);
+	if (ret != 0)
+		goto fail;
+
+	if (default_ng) {
+		const char *N = NULL;
+		const char *g = NULL;
+		librist_get_ng_constants(LIBRIST_SRP_NG_DEFAULT, &N, &g);
+		BIGNUM_FROM_STRING(&ctx->N, N);
+		if (ret != 0)
+			goto fail;
+
+		BIGNUM_FROM_STRING(&ctx->g, g);
+		if (ret != 0)
+			goto fail;
+	} else {
+		BIGNUM_FROM_ARRAY(&ctx->g, g_bytes,g_len);
+		if (ret != 0)
+			goto fail;
+
+		BIGNUM_FROM_ARRAY(&ctx->N, N_bytes, N_len);
+		if (ret != 0)
+			goto fail;
+	}
+
+#if DEBUG_USE_EXAMPLE_CONSTANTS
+	const char a_hex[] = "138AB4045633AD14961CB1AD0720B1989104151C0708794491113302CCCC27D5";
+	BIGNUM_FROM_STRING(&ctx->a, a_hex);
+#else
+	BIGNUM_RANDOM(&ctx->a, &ctx->N);
+	if (ret != 0)
+		goto fail;
+#endif
+
+	BIGNUM_EXP_MOD(&ctx->A, &ctx->g, &ctx->a, &ctx->N);
+	if (ret != 0)
+		goto fail;
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	fprintf(stderr, "%s\n", __func__);
+	BIGNUM_PRINT("N: ", &ctx->N);
+	BIGNUM_PRINT("g: ", &ctx->g);
+	BIGNUM_PRINT("s: ", &ctx->s);
+	BIGNUM_PRINT("a: ", &ctx->a);
+	BIGNUM_PRINT("A: ", &ctx->A);
+#endif
+
+	return ctx;
+fail:
+	librist_crypto_srp_client_ctx_free(ctx);
+	return NULL;
+}
+
+void librist_crypto_srp_client_ctx_free(struct librist_crypto_srp_client_ctx *ctx) {
+	if (!ctx)
+		return;
+	BIGNUM_FREE(&ctx->N);
+	BIGNUM_FREE(&ctx->g);
+	BIGNUM_FREE(&ctx->s);
+	BIGNUM_FREE(&ctx->a);
+	BIGNUM_FREE(&ctx->A);
+	BIGNUM_FREE(&ctx->B);
+	BIGNUM_FREE(&ctx->k);
+
+	free(ctx);
+}
+
+//Creates a verifier & salt as follows:
+//salt 32 byte random
+//v: v = g^x
+int librist_crypto_srp_create_verifier(
+    const char *n_hex, const char *g_hex,
+	const char *username, const char *password,
+	unsigned char **bytes_s, size_t *len_s,
+	unsigned char **bytes_v, size_t *len_v,
+	bool correct)
+
+{
+	if (*bytes_s != NULL || *bytes_v != NULL)
+		return -1;
+
+	int ret = 0;
+	BIGNUM s;
+	BIGNUM v;
+	BIGNUM x;
+	BIGNUM n;
+	BIGNUM g;
+
+	BIGNUM_INIT(&s);
+	BIGNUM_INIT(&v);
+	BIGNUM_INIT(&x);
+	BIGNUM_INIT(&n);
+	BIGNUM_INIT(&g);
+
+	BIGNUM_FROM_STRING(&n, n_hex);
+	if (ret != 0)
+		goto failed;
+
+	BIGNUM_FROM_STRING(&g, g_hex);
+	if (ret != 0)
+		goto failed;
+
+	librist_crypto_srp_init_random();
+	//Fill the salt
+#if DEBUG_USE_EXAMPLE_CONSTANTS
+	const char salt_hex[] = "72F9D5383B7EB7599FB63028F47475B60A55F313D40E0BE023E026C97C0A2C32";
+	BIGNUM_FROM_STRING(&s, salt_hex);
+#else
+#if HAVE_MBEDTLS
+	mbedtls_mpi_fill_random(&s, 32, mbedtls_ctr_drbg_random, &ctr_drbg_ctx);
+#elif HAVE_NETTLE
+	nettle_mpz_random_size(&s, NULL, gnutls_random_wrapper, 8 * 32);
+#endif
+	if (ret != 0)
+		goto failed;
+#endif
+
+	// Calculate x
+	if (librist_crypto_srp_calc_x(&s, username, password, strlen(password),
+									&x, correct) != 0) goto failed;
+
+	BIGNUM_EXP_MOD(&v, &g, &x, &n);
+	if (ret != 0)
+		goto failed;
+
+	BIGNUM_WRITE_BYTES_ALLOC(&s, bytes_s, len_s, failed);
+	BIGNUM_WRITE_BYTES_ALLOC(&v, bytes_v, len_v, failed);
+
+#if DEBUG_EXTRACT_SRP_EXCHANGE
+	fprintf(stderr, "%s\n", __func__);
+	BIGNUM_PRINT("N: ", &n);
+	BIGNUM_PRINT("G: ", &g);
+	BIGNUM_PRINT("s: ", &s);
+	BIGNUM_PRINT("v: ", &v);
+	BIGNUM_PRINT("x: ", &x);
+#endif
+
+	BIGNUM_FREE(&s);
+	BIGNUM_FREE(&v);
+	BIGNUM_FREE(&x);
+	BIGNUM_FREE(&n);
+	BIGNUM_FREE(&g);
+	return 0;
+
+failed:
+	BIGNUM_FREE(&s);
+	BIGNUM_FREE(&v);
+	BIGNUM_FREE(&x);
+	BIGNUM_FREE(&n);
+	BIGNUM_FREE(&g);
+
+	free(*bytes_s);
+	free(*bytes_v);
+
+	return -1;
+}
diff --git a/src/crypto/srp.h b/src/crypto/srp.h
new file mode 100644
index 0000000000000000000000000000000000000000..58a8159404769daf4f4e6cb5b5bed708f368d343
--- /dev/null
+++ b/src/crypto/srp.h
@@ -0,0 +1,38 @@
+#ifndef LIBRIST_CRYPTO_SRH_H
+#define LIBRIST_CRYPTO_SRH_H
+
+#include <librist/common.h>
+#include "common/attributes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define SHA256_DIGEST_LENGTH 32
+
+struct librist_crypto_srp_authenticator_ctx;
+struct librist_crypto_srp_client_ctx;
+
+//Marked as public because we want to use it in ristsrppassword. NOT (yet) intended for public use, so zero API/ABI guarantees/promises.
+RIST_API int librist_crypto_srp_create_verifier(const char *n_hex, const char *g_hex,
+                                       const char *username,
+                                       const char *password,
+                                       unsigned char **bytes_s, size_t *len_s,
+                                       unsigned char **bytes_v, size_t *len_v, bool correct);
+
+RIST_PRIV struct librist_crypto_srp_authenticator_ctx *librist_crypto_srp_authenticator_ctx_create(const char* n_hex, const char *g_hex, const uint8_t *v_bytes, size_t v_len, const uint8_t *s_bytes, size_t s_len, bool correct);
+RIST_PRIV void librist_crypto_srp_authenticator_ctx_free(struct librist_crypto_srp_authenticator_ctx *ctx);
+RIST_PRIV int librist_crypto_srp_authenticator_write_g_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *g_buf, size_t g_buf_len);
+RIST_PRIV int librist_crypto_srp_authenticator_write_n_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *n_buf, size_t n_buf_len);
+RIST_PRIV int librist_crypto_srp_authenticator_handle_A(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *A_buf, size_t A_buf_len);
+RIST_PRIV int librist_crypto_srp_authenticator_write_B_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t* B_buf, size_t B_buf_len);
+RIST_PRIV int librist_crypto_srp_authenticator_verify_m1(struct librist_crypto_srp_authenticator_ctx *ctx,const char *username,  uint8_t *client_m1_buf);
+RIST_PRIV void librist_crypto_srp_authenticator_write_M2_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t* m2_buf);
+
+RIST_PRIV struct librist_crypto_srp_client_ctx *librist_crypto_srp_client_ctx_create(bool default_ng, uint8_t *N_bytes, size_t N_len, uint8_t *g_bytes, size_t g_len, uint8_t *s_bytes, size_t s_len, bool correct);
+RIST_PRIV void librist_crypto_srp_client_ctx_free(struct librist_crypto_srp_client_ctx *ctx);
+RIST_PRIV int librist_crypto_srp_client_write_A_bytes(struct librist_crypto_srp_client_ctx *ctx, uint8_t *A_buf, size_t A_buf_len);
+RIST_PRIV int librist_crypto_srp_client_handle_B(struct librist_crypto_srp_client_ctx *ctx, uint8_t *B_bytes, size_t B_len, const char *username, const char *password);
+RIST_PRIV void librist_crypto_srp_client_write_M1_bytes(struct librist_crypto_srp_client_ctx *ctx, uint8_t M1_buf[SHA256_DIGEST_LENGTH]);
+RIST_PRIV int librist_crypto_srp_client_verify_m2(struct librist_crypto_srp_client_ctx *ctx, uint8_t *m2);
+#endif /* LIBRIST_CRYPTO_SRH_H */
diff --git a/src/crypto/srp_constants.c b/src/crypto/srp_constants.c
new file mode 100644
index 0000000000000000000000000000000000000000..0331f5f848b6b125ccb1235ed92ca695112b9481
--- /dev/null
+++ b/src/crypto/srp_constants.c
@@ -0,0 +1,124 @@
+#include "srp_constants.h"
+
+#include <stddef.h>
+#include <stdbool.h>
+struct NGHex {
+  const char *n_hex;
+  const char *g_hex;
+};
+
+/* All constants here were pulled from Appendix A of RFC 5054 */
+static const struct NGHex global_Ng_constants[] = {
+	{/* 512 */
+		"D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B"
+		"1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3",
+		"2"
+	},
+	{/* 768 */
+		"B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F402653BE7147F"
+		"00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF737D9BE9713CEF8D837ADA"
+		"6380B1093E94B6A529A8C6C2BE33E0867C60C3262B",
+		"2"
+	},
+	{/* 1024 */
+		"EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496"
+		"EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E"
+		"F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA"
+		"9AFD5138FE8376435B9FC61D2FC0EB06E3",
+		"2"
+	},
+	{/* 2048 */
+		"AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4"
+		"A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60"
+		"95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF"
+		"747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907"
+		"8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861"
+		"60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB"
+		"FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73",
+		"2"
+	},
+	{/* 4096 */
+		"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+		"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+		"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+		"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+		"49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+		"FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+		"180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+		"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+		"04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+		"B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+		"1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+		"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+		"E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+		"99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+		"04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+		"233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+		"D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
+		"FFFFFFFFFFFFFFFF",
+		"5"
+	},
+	{/* 8192 */
+		"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+		"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+		"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+		"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+		"49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+		"FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+		"180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+		"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+		"04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+		"B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+		"1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+		"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+		"E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+		"99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+		"04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+		"233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+		"D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+		"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
+		"AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
+		"DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
+		"2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
+		"F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
+		"BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+		"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
+		"B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
+		"387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
+		"6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA"
+		"3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C"
+		"5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+		"22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886"
+		"2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6"
+		"6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5"
+		"0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268"
+		"359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6"
+		"FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
+		"60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
+		"13"
+	},
+	{0, 0} /* null sentinel */
+};
+
+int librist_get_ng_constants(librist_srp_ng_e ng_pair, const char **n, const char **g)
+{
+	if (*n != NULL || *g != NULL) {
+		return -1;
+	}
+	int i = 0;
+	while (true) {
+		if (global_Ng_constants[i].n_hex == NULL) {
+			return -1;
+		}
+		if (i == (int)ng_pair) {
+			*n = global_Ng_constants[i].n_hex;
+			*g = global_Ng_constants[i].g_hex;
+			return 0;
+		}
+		i++;
+	}
+
+
+}
diff --git a/src/crypto/srp_constants.h b/src/crypto/srp_constants.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec1e530d4c8b0edbcb8b47649a69083d810f0890
--- /dev/null
+++ b/src/crypto/srp_constants.h
@@ -0,0 +1,21 @@
+#ifndef LIBRIST_CRYPTO_SRP_CONSTANTS_H
+#define LIBRIST_CRYPTO_SRP_CONSTANTS_H
+
+
+#include <librist/common.h>
+typedef enum
+{
+	LIBRIST_SRP_NG_512,
+	LIBRIST_SRP_NG_768,
+    LIBRIST_SRP_NG_1024,
+    LIBRIST_SRP_NG_2048,
+    LIBRIST_SRP_NG_4096,
+    LIBRIST_SRP_NG_8192
+} librist_srp_ng_e;
+
+#define LIBRIST_SRP_NG_DEFAULT LIBRIST_SRP_NG_2048
+
+//Marked as public because we want to use it in ristsrppassword. NOT (yet) intended for public use, so zero API/ABI guarantees/promises.
+RIST_API int librist_get_ng_constants(librist_srp_ng_e ng_pair, const char **n, const char **g);
+
+#endif /* LIBRIST_CRYPTO_SRP_CONSTANTS_H */
diff --git a/src/eap.c b/src/eap.c
index d1acd5b98d6700c3073208ba54772ba4e346dd95..ad35f83b503cd76cbe2cbcb6621eeee49e001c0a 100644
--- a/src/eap.c
+++ b/src/eap.c
@@ -6,15 +6,18 @@
  */
 
 #include "eap.h"
+#include "config.h"
 #include "endian-shim.h"
-#include "srp.h"
 #include "crypto/crypto-private.h"
+#include "crypto/srp.h"
+#include "crypto/srp_constants.h"
+#include "librist_srp.h"
 #include "rist-private.h"
 #include "udp-private.h"
 #include "log-private.h"
 
-#include <mbedtls/bignum.h>
 #include <stddef.h>
+#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -32,34 +35,29 @@ void eap_reset_data(struct eapsrp_ctx *ctx)
 {
 	if (ctx->role == EAP_ROLE_AUTHENTICATOR)
 	{
+#if HAVE_MBEDTLS
+		free(ctx->authenticator_bytes_salt_old);
+		free(ctx->authenticator_bytes_verifier_old);
+		ctx->authenticator_bytes_salt_old = NULL;
+		ctx->authenticator_bytes_verifier_old = NULL;
+#endif
 		free(ctx->authenticator_bytes_salt);
 		free(ctx->authenticator_bytes_verifier);
+		ctx->authenticator_bytes_salt = NULL;
+		ctx->authenticator_bytes_verifier = NULL;
 	}
-	free(ctx->ascii_g);
-	free(ctx->ascii_n);
+	librist_crypto_srp_authenticator_ctx_free(ctx->auth_ctx);
+	ctx->auth_ctx = NULL;
+	librist_crypto_srp_client_ctx_free(ctx->client_ctx);
+	ctx->client_ctx = NULL;
 	free(ctx->last_pkt);
-	free(ctx->salt);
-	free(ctx->verifier);
-	if (ctx->srp_user)
-		srp_user_delete(ctx->srp_user);
-	if (ctx->srp_session)
-		srp_session_delete(ctx->srp_session);
-	if (ctx->srp_verifier)
-		srp_verifier_delete(ctx->srp_verifier);
-	ctx->ascii_g = NULL;
-	ctx->ascii_n = NULL;
+
 	ctx->last_pkt = NULL;
-	ctx->salt = NULL;
-	ctx->salt_len = 0;
-	ctx->verifier = NULL;
-	ctx->srp_user = NULL;
-	ctx->srp_session = NULL;
-	ctx->srp_verifier = NULL;
-	ctx->authenticator_bytes_salt = NULL;
-	ctx->authenticator_bytes_verifier = NULL;
+
+	ctx->authenticated = false;
 }
 
-static int send_eapol_pkt(struct eapsrp_ctx *ctx, uint8_t eapoltype, uint8_t eapcode, uint8_t identifier, size_t payload_len, uint8_t buf[])
+static int send_eapol_pkt(struct eapsrp_ctx *ctx, uint8_t eapoltype, uint8_t eapcode, uint8_t identifier, size_t payload_len, uint8_t buf[], uint8_t gre_version)
 {
 	size_t offset = 0;
 	struct rist_gre_hdr *gre = (struct rist_gre_hdr *)&buf[offset];
@@ -70,6 +68,7 @@ static int send_eapol_pkt(struct eapsrp_ctx *ctx, uint8_t eapoltype, uint8_t eap
 	offset += sizeof(*eap_hdr);
 	memset(gre, 0, sizeof(*gre));
 	gre->prot_type = htobe16(RIST_GRE_PROTOCOL_TYPE_EAPOL);
+	gre->flags2 = (gre_version &0x7) << 3;
 	eapol_hdr->eapversion = 2;
 	eapol_hdr->eaptype = eapoltype;
 	eap_hdr->code = eapcode;
@@ -109,13 +108,19 @@ static int process_eap_request_identity(struct eapsrp_ctx *ctx, uint8_t identifi
 	offset += strlen(ctx->username);
 	size_t len = offset;
 	len -= EAPOL_EAP_HDRS_OFFSET;
-	return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, len, eapolpkt);
+	return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, len, eapolpkt, ctx->use_correct_hashing? 1 :0);
 }
 
-static int process_eap_request_srp_challenge(struct eapsrp_ctx *ctx, uint8_t identifier, size_t len, uint8_t pkt[])
+static int process_eap_request_srp_challenge(struct eapsrp_ctx *ctx, uint8_t identifier, size_t len, uint8_t pkt[], uint8_t gre_version)
 {
 	if (len < 6)
 		return EAP_LENERR;
+
+#if HAVE_MBEDTLS
+	ctx->use_correct_hashing = (gre_version >= 1);
+#elif HAVE_NETTLE
+	(void)(gre_version);
+#endif
 	size_t offset = 0;
 	uint16_t *tmp_swap = (uint16_t *)&pkt[offset];
 	size_t name_len = be16toh(*tmp_swap);
@@ -129,10 +134,12 @@ static int process_eap_request_srp_challenge(struct eapsrp_ctx *ctx, uint8_t ide
 	offset += 2;
 	if (len < (offset + salt_len))
 		return EAP_LENERR;
-	if (salt_len > ctx->salt_len)
-		ctx->salt = realloc(ctx->salt, salt_len);
-	memcpy(ctx->salt, &pkt[offset], salt_len);
-	ctx->salt_len = salt_len;
+
+	bool use_default_2048 = true;
+	uint8_t *salt = &pkt[offset];
+	uint8_t *g = NULL;
+	uint8_t *N = NULL;
+	size_t N_len = 0;
 	offset += salt_len;
 	tmp_swap = (uint16_t *)&pkt[offset];
 	size_t generator_len = be16toh(*tmp_swap);
@@ -141,74 +148,33 @@ static int process_eap_request_srp_challenge(struct eapsrp_ctx *ctx, uint8_t ide
 	{
 		if (len < (offset + generator_len))
 			return EAP_LENERR;
-		mbedtls_mpi tmp;
-		mbedtls_mpi_init(&tmp);
-		mbedtls_mpi_read_binary(&tmp, (const unsigned char *)&pkt[offset], generator_len);
-		char generator[16];
-		char *generator_buf = generator;
-		size_t olen = 0;
-		int ret = 0;
-		if ((ret = mbedtls_mpi_write_string(&tmp, 16, generator, 16, &olen)) !=0)
-		{
-			if (ret == MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL)
-			{
-				generator_buf = malloc(olen);
-				mbedtls_mpi_write_string(&tmp, 16, generator_buf, olen, &olen);
-			} else
-				return ret;
-		}
+
+		g = &pkt[offset];
 		offset += generator_len;
-		size_t remaining_bytes = len - offset;
-		mbedtls_mpi_read_binary(&tmp, (const unsigned char *)&pkt[offset], remaining_bytes);
-		olen = 0;
-		char *n_modulus = NULL;
-		mbedtls_mpi_write_string(&tmp, 16, n_modulus, 0, &olen);
-		n_modulus = malloc(olen);
-		mbedtls_mpi_write_string(&tmp, 16, n_modulus, olen, &olen);
-		mbedtls_mpi_free(&tmp);
-		if (ctx->srp_session)
-			srp_session_delete(ctx->srp_session);
-		ctx->srp_session = srp_session_new(HASH_ALGO, SRP_NG_CUSTOM, n_modulus, generator_buf);
-		free(n_modulus);
-		if (generator_buf != generator)
-			free(generator_buf);
-	} else {
-		if (ctx->srp_session)
-			srp_session_delete(ctx->srp_session);
-		ctx->srp_session = srp_session_new(HASH_ALGO, SRP_NG_2048, NULL, NULL);
+		N = &pkt[offset];
+		N_len = len - offset;
 	}
-	if (ctx->srp_user)
-		srp_user_delete(ctx->srp_user);
-	ctx->srp_user = srp_user_new(ctx->srp_session, ctx->username, (const unsigned char*)ctx->password, strlen(ctx->password));
+	librist_crypto_srp_client_ctx_free(ctx->client_ctx);
+	ctx->client_ctx = librist_crypto_srp_client_ctx_create(use_default_2048, N, N_len, g, generator_len, salt, salt_len, ctx->use_correct_hashing);
 	size_t len_A;
-	char * bytes_A;
-	char * username;
-	srp_user_start_authentication(ctx->srp_user, (const char **)&username, (const unsigned char **)&bytes_A, &len_A);
-	uint8_t *response = malloc(EAPOL_EAP_HDRS_OFFSET + sizeof(struct eap_srp_hdr) + len_A);
+	uint8_t response[1500] = {0};
 	struct eap_srp_hdr *hdr = (struct eap_srp_hdr *)&response[EAPOL_EAP_HDRS_OFFSET];
 	hdr->type = EAP_TYPE_SRP_SHA1;
 	hdr->subtype = EAP_SRP_SUBTYPE_CHALLENGE;
-	memcpy(&response[EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr)], bytes_A, len_A);
-	int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, (len_A + sizeof(*hdr)), response);
-	free(response);
+	len_A = librist_crypto_srp_client_write_A_bytes(ctx->client_ctx, &response[EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr)], sizeof(response) -(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr)));
+	int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, (len_A + sizeof(*hdr)), response, ctx->use_correct_hashing? 1 :0);
 	return ret;
 }
 
 static int process_eap_request_srp_server_key(struct eapsrp_ctx *ctx, uint8_t identifier, size_t len, uint8_t pkt[])
 {
-	char *bytes_B = (char *)pkt;
-	size_t len_B = len;
-	size_t len_M = 0;
-	char *bytes_M;
-	srp_user_process_challenge(ctx->srp_user, (const unsigned char *)ctx->salt, ctx->salt_len,(const unsigned char *) bytes_B, len_B, (const unsigned char**)&bytes_M, &len_M);
-	if (!bytes_M)
+	if (librist_crypto_srp_client_handle_B(ctx->client_ctx, pkt, len, ctx->username, ctx->password) != 0)
 	{
 		ctx->authentication_state = EAP_AUTH_STATE_FAILED;
 		//"must disconnect immediately, set tries past limit"
 		ctx->tries = 255;
 		return -255;
 	}
-	assert(len_M == DIGEST_LENGTH);
 	size_t out_len = sizeof(struct eap_srp_hdr) + 4 + DIGEST_LENGTH;
 	uint8_t response[(EAPOL_EAP_HDRS_OFFSET + sizeof(struct eap_srp_hdr) + 4 + DIGEST_LENGTH)];
 	size_t offset = EAPOL_EAP_HDRS_OFFSET;
@@ -218,8 +184,8 @@ static int process_eap_request_srp_server_key(struct eapsrp_ctx *ctx, uint8_t id
 	offset += 4;
 	hdr->type = EAP_TYPE_SRP_SHA1;
 	hdr->subtype = EAP_SRP_SUBTYPE_SERVER_KEY;
-	memcpy(&response[offset], bytes_M, len_M);
-	int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, out_len, response);
+	librist_crypto_srp_client_write_M1_bytes(ctx->client_ctx, &response[offset]);
+	int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, out_len, response, ctx->use_correct_hashing? 1 :0);
 	return ret;
 }
 
@@ -227,8 +193,7 @@ static int process_eap_request_srp_server_validator(struct eapsrp_ctx *ctx, uint
 {
 	if (len < (4 + DIGEST_LENGTH))
 		return EAP_LENERR;
-	srp_user_verify_session(ctx->srp_user, &pkt[4]);
-	if (srp_user_is_authenticated(ctx->srp_user))
+	if (librist_crypto_srp_client_verify_m2(ctx->client_ctx, &pkt[4]) == 0)
 	{
 		if (ctx->authentication_state < EAP_AUTH_STATE_SUCCESS)
 			rist_log_priv2(ctx->logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"Successfully authenticated\n");
@@ -239,7 +204,7 @@ static int process_eap_request_srp_server_validator(struct eapsrp_ctx *ctx, uint
 		struct eap_srp_hdr *hdr = (struct eap_srp_hdr *)&outpkt[EAPOL_EAP_HDRS_OFFSET];
 		hdr->type = EAP_TYPE_SRP_SHA1;
 		hdr->subtype = EAP_SRP_SUBTYPE_SERVER_VALIDATOR;
-		return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, sizeof(*hdr), outpkt);
+		return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, sizeof(*hdr), outpkt, ctx->use_correct_hashing? 1 :0);
 	}
 	//perm failure
 	ctx->authentication_state = EAP_AUTH_STATE_FAILED;
@@ -248,7 +213,7 @@ static int process_eap_request_srp_server_validator(struct eapsrp_ctx *ctx, uint
 	return -1;
 }
 
-static int process_eap_request(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len, uint8_t identifier)
+static int process_eap_request(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len, uint8_t identifier, uint8_t gre_version)
 {
 	uint8_t type = pkt[0];
 	if (type == EAP_TYPE_IDENTITY)
@@ -259,7 +224,7 @@ static int process_eap_request(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len
 		switch (subtype)
 		{
 			case EAP_SRP_SUBTYPE_CHALLENGE:
-				return process_eap_request_srp_challenge(ctx, identifier, (len -2), &pkt[2]);
+				return process_eap_request_srp_challenge(ctx, identifier, (len -2), &pkt[2], gre_version);
 				break;
 			case EAP_SRP_SUBTYPE_SERVER_KEY:
 				return process_eap_request_srp_server_key(ctx, identifier, (len -2), &pkt[2]);
@@ -279,7 +244,7 @@ static int process_eap_request(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len
 
 //EAP RESPONSE HANDLING
 
-static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uint8_t pkt[])
+static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uint8_t pkt[], uint8_t gre_version)
 {
 	if (len > 255)
 		return -1;
@@ -292,7 +257,24 @@ static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uin
 	bool std_2048_ng = false;
 	char *ascii_n = NULL;
 	char *ascii_g = NULL;
-	ctx->lookup_func(ctx->username, &len_v, &bytes_v, &len_s, &bytes_s, &std_2048_ng, &ascii_n, &ascii_g, ctx->lookup_func_userdata);
+#if HAVE_MBEDTLS
+	int hashversion = gre_version >= 1 ? 1 : 0;
+#elif HAVE_NETTLE
+	(void)gre_version;
+	int hashversion = 1;
+#endif
+	uint64_t generation = 0;
+	ctx->lookup_func(ctx->username, &len_v, &bytes_v, &len_s, &bytes_s, &std_2048_ng, &ascii_n, &ascii_g, &hashversion, &generation, ctx->lookup_func_userdata);
+#if HAVE_NETTLE
+	if (hashversion == 0) {
+		rist_log_priv2(ctx->logging_settings, RIST_LOG_ERROR, EAP_LOG_PREFIX"Lookup from SRP File got hashversion 0 response, Nettle backend does not support this, authentication likely to fail\n");
+	}
+	hashversion = 1;
+#endif
+	ctx->generation = generation;
+	ctx->use_correct_hashing = (hashversion >= 1);
+	const char *n_hex = ascii_n;
+	const char *g_hex = ascii_g;
 	bool found = (len_v != 0 && bytes_v && len_s != 0 && bytes_s);
 	uint8_t outpkt[1500] = { 0 };//TUNE THIS
 	size_t offset = EAPOL_EAP_HDRS_OFFSET;
@@ -302,12 +284,16 @@ static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uin
 	hdr->subtype = EAP_SRP_SUBTYPE_CHALLENGE;
 	if (found)
 	{
-		ctx->salt = malloc(len_s);
-		memcpy(ctx->salt, bytes_s, len_s);
-		ctx->verifier = malloc(len_v);
-		memcpy(ctx->verifier, bytes_v, len_v);
-		ctx->salt_len = len_s;
-		ctx->verifier_len = len_v;
+		struct librist_crypto_srp_authenticator_ctx *auth_ctx = NULL;
+		if (std_2048_ng)
+			librist_get_ng_constants(LIBRIST_SRP_NG_DEFAULT, &n_hex, &g_hex);
+
+		auth_ctx = librist_crypto_srp_authenticator_ctx_create(n_hex, g_hex, (uint8_t*)bytes_v, len_v, (uint8_t*)bytes_s, len_s, ctx->use_correct_hashing);
+		if (!auth_ctx) {
+			return -1;//Log some error?
+		}
+		librist_crypto_srp_authenticator_ctx_free(ctx->auth_ctx);
+		ctx->auth_ctx = auth_ctx;
 		memset(&pkt[offset], 0, 2);
 		offset += 2;//we dont send the server name
 		uint16_t *tmp_swap = (uint16_t *)&outpkt[offset];
@@ -317,27 +303,21 @@ static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uin
 		offset += len_s;
 		if (std_2048_ng)
 		{
-			if (ctx->srp_session)
-				srp_session_delete(ctx->srp_session);
-			ctx->srp_session = srp_session_new(HASH_ALGO, SRP_NG_2048, NULL, NULL);
 			memset(&outpkt[offset], 0, 2);
 			offset += 2;
 		} else {
-			mbedtls_mpi tmp;
-			mbedtls_mpi_init(&tmp);
-			mbedtls_mpi_read_string(&tmp, 16, ascii_g);
 			tmp_swap = (uint16_t *)&outpkt[offset];
-			*tmp_swap = htobe16((uint16_t)mbedtls_mpi_size(&tmp));
 			offset += 2;
-			mbedtls_mpi_write_binary(&tmp, &outpkt[offset], mbedtls_mpi_size(&tmp));
-			offset += mbedtls_mpi_size(&tmp);
-			mbedtls_mpi_read_string(&tmp, 16, ascii_n);
-			mbedtls_mpi_write_binary(&tmp, &outpkt[offset], mbedtls_mpi_size(&tmp));
-			offset += mbedtls_mpi_size(&tmp);
-			mbedtls_mpi_free(&tmp);
-			if (ctx->srp_session)
-				srp_session_delete(ctx->srp_session);
-			ctx->srp_session = srp_session_new(HASH_ALGO, SRP_NG_CUSTOM, ascii_n, ascii_g);
+			int g_size = librist_crypto_srp_authenticator_write_g_bytes(auth_ctx, &outpkt[offset], sizeof(outpkt) -offset);
+			if (g_size < 0)
+				return -1;
+			*tmp_swap = htobe16(g_size);
+			offset += g_size;
+
+			int n_len = librist_crypto_srp_authenticator_write_n_bytes(auth_ctx, &outpkt[offset], sizeof(outpkt) -offset);
+			if (n_len < 0)
+				return -1;
+			offset += n_len;
 		}
 	}
 	free(bytes_v);
@@ -349,36 +329,20 @@ static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uin
 	ctx->last_identifier++;
 	size_t out_len = offset;
 	out_len -= EAPOL_EAP_HDRS_OFFSET;
-	return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, out_len, outpkt);
+	return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, out_len, outpkt, ctx->use_correct_hashing? 1 :0);
 }
 
 static int process_eap_response_client_key(struct eapsrp_ctx *ctx, size_t len, uint8_t pkt[])
 {
-	char *bytes_B;
-	size_t len_B;
-	if (ctx->srp_verifier)
-		srp_verifier_delete(ctx->srp_verifier);
-
-	ctx->srp_verifier = srp_verifier_new(ctx->srp_session, ctx->username,
-										 (const unsigned char*)ctx->salt, ctx->salt_len,
-										 (const unsigned char*)ctx->verifier, ctx->verifier_len,
-										 pkt, len,
-										 (const unsigned char **)&bytes_B, &len_B);
-	if (!bytes_B || !ctx->srp_verifier)
-	{
-		//perm failure set tries to max
-		ctx->authentication_state = EAP_AUTH_STATE_FAILED;
-		ctx->tries = 255;
-		return -255;
-	}
-	uint8_t *outpkt = malloc((EAPOL_EAP_HDRS_OFFSET + sizeof(struct eap_srp_hdr) + len_B));
+	librist_crypto_srp_authenticator_handle_A(ctx->auth_ctx, pkt, len);
+
+	uint8_t outpkt[1500];
 	struct eap_srp_hdr *hdr = (struct eap_srp_hdr *)&outpkt[EAPOL_EAP_HDRS_OFFSET];
 	hdr->type = EAP_TYPE_SRP_SHA1;
 	hdr->subtype = EAP_SRP_SUBTYPE_SERVER_KEY;
-	memcpy(&outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr))], bytes_B, len_B);
+	size_t len_B = librist_crypto_srp_authenticator_write_B_bytes(ctx->auth_ctx, &outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr))], sizeof(outpkt) - (EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr)));
 	ctx->last_identifier++;
-	int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, (sizeof(struct eap_srp_hdr) + len_B), outpkt);
-	free(outpkt);
+	int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, (sizeof(struct eap_srp_hdr) + len_B), outpkt, ctx->use_correct_hashing? 1 :0);
 	return ret;
 }
 
@@ -386,14 +350,13 @@ static int process_eap_response_client_validator(struct eapsrp_ctx *ctx, size_t
 {
 	if (len < (4 + DIGEST_LENGTH))
 		return EAP_LENERR;
-	char *bytes_HAMK;
-	if (!ctx->srp_verifier) {
+
+	if (!ctx->auth_ctx) {
 		ctx->authentication_state = EAP_AUTH_STATE_FAILED;
 		return -254;
 	}
-	srp_verifier_verify_session(ctx->srp_verifier, &pkt[4], (const unsigned char**)&bytes_HAMK);
-	if (!bytes_HAMK)
-	{
+
+	if (librist_crypto_srp_authenticator_verify_m1(ctx->auth_ctx, ctx->username, &pkt[4]) != 0) {
 		rist_log_priv2(ctx->logging_settings, RIST_LOG_WARN, EAP_LOG_PREFIX"Authentication failed for %s@%s\n", ctx->username, ctx->ip_string);
 		ctx->authentication_state = EAP_AUTH_STATE_FAILED;
 		ctx->tries++;
@@ -403,22 +366,24 @@ static int process_eap_response_client_validator(struct eapsrp_ctx *ctx, size_t
 			ret = -255;
 		}
 		uint8_t buf[EAPOL_EAP_HDRS_OFFSET];
-		send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_FAILURE, ctx->last_identifier, 0, buf);
+		send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_FAILURE, ctx->last_identifier, 0, buf, ctx->use_correct_hashing? 1 :0);
 		eap_reset_data(ctx);
 		return ret;
 	}
+	ctx->authenticated = true;
+
 	uint8_t outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(struct eap_srp_hdr) + 4 + DIGEST_LENGTH)];
 	struct eap_srp_hdr *hdr = (struct eap_srp_hdr *)&outpkt[EAPOL_EAP_HDRS_OFFSET];
 	hdr->type = EAP_TYPE_SRP_SHA1;
 	hdr->subtype = EAP_SRP_SUBTYPE_SERVER_VALIDATOR;
-	memcpy(&outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr) + 4)], bytes_HAMK, DIGEST_LENGTH);
+	librist_crypto_srp_authenticator_write_M2_bytes(ctx->auth_ctx, &outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr) + 4)]);
 	ctx->last_identifier++;
-	return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, (sizeof(*hdr) + 4 + DIGEST_LENGTH), outpkt);
+	return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, (sizeof(*hdr) + 4 + DIGEST_LENGTH), outpkt, ctx->use_correct_hashing? 1 :0);
 }
 
 static int process_eap_response_srp_server_validator(struct eapsrp_ctx *ctx)
 {
-	if (srp_verifier_is_authenticated(ctx->srp_verifier))
+	if (ctx->authenticated)
 	{
 		if (ctx->authentication_state < EAP_AUTH_STATE_SUCCESS)
 			rist_log_priv2(ctx->logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"Successfully authenticated %s@%s\n", ctx->username, ctx->ip_string);
@@ -427,13 +392,13 @@ static int process_eap_response_srp_server_validator(struct eapsrp_ctx *ctx)
 		ctx->tries = 0;
 		ctx->last_identifier++;
 		uint8_t buf[EAPOL_EAP_HDRS_OFFSET];
-		send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_SUCCESS, ctx->last_identifier, 0, buf);
+		send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_SUCCESS, ctx->last_identifier, 0, buf, ctx->use_correct_hashing? 1 :0);
 		return 0;
 	}
 	return 0;
 }
 
-static int process_eap_response(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len)
+static int process_eap_response(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len, uint8_t gre_version)
 {
 	uint8_t type = pkt[0];
 	ctx->timeout_retries = 0;
@@ -441,7 +406,7 @@ static int process_eap_response(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t le
 	ctx->last_pkt_size = 0;
 	ctx->last_pkt = NULL;
 	if (type == EAP_TYPE_IDENTITY)
-		return process_eap_response_identity(ctx, (len -1), &pkt[1]);
+		return process_eap_response_identity(ctx, (len -1), &pkt[1], gre_version);
 	if (type == EAP_TYPE_SRP_SHA1)
 	{
 		uint8_t subtype = pkt[1];
@@ -466,7 +431,7 @@ static int process_eap_response(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t le
 	return -1;
 }
 
-static int process_eap_pkt(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len)
+static int process_eap_pkt(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len, uint8_t gre_version)
 {
 	if (ctx == NULL)
 		return -1;
@@ -486,10 +451,10 @@ static int process_eap_pkt(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len)
 	switch (code)
 	{
 		case EAP_CODE_REQUEST:
-			return process_eap_request(ctx, &pkt[sizeof(*hdr)], (len - sizeof(*hdr)), identifier);
+			return process_eap_request(ctx, &pkt[sizeof(*hdr)], (len - sizeof(*hdr)), identifier, gre_version);
 			break;
 		case EAP_CODE_RESPONSE:
-			return process_eap_response(ctx, &pkt[sizeof(*hdr)], (len - sizeof(*hdr)));
+			return process_eap_response(ctx, &pkt[sizeof(*hdr)], (len - sizeof(*hdr)), gre_version);
 			break;
 		case EAP_CODE_SUCCESS:
 			//handle eap success
@@ -510,7 +475,7 @@ int eap_request_identity(struct eapsrp_ctx *ctx)
 	uint8_t outpkt[EAPOL_EAP_HDRS_OFFSET +1];
 	outpkt[EAPOL_EAP_HDRS_OFFSET] = EAP_TYPE_IDENTITY;
 	ctx->last_identifier = (uint8_t)(prand_u32() >> 24);
-	return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, 1, outpkt);
+	return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, 1, outpkt, ctx->use_correct_hashing? 1 :0);
 }
 
 int eap_start(struct eapsrp_ctx *ctx)
@@ -545,18 +510,38 @@ int eap_clone_ctx(struct eapsrp_ctx *in, struct rist_peer *peer)
 	peer->eap_ctx = ctx;
 	ctx->peer = peer;
 	ctx->logging_settings = in->logging_settings;
+	ctx->use_correct_hashing = true;
 	if (ctx->role == EAP_ROLE_AUTHENTICATOR)
 	{
-		ctx->authenticator_bytes_salt = malloc(1024);
-		ctx->authenticator_bytes_verifier = malloc(1024);
-		ctx->lookup_func = in->lookup_func;
+		ctx->lookup_func_old = in->lookup_func_old;
 		ctx->lookup_func_userdata = in->lookup_func_userdata;
+		ctx->lookup_func = in->lookup_func;
+		ctx->lookup_func_old = in->lookup_func_old;
 		strcpy(ctx->authenticator_username, in->authenticator_username);
-		if (in->authenticator_len_verifier >0 && in->authenticator_bytes_verifier != NULL)
+#if HAVE_MBEDTLS
+		if (in->authenticator_len_verifier_old >0 && in->authenticator_bytes_verifier_old != NULL) {
+			ctx->authenticator_bytes_verifier_old = malloc(in->authenticator_len_verifier_old);
+			memcpy(ctx->authenticator_bytes_verifier_old, in->authenticator_bytes_verifier_old, in->authenticator_len_verifier_old);
+			ctx->authenticator_len_verifier_old = in->authenticator_len_verifier_old;
+		}
+
+		if (in->authenticator_len_salt_old > 0 && in->authenticator_bytes_salt_old != NULL) {
+			ctx->authenticator_bytes_salt_old = malloc(in->authenticator_len_salt_old  );
+			memcpy(ctx->authenticator_bytes_salt_old, in->authenticator_bytes_salt_old, in->authenticator_len_salt_old);
+			ctx->authenticator_len_salt_old = in->authenticator_len_salt_old;
+		}
+#endif
+		if (in->authenticator_len_verifier >0 && in->authenticator_bytes_verifier != NULL) {
+			ctx->authenticator_bytes_verifier = malloc(in->authenticator_len_verifier);
 			memcpy(ctx->authenticator_bytes_verifier, in->authenticator_bytes_verifier, in->authenticator_len_verifier);
-		if (in->authenticator_len_salt > 0 && in->authenticator_bytes_salt != NULL)
+			ctx->authenticator_len_verifier = in->authenticator_len_verifier;
+		}
+
+		if (in->authenticator_len_salt > 0 && in->authenticator_bytes_salt != NULL) {
+			ctx->authenticator_bytes_salt= malloc(in->authenticator_len_salt  );
 			memcpy(ctx->authenticator_bytes_salt, in->authenticator_bytes_salt, in->authenticator_len_salt);
-		ctx->authenticator_len_salt = in->authenticator_len_salt;
+			ctx->authenticator_len_salt = in->authenticator_len_salt;
+		}
 		ctx->authenticator_len_verifier = in->authenticator_len_verifier;
 		if (!ctx->last_pkt)
 			eap_request_identity(ctx);//immediately request identity
@@ -581,7 +566,7 @@ void eap_delete_ctx(struct eapsrp_ctx **in)
 	*in = NULL;
 }
 
-int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len)
+int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len, uint8_t gre_version)
 {
 	assert(ctx != NULL);
 	struct eapol_hdr *hdr = (struct eapol_hdr *)pkt;
@@ -591,7 +576,7 @@ int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len)
 	switch (hdr->eaptype)
 	{
 		case EAPOL_TYPE_EAP:
-			return process_eap_pkt(ctx, &pkt[sizeof(*hdr)], body_len);
+			return process_eap_pkt(ctx, &pkt[sizeof(*hdr)], body_len, gre_version);
 			break;
 		case EAPOL_TYPE_START:
 			if (ctx->role == EAP_ROLE_AUTHENTICATOR && !ctx->last_pkt)
@@ -638,6 +623,15 @@ void eap_periodic(struct eapsrp_ctx *ctx)
 		}
 	} else if (ctx->role == EAP_ROLE_AUTHENTICATOR && ctx->authentication_state == EAP_AUTH_STATE_SUCCESS &&
 	           now > ctx->last_auth_timestamp + reauth_period) {
+		if (ctx->generation > 0) {
+			uint64_t generation = ctx->generation;
+			//If our cached data matches whatever lookup function would return re-auth is pointless.
+			ctx->lookup_func(ctx->username, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &generation, ctx->lookup_func_userdata);
+			if (generation == ctx->generation) {
+				ctx->last_auth_timestamp = now;
+				return;
+			}
+		}
 		ctx->authentication_state = EAP_AUTH_STATE_REAUTH;
 		eap_request_identity(ctx);
 		return;
@@ -663,6 +657,8 @@ static void internal_user_verifier_lookup(char * username,
 							bool *use_default_2048_bit_n_modulus,
 							char **n_modulus_ascii,
 							char **generator_ascii,
+							int *hashversion,
+							uint64_t *generation,
 							void *user_data)
 {
 	(void)n_modulus_ascii;
@@ -670,21 +666,39 @@ static void internal_user_verifier_lookup(char * username,
 	if (user_data == NULL)
 		return;
 
+	if (*generation == 1)
+		return;
+	//This is static data so it can be permanently cached
+	*generation = 1;
+
 	struct eapsrp_ctx *ctx = (struct eapsrp_ctx *)user_data;
 
-	char *decoded_verifier = malloc(1024);
-	char *decoded_salt = malloc(1024);
+	char *decoded_verifier = NULL;
+	char *decoded_salt = NULL;
 
 	if (strcmp(username, ctx->authenticator_username) != 0)
 		goto fail_decode;
 
-	memcpy(decoded_verifier, ctx->authenticator_bytes_verifier, ctx->authenticator_len_verifier);
-	memcpy(decoded_salt, ctx->authenticator_bytes_salt, ctx->authenticator_len_salt);
-
+	if (*hashversion == 0 && HAVE_MBEDTLS) {
+#if HAVE_MBEDTLS
+		decoded_verifier = malloc(ctx->authenticator_len_verifier_old);
+		decoded_salt = malloc(ctx->authenticator_len_salt_old);
+		memcpy(decoded_verifier, ctx->authenticator_bytes_verifier_old, ctx->authenticator_len_verifier_old);
+		memcpy(decoded_salt, ctx->authenticator_bytes_salt_old, ctx->authenticator_len_salt_old);
+		*verifier_len = ctx->authenticator_len_verifier_old;
+		*salt_len = ctx->authenticator_len_salt_old;
+#endif
+	} else {
+		decoded_verifier = malloc(ctx->authenticator_len_verifier);
+		decoded_salt = malloc(ctx->authenticator_len_salt);
+		memcpy(decoded_verifier, ctx->authenticator_bytes_verifier, ctx->authenticator_len_verifier);
+		memcpy(decoded_salt, ctx->authenticator_bytes_salt, ctx->authenticator_len_salt);
+		*verifier_len = ctx->authenticator_len_verifier;
+		*salt_len = ctx->authenticator_len_salt;
+	}
 	*verifier = decoded_verifier;
-	*verifier_len = ctx->authenticator_len_verifier;
 	*salt = decoded_salt;
-	*salt_len = ctx->authenticator_len_salt;
+
 	*use_default_2048_bit_n_modulus = true;
 	goto out;
 
@@ -697,9 +711,24 @@ out:
 	return;
 }
 
-//PUBLIC
-int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata)
+static void old_user_verifier_lookup_wrapper(char * username,
+							size_t *verifier_len, char **verifier,
+							size_t *salt_len, char **salt,
+							bool *use_default_2048_bit_n_modulus,
+							char **n_modulus_ascii,
+							char **generator_ascii,
+							int *hashversion,
+							uint64_t *generation,
+							void *user_data)
 {
+	*hashversion = 0;
+	*generation = 0;
+	struct eapsrp_ctx *ctx = (struct eapsrp_ctx *)user_data;
+	ctx->lookup_func_old(username, verifier_len, verifier, salt_len, salt, use_default_2048_bit_n_modulus, n_modulus_ascii, generator_ascii, user_data);
+}
+
+//PUBLIC
+int rist_enable_eap_srp_2(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_2_t lookup_func, void *userdata) {
 	if (!peer)
 		return RIST_ERR_NULL_PEER;
 	struct rist_common_ctx *cctx = get_cctx(peer);
@@ -721,13 +750,14 @@ int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char
 				return RIST_ERR_INVALID_STRING_LENGTH;
 			}
 			lookup_func = internal_user_verifier_lookup;
-			struct SRPSession * session = srp_session_new(SRP_SHA256, SRP_NG_2048, NULL, NULL);
+			const char *n = NULL;
+			const char *g = NULL;
+			assert(librist_get_ng_constants(LIBRIST_SRP_NG_2048, &n, &g) ==0);
+#if HAVE_MBEDTLS
+			assert(librist_crypto_srp_create_verifier(n, g, username, password, &ctx->authenticator_bytes_salt_old, &ctx->authenticator_len_salt_old, &ctx->authenticator_bytes_verifier_old, &ctx->authenticator_len_verifier_old, false) ==0);
+#endif
+			assert(librist_crypto_srp_create_verifier(n, g, username, password, &ctx->authenticator_bytes_salt, &ctx->authenticator_len_salt, &ctx->authenticator_bytes_verifier, &ctx->authenticator_len_verifier, true) ==0);
 			strcpy(ctx->authenticator_username, username);
-			srp_create_salted_verification_key(session, username,
-									   (const unsigned char *)password, strlen(password),
-									   (const unsigned char **)&ctx->authenticator_bytes_salt, &ctx->authenticator_len_salt,
-									   (const unsigned char **)&ctx->authenticator_bytes_verifier, &ctx->authenticator_len_verifier);
-			srp_session_delete(session);
 			userdata = (void *)ctx;
 			rist_log_priv2(ctx->logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"EAP Authentication enabled, role = authenticator, single user\n");
 		}
@@ -767,6 +797,22 @@ int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char
 	strcpy(ctx->password, password);
 	peer->eap_ctx = ctx;
 	rist_log_priv2(ctx->logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"EAP Authentication enabled, role = authenticatee\n");
+	ctx->use_correct_hashing = true;
 	eap_start(ctx);
 	return 0;
 }
+
+int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata)
+{
+	if (!peer)
+		return RIST_ERR_NULL_PEER;
+
+	user_verifier_lookup_2_t pass_lookup = lookup_func? old_user_verifier_lookup_wrapper : NULL;
+	int ret = rist_enable_eap_srp_2(peer, username, password, pass_lookup, NULL);
+	if (ret == 0) {
+		peer->eap_ctx->lookup_func_old = lookup_func;
+		peer->eap_ctx->lookup_func_userdata = peer->eap_ctx;
+		peer->eap_ctx->lookup_func_userdata_old = userdata;
+	}
+	return ret;
+}
diff --git a/src/eap.h b/src/eap.h
index 6d1958cbe78665081a3d7c2f26fb3483f1bb129c..e77469c3454370c58fcb2fbb7576fc460111c3da 100644
--- a/src/eap.h
+++ b/src/eap.h
@@ -9,8 +9,8 @@
 #define _EAP_H_
 
 #include "common/attributes.h"
-
-#include "srp.h"
+#include "config.h"
+#include "crypto/srp.h"
 #include "librist/librist_srp.h"
 #include <stdint.h>
 #include <stddef.h>
@@ -90,29 +90,32 @@ struct eapsrp_ctx
 	char username[256];
 	char password[256];
 
-	char *salt;
-	size_t salt_len;
-	char *verifier;
-	size_t verifier_len;
-	bool default_2048_ng;
-	char *ascii_n;
-	char *ascii_g;
-
-	user_verifier_lookup_t lookup_func;
+	uint64_t generation;
+	struct librist_crypto_srp_authenticator_ctx *auth_ctx;
+	struct librist_crypto_srp_client_ctx *client_ctx;
+	bool authenticated;
+	user_verifier_lookup_t lookup_func_old;
+	user_verifier_lookup_2_t lookup_func;
+	void *lookup_func_userdata_old;
 	void *lookup_func_userdata;
-	struct SRPSession *srp_session;
-	struct SRPUser *srp_user;
-	struct SRPVerifier *srp_verifier;
 	struct rist_peer *peer;
 	char ip_string[46];
 	struct rist_logging_settings *logging_settings;
 
 	// authenticator data (single user mode)
 	char authenticator_username[256];
+#if HAVE_MBEDTLS
+	size_t authenticator_len_verifier_old;
+	uint8_t *authenticator_bytes_verifier_old;
+	size_t authenticator_len_salt_old;
+	uint8_t *authenticator_bytes_salt_old;
+#endif
 	size_t authenticator_len_verifier;
-	char *authenticator_bytes_verifier;
+	uint8_t *authenticator_bytes_verifier;
 	size_t authenticator_len_salt;
-	char *authenticator_bytes_salt;
+	uint8_t *authenticator_bytes_salt;
+
+	bool use_correct_hashing;
 };
 
 #define EAP_LENERR -1
@@ -121,7 +124,7 @@ struct eapsrp_ctx
 #define EAP_UNEXPECTEDREQUEST -4
 #define EAP_SRP_WRONGSUBTYPE -4
 
-RIST_PRIV int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len);
+RIST_PRIV int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len, uint8_t gre_version);
 RIST_PRIV int eap_request_identity(struct eapsrp_ctx *ctx);
 RIST_PRIV int eap_start(struct eapsrp_ctx *ctx);
 RIST_PRIV void eap_periodic(struct eapsrp_ctx *ctx);
diff --git a/src/rist-common.c b/src/rist-common.c
index 6724b509b542c9b40a9c8e5895f2e649e67550fa..63f95c01eba74a64ee51d68cc84a972a3a47da9f 100755
--- a/src/rist-common.c
+++ b/src/rist-common.c
@@ -16,7 +16,7 @@
 #include "endian-shim.h"
 #include "time-shim.h"
 #include <sys/types.h>
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 #include "eap.h"
 #endif
 #include "mpegts.h"
@@ -2391,7 +2391,7 @@ static void rist_peer_recv(struct evsocket_ctx *evctx, int fd, short revents, vo
 	struct rist_buffer payload = { .data = NULL, .size = 0, .type = 0 };
 	uint32_t flow_id = 0;
 	uint16_t gre_proto = 0;
-
+	uint8_t rist_gre_version = 1;
 	if (cctx->profile > RIST_PROFILE_SIMPLE)
 	{
 		struct rist_gre_hdr *gre = NULL;
@@ -2407,7 +2407,7 @@ static void rist_peer_recv(struct evsocket_ctx *evctx, int fd, short revents, vo
 		uint8_t has_checksum = CHECK_BIT(gre->flags1, 7);
 		uint8_t has_key = CHECK_BIT(gre->flags1, 5);
 		uint8_t has_seq = CHECK_BIT(gre->flags1, 4);
-		uint8_t rist_gre_version = (gre->flags2 >> 3) & 0x7;
+		rist_gre_version = (gre->flags2 >> 3) & 0x7;
 
 		if (recv_bufsize < (sizeof(*gre) + has_checksum*4 + has_key *4 + has_seq *4)) {
 			rist_log_priv(get_cctx(peer), RIST_LOG_ERROR, "Packet too small: %d bytes, ignoring ...\n", recv_bufsize);
@@ -2593,7 +2593,7 @@ protocol_bypass:
 		p->event_recv = peer->event_recv;
 		char incoming_ip_string_buffer[INET6_ADDRSTRLEN];
 		char *incoming_ip_string = get_ip_str(&p->u.address, &incoming_ip_string_buffer[0], INET6_ADDRSTRLEN);
-		#if HAVE_MBEDTLS
+		#if HAVE_SRP_SUPPORT
 		eap_clone_ctx(peer->eap_ctx, p);
 		eap_set_ip_string(p->eap_ctx, incoming_ip_string_buffer);
 		#endif
@@ -2728,7 +2728,7 @@ protocol_bypass:
 		payload.dst_port = p->local_port;
 	}
 	//rist_log_priv(get_cctx(peer), RIST_LOG_INFO, "Port is %d !!!!!\n", addr4.sin_port);
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 	if (payload.type != RIST_PAYLOAD_TYPE_EAPOL && p->eap_ctx && p->eap_ctx->authentication_state < EAP_AUTH_STATE_SUCCESS)
 	{
 		if (now > (p->log_repeat_timer + RIST_LOG_QUIESCE_TIMER)) {
@@ -2792,15 +2792,15 @@ protocol_bypass:
 			}
 			break;
 		case RIST_PAYLOAD_TYPE_EAPOL:
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 			if (p->eap_ctx == NULL) {
 				rist_log_priv(get_cctx(p), RIST_LOG_ERROR, "EAP authentication requested but credentials have not been configured!\n");
 			}
 			else {
 				int eapret = 0;
 				if ((eapret = eap_process_eapol(p->eap_ctx,
-												(void *)(recv_buf + payload_offset),
-												(recv_bufsize - payload_offset))) < 0) {
+												(recv_buf + payload_offset),
+												(recv_bufsize - payload_offset), rist_gre_version)) < 0) {
 					rist_log_priv(get_cctx(p), RIST_LOG_ERROR, "Failed to process EAPOL pkt, return code: %i\n", eapret);
 					if (eapret == 255)//permanent failure, we allow a few retries
 						failed_eap = true;
@@ -3069,7 +3069,7 @@ static void sender_peer_events(struct rist_sender *ctx, uint64_t now)
 				rist_peer_rtcp(NULL, peer);
 			}
 		}
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 		if (!peer->listening || peer->parent)
 			eap_periodic(peer->eap_ctx);
 #endif
@@ -3424,7 +3424,7 @@ int rist_peer_remove(struct rist_common_ctx *ctx, struct rist_peer *peer, struct
 	}
 	_librist_crypto_psk_rist_key_destroy(&peer->key_rx);
 	_librist_crypto_psk_rist_key_destroy(&peer->key_tx);
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 	eap_delete_ctx(&peer->eap_ctx);
 #endif
 	if (peer->url)
@@ -3612,7 +3612,7 @@ void receiver_peer_events(struct rist_receiver *ctx, uint64_t now)
 				rist_peer_rtcp(NULL, p);
 			}
 		}
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 		if (!p->listening && p->parent)
 			eap_periodic(p->eap_ctx);
 #endif
diff --git a/src/udp.c b/src/udp.c
index 3650eb1dbd103db16c31f48b35387f10ec68d9c9..70852862e2bf7bd98cfcc8f2bfe3b13bb383b8c2 100755
--- a/src/udp.c
+++ b/src/udp.c
@@ -12,7 +12,7 @@
 #include "log-private.h"
 #include "socket-shim.h"
 #include "endian-shim.h"
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 #include "eap.h"
 #endif
 #include "crypto/psk.h"
@@ -944,7 +944,7 @@ peer_select:
 
 		if (!peer->is_data || peer->parent)
 			continue;
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 		if (!peer->listening && !eap_is_authenticated(peer->eap_ctx))
 			continue;
 #endif
@@ -969,7 +969,7 @@ peer_select:
 			if (peer->listening) {
 				struct rist_peer *child = peer->child;
 				while (child) {
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 					if (!eap_is_authenticated(child->eap_ctx))
 					{
 						//do nothing
@@ -1001,7 +1001,7 @@ peer_select:
 		if (peer->listening) {
 			struct rist_peer *child = peer->child;
 			while (child) {
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 					if (!eap_is_authenticated(child->eap_ctx))
 					{
 						//do nothing
@@ -1059,7 +1059,7 @@ ssize_t rist_retry_dequeue(struct rist_sender *ctx)
 
 	// If they request a non-sense seq number, we will catch it when we check the seq number against
 	// the one on that buffer position and it does not match
-	
+
 	size_t idx = rist_sender_index_get(ctx, retry->seq);
 	if (RIST_UNLIKELY(ctx->sender_queue[idx] == NULL)) {
 		rist_log_priv(&ctx->common, RIST_LOG_DEBUG,
diff --git a/test/meson.build b/test/meson.build
index 9ba1733de7176c258500058ff788cc64fdf73f9d..20a5534e2e1563ae4f36d6557e91cf285284436e 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -1,12 +1,4 @@
 # librist. Copyright (c) 2020 SipRadius LLC. All right reserved.
 # SPDX-License-Identifier: BSD-2-Clause
 
-all_test_deps = []
-all_test_dep_libs = []
-project_test_sources = []
-
-test_deps = []
-
-test_dep_libs = []
-
 subdir('rist')
\ No newline at end of file
diff --git a/test/rist/example-test.c b/test/rist/example-test.c
deleted file mode 100644
index 31d3955e71877883a97ad0bfaabf6f65af1ac789..0000000000000000000000000000000000000000
--- a/test/rist/example-test.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/* librist. Copyright © 2020 SipRadius LLC. All right reserved.
- * Author: Gijs Peskens <gijs@in2ip.nl>
- * Author: Sergio Ammirata, Ph.D. <sergio@ammirata.net>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include <assert.h>
-#include "librist.h"
-#include <stdarg.h>
-#include <stddef.h>
-#include <setjmp.h>
-#include <stdint.h>
-#include <cmocka.h>
-
-static void basic_test(void** state) {
-    (void)state;
-    assert(1 == 1);
-}
-
-int main(void) {
-    const struct CMUnitTest tests[] = {
-        cmocka_unit_test(basic_test)
-    };
-    return cmocka_run_group_tests(tests, NULL, NULL);
-}
diff --git a/test/rist/meson.build b/test/rist/meson.build
index 893824b7cb697058ac30585528e32599d40182aa..e49b7be4c2b4eb310b15b4d28ea24b80cc3f2275 100644
--- a/test/rist/meson.build
+++ b/test/rist/meson.build
@@ -1,27 +1,7 @@
 # librist. Copyright (c) 2020 SipRadius LLC. All right reserved.
 # SPDX-License-Identifier: BSD-2-Clause
 
-risttest_sources = [
-    'example-test.c'
-]
-
-cmocka = meson.get_compiler('c').find_library('cmocka', required: false)
-risttest_deps = [
-    cmocka
-]
-
-risttest_lib_deps = [
-    librist
-]
-comockatests = cmocka.found()
-if cmocka.found()
-    risttest = executable('risttest',
-                            risttest_sources,
-                            include_directories : inc,
-                            dependencies : [risttest_deps,test_deps],
-                            link_with : [risttest_lib_deps, test_dep_libs])
-
-endif
+subdir('unit')
 
 extra_sources = ['../../contrib/time-shim.c','../../contrib/pthread-shim.c']
 
@@ -41,10 +21,6 @@ test_send_receive = executable('test_send_receive',
                                 ])
 
 
-if comockatests
-    test('rist test', risttest)
-endif
-
 ###Simple profile tests
 #Unicast
 test('Simple profile unicast', test_send_receive, args: ['0', 'rist://@127.0.0.1:1234', 'rist://127.0.0.1:1234', '0'], suite: ['simple', 'unicast'])
@@ -74,7 +50,7 @@ test('Main profile encryption receive server mode, sender client mode unencrypte
 test('Main profile encryption client mode unencrypted, sender server mode', test_send_receive, args: ['1', 'rist://127.0.0.1:6005', 'rist://@127.0.0.1:6005?secret=12345678&aes-type=128', '0'], should_fail: true)
 test('Main profile encryption client mode, sender server mode unencrypted', test_send_receive, args: ['1', 'rist://127.0.0.1:6006?secret=12345678&aes-type=128', 'rist://@127.0.0.1:6006', '0'], should_fail: true)
 #Test SRP Auth
-if use_mbedtls
+if have_srp
 	test('Main profile encryption receive client mode, sender server mode, SRP auth', test_send_receive, args: ['1', 'rist://127.0.0.1:6008?secret=12345678&aes-type=128&username=testuser&password=testpassword', 'rist://@127.0.0.1:6008?secret=12345678&aes-type=128&username=testuser&password=testpassword', '0'],suite: ['main', 'unicast', 'server', 'encryption', 'srp'], should_fail: false)
 	test('Main profile encryption receive client mode, sender server mode, SRP auth, client no SRP', test_send_receive, args: ['1', 'rist://127.0.0.1:6009?secret=12345678&aes-type=128', 'rist://@127.0.0.1:6009?secret=12345678&aes-type=128&username=testuser&password=testpassword', '0'], suite: ['main', 'unicast', 'server', 'encryption', 'srp'], should_fail: true)
 	test('Main profile encryption receive client mode, sender server mode, SRP auth, server no SRP', test_send_receive, args: ['1', 'rist://127.0.0.1:6010?secret=12345678&aes-type=128&username=testuser&password=testpassword', 'rist://@127.0.0.1:6010?secret=12345678&aes-type=128', '0'], suite: ['main', 'unicast', 'server', 'encryption', 'srp'], should_fail: true)
diff --git a/test/rist/test_send_receive.c b/test/rist/test_send_receive.c
index ce31bae157e8a040f3e48be8f5a3d34b2735257e..8eb92279dbd4755b287f5c96c3abdaca6bfffefb 100644
--- a/test/rist/test_send_receive.c
+++ b/test/rist/test_send_receive.c
@@ -56,11 +56,11 @@ struct rist_ctx *setup_rist_receiver(int profile, const char *url) {
 		rist_log(logging_settings_receiver, RIST_LOG_ERROR, "Could not add peer connector to receiver\n");
 		return NULL;
 	}
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
     if (strlen(peer_config->srp_username) > 0 &&
         strlen(peer_config->srp_password) > 0) {
         int srp_error =
-            rist_enable_eap_srp(peer, peer_config->srp_username,
+            rist_enable_eap_srp_2(peer, peer_config->srp_username,
                                 peer_config->srp_password, NULL, NULL);
         if (srp_error)
           rist_log(logging_settings_receiver, RIST_LOG_WARN,
@@ -95,11 +95,11 @@ struct rist_ctx *setup_rist_sender(int profile, const char *url) {
 		return NULL;
 	}
 
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
     if (strlen(peer_config_link->srp_username) > 0 &&
         strlen(peer_config_link->srp_password) > 0) {
         int srp_error =
-            rist_enable_eap_srp(peer, peer_config_link->srp_username,
+            rist_enable_eap_srp_2(peer, peer_config_link->srp_username,
                                 peer_config_link->srp_password, NULL, NULL);
         if (srp_error)
           rist_log(logging_settings_sender, RIST_LOG_WARN,
diff --git a/test/rist/unit/meson.build b/test/rist/unit/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..93cae81c0e44ae1dfe70f5234ca12f0d26897b4f
--- /dev/null
+++ b/test/rist/unit/meson.build
@@ -0,0 +1,14 @@
+cmocka = meson.get_compiler('c').find_library('cmocka', required: false)
+
+if cmocka.found()
+	if have_srp
+		srp_unit = executable('srp_unit', rev_target,
+								'srp_examples.c',
+								'../../../contrib/pthread-shim.c',
+								include_directories : inc,
+								dependencies : [threads, cmocka,crypto_deps],
+		)
+
+		test('srp_unit_test', srp_unit, suite:['unit'])
+	endif
+endif
\ No newline at end of file
diff --git a/test/rist/unit/srp_examples.c b/test/rist/unit/srp_examples.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c5193d20258c6c58fb4c5a978a8a90c130d6177
--- /dev/null
+++ b/test/rist/unit/srp_examples.c
@@ -0,0 +1,433 @@
+//This set of unit tests covers the entire SRP flow verified against the example in the VSF document
+
+#include "config.h"
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <assert.h>
+#include <cmocka.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "librist/librist_config.h"
+
+#include "src/crypto/srp.h"
+#include "src/crypto/srp_constants.h"
+#define DEBUG_USE_EXAMPLE_CONSTANTS 1
+
+#if HAVE_MBEDTLS
+#define malloc(size) _test_malloc(size, __FILE__, __LINE__)
+#define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__)
+#define free(obj) _test_free(obj, __FILE__, __LINE__)
+#endif
+
+#include "src/crypto/srp.c"
+#include "src/crypto/srp_constants.c"
+
+static void hexstr_to_uint(const char *hexstr, uint8_t *buf, size_t buf_len) {
+	for (size_t i = 0, j = 0; j < buf_len; i += 2, j++)
+		buf[j] = (hexstr[i] % 32 + 9) % 25 * 16 + (hexstr[i + 1] % 32 + 9) % 25;
+}
+
+static void uint_to_hex(const uint8_t *buf, size_t buf_len, char *outbuf) {
+	size_t j;
+	for (j = 0; j < buf_len; j++) {
+		outbuf[2 * j] = (buf[j] >> 4) + 48;
+		outbuf[2 * j + 1] = (buf[j] & 15) + 48;
+		if (outbuf[2 * j] > 57)
+			outbuf[2 * j] += 7;
+		if (outbuf[2 * j + 1] > 57)
+			outbuf[2 * j + 1] += 7;
+	}
+	outbuf[2 * j] = '\0';
+}
+
+struct srp_test_state {
+	const char *n;
+	const char *g;
+	uint8_t *salt;
+	size_t salt_len;
+	uint8_t *incorrect_hash_verifier;
+	uint8_t *correct_hash_verifier;
+	size_t verifier_len;
+	struct librist_crypto_srp_authenticator_ctx *wrong_hash_authenticator;
+	struct librist_crypto_srp_authenticator_ctx *correct_hash_authenticator;
+	struct librist_crypto_srp_client_ctx *wrong_hash_client;
+	struct librist_crypto_srp_client_ctx *correct_hash_client;
+};
+
+static int srp_test_state_setup(void **state) {
+	*state = calloc(sizeof(struct srp_test_state), 1);
+	struct srp_test_state *s = *state;
+	librist_get_ng_constants(LIBRIST_SRP_NG_512, &s->n, &s->g);
+#if HAVE_MBEDTLS
+	librist_crypto_srp_create_verifier(s->n, s->g, "rist", "mainprofile", &s->salt, &s->salt_len, &s->incorrect_hash_verifier, &s->verifier_len, false);
+	s->wrong_hash_authenticator = librist_crypto_srp_authenticator_ctx_create(s->n, s->g, s->incorrect_hash_verifier, s->verifier_len, s->salt, s->salt_len, false);
+	size_t v_len = s->verifier_len;
+	free(s->salt);
+	s->salt = NULL;
+#endif
+	librist_crypto_srp_create_verifier(s->n, s->g, "rist", "mainprofile", &s->salt, &s->salt_len, &s->correct_hash_verifier, &s->verifier_len, true);
+#if HAVE_MBEDTLS
+	assert(v_len == s->verifier_len);
+#endif
+	s->correct_hash_authenticator = librist_crypto_srp_authenticator_ctx_create(s->n, s->g, s->correct_hash_verifier, s->verifier_len, s->salt, s->salt_len, true);
+
+
+    const char N_hex[] = "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3";
+	uint8_t N[(sizeof(N_hex) -1)/2];
+	hexstr_to_uint(N_hex, N, sizeof(N));
+	uint8_t g[1] = {0x02};
+#if HAVE_MBEDTLS
+	s->wrong_hash_client = librist_crypto_srp_client_ctx_create(false, N, sizeof(N), g, sizeof(g), s->salt, s->salt_len, false);
+#endif
+	s->correct_hash_client = librist_crypto_srp_client_ctx_create(false, N, sizeof(N), g, sizeof(g), s->salt, s->salt_len, true);
+	return 0;
+}
+
+static int srp_test_state_teardown(void **state) {
+	struct srp_test_state *s = *state;
+	free(s->salt);
+	free(s->incorrect_hash_verifier);
+	free(s->correct_hash_verifier);
+	librist_crypto_srp_authenticator_ctx_free(s->wrong_hash_authenticator);
+	librist_crypto_srp_authenticator_ctx_free(s->correct_hash_authenticator);
+	librist_crypto_srp_client_ctx_free(s->wrong_hash_client);
+	librist_crypto_srp_client_ctx_free(s->correct_hash_client);
+	free(s);
+	return 0;
+}
+
+static void test_hash_func(void **state) {
+	(void)(state);
+	//expected hash gather via: `echo -n "rist:mainprofile" | sha256sum | awk '{print toupper($1)}'`
+	const char expected_hash[] = "8427F6E0E69DC9B99DFE1052DDAF7E50D4FEA316C63C6AD23FE197C9C1DA2AF1";
+	const char test_string[] = "rist:mainprofile";
+	uint8_t hash_data[SHA256_DIGEST_LENGTH];
+	assert_int_equal(librist_crypto_srp_hash((const uint8_t *)test_string, sizeof(test_string) -1, hash_data), 0);
+	char outhash[sizeof(expected_hash)];
+	uint_to_hex(hash_data, sizeof(hash_data), outhash);
+	assert_string_equal(outhash, expected_hash);
+}
+
+static void test_hash_update_func(void **state) {
+	(void)(state);
+	const char expected_hash[] = "8427F6E0E69DC9B99DFE1052DDAF7E50D4FEA316C63C6AD23FE197C9C1DA2AF1";
+	HASH_CONTEXT ctx;
+	HASH_CONTEXT_INIT(&ctx, true);
+	assert_int_equal(librist_crypto_srp_hash_update(&ctx, "rist", strlen("rist")), 0);
+	assert_int_equal(librist_crypto_srp_hash_update(&ctx, ":", 1), 0);
+	assert_int_equal(librist_crypto_srp_hash_update(&ctx, "mainprofile", strlen("mainprofile")), 0);
+	uint8_t hash_data[SHA256_DIGEST_LENGTH];
+	assert_int_equal(librist_crypto_srp_hash_final(&ctx, hash_data), 0);
+	char outhash[sizeof(expected_hash)];
+	uint_to_hex(hash_data, sizeof(hash_data), outhash);
+	assert_string_equal(outhash, expected_hash);
+}
+
+static void test_get_default_ng(void **state) {
+	(void)(state);
+	const char *n = NULL;
+	const char *g = NULL;
+	assert_int_equal(librist_get_ng_constants(LIBRIST_SRP_NG_DEFAULT, &n, &g), 0);
+	assert_string_equal(n,
+		"AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4"
+   		"A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60"
+		"95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF"
+		"747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907"
+		"8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861"
+		"60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB"
+		"FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73"
+	);
+   	assert_string_equal(g, "2");
+
+	//This N,g pair is used in the VSF example flow.
+	n = NULL;
+	g = NULL;
+	assert_int_equal(librist_get_ng_constants(LIBRIST_SRP_NG_512, &n, &g), 0);
+	assert_string_equal(n, "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3");
+	assert_string_equal(g, "2");
+}
+
+#if HAVE_MBEDTLS
+static void test_srp_wrong_hashing_verifier_create(void **state) {
+	struct srp_test_state *s = *state;
+	const char sample_salt[] = "72F9D5383B7EB7599FB63028F47475B60A55F313D40E0BE023E026C97C0A2C32";
+	const char sample_verifier[] = "557EA208F87A23C28936423EC16ABE6BD959933DFBEFC0B36EBD9335DE3997C97DDFA081D64CFBC6EFBFD5BE19F2ED9F77922FD7E88BBA6C6B310A9018EC4305";
+
+	uint8_t *salt = NULL;
+	size_t salt_len = 0;
+	uint8_t *verifier = NULL;
+	size_t verifier_len = 0;
+	assert_int_equal(librist_crypto_srp_create_verifier(s->n, s->g, "rist", "mainprofile", &salt, &salt_len, &verifier, &verifier_len, false), 0);
+
+	assert_int_equal(verifier_len, (sizeof(sample_verifier) -1)/2);
+	assert_int_equal(salt_len, (sizeof(sample_salt) -1)/2);
+
+	char salt_hex[sizeof(sample_salt)];
+	uint_to_hex(salt, salt_len, salt_hex);
+	assert_string_equal(salt_hex, sample_salt);
+
+	char verifier_hex[sizeof(sample_verifier)];
+	uint_to_hex(verifier, verifier_len, verifier_hex);
+	assert_string_equal(sample_verifier, verifier_hex);
+	free(verifier);
+	free(salt);
+}
+
+static void test_srp_wrong_hashing_auth_ctx_create(void **state) {
+	struct srp_test_state *s = *state;
+	struct librist_crypto_srp_authenticator_ctx * ctx = librist_crypto_srp_authenticator_ctx_create(s->n, s->g, s->incorrect_hash_verifier, s->verifier_len, s->salt, s->salt_len, false);
+	assert_non_null(ctx);
+
+	const char well_known_n[] = "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3";
+	uint8_t n[(sizeof(well_known_n) -1)/2];
+	uint8_t g[1];
+
+	assert_int_equal(librist_crypto_srp_authenticator_write_n_bytes(ctx, n, sizeof(n)), sizeof(n));
+	assert_int_equal(librist_crypto_srp_authenticator_write_g_bytes(ctx, g, sizeof(g)), sizeof(g));
+
+	char n_hex[sizeof(well_known_n)];
+	char g_hex[sizeof("02")];
+
+	uint_to_hex(n, sizeof(n), n_hex);
+	assert_string_equal(n_hex, well_known_n);
+
+	uint_to_hex(g, sizeof(g), g_hex);
+	assert_string_equal(g_hex, "02");
+
+	librist_crypto_srp_authenticator_ctx_free(ctx);
+}
+
+static void test_srp_wrong_hashing_auth_handle_A(void **state) {
+	struct srp_test_state *s = *state;
+	const char client_A_hex[] = "92C4CEFB95A1AE2E576A252B19273FD4613F44FDA4AC8CC84A089D5740756223943882BAD34CB55F35139CDDB60E0D19ACD2B884CFB27F53C8EA969269ABE014";
+	uint8_t client_A[(sizeof(client_A_hex) -1)/2];
+	hexstr_to_uint(client_A_hex, client_A, sizeof(client_A));
+	assert_int_equal(librist_crypto_srp_authenticator_handle_A(s->wrong_hash_authenticator, client_A, sizeof(client_A)), 0);
+
+	const char expected_B[] = "85CAE0C578E6927B78BEB173FB0F9BFC8ECB4C13542BB8BE3B0F3447B3764A234177E22D180DCAD21F33302248B7452916DC58ABD309C8A77440A228B8516A4E";
+
+	uint8_t B[(sizeof(expected_B) -1)/2];
+	assert_int_equal(librist_crypto_srp_authenticator_write_B_bytes(s->wrong_hash_authenticator, B, sizeof(B)), sizeof(B));
+
+	char B_hex[sizeof(expected_B)];
+	uint_to_hex(B, sizeof(B), B_hex);
+	assert_string_equal(expected_B, B_hex);
+}
+
+static void test_srp_wrong_hashing_auth_verify_M1(void **state) {
+	struct srp_test_state *s = *state;
+	const char client_M1_hex[] = "EBFC2D79BEB3CBF7BA83C27E2B51524F8CD3F3B2C4804815AD2516D465DF80C9";
+	uint8_t client_M1[(sizeof(client_M1_hex) -1)/2];
+	hexstr_to_uint(client_M1_hex, client_M1, sizeof(client_M1));
+
+	assert_int_equal(librist_crypto_srp_authenticator_verify_m1(s->wrong_hash_authenticator, "rist", client_M1), 0);
+
+	const char expected_m2[] = "FB14D73B5ACBBA101E5A799F80EBCBB43D83890E23DED979110EEFF109C0441A";
+	char m2_hex[sizeof(expected_m2)];
+	uint8_t m2[SHA256_DIGEST_LENGTH];
+
+	librist_crypto_srp_authenticator_write_M2_bytes(s->wrong_hash_authenticator, m2);
+
+	uint_to_hex(m2, sizeof(m2), m2_hex);
+
+	assert_string_equal(m2_hex, expected_m2);
+}
+#endif
+
+//Nothing in client creation relies on hashing, hence this test isn't doubled
+static void test_srp_client_ctx_create(void **state) {
+	(void)(state);
+	const char salt_hex[] = "72F9D5383B7EB7599FB63028F47475B60A55F313D40E0BE023E026C97C0A2C32";
+
+	uint8_t salt[(sizeof(salt_hex) -1)/2];
+	hexstr_to_uint(salt_hex, salt, sizeof(salt));
+
+	struct librist_crypto_srp_client_ctx *ctx = librist_crypto_srp_client_ctx_create(true, NULL, 0, NULL, 0, salt, sizeof(salt), true);
+	assert_non_null(ctx);
+	librist_crypto_srp_client_ctx_free(ctx);
+
+    const char N_hex[] = "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3";
+	uint8_t N[(sizeof(N_hex) -1)/2];
+	hexstr_to_uint(N_hex, N, sizeof(N));
+	uint8_t g[1] = {0x02};
+	ctx = librist_crypto_srp_client_ctx_create(false, N, sizeof(N), g, sizeof(g), salt, sizeof(salt), true);
+
+	const char expected_A[] = "92C4CEFB95A1AE2E576A252B19273FD4613F44FDA4AC8CC84A089D5740756223943882BAD34CB55F35139CDDB60E0D19ACD2B884CFB27F53C8EA969269ABE014";
+	uint8_t A[(sizeof(expected_A)-1)/2];
+	assert_int_equal(librist_crypto_srp_client_write_A_bytes(ctx, A, sizeof(A)), sizeof(A));
+
+	char a_hex[sizeof(expected_A)];
+	uint_to_hex(A, sizeof(A), a_hex);
+	assert_string_equal(a_hex, expected_A);
+	librist_crypto_srp_client_ctx_free(ctx);
+}
+
+#if HAVE_MBEDTLS
+
+static void test_srp_wrong_hashing_client_handle_B(void **state) {
+	struct srp_test_state *ctx = *state;
+	const char server_B[] = "85CAE0C578E6927B78BEB173FB0F9BFC8ECB4C13542BB8BE3B0F3447B3764A234177E22D180DCAD21F33302248B7452916DC58ABD309C8A77440A228B8516A4E";
+	uint8_t B[(sizeof(server_B) -1)/2];
+	hexstr_to_uint(server_B, B, sizeof(B));
+
+	assert_int_equal(librist_crypto_srp_client_handle_B(ctx->wrong_hash_client, B, sizeof(B), "rist", "mainprofile"), 0);
+
+	const char expected_M1[] = "EBFC2D79BEB3CBF7BA83C27E2B51524F8CD3F3B2C4804815AD2516D465DF80C9";
+	uint8_t m1[SHA256_DIGEST_LENGTH];
+
+	librist_crypto_srp_client_write_M1_bytes(ctx->wrong_hash_client, m1);
+
+	char m1_hex[sizeof(expected_M1)];
+	uint_to_hex(m1, sizeof(m1), m1_hex);
+	assert_string_equal(m1_hex, expected_M1);
+}
+
+static void test_srp_wrong_hashing_client_verify_M2(void **state) {
+	struct srp_test_state *ctx = *state;
+	const char server_M2[] = "FB14D73B5ACBBA101E5A799F80EBCBB43D83890E23DED979110EEFF109C0441A";
+	uint8_t M2[(sizeof(server_M2)-1)/2];
+	hexstr_to_uint(server_M2, M2, sizeof(M2));
+	assert_int_equal(librist_crypto_srp_client_verify_m2(ctx->wrong_hash_client, M2), 0);
+}
+
+#endif
+
+static void test_srp_correct_hashing_verifier_create(void **state) {
+	struct srp_test_state *s = *state;
+	const char sample_salt[] = "72F9D5383B7EB7599FB63028F47475B60A55F313D40E0BE023E026C97C0A2C32";
+	const char sample_verifier[] = "2E06FEA163D6E9FF0FA7ED6C59233389D0DBA0C08C0F72F6DAD1E2A3D8B92A772F070439D1C11B87FA990D2DAF04EB830CC77D61ACC4B253297379CD8E6DC3AF";
+
+	uint8_t *salt = NULL;
+	size_t salt_len = 0;
+	uint8_t *verifier = NULL;
+	size_t verifier_len = 0;
+	assert_int_equal(librist_crypto_srp_create_verifier(s->n, s->g, "rist", "mainprofile", &salt, &salt_len, &verifier, &verifier_len, true), 0);
+
+	assert_int_equal(verifier_len, (sizeof(sample_verifier) -1)/2);
+	assert_int_equal(salt_len, (sizeof(sample_salt) -1)/2);
+
+	char salt_hex[sizeof(sample_salt)];
+	uint_to_hex(salt, salt_len, salt_hex);
+	assert_string_equal(salt_hex, sample_salt);
+
+	char verifier_hex[sizeof(sample_verifier)];
+	uint_to_hex(verifier, verifier_len, verifier_hex);
+	assert_string_equal(sample_verifier, verifier_hex);
+	free(verifier);
+	free(salt);
+}
+
+static void test_srp_correct_hashing_auth_ctx_create(void **state) {
+	struct srp_test_state *s = *state;
+	struct librist_crypto_srp_authenticator_ctx * ctx = librist_crypto_srp_authenticator_ctx_create(s->n, s->g, s->correct_hash_verifier, s->verifier_len, s->salt, s->salt_len, true);
+	assert_non_null(ctx);
+
+	const char well_known_n[] = "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3";
+	uint8_t n[(sizeof(well_known_n) -1)/2];
+	uint8_t g[1];
+
+	assert_int_equal(librist_crypto_srp_authenticator_write_n_bytes(ctx, n, sizeof(n)), sizeof(n));
+	assert_int_equal(librist_crypto_srp_authenticator_write_g_bytes(ctx, g, sizeof(g)), sizeof(g));
+
+	char n_hex[sizeof(well_known_n)];
+	char g_hex[sizeof("02")];
+
+	uint_to_hex(n, sizeof(n), n_hex);
+	assert_string_equal(n_hex, well_known_n);
+
+	uint_to_hex(g, sizeof(g), g_hex);
+	assert_string_equal(g_hex, "02");
+
+	librist_crypto_srp_authenticator_ctx_free(ctx);
+}
+
+static void test_srp_correct_hashing_auth_handle_A(void **state) {
+	struct srp_test_state *s = *state;
+	const char client_A_hex[] = "92C4CEFB95A1AE2E576A252B19273FD4613F44FDA4AC8CC84A089D5740756223943882BAD34CB55F35139CDDB60E0D19ACD2B884CFB27F53C8EA969269ABE014";
+	uint8_t client_A[(sizeof(client_A_hex) -1)/2];
+	hexstr_to_uint(client_A_hex, client_A, sizeof(client_A));
+	assert_int_equal(librist_crypto_srp_authenticator_handle_A(s->correct_hash_authenticator, client_A, sizeof(client_A)), 0);
+
+	const char expected_B[] = "858CDC811B5EEAA7F58C12767D309EBD2DF1D46F59EF5686052E6511CF853CA4E66910BDBD28CBEAE2F2DEE7F6BF3756757BD69E88D48C77B5371A82EF52AD84";
+
+	uint8_t B[(sizeof(expected_B) -1)/2];
+	assert_int_equal(librist_crypto_srp_authenticator_write_B_bytes(s->correct_hash_authenticator, B, sizeof(B)), sizeof(B));
+
+	char B_hex[sizeof(expected_B)];
+	uint_to_hex(B, sizeof(B), B_hex);
+	assert_string_equal(expected_B, B_hex);
+}
+
+static void test_srp_correct_hashing_auth_verify_M1(void **state) {
+	struct srp_test_state *s = *state;
+	const char client_M1_hex[] = "E28147C801BAB9C37647C1FF4A29FA720E3F5676434FB85EA9A752CC1F9B1AD4";
+	uint8_t client_M1[(sizeof(client_M1_hex) -1)/2];
+	hexstr_to_uint(client_M1_hex, client_M1, sizeof(client_M1));
+
+	assert_int_equal(librist_crypto_srp_authenticator_verify_m1(s->correct_hash_authenticator, "rist", client_M1), 0);
+
+	const char expected_m2[] = "84F19797916FBDCAB1321CA78B575B145B586150248AFAA156361B8BCB139B32";
+	char m2_hex[sizeof(expected_m2)];
+	uint8_t m2[SHA256_DIGEST_LENGTH];
+
+	librist_crypto_srp_authenticator_write_M2_bytes(s->correct_hash_authenticator, m2);
+
+	uint_to_hex(m2, sizeof(m2), m2_hex);
+
+	assert_string_equal(m2_hex, expected_m2);
+}
+
+static void test_srp_correct_hashing_client_handle_B(void **state) {
+	struct srp_test_state *ctx = *state;
+	const char server_B[] = "858CDC811B5EEAA7F58C12767D309EBD2DF1D46F59EF5686052E6511CF853CA4E66910BDBD28CBEAE2F2DEE7F6BF3756757BD69E88D48C77B5371A82EF52AD84";
+	uint8_t B[(sizeof(server_B) -1)/2];
+	hexstr_to_uint(server_B, B, sizeof(B));
+
+	assert_int_equal(librist_crypto_srp_client_handle_B(ctx->correct_hash_client, B, sizeof(B), "rist", "mainprofile"), 0);
+
+	const char expected_M1[] = "E28147C801BAB9C37647C1FF4A29FA720E3F5676434FB85EA9A752CC1F9B1AD4";
+	uint8_t m1[SHA256_DIGEST_LENGTH];
+
+	librist_crypto_srp_client_write_M1_bytes(ctx->correct_hash_client, m1);
+
+	char m1_hex[sizeof(expected_M1)];
+	uint_to_hex(m1, sizeof(m1), m1_hex);
+	assert_string_equal(m1_hex, expected_M1);
+}
+
+static void test_srp_correct_hashing_client_verify_M2(void **state) {
+	struct srp_test_state *ctx = *state;
+	const char server_M2[] = "84F19797916FBDCAB1321CA78B575B145B586150248AFAA156361B8BCB139B32";
+	uint8_t M2[(sizeof(server_M2)-1)/2];
+	hexstr_to_uint(server_M2, M2, sizeof(M2));
+	assert_int_equal(librist_crypto_srp_client_verify_m2(ctx->correct_hash_client, M2), 0);
+}
+
+int main(void) {
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(test_hash_func),
+		cmocka_unit_test(test_hash_update_func),
+		cmocka_unit_test(test_get_default_ng),
+#if HAVE_MBEDTLS
+		cmocka_unit_test(test_srp_wrong_hashing_auth_handle_A),
+		cmocka_unit_test(test_srp_wrong_hashing_auth_verify_M1),
+		cmocka_unit_test(test_srp_wrong_hashing_verifier_create),
+		cmocka_unit_test(test_srp_wrong_hashing_auth_ctx_create),
+#endif
+		cmocka_unit_test(test_srp_correct_hashing_verifier_create),
+		cmocka_unit_test(test_srp_correct_hashing_auth_ctx_create),
+		cmocka_unit_test(test_srp_correct_hashing_auth_handle_A),
+		cmocka_unit_test(test_srp_correct_hashing_auth_verify_M1),
+		cmocka_unit_test(test_srp_client_ctx_create),
+#if HAVE_MBEDTLS
+		cmocka_unit_test(test_srp_wrong_hashing_client_handle_B),
+		cmocka_unit_test(test_srp_wrong_hashing_client_verify_M2),
+#endif
+		cmocka_unit_test(test_srp_correct_hashing_client_handle_B),
+		cmocka_unit_test(test_srp_correct_hashing_client_verify_M2),
+	};
+
+    return cmocka_run_group_tests(tests, srp_test_state_setup, srp_test_state_teardown);
+}
diff --git a/tools/meson.build b/tools/meson.build
index dd6a4d2cf74d120f92d4415761c79c2f06d5381b..8e2dc8b76decc58df7253fd9c437d336d4fd91b3 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -17,9 +17,9 @@ if filter_obj
 endif
 
 srp_shared = []
-if use_mbedtls
+if have_srp
 	srp_shared += 'srp_shared.c'
-	tools_dependencies += mbedcrypto_lib
+	tools_dependencies += crypto_deps
 endif
 
 if compile_prometheus
@@ -60,12 +60,12 @@ executable('rist2rist',
 	include_directories: inc,
 	install: should_install)
 
-if use_mbedtls
+if mbedcrypto_lib_found or use_nettle
 	executable('ristsrppasswd',
-			['ristsrppasswd.c', '../contrib/srp.c', tools_deps],
+			['ristsrppasswd.c', tools_deps],
 			dependencies: [
-				mbedcrypto_lib,
 				librist_dep,
+				crypto_deps,
 			],
 			include_directories: inc,
 			install: should_install)
diff --git a/tools/rist2rist.c b/tools/rist2rist.c
index ea035791283c333f02ae90b5c2888b592a1cc0b4..0c71d5867591a3fa16f53897fbfc42de94f98b73 100644
--- a/tools/rist2rist.c
+++ b/tools/rist2rist.c
@@ -11,7 +11,7 @@
 #include "librist/version.h"
 #include "risturlhelp.h"
 #include "config.h"
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 #include "librist/librist_srp.h"
 #include "srp_shared.h"
 #endif
@@ -56,7 +56,7 @@ static struct option long_options[] = {
 { "statsinterval",   required_argument, NULL, 'S' },
 { "verbose-level",   required_argument, NULL, 'v' },
 { "remote-logging",  required_argument, NULL, 'r' },
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 { "srpfile",         required_argument, NULL, 'F' },
 #endif
 { "help",            no_argument,       NULL, 'h' },
@@ -72,7 +72,7 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n"
 "       -N | --cname identifier                   | Manually configured identifier                           |\n"
 "       -v | --verbose-level value                | To disable logging: -1, log levels match syslog levels   |\n"
 "       -r | --remote-logging IP:PORT             | Send logs and stats to this IP:PORT using udp messages   |\n"
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 "       -F | --srpfile filepath                   | When in listening mode, use this file to hold the list   |\n"
 "                                                 | of usernames and passwords to validate against. Use the  |\n"
 "                                                 | ristsrppasswd tool to create the line entries.           |\n"
@@ -84,8 +84,8 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n"
 "       --statsinterval 1000      \\\n"
 "       --verbose-level 6         \n";
 
-#if HAVE_MBEDTLS
-	FILE *srpfile = NULL;
+#if HAVE_SRP_SUPPORT
+	char *srpfile = NULL;
 #endif
 
 static void usage(char *cmd)
@@ -208,17 +208,17 @@ static struct rist_ctx* setup_rist_sender(struct rist_sender_args *setup) {
 		exit(1);
 	}
 
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 	int srp_error = 0;
 	if (strlen(peer_config->srp_username) > 0 && strlen(peer_config->srp_password) > 0)
 	{
-		srp_error = rist_enable_eap_srp(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL);
+		srp_error = rist_enable_eap_srp_2(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL);
 		if (srp_error)
 			rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP for peer\n", srp_error);
 	}
 	if (srpfile)
 	{
-		srp_error = rist_enable_eap_srp(peer, NULL, NULL, user_verifier_lookup, srpfile);
+		srp_error = rist_enable_eap_srp_2(peer, NULL, NULL, user_verifier_lookup, srpfile);
 		if (srp_error)
 			rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP global authenticator, file %s\n", srp_error, srpfile);
 	}
@@ -246,7 +246,7 @@ static int cb_recv(void *arg, struct rist_data_block *b)
 		rist_sender_flow_id_set(cb_arg->sender_ctx, b->flow_id);
 	}
 	b->virt_src_port = cb_arg->src_port;
-	b->virt_dst_port = cb_arg->dst_port; 
+	b->virt_dst_port = cb_arg->dst_port;
 	block->flags = RIST_DATA_FLAGS_USE_SEQ;//We only need this flag set, this way we don't have to null it beforehand.
 	int ret = rist_sender_data_write(cb_arg->sender_ctx, b);
 	rist_receiver_data_block_free2(&b);
@@ -303,17 +303,17 @@ int main (int argc, char **argv) {
 		case 'i':
 			if (inputurl != NULL)
 				goto usage;
-			inputurl = strdup(optarg); 
+			inputurl = strdup(optarg);
 			break;
 		case 'o':
 			if (outputurl != NULL)
 				goto usage;
-			outputurl = strdup(optarg); 
+			outputurl = strdup(optarg);
 			break;
 		case 's':
 			if (client_args.shared_secret != NULL)
 				goto usage;
-			client_args.shared_secret = strdup(optarg); 
+			client_args.shared_secret = strdup(optarg);
 			break;
 		case 'e':
 			client_args.encryption_type =atoi(optarg);
@@ -321,7 +321,7 @@ int main (int argc, char **argv) {
 		case 'N':
 			if (cname != NULL)
 				goto usage;
-			cname = strdup(optarg); 
+			cname = strdup(optarg);
 			break;
 		case 'v':
 			loglevel = (enum rist_log_level) atoi(optarg);
@@ -331,14 +331,15 @@ int main (int argc, char **argv) {
 				goto usage;
 			remote_log_address = strdup(optarg);
 		break;
-#if HAVE_MBEDTLS
-		case 'F':
-			srpfile = fopen(optarg, "r");
-			if (!srpfile) {
+#if HAVE_SRP_SUPPORT
+		case 'F': {
+			FILE* f = fopen(optarg, "r");
+			if (!f) {
 				rist_log(&logging_settings, RIST_LOG_ERROR, "Could not open srp file %s\n", optarg);
-				exitcode = 1;
-				goto out;
+				return 1;
 			}
+			srpfile = strdup(optarg);
+		}
 		break;
 #endif
 		case 'S':
@@ -480,7 +481,7 @@ out:
 		free(outputurl);
 	if (remote_log_address)
 		free(remote_log_address);
-	
+
 
 
 	return exitcode;
diff --git a/tools/ristreceiver.c b/tools/ristreceiver.c
index 651fb022e8d97cf5299ee55aff111be8d22620a4..e14dbf9eaa09f2db8e73e6ab3725dba7ef7b3f7e 100644
--- a/tools/ristreceiver.c
+++ b/tools/ristreceiver.c
@@ -10,7 +10,7 @@
 #include "headers.h"
 #include "librist/version.h"
 #include "config.h"
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 #include "librist/librist_srp.h"
 #include "srp_shared.h"
 #endif
@@ -81,7 +81,7 @@ static struct option long_options[] = {
 { "stats",           required_argument, NULL, 'S' },
 { "verbose-level",   required_argument, NULL, 'v' },
 { "remote-logging",  required_argument, NULL, 'r' },
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 { "srpfile",         required_argument, NULL, 'F' },
 #endif
 { "help",            no_argument,       NULL, 'h' },
@@ -117,7 +117,7 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n"
 "       -S | --statsinterval value (ms)           | Interval at which stats get printed, 0 to disable        |\n"
 "       -v | --verbose-level value                | To disable logging: -1, log levels match syslog levels   |\n"
 "       -r | --remote-logging IP:PORT             | Send logs and stats to this IP:PORT using udp messages   |\n"
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 "       -F | --srpfile filepath                   | When in listening mode, use this file to hold the list   |\n"
 "                                                 | of usernames and passwords to validate against. Use the  |\n"
 "                                                 | ristsrppasswd tool to create the line entries.           |\n"
@@ -525,8 +525,8 @@ int main(int argc, char *argv[])
 	int receiver_pipe[2];
 #endif
 
-#if HAVE_MBEDTLS
-	FILE *srpfile = NULL;
+#if HAVE_SRP_SUPPORT
+	char *srpfile = NULL;
 #endif
 
 	for (size_t i = 0; i < MAX_OUTPUT_COUNT; i++)
@@ -591,13 +591,15 @@ int main(int argc, char *argv[])
 		case 'r':
 			remote_log_address = strdup(optarg);
 		break;
-#if HAVE_MBEDTLS
-		case 'F':
-			srpfile = fopen(optarg, "r");
-			if (!srpfile) {
+#if HAVE_SRP_SUPPORT
+		case 'F': {
+			FILE* f = fopen(optarg, "r");
+			if (!f) {
 				rist_log(&logging_settings, RIST_LOG_ERROR, "Could not open srp file %s\n", optarg);
 				return 1;
 			}
+			srpfile = strdup(optarg);
+		}
 		break;
 #endif
 		case 'u':
@@ -754,18 +756,18 @@ int main(int argc, char *argv[])
 			rist_log(&logging_settings, RIST_LOG_ERROR, "Could not add peer connector to receiver #%i\n", (int)(i + 1));
 			exit(1);
 		}
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 		int srp_error = 0;
 		if (profile != RIST_PROFILE_SIMPLE) {
 			if (strlen(peer_config->srp_username) > 0 && strlen(peer_config->srp_password) > 0)
 			{
-				srp_error = rist_enable_eap_srp(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL);
+				srp_error = rist_enable_eap_srp_2(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL);
 				if (srp_error)
 					rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP for peer\n", srp_error);
 			}
 			if (srpfile)
 			{
-				srp_error = rist_enable_eap_srp(peer, NULL, NULL, user_verifier_lookup, srpfile);
+				srp_error = rist_enable_eap_srp_2(peer, NULL, NULL, user_verifier_lookup, srpfile);
 				if (srp_error)
 					rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP global authenticator, file %s\n", srp_error, srpfile);
 			}
diff --git a/tools/ristsender.c b/tools/ristsender.c
index afc0c1ad1c09b0e7a0ce4d385311e9874f9ce5b9..335c012f7faded86c8c7a826bd2661d57e8f1bf6 100644
--- a/tools/ristsender.c
+++ b/tools/ristsender.c
@@ -9,7 +9,7 @@
 #include <stdint.h>
 #include "librist/version.h"
 #include "config.h"
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 #include "librist/librist_srp.h"
 #include "srp_shared.h"
 #endif
@@ -123,7 +123,7 @@ static struct option long_options[] = {
 { "stats",           required_argument, NULL, 'S' },
 { "verbose-level",   required_argument, NULL, 'v' },
 { "remote-logging",  required_argument, NULL, 'r' },
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 { "srpfile",         required_argument, NULL, 'F' },
 #endif
 { "fast-start",      required_argument, NULL, 'f' },
@@ -161,7 +161,7 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n"
 "       -S | --statsinterval value (ms)           | Interval at which stats get printed, 0 to disable        |\n"
 "       -v | --verbose-level value                | To disable logging: -1, log levels match syslog levels   |\n"
 "       -r | --remote-logging IP:PORT             | Send logs and stats to this IP:PORT using udp messages   |\n"
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 "       -F | --srpfile filepath                   | When in listening mode, use this file to hold the list   |\n"
 "                                                 | of usernames and passwords to validate against. Use the  |\n"
 "                                                 | ristsrppasswd tool to create the line entries.           |\n"
@@ -211,8 +211,8 @@ static uint64_t risttools_convertRTPtoNTP(uint32_t i_rtp)
 }
 */
 
-#if HAVE_MBEDTLS
-	FILE *srpfile = NULL;
+#if HAVE_SRP_SUPPORT
+	char *srpfile = NULL;
 #endif
 
 static void input_udp_recv(struct evsocket_ctx *evctx, int fd, short revents, void *arg)
@@ -536,18 +536,18 @@ static struct rist_peer* setup_rist_peer(struct rist_ctx_wrap *w, struct rist_se
 		}
 	}
 #endif
-#if HAVE_MBEDTLS
+#if HAVE_SRP_SUPPORT
 	int srp_error = 0;
 	if (setup->profile != RIST_PROFILE_SIMPLE) {
 		if (strlen(peer_config_link->srp_username) > 0 && strlen(peer_config_link->srp_password) > 0)
 		{
-			srp_error = rist_enable_eap_srp(peer, peer_config_link->srp_username, peer_config_link->srp_password, NULL, NULL);
+			srp_error = rist_enable_eap_srp_2(peer, peer_config_link->srp_username, peer_config_link->srp_password, NULL, NULL);
 			if (srp_error)
 				rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP for peer\n", srp_error);
 		}
 		if (srpfile)
 		{
-			srp_error = rist_enable_eap_srp(peer, NULL, NULL, user_verifier_lookup, srpfile);
+			srp_error = rist_enable_eap_srp_2(peer, NULL, NULL, user_verifier_lookup, srpfile);
 			if (srp_error)
 				rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP global authenticator, file %s\n", srp_error, srpfile);
 		}
@@ -790,13 +790,15 @@ int main(int argc, char *argv[])
 		case 'r':
 			remote_log_address = strdup(optarg);
 		break;
-#if HAVE_MBEDTLS
-		case 'F':
-			srpfile = fopen(optarg, "r");
-			if (!srpfile) {
+#if HAVE_SRP_SUPPORT
+		case 'F': {
+			FILE* f = fopen(optarg, "r");
+			if (!f) {
 				rist_log(&logging_settings, RIST_LOG_ERROR, "Could not open srp file %s\n", optarg);
 				return 1;
 			}
+			srpfile = strdup(optarg);
+		}
 		break;
 #endif
 		case 'u':
diff --git a/tools/ristsrppasswd.c b/tools/ristsrppasswd.c
index 9702169db23e3644a5ceb483b08b80a775cca7f1..1ce257cc2d255f767d3d4f9bfaa5117c00a0a438 100644
--- a/tools/ristsrppasswd.c
+++ b/tools/ristsrppasswd.c
@@ -5,10 +5,43 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include "srp.h"
+#include "config.h"
+#include "crypto/srp.h"
+#include "crypto/srp_constants.h"
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#if HAVE_MBEDTLS
 #include <mbedtls/base64.h>
+#elif HAVE_NETTLE
+#include <nettle/base64.h>
+#endif
+
+int create_and_print(const char *username, const char *password, const char *n_hex, const char* g_hex, bool correct) {
+	uint8_t *salt = NULL;
+	size_t salt_len = 0;
+	uint8_t *verifier = NULL;
+	size_t verifier_len = 0;
+	int ret = librist_crypto_srp_create_verifier(n_hex, g_hex, username, password, &salt, &salt_len, &verifier, &verifier_len, correct);
+	if (ret != 0)
+		return ret;
+
+	char salt64[1024] = {0};
+	char verifier64[1024] = {0};
+#if HAVE_MBEDTLS
+	size_t salt_written_len = 0;
+	mbedtls_base64_encode((unsigned char*)salt64, sizeof(salt64), &salt_written_len, salt, salt_len);
+	size_t verifier_written_len = 0;
+	mbedtls_base64_encode((unsigned char*)verifier64, sizeof(verifier64), &verifier_written_len, verifier, verifier_len);
+#elif HAVE_NETTLE
+	nettle_base64_encode_raw(salt64, salt_len, salt);
+	nettle_base64_encode_raw(verifier64, verifier_len, verifier);
+#endif
+	free(salt);
+	free(verifier);
+	printf("%s:%s:%s:3:%d\n", username, verifier64, salt64, correct? 1 :0);
+	return 0;
+}
 
 int main(int argc, char *argv[])
 {
@@ -17,42 +50,14 @@ int main(int argc, char *argv[])
 		return 1;
 	}
 
-	struct SRPSession * session = srp_session_new(SRP_SHA256, SRP_NG_2048, NULL, NULL);
 	const char *username = argv[1];
 	const char *password = argv[2];
-	size_t len_s = 0;
-	size_t len_v = 0;
-	char *bytes_s = NULL;
-	char *bytes_v = NULL;
-	srp_create_salted_verification_key(session, username,
-									   (const unsigned char *)password, strlen(password),
-									   (const unsigned char **)&bytes_s, &len_s,
-									   (const unsigned char **)&bytes_v, &len_v);
-	unsigned char verifier[512] = { 0 };
-	size_t olen_v = 0;
-	unsigned char salt[512] = { 0 };
-	size_t olen_s = 0;
-	mbedtls_base64_encode(verifier, 512, &olen_v, (const unsigned char *)bytes_v, len_v);
-	unsigned char *test = &verifier[0];
-	while (*test != '\0')
-	{
-		if (*test == '=')
-		{
-			*test = '\0';
-			break;
-		}
-		test++;
-	}
-	mbedtls_base64_encode(salt, 512, &olen_s, (const unsigned char *)bytes_s, len_s);
-	test = &salt[0];
-	while (*test != '\0')
-	{
-		if (*test == '=')
-		{
-			*test = '\0';
-			break;
-		}
-		test++;
-	}
-	printf("%s:%s:%s:3\n", username, verifier, salt);
+	const char *n_hex = NULL;
+	const char *g_hex = NULL;
+
+	librist_get_ng_constants(LIBRIST_SRP_NG_DEFAULT, &n_hex, &g_hex);
+#if HAVE_MBEDTLS
+	create_and_print(username, password, n_hex, g_hex, false);
+#endif
+	create_and_print(username, password, n_hex, g_hex, true);
 }
diff --git a/tools/srp_shared.c b/tools/srp_shared.c
index cec2108ae6b4aae5ed36077bb8785b95c84bc91d..80d95015e9484feda40399eaaa415f0ac0e9ffe1 100644
--- a/tools/srp_shared.c
+++ b/tools/srp_shared.c
@@ -5,12 +5,126 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include "config.h"
+#include <librist/librist_config.h>
+#if HAVE_MBEDTLS
 #include <mbedtls/base64.h>
+#elif HAVE_NETTLE
+#include <nettle/base64.h>
+#endif
 #include <stddef.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdint.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#define stat _stat
+#endif
+
+typedef enum {
+	IN_USERNAME = 0,
+	IN_VERIFIER,
+	IN_SALT,
+	IN_HASH_ALGO,
+	IN_HASH_VERSION,
+} user_verifier_state_e;
+
+#define READ_VERIFIER_LEN 1025
+#define READ_SALT_LEN 1025
+#define MAX_LINE_LEN (READ_VERIFIER_LEN + READ_SALT_LEN + 1)
+
+int srp_base64_decode(char *string, size_t string_len, size_t *out_len, uint8_t **out) {
+	//Add padding if needed
+	if ((string_len % 4) != 0)
+	{
+		size_t needed_padding = 4 - (string_len % 4);
+		for (size_t i = 0; i < needed_padding; i++)
+			string[(string_len + i)] = '=';
+		string_len += needed_padding;
+		string[string_len] = '\0';
+	}
+#if HAVE_MBEDTLS
+	size_t len = 0;
+
+	int ret =mbedtls_base64_decode(NULL, 0, &len, (unsigned char *)string, string_len);
+	if (ret != 0 && ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL)
+		return -1;
+
+	*out = malloc(len);
+	if (mbedtls_base64_decode(*out, len, out_len, (unsigned char *)string, string_len) != 0)
+		goto fail_decode;
+
+	return 0;
+#elif HAVE_NETTLE
+	struct base64_decode_ctx ctx;
+	nettle_base64_decode_init(&ctx);
+	size_t len = BASE64_ENCODE_LENGTH(string_len);
+	*out = malloc(len);
+	if (nettle_base64_decode_update(&ctx, out_len, *out, string_len, string) != 1)
+		goto fail_decode;
+	if (nettle_base64_decode_final(&ctx) != 1)
+		goto fail_decode;
+	return 0;
+#endif
+
+fail_decode:
+	free(*out);
+	*out = NULL;
+	return -1;
+}
+
+int parse_line(const char *line, size_t line_len, uint8_t **decoded_verifier, size_t *decoded_verifier_len, uint8_t **decoded_salt, size_t *decoded_salt_len) {
+	char read = '\0';
+	user_verifier_state_e state = IN_VERIFIER;
+	int ret = -1;
+	size_t read_verifier_len = 0;
+	char *read_verifier = calloc(READ_VERIFIER_LEN, 1);
+	size_t read_salt_len = 0;
+	char *read_salt = calloc(READ_SALT_LEN, 1);
+	if (!read_salt || !read_verifier)
+		goto out;
+	for (size_t i=0; i < line_len; i++) {
+		read = line[i];
+		if (read == ':')
+		{
+			if (state >= IN_SALT && read == '\n')
+				break;
+			if (state == IN_VERIFIER)
+				read_verifier[read_verifier_len+1] = '\0';
+			else if (state == IN_SALT)
+			{
+				read_salt[read_salt_len +1] = '\0';
+			}
+			state++;
+		} else if (state == IN_VERIFIER)
+		{
+			if (read_verifier_len == READ_VERIFIER_LEN)
+				return -1;
+			read_verifier[read_verifier_len] = read;
+			read_verifier_len++;
+		} else if (state == IN_SALT)
+		{
+			if (read_salt_len == READ_SALT_LEN)
+				return -1;
+			read_salt[read_salt_len] = read;
+			read_salt_len++;
+		}
+	}
+	ret = srp_base64_decode(read_verifier, read_verifier_len, decoded_verifier_len, decoded_verifier);
+	if (ret != 0)
+		goto out;
+	ret = srp_base64_decode(read_salt, read_salt_len, decoded_salt_len, decoded_salt);
+	if (ret != 0)
+		free(*decoded_verifier);
+out:
+	free(read_verifier);
+	free(read_salt);
+	return ret;
+}
+
 
 void user_verifier_lookup(char * username,
 							size_t *verifier_len, char **verifier,
@@ -18,110 +132,137 @@ void user_verifier_lookup(char * username,
 							bool *use_default_2048_bit_n_modulus,
 							char **n_modulus_ascii,
 							char **generator_ascii,
+							int *hashversion,
+							uint64_t *generation,
 							void *user_data)
 {
+#if HAVE_NETTLE
+	struct base64_decode_ctx ctx;
+	nettle_base64_decode_init(&ctx);
+#endif
 	(void)n_modulus_ascii;
 	(void)generator_ascii;
 	if (user_data == NULL)
 		return;
-	FILE *fh = (FILE *)user_data;
-	size_t username_offset = 0;
 
-	size_t read_verifier_len = 0;
-	char *read_verifier = malloc(1024);
-	size_t read_salt_len = 0;
-	char *read_salt = malloc(1024);
+	char *srpfile = user_data;
+
+	struct stat buf;
+	if (stat(srpfile, &buf) != 0)
+		return;
+
+	if (!generation)
+		return;
+	*generation = (buf.st_mtim.tv_sec << 32) | buf.st_mtim.tv_nsec;
 
-	int reading = 0;//0 = username, 1 = verifier, 2 = salt
+	if (!verifier || !verifier_len || !salt || !salt_len || !hashversion || !use_default_2048_bit_n_modulus)
+		return;
+
+	FILE *fh = fopen(srpfile, "r");
+	if (!fh)
+		return;
+
+	size_t username_offset = 0;
+
+	char read_hashver[3] = {0};
+	int read_hashver_len = 0;
+	user_verifier_state_e state = IN_USERNAME;
 	bool skipnextline = false;
 	int read = getc(fh);
 	//expected format: username:verifier:salt:3
+	int maxhashversion = *hashversion;
+	size_t username_len = strlen(username);
+	char *line_even = malloc(MAX_LINE_LEN);
+	size_t line_even_len =0;
+	bool line_one_done = false;
+	char *line_odd = malloc(MAX_LINE_LEN);
+	size_t line_odd_len = 0;
+
+	size_t line_len = 0;
 	while (read != EOF)
 	{
+		char *line = line_one_done? line_odd : line_even;
 		if (skipnextline)
 		{
 			if (read == '\n')
 				skipnextline = false;
+		}
+		else if (state >= IN_SALT && read == '\n') {
+			if (state >= IN_HASH_VERSION) {
+				state = IN_USERNAME;
+				username_offset = 0;
+				*hashversion = atoi(read_hashver);
+				if (line_one_done) {
+					line_odd_len = line_len;
+				} else {
+					line_even_len = line_len;
+					line_len = 0;
+					line_one_done = true;
+					if (*hashversion < maxhashversion) {
+						read = getc(fh);
+						continue;
+					}
+				}
+			}
+			break;
 		} else if (read == ':')
 		{
-			if (reading == 0 && username_offset != (strlen(username))) {
+			if (state == IN_VERIFIER)
+				line[line_len++] = read;
+			if (state == IN_USERNAME && username_offset != username_len) {
+				if (line_one_done) {
+					break;
+				}
 				skipnextline = true;
 				username_offset = 0;
 				continue;
 			}
-			if (reading == 1)
-				read_verifier[read_verifier_len+1] = '\0';
-			else if (reading == 2)
-			{
-				read_salt[read_salt_len +1] = '\0';
-				break;
-			}
-			reading++;
+			state++;
 		}
-		else if (reading == 0)
+		else if (state == IN_USERNAME)
 		{
+			if (username_offset == username_len) {
+				username_offset = 0;
+				skipnextline = true;
+				continue;
+			}
 			if (username[username_offset] != read)
 			{
 				username_offset = 0;
 				skipnextline = true;
-			}
-			 else
+			} else
 				username_offset++;
-		} else if (reading == 1)
-		{
-			if (read_verifier_len == 1024)
-				goto out;
-			read_verifier[read_verifier_len] = read;
-			read_verifier_len++;
-		} else if (reading == 2)
-		{
-			if (read_salt_len == 1024)
-				goto out;
-			read_salt[read_salt_len] = read;
-			read_salt_len++;
+		} else if (state >= IN_VERIFIER && state <= IN_SALT) {
+			if (line_len >= MAX_LINE_LEN) {
+				if (!line_one_done)
+					goto out;
+				break;
+			}
+			line[line_len++] = read;
+		} else if (state == IN_HASH_VERSION && read_hashver_len < 3) {
+			read_hashver[read_hashver_len] = read;
+			read_hashver_len++;
 		}
 		read = getc(fh);
 	}
-	if (reading != 2)
+
+	*hashversion = atoi(read_hashver);
+	if (state < IN_SALT && !line_one_done)
 		goto out;
-	//PAD with ==
-	if ((read_verifier_len % 4) != 0)
-	{
-		size_t needed_padding = 4 - (read_verifier_len % 4);
-		for (size_t i = 0; i < needed_padding; i++)
-			read_verifier[(read_verifier_len + i)] = '=';
-		read_verifier_len += needed_padding;
-		read_verifier[read_verifier_len] = '\0';
-	}
-	if ((read_salt_len % 4) != 0)
-	{
-		size_t needed_padding = 4 - (read_salt_len % 4);
-		for (size_t i = 0; i < needed_padding; i++)
-			read_salt[(read_salt_len + i)] = '=';
-		read_salt_len += needed_padding;
-		read_salt[read_salt_len] = '\0';
-	}
-	char *decoded_verifier = malloc(1024);
-	char *decoded_salt = malloc(1024);
-	if (mbedtls_base64_decode((unsigned char *)decoded_verifier, 1024, verifier_len, (unsigned char *)read_verifier, read_verifier_len) != 0)
-		goto fail_decode;
 
-	if (mbedtls_base64_decode((unsigned char *)decoded_salt, 1024, salt_len, (unsigned char *)read_salt, read_salt_len) != 0)
-		goto fail_decode;
+	char *line = line_even;
+	line_len = line_even_len;
+	if (line_one_done && line_odd_len != 0) {
+		line = line_odd;
+		line_len = line_odd_len;
+	}
 
-	*verifier = decoded_verifier;
-	*salt = decoded_salt;
+	parse_line(line, line_len, (uint8_t**)verifier, verifier_len, (uint8_t **)salt, salt_len);
 	*use_default_2048_bit_n_modulus = true;
-	goto out;
 
-fail_decode:
-	*verifier_len = 0;
-	*salt_len = 0;
-	free(decoded_verifier);
-	free(decoded_salt);
 out:
-	free(read_verifier);
-	free(read_salt);
-	rewind(fh);
+	free(line_even);
+	free(line_odd);
+	fclose(fh);
 	return;
 }
diff --git a/tools/srp_shared.h b/tools/srp_shared.h
index a1f08e040958c104c483a97e106783707b139375..9b32a2cd3e4530221d9603043fa2a129bc780f6f 100644
--- a/tools/srp_shared.h
+++ b/tools/srp_shared.h
@@ -7,11 +7,11 @@
 
 #include <stddef.h>
 #include <stdbool.h>
+#include <stdint.h>
 
-void user_verifier_lookup(char * username,
-							size_t *verifier_len, char **verifier,
-							size_t *salt_len, char **salt,
-							bool *use_default_2048_bit_n_modulus,
-							char **n_modulus_ascii,
-							char **generator_ascii,
-							void *user_data);
+void user_verifier_lookup(char *username, size_t *verifier_len, char **verifier,
+                          size_t *salt_len, char **salt,
+                          bool *use_default_2048_bit_n_modulus,
+                          char **n_modulus_ascii, char **generator_ascii,
+                          int *hashversion, uint64_t *generation,
+                          void *user_data);