:mod:`srp` --- Secure Remote Password ===================================== .. module:: srp :synopsis: Secure Remote Password .. moduleauthor:: Tom Cocagne .. sectionauthor:: Tom Cocagne This module provides an implementation of the Secure Remote Password Protocol (SRP). SRP is a simple and secure protocol for password-based, mutual authentication. Successful SRP authentication proves that the client knows the user's password and proves that the server knows the verification key that was derived from the user's password at the time it was set. An additional benefit of SRP is that successful authentication results in a cryptographically strong shared key that can be used for symmetric key encryption. Unlike Kerberos & SSL, SRP does not require a trusted third party. The server simply needs to store a salted verification key that is derived from the user's password. This verification key should be protected as it's compromise would allow an attacker to impersonate the server. An advantage of the SRP protocol is that, even in the event that the verification key is compromised, the protocol remains reasonably secure. While an attacker would be able to impersonate the server side of a connection, he or she would not be able to directly impersonate a user or discover the user's password. It would require a computationally infeasible dictionary attack to obtain the user's password from the verification key. Briefly stated, the advantages of SRP are: * It does not require a trusted third party (unlike Kerberos & SSL) * It provides strong, mutual authentication * Successful authentication results in a cryptographically strong shared key that may be used for subsequent symmetric-key encryption. * It is resists both passive and active network attacks * Compromised verification keys do not allow the attacker to impersonate the client. Usage ----- Use of SRP begins by using the create_salted_verification_key() function to create a salted verification key from the user's password. The salt and key are stored on the server and will be used during the authentication process. The rest of the authentication process occurs as an exchange of messages between the clent and the server. The :ref:`example` below provides a simple demonstration of the protocol. A comprehensive description of the SRP protocol is contained in the :ref:`protocol-description` section. The User & Verifier construtors, as well as the create_salted_verification_key() function, take optional hashing algorithm and prime number arguments. Generally speaking, more bits means more security but comes at the cost of increased computation time. The hashing and prime number parameters passed to the User and Verifier constructors must match those used to create the verification key. Constants --------- .. table:: Hashing Algorithm Constants ============== ============== Hash Algorithm Number of Bits ============== ============== SHA1 160 SHA224 224 SHA256 256 SHA384 384 SHA512 512 ============== ============== Larger hashing algorithms will result in larger session keys. .. table:: Prime Number Constants ================= ============== Prime Number Size Number of Bits ================= ============== NG_1024 1024 NG_2048 2048 NG_4096 4096 NG_CUSTOM User Supplied ================= ============== 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:: create_salted_verification_key ( 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) :class:`Verifier` Objects ------------------------- A :class:`Verifier` object is used to verify the identity of a remote user. .. note:: The standard SRP 6 protocol allows only one password attempt per connection. .. 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. *bytes_s* Salt generated by :func:`create_salted_verification_key`. *bytes_v* Verifier generated by :func:`create_salted_verification_key`. *bytes_A* Challenge from the remote user. Generated by :meth:`User.start_authentication` .. method:: Verifier.authenticated() Returns True if the authentication succeeded. False otherwise. .. method:: Verifier.get_username() Returns the name of the user this :class:`Verifier` object is for. .. method:: Verifier.get_session_key() Returns the session key for an authenticated user or None if the authentication failed or has not yet completed. .. method:: Verifier.get_challenge() Returns (bytes_s, bytes_B) on success or (None, None) if authentication has failed. .. method:: Verifier.verify_session( user_M ) Completes the :class:`Verifier` side of the authentication process. If the authentication succeded the return result, bytes_H_AMK should be returned to the remote user. On failure, this method returns None. :class:`User` Objects ------------------------- A :class:`User` object is used to perform mutual authentication with a remote :class:`Verifier`. Successful authentication requires not only 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[, hash_alg=SHA1, ng_type=NG_1024, n_hex=None, g_hex=None] ) *username* Name of the user being authenticated. *password* Password for the user. .. method:: User.authenticated() Returns True if authentication succeeded. False otherwise. .. method:: User.get_username() Returns the username passed to the constructor. .. method:: User.get_session_key() Returns the session key if authentication succeeded or None if the authentication failed or has not yet completed. .. method:: User.start_authentication() Returns (username, bytes_A). These should be passed to the constructor of the remote :class:`Verifer` .. method:: User.process_challenge( bytes_s, bytes_B ) Processes the challenge returned by :meth:`Verifier.get_challenge` on success this method returns bytes_M that should be sent to :meth:`Verifier.verify_session` if authentication failed, it returns None. .. method:: User.verify_session( bytes_H_AMK ) Completes the :class:`User` side of the authentication process. If the authentication succeded :meth:`authenticated` will return True .. _example: Example ------- Simple Usage Example:: import srp # The salt and verifier returned from srp.create_salted_verification_key() should be # stored on the server. salt, verifier = srp.create_salted_verification_key( 'testuser', 'testpassword' ) # ~~~ Begin Authentication ~~~ usr = srp.User( 'testuser', 'testpassword' ) uname, A = usr.start_authentication() # The authentication process can fail at each step from this # point on. To comply with the SRP protocol, the authentication # process should be aborted on the first failure. # Client => Server: username, A svr = srp.Verifier( uname, salt, verifier, A ) s,B = svr.get_challenge() # Server => Client: s, B M = usr.process_challenge( s, B ) # Client => Server: M HAMK = svr.verify_session( M ) # SRP 6a requies the server to abort authentication and to specifically # NOT send the HAMK message to the client if detects failed authentication # at this point: if not svr.authenticated(): raise Exception("authentication failed!") # Server => Client: HAMK usr.verify_session( HAMK ) # At this point the authentication process is complete. assert usr.authenticated() assert svr.authenticated() Implementation Notes -------------------- This implementation of SRP consists of both a pure-python module and a C-based implementation that is approximately 10x faster. By default, the C-implementation will be used if it is available. An additional benefit of the C implementation is that it can take advantage of of multiple CPUs. For cases in which the number of connections per 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. .. _protocol-description: SRP 6a Protocol Description --------------------------- For the original, authoritative definition of SRP-6a please refer to http://srp.stanford.edu. RFC 5054 also contains SRP related information and is the source of the predefined N and g constants used in this implementation. The following is a complete description of the SRP-6a protocol as implemented by this library. Note that the ^ symbol indicates exponentiaion and the | symbol indicates concatenation. .. rubric:: Primary Variables used in SRP 6a ========= ================================================================= Variables Description ========= ================================================================= N A large, safe prime (N = 2q+1, where q is a Sophie Germain prime) All arithmetic is performed in the field of integers modulo N g A generator modulo N s Small salt for the verification key I Username p Cleartext password H() One-way hash function a,b Secret, random values K Session key ========= ================================================================= .. rubric:: Derived Values used in SRP 6a ====================================== ==================================== Derived Values Description ====================================== ==================================== k = H(N,g) Multiplier Parameter A = g^a Public ephemeral value B = kv + g^b Public ephemeral value x = H(s, H( I | ':' | p )) Private key (as defined by RFC 5054) v = g^x Password verifier u = H(A,B) Random scrambling parameter M = H(H(N) xor H(g), H(I), s, A, B, K) Session key verifier ====================================== ==================================== .. rubric:: Protocol Description The server stores the password verifier *v*. Authentication begins with a message from the client:: client -> server: I, A = g^a The server replies with the verifier salt and challenge:: server -> client: s, B = kv + g^b At this point, both the client and server calculate the shared session key:: client & server: u = H(A,B) :: server: K = H( (Av^u) ^ b ) :: client: x = H( s, H( I + ':' + p ) ) client: K = H( (B - kg^x) ^ (a + ux) ) Now both parties have a shared, strong session key *K*. To complete authentication they need to prove to each other that their keys match:: client -> server: M = H(H(N) xor H(g), H(I), s, A, B, K) server -> client: H(A, M, K) SRP 6a requires the two parties to use the following safeguards: 1. The client will abort if it recieves B == 0 (mod N) or u == 0 2. The server will abort if it detects A == 0 (mod N) 3. The client must show its proof of K first. If the server detects that this proof is incorrect it must abort without showing its own proof of K