From 7761b24a526987fad55af130e20417503d2cea51 Mon Sep 17 00:00:00 2001 From: Ben Carrillo Date: Mon, 28 Jan 2013 09:09:07 +0900 Subject: initial packaging attempt --- srp/doc/conf.py | 216 +++++++++++++++++++++++++++++++ srp/doc/index.rst | 22 ++++ srp/doc/srp.rst | 377 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 615 insertions(+) create mode 100644 srp/doc/conf.py create mode 100644 srp/doc/index.rst create mode 100644 srp/doc/srp.rst (limited to 'srp/doc') diff --git a/srp/doc/conf.py b/srp/doc/conf.py new file mode 100644 index 0000000..ba75a8c --- /dev/null +++ b/srp/doc/conf.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +# +# Secure Remote Password documentation build configuration file, created by +# sphinx-quickstart on Fri Mar 25 10:20:52 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Secure Remote Password' +copyright = u'2011, Tom Cocagne' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'SecureRemotePassworddoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'SecureRemotePassword.tex', u'Secure Remote Password Documentation', + u'Tom Cocagne', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'secureremotepassword', u'Secure Remote Password Documentation', + [u'Tom Cocagne'], 1) +] diff --git a/srp/doc/index.rst b/srp/doc/index.rst new file mode 100644 index 0000000..0c13606 --- /dev/null +++ b/srp/doc/index.rst @@ -0,0 +1,22 @@ +.. Secure Remote Password documentation master file, created by + sphinx-quickstart on Fri Mar 25 10:20:52 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Secure Remote Password's documentation! +================================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + srp.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/srp/doc/srp.rst b/srp/doc/srp.rst new file mode 100644 index 0000000..9cdd967 --- /dev/null +++ b/srp/doc/srp.rst @@ -0,0 +1,377 @@ +:mod:`srp` --- Secure Remote Password +===================================== + +.. module:: srp + :synopsis: Secure Remote Password + +.. moduleauthor:: Tom Cocagne + +.. sectionauthor:: Tom Cocagne + + +The Secure Remote Password protocol (SRP) is a cryptographically +strong authentication protocol for password-based, mutual +authentication over an insecure network connection. Successful SRP +authentication requires both sides of the connection to have knowledge +of the user's password. In addition to password verification, the SRP +protocol also performs a secure key exchange during the authentication +process. This key may be used to protect network traffic via symmetric +key encryption. + +SRP offers security and deployment advantages over other +challenge-response protocols, such as Kerberos and SSL, in that it +does not require trusted key servers or certificate infrastructures. +Instead, small verification keys derived from each user's password are +stored and used by each SRP server application. SRP provides a +near-ideal solution for many applications requiring simple and secure +password authentication that does not rely on an external +infrastructure. + +Another favorable aspect of the SRP protocol is that compromized +verification keys are of little value to an attacker. Possesion of a +verification key does not allow a user to be impersonated +and it cannot be used to obtain the users password except by way of a +computationally infeasible dictionary attack. A compromized key would, +however, allow an attacker to impersonate the server side of an SRP +authenticated connection. Consequently, care should be taken to +prevent unauthorized access to verification keys for applications in +which the client side relies on the server being genuine. + + + +Usage +----- + +SRP usage begins with *create_salted_verification_key()*. This function +creates a salted verification key from the user's password. The resulting salt +and key are stored by the server application and will be used during the +authentication process. + +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* constructors, as well as the +*create_salted_verification_key()* function, accept optional arguments +to specify which hashing algorithm and prime number arguments should +be used during the authentication process. These options may be used +to tune the security/performance tradeoff for an application. +Generally speaking, specifying arguments with a higher number of bits +will result in a greater level of security. However, it will come at +the cost of increased computation time. The default values of SHA1 +hashes and 2048 bit prime numbers strike a good balance between +performance and security. These values should be sufficient for most +applications. Regardless of which values are used, the parameters +passed to the *User* and *Verifier* constructors must exactly match +those passed to *create_salted_verification_key()* + + +.. _constants: + +Constants +--------- + +.. table:: Hashing Algorithm Constants + + ============== ============== + Hash Algorithm Number of Bits + ============== ============== + SHA1 160 + SHA224 224 + SHA256 256 + SHA384 384 + SHA512 512 + ============== ============== + +.. note:: + + 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_8192 8192 + NG_CUSTOM User Supplied + ================= ============== + +.. note:: + + 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_2048, n_hex=None, g_hex=None] ) + + *username* Name of the user + + *password* Plaintext user password + + *hash_alg*, *ng_type*, *n_hex*, *g_hex* Refer to the :ref:`constants` section. + + Generate a salted verification key for the given username and password and return the tuple: + (salt_bytes, verification_key_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_2048, 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* Verification Key generated by :func:`create_salted_verification_key`. + + *bytes_A* Challenge from the remote user. Generated by + :meth:`User.start_authentication` + + *hash_alg*, *ng_type*, *n_hex*, *g_hex* Refer to the :ref:`constants` section. + + .. method:: Verifier.authenticated() + + Return True if the authentication succeeded. False + otherwise. + + .. method:: Verifier.get_username() + + Return the name of the user this :class:`Verifier` object is for. + + .. method:: Verifier.get_session_key() + + Return the session key for an authenticated user or None if the + authentication failed or has not yet completed. + + .. method:: Verifier.get_challenge() + + Return (bytes_s, bytes_B) on success or (None, None) if + authentication has failed. + + .. method:: Verifier.verify_session( user_M ) + + Complete 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 prove a user's identity to a remote :class:`Verifier` and +verifiy that the remote :class:`Verifier` knows the verification key associated with +the user's password. + +.. class:: User( username, password[, hash_alg=SHA1, ng_type=NG_2048, n_hex=None, g_hex=None] ) + + *username* Name of the user being authenticated. + + *password* Password for the user. + + *hash_alg*, *ng_type*, *n_hex*, *g_hex* Refer to the :ref:`constants` section. + + .. method:: User.authenticated() + + Return True if authentication succeeded. False + otherwise. + + .. method:: User.get_username() + + Return the username passed to the constructor. + + .. method:: User.get_session_key() + + Return the session key if authentication succeeded or None if the + authentication failed or has not yet completed. + + .. method:: User.start_authentication() + + Return (username, bytes_A). These should be passed to the + constructor of the remote :class:`Verifer` + + .. method:: User.process_challenge( bytes_s, bytes_B ) + + Processe 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 ) + + Complete the :class:`User` side of the authentication process. By + verifying the *bytes_H_AMK* value returned by + :meth:`Verifier.verify_session`. 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, vkey = srp.create_salted_verification_key( 'testuser', 'testpassword' ) + + class AuthenticationFailed (Exception): + pass + + # ~~~ 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, vkey, A ) + s,B = svr.get_challenge() + + if s is None or B is None: + raise AuthenticationFailed() + + # Server => Client: s, B + M = usr.process_challenge( s, B ) + + if M is None: + raise AuthenticationFailed() + + # Client => Server: M + HAMK = svr.verify_session( M ) + + if HAMK is None: + raise AuthenticationFailed() + + # 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 +--------------------------- + +The original SRP protocol, known as SRP-3, is defined in +RFC 2945. This implementation, however, uses SRP-6a which is a slight +improvement over SRP-3. The authoritative definition for the SRP-6a +protocol is available at http://srp.stanford.edu. An additional +resource is RFC 5054 which covers the integration of SRP into +TLS. This RFC is the source of hashing strategy and 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 + -- cgit v1.2.3