diff options
-rw-r--r-- | _ctsrp.py | 6 | ||||
-rw-r--r-- | _pysrp.py | 8 | ||||
-rw-r--r-- | _srp.c | 893 | ||||
-rw-r--r-- | doc/srp.rst | 47 | ||||
-rw-r--r-- | srp.py | 36 | ||||
-rw-r--r-- | test_srp.py | 33 |
6 files changed, 703 insertions, 320 deletions
@@ -24,9 +24,9 @@ import time SHA1 = 0
SHA224 = 1
-SHA256 = 3
-SHA384 = 4
-SHA512 = 5
+SHA256 = 2
+SHA384 = 3
+SHA512 = 4
NG_1024 = 0
NG_2048 = 1
@@ -19,9 +19,9 @@ import binascii SHA1 = 0 SHA224 = 1 -SHA256 = 3 -SHA384 = 4 -SHA512 = 5 +SHA256 = 2 +SHA384 = 3 +SHA512 = 4 NG_1024 = 0 NG_2048 = 1 @@ -34,7 +34,7 @@ _hash_map = { SHA1 : hashlib.sha1, SHA384 : hashlib.sha384, SHA512 : hashlib.sha512 } - + _ng_const = ( # 1024-bit ('''\ @@ -8,30 +8,257 @@ #include <openssl/crypto.h> #include <openssl/rand.h> -/* 2048-bit prime & generator pair from RFC 5054 */ -#define N_HEX "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73" -#define G_HEX "2" +/*****************************************************************************/ +/* Begin SRP Header */ +/*****************************************************************************/ +struct SRPVerifier; +struct SRPUser; + +typedef enum +{ + SRP_NG_1024, + SRP_NG_2048, + SRP_NG_4096, + 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 OpenSSL random number generator + * using cryptographically sound random data on Windows & Linux. If this is + * undesirable behavior or the host OS does not provide a /dev/urandom file, + * this function may be called to seed the random number generator with + * alternate data. + * + * 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. + * + * * This function is mandatory on all other platforms. Although it + * will appear to work on other platforms, this library uses the current + * time of day to seed the random number generator. This is well known to + * be insecure. + * + * * When using this function, ensure the provided random data is + * cryptographically strong. + */ +void srp_random_seed( const unsigned char * random_data, int data_length ); + + +/* Out: bytes_s, len_s, bytes_v, len_v + * + * The caller is responsible for freeing the memory allocated for bytes_s and bytes_v + * + * 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. + */ +void srp_gen_sv( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, + const unsigned char * password, int len_password, + const unsigned char ** bytes_s, int * len_s, + const unsigned char ** bytes_v, int * len_v, + const char * n_hex, const char * g_hex ); + + +/* Out: bytes_B, len_B. + * + * On failure, bytes_B will be set to NULL and len_B will be set to 0 + * + * The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type + */ +struct SRPVerifier * srp_verifier_new( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, + const unsigned char * bytes_s, int len_s, + const unsigned char * bytes_v, int len_v, + const unsigned char * bytes_A, int len_A, + const unsigned char ** bytes_B, int * len_B, + const char * n_hex, const char * g_hex ); + + +void srp_verifier_delete( struct SRPVerifier * ver ); -static const BIGNUM * N = 0; -static const BIGNUM * g = 0; -static const BIGNUM * k = 0; + +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, int * 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( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, + const unsigned char * bytes_password, int len_password, + const char * n_hex, const char * g_hex ); + +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, int * 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, int * 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, int len_s, + const unsigned char * bytes_B, int len_B, + const unsigned char ** bytes_M, int * 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 ); + + +/*****************************************************************************/ +/* Begin SRP Library */ +/*****************************************************************************/ + + +static int g_initialized = 0; + +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[] = { + { /* 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" + }, + {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 = BN_new(); + ng->g = BN_new(); + + if ( ng_type != SRP_NG_CUSTOM ) + { + n_hex = global_Ng_constants[ ng_type ].n_hex; + g_hex = global_Ng_constants[ ng_type ].g_hex; + } + + BN_hex2bn( &ng->N, n_hex ); + BN_hex2bn( &ng->g, g_hex ); + + return ng; +} + +static void delete_ng( NGConstant * ng ) +{ + BN_free( ng->N ); + BN_free( ng->g ); + ng->N = 0; + ng->g = 0; + free(ng); +} + + + +typedef union +{ + SHA_CTX sha; + SHA256_CTX sha256; + SHA512_CTX sha512; +} HashCTX; struct SRPVerifier { + SRP_HashAlgorithm hash_alg; + NGConstant *ng; + const char * username; const unsigned char * bytes_B; int authenticated; - unsigned char M [SHA256_DIGEST_LENGTH]; - unsigned char H_AMK [SHA256_DIGEST_LENGTH]; - unsigned char session_key [SHA256_DIGEST_LENGTH]; + 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; @@ -43,210 +270,226 @@ struct SRPUser const unsigned char * password; int password_len; - unsigned char M [SHA256_DIGEST_LENGTH]; - unsigned char H_AMK [SHA256_DIGEST_LENGTH]; - unsigned char session_key [SHA256_DIGEST_LENGTH]; + unsigned char M [SHA512_DIGEST_LENGTH]; + unsigned char H_AMK [SHA512_DIGEST_LENGTH]; + unsigned char session_key [SHA512_DIGEST_LENGTH]; }; -/****************************************************************************** - * - * SRP Internal Helper Functions - * - *****************************************************************************/ - -/* -static BIGNUM * H_s( const char * s ) +static int hash_init( SRP_HashAlgorithm alg, HashCTX *c ) { - unsigned char buff[ SHA256_DIGEST_LENGTH ]; - SHA256( (const unsigned char *)s, strlen(s), buff ); - return BN_bin2bn(buff, SHA256_DIGEST_LENGTH, NULL); + switch (alg) + { + case SRP_SHA1 : return SHA1_Init( &c->sha ); + case SRP_SHA224: return SHA224_Init( &c->sha256 ); + case SRP_SHA256: return SHA256_Init( &c->sha256 ); + case SRP_SHA384: return SHA384_Init( &c->sha512 ); + case SRP_SHA512: return SHA512_Init( &c->sha512 ); + default: + return -1; + }; } - - -static BIGNUM * H_n( const BIGNUM * n ) +static int hash_update( SRP_HashAlgorithm alg, HashCTX *c, const void *data, size_t len ) { - unsigned char buff[ SHA256_DIGEST_LENGTH ]; - int nbytes = BN_num_bytes(n); - unsigned char * bin = (unsigned char *) malloc( nbytes ); - BN_bn2bin(n, bin); - SHA256( bin, nbytes, buff ); - free(bin); - return BN_bin2bn(buff, SHA256_DIGEST_LENGTH, NULL); + switch (alg) + { + case SRP_SHA1 : return SHA1_Update( &c->sha, data, len ); + case SRP_SHA224: return SHA224_Update( &c->sha256, data, len ); + case SRP_SHA256: return SHA256_Update( &c->sha256, data, len ); + case SRP_SHA384: return SHA384_Update( &c->sha512, data, len ); + case SRP_SHA512: return SHA512_Update( &c->sha512, data, len ); + default: + return -1; + }; +} +static int hash_final( SRP_HashAlgorithm alg, HashCTX *c, unsigned char *md ) +{ + switch (alg) + { + case SRP_SHA1 : return SHA1_Final( md, &c->sha ); + case SRP_SHA224: return SHA224_Final( md, &c->sha256 ); + case SRP_SHA256: return SHA256_Final( md, &c->sha256 ); + case SRP_SHA384: return SHA384_Final( md, &c->sha512 ); + case SRP_SHA512: return SHA512_Final( md, &c->sha512 ); + default: + return -1; + }; +} +static unsigned char * hash( SRP_HashAlgorithm alg, const unsigned char *d, size_t n, unsigned char *md ) +{ + switch (alg) + { + case SRP_SHA1 : return SHA1( d, n, md ); + case SRP_SHA224: return SHA224( d, n, md ); + case SRP_SHA256: return SHA256( d, n, md ); + case SRP_SHA384: return SHA384( d, n, md ); + case SRP_SHA512: return SHA512( d, n, md ); + default: + return 0; + }; +} +static int hash_length( SRP_HashAlgorithm alg ) +{ + switch (alg) + { + case SRP_SHA1 : return SHA_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( const BIGNUM * n1, const BIGNUM * n2 ) + +static BIGNUM * H_nn( SRP_HashAlgorithm alg, const BIGNUM * n1, const BIGNUM * n2 ) { - unsigned char buff[ SHA256_DIGEST_LENGTH ]; + unsigned char buff[ SHA512_DIGEST_LENGTH ]; int len_n1 = BN_num_bytes(n1); int len_n2 = BN_num_bytes(n2); int nbytes = len_n1 + len_n2; unsigned char * bin = (unsigned char *) malloc( nbytes ); BN_bn2bin(n1, bin); BN_bn2bin(n2, bin + len_n1); - SHA256( bin, nbytes, buff ); + hash( alg, bin, nbytes, buff ); free(bin); - return BN_bin2bn(buff, SHA256_DIGEST_LENGTH, NULL); + return BN_bin2bn(buff, hash_length(alg), NULL); } - -static BIGNUM * H_ns( const BIGNUM * n, - const unsigned char * bytes, - int len_bytes ) +static BIGNUM * H_ns( SRP_HashAlgorithm alg, const BIGNUM * n, const unsigned char * bytes, int len_bytes ) { - unsigned char buff[ SHA256_DIGEST_LENGTH ]; + unsigned char buff[ SHA512_DIGEST_LENGTH ]; int len_n = BN_num_bytes(n); int nbytes = len_n + len_bytes; unsigned char * bin = (unsigned char *) malloc( nbytes ); BN_bn2bin(n, bin); memcpy( bin + len_n, bytes, len_bytes ); - SHA256( bin, nbytes, buff ); + hash( alg, bin, nbytes, buff ); free(bin); - return BN_bin2bn(buff, SHA256_DIGEST_LENGTH, NULL); + return BN_bin2bn(buff, hash_length(alg), NULL); } + +static BIGNUM * calculate_x( SRP_HashAlgorithm alg, const BIGNUM * salt, const char * username, const unsigned char * password, int password_len ) +{ + unsigned char ucp_hash[SHA512_DIGEST_LENGTH]; + HashCTX ctx; + hash_init( alg, &ctx ); -static BIGNUM * calculate_x( const BIGNUM * salt, - const char * username, - const unsigned char * password, - int password_len ) -{ - unsigned char ucp_hash[SHA256_DIGEST_LENGTH]; - SHA256_CTX ctx; - - SHA256_Init( &ctx ); + hash_update( alg, &ctx, username, strlen(username) ); + hash_update( alg, &ctx, ":", 1 ); + hash_update( alg, &ctx, password, password_len ); - SHA256_Update( &ctx, username, strlen(username) ); - SHA256_Update( &ctx, ":", 1 ); - SHA256_Update( &ctx, password, password_len ); - - SHA256_Final( ucp_hash, &ctx ); + hash_final( alg, &ctx, ucp_hash ); - return H_ns( salt, ucp_hash, sizeof(ucp_hash) ); + return H_ns( alg, salt, ucp_hash, hash_length(alg) ); } - -static void update_hash( SHA256_CTX *ctx, const BIGNUM * n ) +static void update_hash_n( SRP_HashAlgorithm alg, HashCTX *ctx, const BIGNUM * n ) { unsigned long len = BN_num_bytes(n); unsigned char * n_bytes = (unsigned char *) malloc( len ); BN_bn2bin(n, n_bytes); - SHA256_Update(ctx, n_bytes, len); - free( n_bytes ); + hash_update(alg, ctx, n_bytes, len); + free(n_bytes); } - -static void hash_num( const BIGNUM * n, unsigned char * dest ) +static void hash_num( SRP_HashAlgorithm alg, const BIGNUM * n, unsigned char * dest ) { int nbytes = BN_num_bytes(n); unsigned char * bin = (unsigned char *) malloc( nbytes ); BN_bn2bin(n, bin); - SHA256( bin, nbytes, dest ); - free( bin ); + hash( alg, bin, nbytes, dest ); + free(bin); } - -static void calculate_M( unsigned char * dest, - const char * I, - const BIGNUM * s, - const BIGNUM * A, - const BIGNUM * B, - const unsigned char * K ) +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[ SHA256_DIGEST_LENGTH ]; - unsigned char H_g[ SHA256_DIGEST_LENGTH ]; - unsigned char H_I[ SHA256_DIGEST_LENGTH ]; - unsigned char H_xor[ SHA256_DIGEST_LENGTH ]; - SHA256_CTX ctx; + unsigned char H_N[ SHA512_DIGEST_LENGTH ]; + unsigned char H_g[ SHA512_DIGEST_LENGTH ]; + unsigned char H_I[ SHA512_DIGEST_LENGTH ]; + unsigned char H_xor[ SHA512_DIGEST_LENGTH ]; + HashCTX ctx; int i = 0; + int hash_len = hash_length(alg); - hash_num( N, H_N ); - hash_num( g, H_g ); + hash_num( alg, ng->N, H_N ); + hash_num( alg, ng->g, H_g ); + + hash(alg, (const unsigned char *)I, strlen(I), H_I); - SHA256((const unsigned char *)I, strlen(I), H_I); - for (i=0; i < SHA256_DIGEST_LENGTH; i++ ) + for (i=0; i < hash_len; i++ ) H_xor[i] = H_N[i] ^ H_g[i]; - SHA256_Init( &ctx ); + hash_init( alg, &ctx ); - SHA256_Update( &ctx, H_xor, sizeof(H_xor) ); - SHA256_Update( &ctx, H_I, sizeof(H_I) ); - update_hash( &ctx, s ); - update_hash( &ctx, A ); - update_hash( &ctx, B ); - SHA256_Update( &ctx, K, SHA256_DIGEST_LENGTH ); + 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 ); - SHA256_Final( dest, &ctx ); + hash_final( alg, &ctx, dest ); } - -static void calculate_H_AMK( unsigned char * dest, - const BIGNUM * A, - const unsigned char * M, - const unsigned char * K ) +static void calculate_H_AMK( SRP_HashAlgorithm alg, unsigned char *dest, const BIGNUM * A, const unsigned char * M, const unsigned char * K ) { - SHA256_CTX ctx; + HashCTX ctx; - SHA256_Init( &ctx ); + hash_init( alg, &ctx ); - update_hash( &ctx, A ); - SHA256_Update( &ctx, M, SHA256_DIGEST_LENGTH); - SHA256_Update( &ctx, K, SHA256_DIGEST_LENGTH); + update_hash_n( alg, &ctx, A ); + hash_update( alg, &ctx, M, hash_length(alg) ); + hash_update( alg, &ctx, K, hash_length(alg) ); - SHA256_Final( dest, &ctx ); + hash_final( alg, &ctx, dest ); } -/****************************************************************************** +static void init_random() +{ + /* Python module calls random_seed during module initialization */ +} + + +/*********************************************************************************************************** * - * SRP "external" API + * Exported Functions * - *****************************************************************************/ + ***********************************************************************************************************/ -static void srp_init( const char * random_seed, int seed_len ) +void srp_random_seed( const unsigned char * random_data, int data_length ) { - BIGNUM *tN = BN_new(); - BIGNUM *tg = BN_new(); - - BN_hex2bn( &tN, N_HEX ); - BN_hex2bn( &tg, G_HEX ); - - N = tN; - g = tg; - - k = H_nn(N,g); - - RAND_seed( random_seed, seed_len ); -} + g_initialized = 1; -static void srp_fini( void ) -{ - BN_free((BIGNUM *)N); - BN_free((BIGNUM *)g); - BN_free((BIGNUM *)k); - - N = 0; - g = 0; + if (random_data) + RAND_seed( random_data, data_length ); } -static void srp_gen_sv( const char * username, - const unsigned char * password, int len_password, - const unsigned char ** bytes_s, int * len_s, - const unsigned char ** bytes_v, int * len_v ) +void srp_gen_sv( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, + const unsigned char * password, int len_password, + const unsigned char ** bytes_s, int * len_s, + const unsigned char ** bytes_v, int * len_v, + const char * n_hex, const char * g_hex ) { - BIGNUM * s = BN_new(); - BIGNUM * v = BN_new(); - BIGNUM * x = 0; - BN_CTX *ctx = BN_CTX_new(); - - BN_rand(s, 32, -1, 0); - - x = calculate_x( s, username, password, len_password ); - - BN_mod_exp(v, g, x, N, ctx); + BIGNUM * s = BN_new(); + BIGNUM * v = BN_new(); + BIGNUM * x = 0; + BN_CTX * ctx = BN_CTX_new(); + NGConstant * ng = new_ng( ng_type, n_hex, g_hex ); + + init_random(); /* Only happens once */ + + BN_rand(s, 32, -1, 0); + + x = calculate_x( alg, s, username, password, len_password ); + + BN_mod_exp(v, ng->g, x, ng->N, ctx); *len_s = BN_num_bytes(s); *len_v = BN_num_bytes(v); @@ -257,6 +500,7 @@ static void srp_gen_sv( const char * username, BN_bn2bin(s, (unsigned char *) *bytes_s); BN_bn2bin(v, (unsigned char *) *bytes_v); + delete_ng( ng ); BN_free(s); BN_free(v); BN_free(x); @@ -264,68 +508,76 @@ static void srp_gen_sv( const char * username, } + /* Out: bytes_B, len_B. * * On failure, bytes_B will be set to NULL and len_B will be set to 0 */ -static struct SRPVerifier * srp_verifier_new( const char * username, - const unsigned char * bytes_s, int len_s, - const unsigned char * bytes_v, int len_v, - const unsigned char * bytes_A, int len_A, - const unsigned char ** bytes_B, int * len_B) +struct SRPVerifier * srp_verifier_new( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, + const unsigned char * bytes_s, int len_s, + const unsigned char * bytes_v, int len_v, + const unsigned char * bytes_A, int len_A, + const unsigned char ** bytes_B, int * len_B, + const char * n_hex, const char * g_hex ) { - BIGNUM *s = BN_bin2bn(bytes_s, len_s, NULL); - BIGNUM *v = BN_bin2bn(bytes_v, len_v, NULL); - BIGNUM *A = BN_bin2bn(bytes_A, len_A, NULL); - BIGNUM *u = 0; - BIGNUM *B = BN_new(); - BIGNUM *S = BN_new(); - BIGNUM *b = BN_new(); - BIGNUM *tmp1 = BN_new(); - BIGNUM *tmp2 = BN_new(); - BN_CTX *ctx = BN_CTX_new(); - int ulen = strlen(username) + 1; - - struct SRPVerifier * ver; - - ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) ); + BIGNUM *s = BN_bin2bn(bytes_s, len_s, NULL); + BIGNUM *v = BN_bin2bn(bytes_v, len_v, NULL); + BIGNUM *A = BN_bin2bn(bytes_A, len_A, NULL); + BIGNUM *u = 0; + BIGNUM *B = BN_new(); + BIGNUM *S = BN_new(); + BIGNUM *b = BN_new(); + BIGNUM *k = 0; + BIGNUM *tmp1 = BN_new(); + BIGNUM *tmp2 = BN_new(); + BN_CTX *ctx = BN_CTX_new(); + int ulen = strlen(username) + 1; + NGConstant *ng = new_ng( ng_type, n_hex, g_hex ); + + struct SRPVerifier * ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) ); + + init_random(); /* Only happens once */ ver->username = (char *) malloc( ulen ); + ver->hash_alg = alg; + ver->ng = ng; memcpy( (char*)ver->username, username, ulen ); ver->authenticated = 0; - + /* SRP-6a safety check */ - BN_mod(tmp1, A, N, ctx); + BN_mod(tmp1, A, ng->N, ctx); if ( !BN_is_zero(tmp1) ) - { - BN_rand(b, 256, -1, 0); - - /* B = kv + g^b */ - BN_mul(tmp1, k, v, ctx); - BN_mod_exp(tmp2, g, b, N, ctx); - BN_add(B, tmp1, tmp2); - - u = H_nn(A,B); - - /* S = (A *(v^u)) ^ b */ - BN_mod_exp(tmp1, v, u, N, ctx); - BN_mul(tmp2, A, tmp1, ctx); - BN_mod_exp(S, tmp2, b, N, ctx); - - hash_num(S, ver->session_key); - - calculate_M( ver->M, username, s, A, B, ver->session_key ); - calculate_H_AMK( ver->H_AMK, A, ver->M, ver->session_key ); - + { + BN_rand(b, 256, -1, 0); + + k = H_nn(alg, ng->N, ng->g); + + /* B = kv + g^b */ + BN_mul(tmp1, k, v, ctx); + BN_mod_exp(tmp2, ng->g, b, ng->N, ctx); + BN_add(B, tmp1, tmp2); + + u = H_nn(alg, A, B); + + /* S = (A *(v^u)) ^ b */ + BN_mod_exp(tmp1, v, u, ng->N, ctx); + BN_mul(tmp2, A, tmp1, ctx); + BN_mod_exp(S, tmp2, b, ng->N, ctx); + + hash_num(alg, S, ver->session_key); + + calculate_M( alg, ng, ver->M, username, s, A, B, ver->session_key ); + calculate_H_AMK( alg, ver->H_AMK, A, ver->M, ver->session_key ); + *len_B = BN_num_bytes(B); *bytes_B = malloc( *len_B ); BN_bn2bin( B, (unsigned char *) *bytes_B ); ver->bytes_B = *bytes_B; - } + } else { *len_B = 0; @@ -336,6 +588,7 @@ static struct SRPVerifier * srp_verifier_new( const char * username, BN_free(v); BN_free(A); if (u) BN_free(u); + if (k) BN_free(k); BN_free(B); BN_free(S); BN_free(b); @@ -347,40 +600,48 @@ static struct SRPVerifier * srp_verifier_new( const char * username, } -static void srp_verifier_delete( struct SRPVerifier * ver ) + + +void srp_verifier_delete( struct SRPVerifier * ver ) { + delete_ng( ver->ng ); free( (char *) ver->username ); free( (unsigned char *) ver->bytes_B ); free( ver ); } -static int srp_verifier_is_authenticated( struct SRPVerifier * ver ) + +int srp_verifier_is_authenticated( struct SRPVerifier * ver ) { return ver->authenticated; } -static const char * srp_verifier_get_username( struct SRPVerifier * ver ) +const char * srp_verifier_get_username( struct SRPVerifier * ver ) { return ver->username; } -/* Key length is SHA256_DIGEST_LENGTH */ -static const unsigned char * -srp_verifier_get_session_key( struct SRPVerifier * ver ) +const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, int * key_length ) { + if (key_length) + *key_length = hash_length( ver->hash_alg ); return ver->session_key; } -/* user_M must be exactly SHA256_DIGEST_LENGTH bytes in size */ -static void srp_verifier_verify_session( struct SRPVerifier * ver, - const unsigned char * user_M, - const unsigned char ** bytes_HAMK ) +int srp_verifier_get_session_key_length( struct SRPVerifier * ver ) { - if ( memcmp( ver->M, user_M, SHA256_DIGEST_LENGTH ) == 0 ) + 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; @@ -389,17 +650,19 @@ static void srp_verifier_verify_session( struct SRPVerifier * ver, *bytes_HAMK = NULL; } - /*******************************************************************************/ -static struct SRPUser * srp_user_new( const char * username, - const unsigned char * bytes_password, - int len_password ) +struct SRPUser * srp_user_new( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, + const unsigned char * bytes_password, int len_password, + const char * n_hex, const char * g_hex ) { - struct SRPUser *usr; + struct SRPUser *usr = (struct SRPUser *) malloc( sizeof(struct SRPUser) ); int ulen = strlen(username) + 1; + + init_random(); /* Only happens once */ - usr = (struct SRPUser *) malloc( sizeof(struct SRPUser) ); + usr->hash_alg = alg; + usr->ng = new_ng( ng_type, n_hex, g_hex ); usr->a = BN_new(); usr->A = BN_new(); @@ -413,17 +676,20 @@ static struct SRPUser * srp_user_new( const char * username, memcpy((char *)usr->password, bytes_password, len_password); usr->bytes_A = 0; - + return usr; } -static void srp_user_delete( struct SRPUser * usr ) + +void srp_user_delete( struct SRPUser * usr ) { BN_free( usr->a ); BN_free( usr->A ); BN_free( usr->S ); + delete_ng( usr->ng ); + free((char *)usr->username); free((char *)usr->password); @@ -434,37 +700,45 @@ static void srp_user_delete( struct SRPUser * usr ) } -static int srp_user_is_authenticated( struct SRPUser * usr) + +int srp_user_is_authenticated( struct SRPUser * usr) { return usr->authenticated; } -static const char * srp_user_get_username( struct SRPUser * usr ) +const char * srp_user_get_username( struct SRPUser * usr ) { return usr->username; } -/* Key length is SHA256_DIGEST_LENGTH */ -static const unsigned char * srp_user_get_session_key( struct SRPUser * usr ) + +const unsigned char * srp_user_get_session_key( struct SRPUser * usr, int * 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 */ -static void srp_user_start_authentication( struct SRPUser * usr, - const char ** username, - const unsigned char ** bytes_A, - int * len_A ) +void srp_user_start_authentication( struct SRPUser * usr, const char ** username, + const unsigned char ** bytes_A, int * len_A ) { BN_CTX *ctx = BN_CTX_new(); BN_rand(usr->a, 256, -1, 0); - - BN_mod_exp(usr->A, g, usr->a, N, ctx); - + + BN_mod_exp(usr->A, usr->ng->g, usr->a, usr->ng->N, ctx); + BN_CTX_free(ctx); *len_A = BN_num_bytes(usr->A); @@ -477,57 +751,63 @@ static void srp_user_start_authentication( struct SRPUser * usr, } -/* Output: bytes_M. Buffer length is SHA256_DIGEST_LENGTH */ -static void srp_user_process_challenge( struct SRPUser * usr, - const unsigned char * bytes_s, - int len_s, - const unsigned char * bytes_B, - int len_B, - const unsigned char ** bytes_M ) +/* Output: bytes_M. Buffer length is SHA512_DIGEST_LENGTH */ +void srp_user_process_challenge( struct SRPUser * usr, + const unsigned char * bytes_s, int len_s, + const unsigned char * bytes_B, int len_B, + const unsigned char ** bytes_M, int * len_M ) { BIGNUM *s = BN_bin2bn(bytes_s, len_s, NULL); BIGNUM *B = BN_bin2bn(bytes_B, len_B, NULL); BIGNUM *u = 0; BIGNUM *x = 0; + BIGNUM *k = 0; BIGNUM *v = BN_new(); BIGNUM *tmp1 = BN_new(); BIGNUM *tmp2 = BN_new(); BIGNUM *tmp3 = BN_new(); BN_CTX *ctx = BN_CTX_new(); - u = H_nn(usr->A,B); + u = H_nn(usr->hash_alg, usr->A, B); + + x = calculate_x( usr->hash_alg, s, usr->username, usr->password, usr->password_len ); + + k = H_nn(usr->hash_alg, usr->ng->N, usr->ng->g); - x = calculate_x( s, usr->username, usr->password, usr->password_len ); - /* SRP-6a safety check */ if ( !BN_is_zero(B) && !BN_is_zero(u) ) { - BN_mod_exp(v, g, x, N, ctx); + BN_mod_exp(v, usr->ng->g, x, usr->ng->N, ctx); /* S = (B - k*(g^x)) ^ (a + ux) */ BN_mul(tmp1, u, x, ctx); BN_add(tmp2, usr->a, tmp1); /* tmp2 = (a + ux) */ - BN_mod_exp(tmp1, g, x, N, ctx); + BN_mod_exp(tmp1, usr->ng->g, x, usr->ng->N, ctx); BN_mul(tmp3, k, tmp1, ctx); /* tmp3 = k*(g^x) */ BN_sub(tmp1, B, tmp3); /* tmp1 = (B - K*(g^x)) */ - BN_mod_exp(usr->S, tmp1, tmp2, N, ctx); + BN_mod_exp(usr->S, tmp1, tmp2, usr->ng->N, ctx); - hash_num(usr->S, usr->session_key); + hash_num(usr->hash_alg, usr->S, usr->session_key); - calculate_M( usr->M, usr->username, s, usr->A, B, usr->session_key ); - calculate_H_AMK( usr->H_AMK, usr->A, usr->M, 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 ); *bytes_M = usr->M; + if (len_M) + *len_M = hash_length( usr->hash_alg ); } else { *bytes_M = NULL; + if (len_M) + *len_M = 0; } BN_free(s); BN_free(B); BN_free(u); BN_free(x); + BN_free(k); BN_free(v); BN_free(tmp1); BN_free(tmp2); @@ -535,11 +815,10 @@ static void srp_user_process_challenge( struct SRPUser * usr, BN_CTX_free(ctx); } -/* bytes_HAMK must be exactly SHA256_DIGEST_LENGTH bytes in size */ -static void srp_user_verify_session( struct SRPUser * usr, - const unsigned char * bytes_HAMK ) + +void srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK ) { - if ( memcmp( usr->H_AMK, bytes_HAMK, SHA256_DIGEST_LENGTH ) == 0 ) + if ( memcmp( usr->H_AMK, bytes_HAMK, hash_length(usr->hash_alg) ) == 0 ) usr->authenticated = 1; } @@ -623,6 +902,13 @@ static int ver_init( PyVerifier *self, PyObject *args, PyObject *kwds ) const char *username; const unsigned char *bytes_s, *bytes_v, *bytes_A; int len_s, len_v, len_A; + int hash_alg = SRP_SHA1; + int ng_type = SRP_NG_1024; + const char *n_hex = 0; + const char *g_hex = 0; + static char * kwnames[] = { "username", "bytes_s", "bytes_v", "bytes_A", + "hash_alg", "ng_type", + "n_hex", "g_hex", NULL }; if ( self->ver != NULL ) { @@ -630,10 +916,15 @@ static int ver_init( PyVerifier *self, PyObject *args, PyObject *kwds ) return -1; } - if ( ! PyArg_ParseTuple(args, "st#t#t#", &username, - &bytes_s, &len_s, - &bytes_v, &len_v, - &bytes_A, &len_A) ) + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "st#t#t#|iiss", kwnames, + &username, + &bytes_s, &len_s, + &bytes_v, &len_v, + &bytes_A, &len_A, + &hash_alg, + &ng_type, + &n_hex, + &g_hex ) ) { return -1; } @@ -643,11 +934,15 @@ static int ver_init( PyVerifier *self, PyObject *args, PyObject *kwds ) * things up for multi-cpu machines */ Py_BEGIN_ALLOW_THREADS - self->ver = srp_verifier_new( username, - bytes_s, len_s, - bytes_v, len_v, - bytes_A, len_A, - &self->bytes_B, &self->len_B ); + self->ver = srp_verifier_new( (SRP_HashAlgorithm) hash_alg, + (SRP_NGType) ng_type, + username, + bytes_s, len_s, + bytes_v, len_v, + bytes_A, len_A, + &self->bytes_B, &self->len_B, + n_hex, + g_hex ); Py_END_ALLOW_THREADS if ( self->bytes_B == NULL ) @@ -667,9 +962,16 @@ static int ver_init( PyVerifier *self, PyObject *args, PyObject *kwds ) static int usr_init( PyUser *self, PyObject *args, PyObject *kwds ) { - const char *username; - const unsigned char *bytes_password; - int len_password; + const char *username = 0; + const unsigned char *bytes_password = 0; + int len_password = 0; + int hash_alg = SRP_SHA1; + int ng_type = SRP_NG_1024; + const char *n_hex = 0; + const char *g_hex = 0; + static char * kwnames[] = { "username", "password", "hash_alg", + "ng_type", "n_hex", "g_hex", NULL }; + if ( self->usr != NULL ) { @@ -677,15 +979,26 @@ static int usr_init( PyUser *self, PyObject *args, PyObject *kwds ) return -1; } - if ( ! PyArg_ParseTuple(args, "st#", &username, - &bytes_password, - &len_password) ) + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "st#|iiss", kwnames, + &username, + &bytes_password, + &len_password, + &hash_alg, + &ng_type, + &n_hex, + &g_hex) ) { return -1; } - self->usr = srp_user_new( username, bytes_password, len_password ); + self->usr = srp_user_new( (SRP_HashAlgorithm) hash_alg, + (SRP_NGType) ng_type, + username, + bytes_password, + len_password, + n_hex, + g_hex ); return 0; } @@ -747,8 +1060,9 @@ static PyObject * ver_get_session_key( PyVerifier * self ) } if ( srp_verifier_is_authenticated(self->ver) ) { - const char * u = (const char *)srp_verifier_get_session_key(self->ver); - return PyString_FromStringAndSize(u, SHA256_DIGEST_LENGTH); + int key_len; + const char * u = (const char *)srp_verifier_get_session_key(self->ver, &key_len); + return PyString_FromStringAndSize(u, key_len); } else Py_RETURN_NONE; @@ -763,8 +1077,9 @@ static PyObject * usr_get_session_key( PyUser * self ) } if ( srp_user_is_authenticated(self->usr) ) { - const char * u = (const char *) srp_user_get_session_key(self->usr); - return PyString_FromStringAndSize(u, SHA256_DIGEST_LENGTH); + int key_len; + const char * u = (const char *) srp_user_get_session_key(self->usr, &key_len); + return PyString_FromStringAndSize(u, key_len); } else Py_RETURN_NONE; @@ -805,7 +1120,7 @@ static PyObject * ver_verify_session( PyVerifier * self, PyObject * args ) return NULL; } - if ( len_M != SHA256_DIGEST_LENGTH ) + if ( len_M != srp_verifier_get_session_key_length( self->ver ) ) Py_RETURN_NONE; srp_verifier_verify_session( self->ver, bytes_M, &bytes_HAMK ); @@ -814,7 +1129,7 @@ static PyObject * ver_verify_session( PyVerifier * self, PyObject * args ) Py_RETURN_NONE; else return PyString_FromStringAndSize((const char *) bytes_HAMK, - SHA256_DIGEST_LENGTH); + srp_verifier_get_session_key_length( self->ver )); } @@ -838,7 +1153,7 @@ static PyObject * usr_start_authentication( PyUser * self ) static PyObject * usr_process_challenge( PyUser * self, PyObject * args ) { const unsigned char * bytes_s, *bytes_B; - int len_s, len_B; + int len_s, len_B, len_M; const unsigned char * bytes_M; if ( self->usr == NULL ) { @@ -858,14 +1173,13 @@ static PyObject * usr_process_challenge( PyUser * self, PyObject * args ) */ Py_BEGIN_ALLOW_THREADS srp_user_process_challenge( self->usr, bytes_s, len_s, bytes_B, len_B, - &bytes_M ); + &bytes_M, &len_M ); Py_END_ALLOW_THREADS if (bytes_M == NULL) Py_RETURN_NONE; else - return PyString_FromStringAndSize((const char *) bytes_M, - SHA256_DIGEST_LENGTH); + return PyString_FromStringAndSize((const char *) bytes_M, len_M); } @@ -884,27 +1198,43 @@ static PyObject * usr_verify_session( PyUser * self, PyObject * args ) return NULL; } - if ( len_HAMK == SHA256_DIGEST_LENGTH ) + if ( len_HAMK == srp_user_get_session_key_length( self->usr ) ) srp_user_verify_session( self->usr, bytes_HAMK ); Py_RETURN_NONE; } -static PyObject * py_gen_sv( PyObject *self, PyObject *args ) +static PyObject * py_gen_sv( PyObject *self, PyObject *args, PyObject *kwds ) { + PyObject *ret; const char *username; const unsigned char *bytes_password, *bytes_s, *bytes_v; int len_password, len_s, len_v; - PyObject *ret; + int hash_alg = SRP_SHA1; + int ng_type = SRP_NG_1024; + const char *n_hex = 0; + const char *g_hex = 0; + static char * kwnames[] = { "username", "password", "hash_alg", + "ng_type", "n_hex", "g_hex", NULL }; - if ( ! PyArg_ParseTuple(args, "st#", &username, &bytes_password, - &len_password) ) + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "st#|iiss", kwnames, + &username, + &bytes_password, + &len_password, + &hash_alg, + &ng_type, + &n_hex, + &g_hex) ) return NULL; - srp_gen_sv( username, bytes_password, len_password, &bytes_s, &len_s, - &bytes_v, &len_v ); + srp_gen_sv( (SRP_HashAlgorithm) hash_alg, + (SRP_NGType) ng_type, + username, bytes_password, len_password, &bytes_s, &len_s, + &bytes_v, &len_v, + n_hex, + g_hex ); ret = Py_BuildValue("s#s#", bytes_s, len_s, bytes_v, len_v); @@ -971,7 +1301,7 @@ static PyMethodDef PyUser_methods[] = { static PyMethodDef srp_module_methods[] = { - {"gen_sv", (PyCFunction) py_gen_sv, METH_VARARGS, + {"gen_sv", (PyCFunction) py_gen_sv, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Returns (s,v): Generates a salt + verifier for the " "given username and password") }, @@ -1096,7 +1426,7 @@ init_srp(void) Py_ssize_t slen = 0; if (!PyString_AsStringAndSize(randstr, &buff, &slen)) { - srp_init( buff, slen ); + srp_random_seed( (const unsigned char *)buff, slen ); init_ok = 1; } } @@ -1114,13 +1444,7 @@ init_srp(void) return; } - if ( Py_AtExit( &srp_fini ) ) - { - PyErr_SetString(PyExc_ImportError, "Failed to register atexit handler"); - return; - } - - + if (PyType_Ready(&PyVerifier_Type) < 0 || PyType_Ready(&PyUser_Type)) return; @@ -1133,5 +1457,18 @@ init_srp(void) Py_INCREF(&PyUser_Type); PyModule_AddObject(m, "Verifier", (PyObject*) &PyVerifier_Type ); - PyModule_AddObject(m, "User", (PyObject*) &PyUser_Type ); + PyModule_AddObject(m, "User", (PyObject*) &PyUser_Type ); + + PyModule_AddIntConstant(m, "NG_1024", SRP_NG_1024); + PyModule_AddIntConstant(m, "NG_2048", SRP_NG_2048); + PyModule_AddIntConstant(m, "NG_4096", SRP_NG_4096); + PyModule_AddIntConstant(m, "NG_CUSTOM", SRP_NG_CUSTOM); + + + PyModule_AddIntConstant(m, "SHA1", SRP_SHA1); + PyModule_AddIntConstant(m, "SHA224", SRP_SHA224); + PyModule_AddIntConstant(m, "SHA256", SRP_SHA256); + PyModule_AddIntConstant(m, "SHA384", SRP_SHA384); + PyModule_AddIntConstant(m, "SHA512", SRP_SHA512); + }
\ No newline at end of file diff --git a/doc/srp.rst b/doc/srp.rst index c9e65cf..ef55add 100644 --- a/doc/srp.rst +++ b/doc/srp.rst @@ -10,14 +10,14 @@ This module provides an implementation of the Secure Remote Password -Protocol. It may be used for secure authentication across an unsecured +Protocol. It is used for secure authentication across an unsecured network connection and verifies that both sides, the user and server, have knowledge of the user's password. Unlike other commonly used -authentication protocols such as Kerberos and certificate-based SSL, +authentication protocols, such as Kerberos and certificate-based SSL, SRP does not require a trusted third party. With SRP, the user's password is never sent over the network and a successful authentication results -in a cryptographically secure shared key that may be used for symmetric -key encryption. +in a cryptographically secure shared key that may be used for subsequent +symmetric key encryption. SRP authentication requires the server to store a salted verification key that is computed from user's password. While care should be taken @@ -36,12 +36,45 @@ second is an issue, using a small pool of threads to perform the authentication steps on multi-core systems will yield a substantial performance increase. +The User & Verifier construtors, as well as the gen_sv() function, +take optional hashing algorithm and prime number arguments. Generally +speaking, more bits means more computation time and more security. The +hashing and prime number parameters passed to the User and Verifier +constructors must match those used to create the verification key. + See http://srp.stanford.edu/ for a full description of the SRP protocol. +Constants +--------- +============== ============== +Hash Algorithm Number of Bits +============== ============== +SHA1 160 +SHA224 224 +SHA256 256 +SHA384 384 +SHA512 512 +============== ============== + +================= +Prime Number Size +================= +NG_1024 +NG_2048 +NG_4096 +NG_CUSTOM +================= + +If NG_CUSTOM is used, the 'n_hex' and 'g_hex' parameters are required. +These parameters must be ASCII text containing hexidecimal notation of the +prime number 'n_hex' and the corresponding generator number 'g_hex'. Appendix +A of RFC 5054 contains several large prime number, generator pairs that may +be used with NG_CUSTOM. + Functions --------- -.. function:: gen_sv ( username, password ) +.. function:: gen_sv ( username, password[, hash_alg=SHA1, ng_type=NG_1024, n_hex=None, g_hex=None] ) Generates a salt and verifier for the given username and password. Returns (salt_bytes, verifier_bytes) @@ -58,7 +91,7 @@ user. The standard SRP 6 protocol allows only one password attempt per connection. -.. class:: Verifier( username, bytes_s, bytes_v, bytes_A ) +.. class:: Verifier( username, bytes_s, bytes_v, bytes_A[, hash_alg=SHA1, ng_type=NG_1024, n_hex=None, g_hex=None] ) *username* Name of the remote user being authenticated. @@ -105,7 +138,7 @@ that the :class:`User` be provided with a valid username/password but also that the remote :class:`Verifier` have a salt & verifier for that username/password pair. -.. class:: User( username, password ) +.. class:: User( username, password[, hash_alg=SHA1, ng_type=NG_1024, n_hex=None, g_hex=None] ) *username* Name of the user being authenticated. @@ -1,30 +1,38 @@ -User = None
-Verifier = None
-gen_sv = None
+_mod = None
try:
import _srp
- User = _srp.User
- Verifier = _srp.Verifier
- gen_sv = _srp.gen_sv
+ _mod = _srp
except ImportError:
pass
-if not User:
+if not _mod:
try:
import _ctsrp
- User = _ctsrp.User
- Verifier = _ctsrp.Verifier
- gen_sv = _ctsrp.gen_sv
+ _mod = _ctsrp
except ImportError:
pass
-if not User:
+if not _mod:
import _pysrp
- User = _pysrp.User
- Verifier = _pysrp.Verifier
- gen_sv = _pysrp.gen_sv
+ _mod = _pysrp
+
+
+User = _mod.User
+Verifier = _mod.Verifier
+gen_sv = _mod.gen_sv
+
+SHA1 = _mod.SHA1
+SHA224 = _mod.SHA224
+SHA256 = _mod.SHA256
+SHA384 = _mod.SHA384
+SHA512 = _mod.SHA512
+
+NG_1024 = _mod.NG_1024
+NG_2048 = _mod.NG_2048
+NG_4096 = _mod.NG_4096
+NG_CUSTOM = _mod.NG_CUSTOM
diff --git a/test_srp.py b/test_srp.py index d833f74..f983911 100644 --- a/test_srp.py +++ b/test_srp.py @@ -1,34 +1,39 @@ #!/usr/bin/python +import sys +sys.path.append( 'build/lib.linux-i686-2.6/' ) + NTHREADS = 1 NTEST = 10 import _pysrp -User = _pysrp.User -Verifier = _pysrp.Verifier -gen_sv = _pysrp.gen_sv +u_mod = _pysrp +v_mod = _pysrp +g_mod = _pysrp import _ctsrp -User = _ctsrp.User -Verifier = _ctsrp.Verifier -gen_sv = _ctsrp.gen_sv +u_mod = _ctsrp +#v_mod = _ctsrp +#g_mod = _ctsrp try: import _srp - #User = _srp.User - #Verifier = _srp.Verifier - #gen_sv = _srp.gen_sv + u_mod = _srp + v_mod = _srp + g_mod = _srp except: print 'C-module not available' pass import srp -HASH = _pysrp.SHA1 -NG = _pysrp.NG_1024 -#User = srp.User -#Verifier = srp.Verifier -#gen_sv = srp.gen_sv +User = u_mod.User +Verifier = v_mod.Verifier +gen_sv = g_mod.gen_sv + +HASH = srp.SHA256 +NG = srp.NG_2048 + username = 'testuser' password = 'testpassword' |