\documentclass{howto}

\title{Python bindings for cracklib}

\input{boilerplate}

\declaremodule{}{crack}

\begin{document}
\maketitle

\ifhtml
\chapter*{Front Matter\label{front}}
\fi

Copyright \copyright{} 2003 Domenico Andreoli.

Permission is granted to copy, distribute and/or modify this document
under the terms of the
\citetitle[http://www.gnu.org/licenses/fdl.html]{GNU Free Documentation License}, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of the license is available at the \citetitle[http://www.gnu.org]{GNU} site.

%\begin{abstract}
%\noindent
%This document describes how to use Cracklib in Python programs.
%\end{abstract}

\tableofcontents{\label{contents}}

Checking the strength of passwords from Python programs is now easy.

\section{What is \module{crack}? \label{what}}

\module{crack} is a Python module that exposes a simple interface to
check the strength of passwords. This can be used from within Python
programs as easily as calling a function and catching an exception.

\module{crack} can be very severe in performing checks. It uses the
standard cracklib2 library to discover whether passwords are based on
dictionary words or are too simple. Moreover additional checks such
as minimum difference characters and rotation of old password have been
written on the model of those found in PAM cracklib module.

It is possible for the user to tune the severity of checks by the use
of some parameters.

\section{Why Use \module{crack}? \label{why}}

Passwords are the most common way a computer uses to authenticate the
user. The key point is in the little possibility for any user to guess
other users' passwords and then use their identities. Sadly nowadays
this often shows to be also the weakest ring of the whole security chain.

Reducing the possibility of password guessing and then improving
passwords' strength can greatly improve the overall system security.

\module{crack} and cracklib have been written for this purpose: mandate
the use of \emph{stronger} passwords. Whether these passwords are strong
enough for his purpose is solely a matter of the user.

\section{Software Requirements \label{requirements}}

Author uses Python 2.2 and cracklib 2.7. Python 2.1 has been tested, it
works as expected. Because of the simple interfaces being involved it is
far from being impossible to build \module{crack} on top of older
versions of both Python and cracklib.

Any suggestion or patch allowing the use with ancient versions is
welcome.  Reports of runs with older versions are welcome as well. The author
will keep record of the oldest reported versions. Contest starts... now :)

\section{\module{crack} --- Interface Details \label{crack-api}}

% Leave at least one blank line after this, to simplify ad-hoc tools
% that are sometimes used to massage these files.
\modulesynopsis{This is a one-line description, for the chapter header.}


The \module{crack} module defines check functions and parameters used
to test passwords' strength.


\begin{funcdesc}{FascistCheck}{passwd \optional{, dictpath}}
It maps the homonym cracklib function with few differences.

First, it always returns the given \var{passwd}. If it is found to be
weak \exception{ValueError} exception is raised with parameter set to the
reason returned by cracklib's FascistCheck.

Second, \var{dictpath} parameter is optional. If it is not specified the default
one, determined at build time, is used. See \var{default\_dictpath} variable.
\end{funcdesc}

\begin{funcdesc}{VeryFascistCheck}{passwd \optional{, old\_passwd \optional{, dictpath}}}
It behaves like \function{FascistCheck} but performs also checks for
palindrome and simple passwords.

If the optional \var{old\_password} is provided additional checks for
minimum distance between the two passwords, for similarity, for change
of case only and for rotation are performed.

Exception \exception{ValueError} is raised in case of weak password.

\var{dictpath} parameter is used only for the inner call to \function{FascistCheck},
hence it has the same signification it has for \function{FascistCheck}.
\end{funcdesc}

\begin{datadesc}{default\_dictpath}
It is the default prefix to the cracklib dictionary database. Its value
is determined at build time.

It is used automatically if \var{dictpath} parameter is not specified
when calling \function{FascistCheck} or \function{VeryFascistCheck}.
\end{datadesc}

\begin{datadesc}{diff\_ok}
This argument will change the default of 10 for the number of characters in the new
password that must not be present in the old password. In addition, if 1/2 of the characters
in the new password are different then the new password will be accepted anyway.
\end{datadesc}

\begin{datadesc}{min\_length}
The minimum acceptable size for the new password (plus one if credits are not disabled
which is the default). In addition to the number of characters in the new password, credit
(of +1 in length) is given for each different kind of character (digit, upper, lower and
other). The default for this parameter is 9 which is good for a old style \UNIX{} password all
of the same type of character but may be too low to exploit the added security of a md5 system.
Note that there is a pair of length limits in cracklib itself, a "way too short" limit of 4
which is hard coded in and a defined limit of 6 that will be checked without reference to
\var{min\_length}. If you want to allow passwords as short as 5 characters you should either
not use this module or recompile the crack library and then recompile this module.
\end{datadesc}

\begin{datadesc}{dig\_credit}
(N >= 0) This is the maximum credit for having digits in the new password. If you have less
than or N digits, each digit will count +1 towards meeting the current \var{min\_length} value.
The default for \var{dig\_credit} is 1 which is the recommended value for \var{min\_length} less
than 10. (N < 0) This is the minimum number of digits that must be met for a new password.
\end{datadesc}

\begin{datadesc}{up\_credit}
(N >= 0) This is the maximum credit for having upper case letters in the new password. If
you have less than or N upper case letters each letter will count +1 towards meeting the current
\var{min\_length} value. The default for \var{up\_credit} is 1 which is the recommended value for
\var{min\_length} less than 10. (N < 0) This is the minimum number of upper case letters that
must be met for a new password.
\end{datadesc}

\begin{datadesc}{low\_credit}
(N >= 0) This is the maximum credit for having lower case letters in the new password. If
you have less than or N lower case letters, each letter will count +1 towards meeting the current
\var{min\_length} value. The default for \var{low\_credit} is 1 which is the recommended value for
\var{min\_length} less than 10. (N < 0) This is the minimum number of lower case letters that must
be met for a new password.
\end{datadesc}

\begin{datadesc}{oth\_credit}
(N >= 0) This is the maximum credit for having other characters in the new password. If you have
less than or N other characters, each character will count +1 towards meeting the current
\var{min\_length} value. The default for \var{oth\_credit} is 1 which is the recommended value for
\var{min\_length} less than 10.  (N < 0) This is the minimum number of other characters that must
be met for a new password.
\end{datadesc}


\subsection{Example \label{crack-example}}

The following example shows how to check a password using the \module{crack} module.

\begin{verbatim}
>>> import crack
>>> crack.FascistCheck("abcdefghilmn")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "/usr/lib/python2.2/site-packages/crack.py", line 194, in VeryFascistCheck
    return FascistCheck(new, dictpath)
ValueError: it is too simplistic/systematic
>>> crack.FascistCheck("secret")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: it is based on a dictionary word
>>> crack.VeryFascistCheck("secret", "scrt")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "/usr/lib/python2.2/site-packages/crack.py", line 187, in VeryFascistCheck
    raise ValueError, "is too similar to the old one"
ValueError: is too similar to the old one
>>> crack.VeryFascistCheck("secret", "cretse")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "/usr/lib/python2.2/site-packages/crack.py", line 185, in VeryFascistCheck
    raise ValueError, "is rotated"
ValueError: is rotated
>>> crack.FascistCheck("this is a really secure secret but do not use it!!")
'this is a really secure secret but do not use it!!'
\end{verbatim}
% Note that there is no trailing ">>> " prompt shown.

\section{Security \label{security}}

Beware of a little, tiny particular. Python does not allow direct memory
management.

Python objects, and then strings and passwords, are garbage collected
automatically. There is no way (known to the author) to clean passwords
safely. So might happen that other programs are able to see the left
passwords in they dirty (not initialized) memory.

If the user cannot live with this limitation, he is better to change
module or language.

\end{document}
