From 04ba78abb6f8f673da0cc75056df876178e504fb Mon Sep 17 00:00:00 2001
From: Gijs Peskens <gijs@peskens.net>
Date: Wed, 28 Jun 2023 17:43:06 +0200
Subject: [PATCH] New SRP crypto module

Clean re-implementation of imported SRP code that fixes some bugs and adds support for other crypto backends.

We now fully support all crypto via either MbedTLS or GnuTLS+Nettle+GMP, though for now MbedTLS remains preferred.

During the rewrite a bug was found in the old imported code that leads to incorrect hashes when mbedtls_sha256_update was used.
This bug unfortunately creates an incompatibility between wrongly and correctly hashing versions.
For compatibility reasons we still support the wrong hashing (only via MbedTLS), this is detected at runtime via signalled rist gre version (old versions had version set to 0, the spec allows for version 1).
This also affects generated SRP files.
An extra identifier is added to each line to differentiate between broken and correct hashing.
Thus it's strongly recommended to update SRP files with correct hashing.
The ristsrppassword utility is updated to generate both correct and wrong hashes.
Calling applications should take care to use the new lookup callback and supply the correctly hashed verifier & salt when called with hashversion >= 1

Also added to the lookup callback is a generation variable, which allows libRIST to cache verifier & salt.

We now also have (partial) unit tests for the SRP code, based on the example constants written in the spec. The example constants are unfortunately generated with the wrong hashing algorithm.
---
 contrib/mbedtls/meson.build   |   11 +-
 contrib/srp.c                 | 1208 ---------------------------------
 contrib/srp.h                 |  210 ------
 include/librist/config.h.in   |    4 +-
 include/librist/librist_srp.h |   58 +-
 include/librist/meson.build   |    3 +-
 meson.build                   |   35 +-
 src/crypto/psk.c              |   14 +
 src/crypto/psk.h              |    3 +-
 src/crypto/srp.c              |  992 +++++++++++++++++++++++++++
 src/crypto/srp.h              |   38 ++
 src/crypto/srp_constants.c    |  124 ++++
 src/crypto/srp_constants.h    |   21 +
 src/eap.c                     |  390 ++++++-----
 src/eap.h                     |   37 +-
 src/rist-common.c             |   22 +-
 src/udp.c                     |   10 +-
 test/meson.build              |    8 -
 test/rist/example-test.c      |   26 -
 test/rist/meson.build         |   28 +-
 test/rist/test_send_receive.c |    8 +-
 test/rist/unit/meson.build    |   14 +
 test/rist/unit/srp_examples.c |  433 ++++++++++++
 tools/meson.build             |   10 +-
 tools/rist2rist.c             |   41 +-
 tools/ristreceiver.c          |   26 +-
 tools/ristsender.c            |   26 +-
 tools/ristsrppasswd.c         |   79 ++-
 tools/srp_shared.c            |  273 ++++++--
 tools/srp_shared.h            |   14 +-
 30 files changed, 2301 insertions(+), 1865 deletions(-)
 delete mode 100644 contrib/srp.c
 delete mode 100644 contrib/srp.h
 create mode 100644 src/crypto/srp.c
 create mode 100644 src/crypto/srp.h
 create mode 100644 src/crypto/srp_constants.c
 create mode 100644 src/crypto/srp_constants.h
 delete mode 100644 test/rist/example-test.c
 create mode 100644 test/rist/unit/meson.build
 create mode 100644 test/rist/unit/srp_examples.c

diff --git a/contrib/mbedtls/meson.build b/contrib/mbedtls/meson.build
index 6819bab1..06929f90 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 fab531b0..00000000
--- 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 fcfc0b87..00000000
--- 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 7a288f92..feb270a0 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 49d015cb..2091e83c 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 15952828..596c2e76 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 a921e1f8..ed573ae6 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 97b994d3..6443fbfd 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 0452cecc..4aed1f35 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 00000000..704ff0ba
--- /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 00000000..58a81594
--- /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 00000000..0331f5f8
--- /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 00000000..ec1e530d
--- /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 d1acd5b9..ad35f83b 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 6d1958cb..e77469c3 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 6724b509..63f95c01 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 3650eb1d..70852862 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 9ba1733d..20a5534e 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 31d3955e..00000000
--- 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 893824b7..e49b7be4 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 ce31bae1..8eb92279 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 00000000..93cae81c
--- /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 00000000..1c5193d2
--- /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 dd6a4d2c..8e2dc8b7 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 ea035791..0c71d586 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 651fb022..e14dbf9e 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 afc0c1ad..335c012f 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 9702169d..1ce257cc 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 cec2108a..80d95015 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 a1f08e04..9b32a2cd 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);
-- 
GitLab