CGI::EncryptForm - Implement trusted stateful CGI Form Data using cryptography.

CHANGES
Revision history for CGI::EncryptForm

1.01 1999-10-20

	- Removed dependancy on Math::TrulyRandom because of portability issues.
    Replaced random number generator with perl's builtin rand(). Given
    the purpose of this module, I believe rand() will surfice.
    If you disagree make me understand why and I will look into it further.

1.00 1999-10-18

  -	First Release

AUTHOR
    Copyright 1999, Peter Marelas. All rights reserved.

    This library is free software; you can redistribute it and/or
    modify it under the same terms as Perl itself.

    Bug reports and comments to maral@phase-one.com.au.

    Thanks to the authors of these fine perl modules Storable,
    Math::TrulyRandom, Digest::SHA1, Crypt::HCE_SHA and CGI.

INSTALLATION

    perl Makefile.PL
		make test
		make install

SYNOPSIS
      use CGI::EncryptForm;
      
      my $cfo = new CGI::EncryptForm(secret_key => 'my secret');
      
      my $hashref = { username => 'joe', password => 'test' };

      my $encrypted_string = $cfo->encrypt($hashref);
      if ($encrypted_string == -1) {
        print $cfo->error();
        return;
      }

      my $newhashref = $cfo->decrypt($encrypted_string);
      if ($newhashref == -1) {
        print $cfo->error();
        return;
      }

PREREQUISITES
    This modules requires the following perl modules:

    Math::TrulyRandom, Digest::SHA1, Crypt::HCE_SHA and Storable

ABSTRACT
    Many CGI programmers take for granted the validity of stateful
    CGI form data.

    Im talking about the common scenario where you present a form to
    the browser, the user fills in the form, you verify the form
    values, store them in the next form as hidden fields, the user
    fills in another form, the script appends these results to the
    next form in hidden fields and so on.

    Using hidden form fields is one mechanism where by CGI scripts
    can maintain state in the process of collecting information from
    the user.

    Unfortunately, it is also one of the weakest to implement
    because the CGI script must trust the hidden form fields and
    there values, provided by the users browser. At some point in
    time the CGI program does something with this stateful
    information. To be completely sure the hidden fields haven't
    been altered along the way and thus rendered initial
    verification checks useless, the programmer must continually
    verify all new form fields and previous state (encapsulated in
    hidden form fields) to be sure the desired constraints are met.
    This process of verification becomes tedious to program
    especially if there are many forms required to produce a final
    result.

    To tackle this problem I created CGI::EncryptForm, where by
    instead of including state in hidden form fields verbatim, we
    use SHA1 encryption algorithm to provide a satisfactory level of
    trust between the users browser and the CGI script.

DESCRIPTION
    An object is created with a secret key defined by the CGI
    script. The objects encrypt() method is called with a perl data
    structure, which in the context of CGI scripts would normally
    contain key/value pairs. The encrypt() method returns an
    encrypted string. The encrypted string is stored in a hidden
    form field. The user fills in the form. The CGI script processes
    the form, extracts the encrypted string from the hidden form
    field, decrypts the string and returns the original data
    structure. Further results from the form are added to the data
    structure, then it is encrypted again and stored in the next
    form as a hidden field. This process continues until the CGI
    script has all the desired information and is ready to process
    it. To process the results, the CGI script decrypts the
    encrypted string from the last hidden form field, which contains
    the collective state of all previous form input.

    Along the way, the users input was verified only once. The fact
    that state was encrypted and therefore trusted, renders the
    process of continually verifying all state for each form
    processed, unnecessary.

METHODS
    new CGI::EncryptForm([secret_key => $s [, autoescape => $a]])
        Create a new CGI::EncryptForm object. All of the paramaters
        are optional. $s specifies the secret key to use during
        encryption/decryption. $a specifies whether to enable (1) or
        disable (0) the automatic URL escape/unescape of the
        encrypted/decrypted result. By default this is enabled.

    encrypt($hashref)
        Encrypt the data structure and return an encrypted string.
        $hashref must be a reference to an associative array
        supported by the Storable module. If called with no
        arguement, returns the previous encrypted string.

        Upon error, the method returns -1 and sets error().

    decrypt($encrypted_string)
        Decrypt the encrypted string and return a reference to an
        associative array. $encrypted_string must be a scalar
        previously generated by encrypt(). If called with no
        arguement, returns the previous reference.

        Upon error, the method returns -1 and sets error(). If the
        encrypted string is tampered with the decryption routine
        should fail with -1, but this is ultimately dependant on the
        strength of SHA1 digests.

    secret_key($secret)
        Sets the secret key for use during encryption/decryption.
        This method is analogues to the secret_key paramater when
        creating a CGI::EncryptForm object. If called with no
        $secret it returns the current secret key or -1 if
        undefined.

        Upon error, the method returns -1 and sets error().

    autoescape(1)
        Enables or disables the automatic URL escape/unescape of
        encrypted/decrypted strings. This method is analogues to the
        autoescape paramater when creating a CGI::EncryptForm
        object. By default autoescape is enabled (1) and should be
        ignored unless you use this module in non CGI programs.

    error()
        Returns the last error as a scalar. You would normally read
        this if any method returns -1. error() is always cleared for
        each method that executes successfully.

EXAMPLE
    This example illustrates the use of CGI::EncryptForm in
    combination with CGI.pm to maintain stateful information in a
    multi-form CGI script.

      #!/usr/local/bin/perl

      use CGI::EncryptForm;
      use CGI;

      my $cgi = new CGI();
      my $cfo = new CGI::EncryptForm(secret_key => 'blah');

      print $cgi->header(), $cgi->start_html(), $cgi->start_form();

      if (defined $cgi->param('enc')) {
          form3();
      }
      elsif (defined $cgi->param('something')) {
          form2();
      }
      else {
          form1();
      }

      print $cgi->end_html(), $cgi->end_form();

      sub form1 {

        print "<h1>form1</h1>",
              "Type something and we will remember it: ",
              $cgi->textfield('something'), $cgi->submit();
      }

      sub form2 {

        print "<h1>form2</h1>",
              $cgi->hidden(-name=>'enc', value=>$cfo->encrypt({ $cgi->Vars })),
              "Now click here and I will tell you what you typed based on ",
              "the encrypted hidden form field, which you would normally ",
              "only see if you view the HTML source. For the sake of this ",
              "demonstration the encrypted field is included below.<p>",
              $cfo->encrypt(), "<p>",
              "Before proceeding with this form I suggest you take note of ",
              "what the encrypted field looks like, then click the back ",
              "button and resubmit the previous form with the same value ",
              "again. What you will notice is the encrypted field will ",
              "change. This is because the SHA encryption algorithm is ",
              "based on a secret key and a random key. In the module we ",
              "take care of generating a unique random key for each ",
              "invocation of the encryption routine, which is why a ",
              "distinct encrypted string is produced each time.",
              "<p>", $cgi->submit();
      }

      sub form3 {

        my $hashref = $cfo->decrypt($cgi->param('enc'));
        if ($hashref == -1) {
          print $cfo->error();
          return;
        }
        print "<h1>form3</h1>",
              "Previously in the first form you typed:<p>", $hashref->{something},
              "<p>We reproduced this data by decrypting the hidden form ",
              "field called 'enc', which was passed to us from the previous ",
              "form. You may like to try and tamper with the hidden form ",
              "field in form2, to see if you can alter the result of the ",
              "data as it originally flows from form 1 to form 3. Good luck";
      }

BUGS
    None that I know of.

TODO
    Math::TrulyRandom may be replaced with an alternative in the
    near future, as it is expensive in computing terms.

SEE ALSO
    Storable, Digest::SHA1, Digest::HCE_SHA1, Math::TrulyRandom