\documentclass{article} \usepackage{listings} \usepackage{a4} \usepackage{courier} \usepackage{hyperref} \usepackage{html} \lstdefinelanguage{ASN1} { morekeywords={}, sensitive=false, morecomment=[s]{(--}{--)} } \lstdefinelanguage{shell} { sensitive=true } \setlength{\parskip}{\medskipamount} \setlength{\parindent}{0pt} \title{Haskell Cryptographic Library 3.0.3} \author{Dominic Steinitz} \begin{document} \maketitle The \htmladdnormallinkfoot {Haskell Cryptographic Library 3.0.3} {http://www.haskell.org/crypto} collects together existing Haskell cryptographic functions into one cabalized package, together with HUnit tests, QuickCheck property tests, examples showing how to interwork with other cryptographic implementations and examples showing how to handle other ASN.1 definitions. This release contains: \begin{itemize} \item DES \item Blowfish \item AES \item Cipher Block Chaining (CBC) \item PKCS\#5 and nulls padding \item SHA-1 \item MD5 \item RSA \item OAEP-based encryption (Bellare-Rogaway) \item PKCS\#1v1.5 signature scheme \item ASN.1 \item PKCS\#8 \item X.509 Identity Certificates \item X.509 Attribute Certificates \end{itemize} Haddock documentation for the library is available \htmladdnormallinkfoot {here} {http://www.haskell.org/crypto/doc/html} . \section{System Requirements} \begin{itemize} \item The code has been tested on GHC 6.4. It does not currently work with Hugs or NHC. \item It requires the use of \htmladdnormallinkfoot {{\tt NewBinary.Binary}} {http://www.n-heptane.com/nhlab/repos/NewBinary} . This uses an old version of cabal and you will need to download \htmladdnormallinkfoot {this} {http://www.haskell.org/crypto/downloads/NewBinary.cabal} this in order to build and install it. \end{itemize} \section{Installation Instructions} Get the sources: \lstset{language=shell,basicstyle=\ttfamily\small} \begin{lstlisting}[frame=single] darcs get --tag "3.0.3" http://www.haskell.org/crypto/src \end{lstlisting} Build and install ready for testing: \begin{lstlisting}[frame=single] ghc -o Setup Setup.hs -package Cabal ./Setup configure --prefix=/my/chosen/dir ./Setup build ./Setup install --user \end{lstlisting} Run the tests. \begin{lstlisting}[frame=single] cd /my/chosen/dir/bin ./BERTest ./RSATest ./SymmetricTest ./QuickTest \end{lstlisting} You can now run the examples to confirm further that everything is working satisfactorily. When you are happy, build and install them in their final destination: \begin{lstlisting}[frame=single] ./Setup unregister --user ./Setup clean ./Setup configure ./Setup build ./Setup install \end{lstlisting} \section{Asymmetric Encryption and Digital Signing} \subsection{Preliminaries} First of all, create a self-signed (identity) certificate and private key. Be careful as not all OIDs are supported (although they are easy to add). \lstset{language=shell,basicstyle=\ttfamily\small} \begin{lstlisting}[frame=single] openssl req -new -nodes -x509 -outform PEM -out cert.pem \ -keyout key.pem -days 365 -subj "/C=UK/L=Tooting/CN=Dan" \end{lstlisting} Copy the certificate and save it using the Distinguished Encoding Rules (DER) format. \begin{lstlisting}[frame=single] openssl x509 -inform PEM -outform DER -in cert.pem \ -out cert.der \end{lstlisting} Extract the public key from the certificate. \begin{lstlisting}[frame=single] openssl x509 -in cert.pem -pubkey -noout > pubkey.pem \end{lstlisting} Copy the private key and store it using DER. \begin{lstlisting}[frame=single] openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem \ -nocrypt -out key.der \end{lstlisting} Notes: \begin{itemize} \item The private key is produced in PKCS\#8 format. You can look at it with Peter Gutmann's ASN.1 \htmladdnormallinkfoot {object dump program} {http://www.cs.auckland.ac.nz/~pgut001/dumpasn1.c} if required. \item The private key is unencrypted. Storing private keys in clear is not good security practice. The current implementation does not support encrypted private keys but this should be straightforward to add. \end{itemize} Run the examples to examine your private and public keys. \begin{lstlisting}[frame=single] PKCS8Example key.der X509Example cert.der \end{lstlisting} \subsection{Attribute Certificates} \htmladdnormallinkfoot {PERMIS} {http://sec.isi.salford.ac.uk/permis} provides facilities for generating attribute certificates using the \htmladdnormallinkfoot {Attribute Certicate Manager} {http://sec.isi.salford.ac.uk/permis/private/wip.html\#ACM} . Run the example to examine your certificate. \begin{lstlisting}[frame=single] AttributeCertificate attCert.der \end{lstlisting} \subsection{Encryption} Run the example to encrypt using Haskell and decrypt using openssl. Note that only OAEP is supported currently. This is not the default for openssl so you must remember to add the correct option. \begin{lstlisting}[frame=single] echo plaintext > plaintext RSAEncryptionExample --cert=cert.der --plain=plaintext \ --cipher=ciphertext openssl rsautl -decrypt -inkey key.pem -in ciphertext \ -out unciphertext -oaep \end{lstlisting} \subsection{Signing and Verification} Signing is more complicated than encryption so it is best to check that you are using signatures correctly before using the library. You can sign a "small" amount of data with \begin{tt}openssl rsautl\end{tt}. Doing this with more data than allowed by the encryption algorithm will result in error messages. It's important to understand that this operation signs the raw data and does not digest it beforehand. However, the operation does apply the padding algorithm described in the \htmladdnormallinkfoot {PKCS \#1 v2.1: RSA Cryptography Standard} {ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf} and in \htmladdnormallinkfoot {PKCS \#1: RSA Encryption Standard: An RSA Laboratories Technical Note Version 1.5 Revised November 1, 1993} {ftp://ftp.rsasecurity.com/pub/pkcs/ps/pkcs-1.ps} . This prepends the data to be signed with \begin{tt}00 01 ff \ldots ff 00\end{tt} as can be seen below. \begin{lstlisting}[frame=single] echo small > small.txt openssl rsautl -in small.txt -inkey key.pem -sign -out small.sgn openssl rsautl -verify -in small.sgn -inkey pubkey.pem -pubin \ -hexdump -raw \end{lstlisting} \begin{lstlisting} 0000 - 00 01 ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0010 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0020 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0030 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0040 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0050 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0060 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0070 - ff ff ff ff ff ff ff ff-ff 00 73 6d 61 6c 6c 0a ..........small. \end{lstlisting} You can sign larger amounts of data with \begin{tt}openssl dgst\end{tt}. In contrast to \begin{tt}openssl rsautl\end{tt} this digests the data, encodes the digest in \lstset{language=ASN1} \begin{lstlisting}[frame=single] DigestInfo ::= SEQUENCE { digestAlgorithm DigestAlgorithm, digest OCTET STRING } \end{lstlisting} as DER and then encrypts it with the the private key. Again, this DER is prepended with \begin{tt}00 01 ff \ldots ff 00\end{tt} as can be seen below. \lstset{language=shell,basicstyle=\ttfamily\small} \begin{lstlisting}[frame=single] openssl dgst -sha1 -sign key.pem -out ReadMe.sgn ReadMe.tex openssl rsautl -verify -in ReadMe.sgn -inkey pubkey.pem -pubin \ -hexdump -raw \end{lstlisting} \begin{lstlisting} 0000 - 00 01 ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0010 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0020 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0030 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0040 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0050 - ff ff ff ff ff ff ff ff-ff ff ff ff 00 30 21 30 .............0!0 0060 - 09 06 05 2b 0e 03 02 1a-05 00 04 14 90 d0 00 b2 ...+............ 0070 - f6 b3 d7 2f 2c ab e7 40-6a 75 89 7c bb 56 54 19 .../,..@ju.|.VT. \end{lstlisting} The ASN.1 can be parsed using the following command. \begin{lstlisting}[frame=single] openssl rsautl -in ReadMe.sgn -verify -asn1parse \ -inkey pubkey.pem -pubin \end{lstlisting} \begin{lstlisting} 0:d=0 hl=2 l= 33 cons: SEQUENCE 2:d=1 hl=2 l= 9 cons: SEQUENCE 4:d=2 hl=2 l= 5 prim: OBJECT :sha1 11:d=2 hl=2 l= 0 prim: NULL 13:d=1 hl=2 l= 20 prim: OCTET STRING 0000 - 90 d0 00 b2 f6 b3 d7 2f-2c ab e7 40 6a 75 89 7c ......./,..@ju.| 0010 - bb 56 54 19 .VT. \end{lstlisting} As a final verification, compare the parsed digest against a digest of the plaintext file. \begin{lstlisting}[frame=single] openssl dgst -sha1 ReadMe.tex SHA1(ReadMe.tex)= 90d000b2f6b3d72f2cabe7406a75897cbb565419 sha1sum ReadMe.tex 90d000b2f6b3d72f2cabe7406a75897cbb565419 ReadMe.tex \end{lstlisting} Now that you have confirmed that signatures are working satisfactorily, you can verify one using the Haskell example. \begin{lstlisting}[frame=single] RSAVerifyExample -ecert.der -pReadMe.tex -sReadMe.sgn \end{lstlisting} \begin{lstlisting} AlgorithmIdentifier {algorithm1 = OID [1,3,14,3,2,26], parameters1 = Nothing} Given digest: OctetString [144,208,0,178,246,179,215,47,44, \ 171,231,64,106,117,137,124,187,86,84,25] Calculated digest: OctetString [144,208,0,178,246,179,215,47,44,171, \ 231,64,106,117,137,124,187,86,84,25] Verified \end{lstlisting} \section{ASN.1 Support} The package contains some enough general ASN.1 support to decode PKCS\#8 and X.509 identity and attribute certificates encoded using BER. See the examples that are provided with the package: \begin{tt}X509Example\end{tt}, \begin{tt}PKCS8Example\end{tt}, and \begin{tt}AttributeCertificate\end{tt}. Here's a further example. Suppose you have an ASN.1 module and have checked that it conforms to the standard using, for example, the on-line tool, \htmladdnormallinkfoot{Asnp}{http://asn1.elibel.tm.fr/en/tools/asnp/index.htm} \footnote{Definitions using ANY DEFINED BY have to be checked with -1990.} \footnote{Asnp was developed in Objective Caml.} \lstset{language=ASN1} \begin{lstlisting}[frame=single] FooBar {1 2 0 0 6 1} DEFINITIONS ::= BEGIN Journey ::= SEQUENCE { origin IA5String, stop1 [0] IA5String OPTIONAL, stop2 [1] IA5String OPTIONAL, destination IA5String } Odyssey ::= SEQUENCE { start Journey, trip1 [0] Journey OPTIONAL, trip2 [1] Journey OPTIONAL, trip3 [2] Journey OPTIONAL, end Journey } END \end{lstlisting} Create abstract Haskell representations of the ASN.1 types. \lstset{language=Haskell} \begin{lstlisting}[frame=single] journey = "Journey" ::= AbsSeq Universal 16 Implicit [ Regular (Just "origin" :>: (Nothing :@: absIA5String)), Optional (Just "stop1" :>: (Just 0 :@: absIA5String)), Optional (Just "stop2" :>: (Just 1 :@: absIA5String)), Regular (Just "destination" :>: (Nothing :@: absIA5String)) ] odyssey = "Odyssey" ::= AbsSeq Universal 16 Implicit [ Regular (Just "start" :>: (Nothing :@: journey)), Optional (Just "trip1" :>: (Just 0 :@: journey)), Optional (Just "trip2" :>: (Just 1 :@: journey)), Optional (Just "trip3" :>: (Just 2 :@: journey)), Regular (Just "end" :>: (Nothing :@: journey)) ] \end{lstlisting} Then you can check that (abstract representations of) BER values conform to these types. \begin{lstlisting}[frame=single] module Main(main) where import Codec.ASN1.BER import Codec.ASN1 -- Other definitions main = do (w,y) <- typeCheck odyssey berValue putStrLn (show w) \end{lstlisting} Now suppose that the BER value conforms to the ASN.1 type and that you wish to manipulate the various values in the encoding. First create some Haskell types to hold the decoded values. \begin{lstlisting}[frame=single] data Journey = Journey { origin :: IA5String, stop1 :: Maybe IA5String, stop2 :: Maybe IA5String, destination :: IA5String } deriving (Eq,Show) data Odyssey = Odyssey { start :: Journey, trip1 :: Maybe Journey, trip2 :: Maybe Journey, trip3 :: Maybe Journey, end :: Journey } deriving (Eq,Show) \end{lstlisting} Then make them instances of the class {\begin{tt}Encode\end{tt}}. \begin{lstlisting}[frame=single] instance Encode Journey where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ Journey { origin = fromJust (decode (as!!0) (bs!!0)), stop1 = do decode (as!!1) (bs!!1), stop2 = do decode (as!!2) (bs!!2), destination = fromJust (decode (as!!3) (bs!!3)) } instance Encode Odyssey where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ Odyssey { start = fromJust (decode (as!!0) (bs!!0)), trip1 = do decode (as!!1) (bs!!1), trip2 = do decode (as!!2) (bs!!2), trip3 = do decode (as!!3) (bs!!3), end = fromJust (decode (as!!4) (bs!!4)) } \end{lstlisting} Finally, you can extract values from the decoded value. \begin{lstlisting}[frame=single] module Main(main) where import Codec.ASN1.BER import Codec.ASN1 -- Other definitions main = do (w,y) <- typeCheck odyssey berValue let (_ ::= c) = w d = decode c (Just y) (Just x) = d putStrLn . show . start $ x \end{lstlisting} Further examples can be found in {\tt BERTest.hs} \section{To Do} In no particular order: \begin{itemize} \item Read and generate PKCS12 private keys so that it is easy to inter-work with other RSA implementations. \item Incorporate other symmetric key algorithms already coded in Haskell. \item Performance analysis as Blowfish ought to run more quickly than DES. \item Other modes / padding schemes. \item Fix the known issue with ASN.1 CHOICE types where an error in one of the choices will give an error message which indicates that no valid choice was found. It would be better to report an error indicating the problem in choice. \item Although support for {\begin{tt}ANY DEFINED BY\end{tt}} has been improved, it and its replacement in later versions of the ASN.1 standards need yet further improvement. In particular, replace the index number by a label and do not treat as equivalent to {\tt OPTIONAL} or {\tt DEFAULT}. \item Extend typechecking to ensure that only the appropriate key sizes are used for a given algorithm. \item Although some ASN.1 definitions have been put into more appropriate modules, more work needs to be done, for example, {\tt AlgorithmIdentifier}. \item Check lengths for correctness when decoding BER. See the Codec.ASN1.TLV source for more on this. \item Improve the error messages when checking a BER encoding against its ASN.1 specification. Currently the messages say what has failed but does not give the context. \end{itemize} \section{Contact} All questions, comments, bug reports, flames, requests for updates / changes and suggestions should be directed to Dominic Steinitz. \section{Licensing} The modules in the library come from different authors and have been released under different licences. \subsection{Contributors} \subsubsection{Codec.ASN1} \begin{tabular}{|p{6cm}|p{3cm}|p{3cm}|p{1cm}|} \hline\hline Codec.ASN1 & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.ASN1.BER & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.ASN1.PKCS8 & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.ASN1.PKCS1v15 & Dominic Steinitz & Copyright \copyright\ 2006, All rights reserved & BSD \\ \hline Codec.ASN1.TLV & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.ASN1.X509 & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.ASN1.X509.Information\-Framework & Dominic Steinitz & Copyright \copyright\ 2006, All rights reserved & BSD \\ \hline Codec.ASN1.X509.Attribute\-Certificate\-Definitions & Dominic Steinitz & Copyright \copyright\ 2006, All rights reserved & BSD \\ \hline\hline \end{tabular} \subsubsection{Codec.Binary} \begin{tabular}{|p{6cm}|p{3cm}|p{3cm}|p{1cm}|} \hline\hline Codec.Binary.Base64 & Warrick Gray & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline\hline \end{tabular} \subsubsection{Codec.Text} \begin{tabular}{|p{6cm}|p{3cm}|p{3cm}|p{1cm}|} \hline\hline Codec.Text.Raw & Dominic Steinitz & Copyright \copyright\ 2006, All rights reserved & BSD \\ \hline\hline \end{tabular} \subsubsection{Codec.Encryption} \begin{tabular}{|p{6cm}|p{3cm}|p{3cm}|p{1cm}|} \hline\hline Codec.Encryption.AES & Lukasz Anforowicz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.AESAux & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.Blowfish & Doug Hoyte & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.BlowfishAux & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.DES & Ian Lynagh & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.DESAux & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.Modes & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.Padding & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.RSA & David Sankel & Copyright \copyright\ 2005, All rights reserved & GPL \\ \hline Codec.Encryption.RSA.EMEOAEP & David Sankel & Copyright \copyright\ 2005, All rights reserved & GPL \\ \hline Codec.Encryption.RSA.MGF & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Codec.Encryption.RSA.NumberTheory & David Sankel & Copyright \copyright\ 2005, All rights reserved & GPL \\ \hline\hline \end{tabular} \subsubsection{Codec} \begin{tabular}{|p{6cm}|p{3cm}|p{3cm}|p{1cm}|} \hline\hline Codec.Utils & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline\hline \end{tabular} \subsubsection{Data.Digest} \begin{tabular}{|p{6cm}|p{3cm}|p{3cm}|p{1cm}|} \hline\hline Data.Digest.MD5 & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Data.Digest.MD5Aux & Ian Lynagh & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Data.Digest.SHA1 & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline Data.Digest.SHA1Aux & Ian Lynagh & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline\hline \end{tabular} \subsubsection{Data} \begin{tabular}{|p{6cm}|p{3cm}|p{3cm}|p{1cm}|} \hline\hline Data.LargeWord & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline\hline \end{tabular} \subsubsection{Tests and Examples} \begin{tabular}{|p{6cm}|p{3cm}|p{3cm}|p{1cm}|} \hline\hline BERTest & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline RSATest & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline X509Example & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline QuickTest & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline SymmetricTest & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline PKCS8Example & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline RSAEncryptionExample & Dominic Steinitz & Copyright \copyright\ 2005, All rights reserved & BSD \\ \hline AttributeCertificate & Dominic Steinitz & Copyright \copyright\ 2006, All rights reserved & BSD \\ \hline RSAVerifyExample & Dominic Steinitz & Copyright \copyright\ 2006, All rights reserved & BSD \\ \hline\hline \end{tabular} \subsection{The BSD License} This license is based on \htmladdnormallinkfoot {The BSD License} {http://www.opensource.org/licenses/bsd-license.php}. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: \begin{itemize} \item Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. \item Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. \item The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. \end{itemize} \begin{sc} This software is provided by the copyright holders and contributors ``AS IS'' and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright onwers or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. \end{sc} \subsection{The GNU General Public License (GPL)} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You can find a copy of the GNU General Public License \htmladdnormallinkfoot {here} {http://www.opensource.org/licenses/gpl-license.php} ; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \section{Disclaimer} Cryptography is a notoriously easy area in which to make mistakes, not necessarily with the algorithms but with how they are implemented (for example not protecting keys, using weak keys and so on). For a readable account of some of the pitfalls, see \htmladdnormallinkfoot {Ross Anderson} {http://www.cl.cam.ac.uk/users/rja14/} 's book. \begin{sc} This software is provided by the copyright holders and contributors ``AS IS'' and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright onwers or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. \end{sc} \section{Acknowledgements} \begin{itemize} \item Doug Hoyte (HardCore SoftWare) \item \htmladdnormallinkfoot {Ian Lynagh} {http://web.comlab.ox.ac.uk/oucl/work/ian.lynagh} \item \htmladdnormallinkfoot {David Sankel} {http://www.electronconsulting.com/whois.html} \item \htmladdnormallinkfoot {Ross Paterson} {http://www.soi.city.ac.uk/~ross} \item Lukasz Anforowicz \item \htmladdnormallinkfoot {Warrick Gray} {http://homepages.paradise.net.nz/warrickg/haskell/http/} \end{itemize} This document was last updated on 1st April 2006. \copyright\ 2006 Dominic Steinitz. \end{document}