talexb has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to encrypt some information and add it to a web page form via a hidden form variable. The problem I am having is that I can't figure out how long the pack and unpack are supposed to be.

In other words, is the length of the encrypted data the same as the original data? It seems that it should be. My test code is as follows:

my $What = "Some text to be encrypted."; my $Length = length ( $What ) * 2; my $Cipher = Crypt::CBC->new ( [ key => $DBITT::CryptString ] ); my $CipherText = $Cipher->encrypt ( $What ); my $ASCII = unpack ( "H$Length", $CipherText ); print "Encrypted result of $What is $ASCII."; print " That was " . length ( $ASCII ) . " bytes long.\n"; my $PlainText = $Cipher->decrypt ( $CipherText ); print "And back into the real world we have '$PlainText'.\n"; $PlainText = $Cipher->decrypt ( pack ( "H$Length", $ASCII ) ); print "Try via ASCII string it's '$PlainText'.\n";

and when I run it I get

Encrypted result of Some text to be encrypted. is 52616e646f6d49568bd87928f7ccbbbef6b6fcd504407b611fd9. That was 52 bytes long. And back into the real world we have 'Some text to be encrypted.'. Try via ASCII string it's ''.
The two values of $PlainText don't match. Assistance would be greatly appreciated.

--t. alex

"Here's the chocolates, and here's the flowers. Now how 'bout it, widder hen, will ya marry me?" --Foghorn Leghorn

Replies are listed 'Best First'.
Re: Length of Crypt::CBC result
by tachyon (Chancellor) on Apr 04, 2002 at 01:58 UTC

    You need to read up on pack and unpack The * is a useful widget and using it fixes your problem.

    use Crypt::CBC; my $What = "Some text to be encrypted."; # my $Length = length ( $What ) * 2; my $Cipher = Crypt::CBC->new ( [ key => $DBITT::CryptString ] ); my $CipherText = $Cipher->encrypt ( $What ); my $ASCII = unpack ( "H*", $CipherText ); print "Encrypted result of $What is $ASCII.\n"; print " That was " . length ( $ASCII ) . " bytes long.\n"; my $PlainText = $Cipher->decrypt ( $CipherText ); print "And back into the real world we have '$PlainText'.\n"; $PlainText = $Cipher->decrypt ( pack ( "H*", $ASCII ) ); print "Try via ASCII string it's '$PlainText'.\n"; __DATA__ Encrypted result of Some text to be encrypted. is 52616e646f6d49569aee +93f3d204172c101f93dcae2a2a94dd1142acf98a0067bdf2f0edfcb06b3543f3cf8d0 +5decc33. That was 96 bytes long. And back into the real world we have 'Some text to be encrypted.'. Try via ASCII string it's 'Some text to be encrypted.'.

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      I swear that I tried out "H*" and it failed with flying colours. And now I try it again and I can see plainly that it works. Oy.

      Murphy lives. Thanks.

      --t. alex

      "Here's the chocolates, and here's the flowers. Now how 'bout it, widder hen, will ya marry me?" --Foghorn Leghorn

Re: Length of Crypt::CBC result
by rjray (Chaplain) on Apr 04, 2002 at 01:42 UTC

    Block-chain ciphers are (IIRC) always on 8-byte boundaries. This means that if the input text is not an even multipe-of-8 bytes in length, it gets padded in such a way that the decryption stage knows to discard the padding.

    That having been said, your input string is 26 bytes long. Padding to an 8-byte boundary would yield a block of 32 bytes. I'm not sure why you are taking the length and multiplying it by two, except that you are displaying hexadecimal and may be under the impression that the hex value "aa" requires two bytes simply because it is two characters when printed-- it's still one byte (decimal value 170, in fact).

    --rjray

Re: Length of Crypt::CBC result
by cacharbe (Curate) on Apr 04, 2002 at 02:01 UTC
Re: Length of Crypt::CBC result
by Ryszard (Priest) on Apr 04, 2002 at 11:45 UTC
    Given that no one has mentioned it yet, encrypting information and sending it back to the browser is generally considered bad form. (I'm making the assumption here that your not using said information as a sess_id).

    The reason it is generally considered bad form is you have no control over the data:

    1. Consider a replay attack. Someone gets the encrypted information stores it for a while and sends it back.
    2. Consider a crack of the cypher. Someone determines the plaintext, modifies it and sends it back (not to mention your entire application is now exposed).
    3. Consider a corruption. Someone arbitrarily changes some bytes and sends it back. It may decrypt and crash (or worse!) your application.

    For these reasons (and others) the safest method of managing state, is by sending a non determinate token to the browser as a cookie (or in a url), then retrieving the token and looking up the associated details.

    You now have complete control over when, where, how and the manipulation of the data.

      The reason it is generally considered bad form is you have no control over the data:
      1. Consider a replay attack. Someone gets the encrypted information stores it for a while and sends it back.

        I have other measures to counter a replay attack -- the data can only be entered into the database once. Replays fail if the record already exists in the database.

      2. Consider a crack of the cypher. Someone determines the plaintext, modifies it and sends it back (not to mention your entire application is now exposed).

        Interesting point -- I'll amend my approach to modify the data before encryption, then reverse that process when it comes out the other side.

      3. Consider a corruption. Someone arbitrarily changes some bytes and sends it back. It may decrypt and crash (or worse!) your application.

        I'll have to live with that .. it's been a while since I saw a web page corrupted.

      --t. alex

      "Here's the chocolates, and here's the flowers. Now how 'bout it, widder hen, will ya marry me?" --Foghorn Leghorn

      This is NOT a bad idea. 1) Associate an expire time, and ip address with the data being stored. 2) Also change the private key every day. 3) eval it. Why use a session cookie, or other means when you can do the above?
        Ok, so there are methods that can be used to make the data more secure (altho' using an IP address is not a great idea).

        My point is control. Once you send the data out to the browser you lose control.

        If you have a public web server, most of your server side security should already be done. Why create more processes and procedures if you dont need to? The more processes and procedures you add, the greater the chance something could be missed.

        There is a reason why most web apps use a non determinate token and associated session management - it works and it simple to do.

Re: Length of Crypt::CBC result
by Anonymous Monk on Apr 04, 2002 at 17:21 UTC
    Why use pack at all? Try this:
    use Crypt::CBC; use Storable qw(freeze thaw); use MIME::Base64 qw(encode_base64 decode_base64); my $priv_key = "fdslgjlsdgjl flds"; my $encrypt_method = "Crypt::Blowfish"; my $cipher = new Crypt::CBC($priv_key,$encrypt_method); sub save { my $data = shift; #data struct you want to save return encode_base64($cipher->encrypt(freeze($data)),""); } sub reload { my $string = shift; #string you got back from form return thaw($cipher->decrypt(decode_base64($string))); }
    I use this to preserve the state in a cookie typically, but you could also pass it along in a form. If you want to pass it in the uri you need to translate some chars (I don't remember which ones though).
Re: Length of Crypt::CBC result
by no_slogan (Deacon) on Apr 04, 2002 at 19:37 UTC
    Yes, the Crypt::CBC output is longer than the original text. That's because it
    • Pads the string to a multiple of the cipher block size (usually 8 bytes)
    • Prepends a one-block random initialization vector (IV)
    • Prepends the string "RandomIV"
    Newer versions of Crypt::CBC let you control some of the IV behavior. A random IV is a Good Thing, though, because it prevents the same message from being encrypted to the same ciphertext every time.