I am writing an application that uses OpenSSL 256-bit AES CBC
encryption on a Windows system to communicate with a UNIX web
application written in Perl using Crypt::CBC with the
Crypt::OpenSSL::AES cipher.  After a lot of experimentation
and testing, it appears that the two AES CBC implementations
are not compatible.  Technically, the Perl AES implementation
is supposed to use the OpenSSL library for encryption and
decryption, so I am a little confused on why this is not
working.

I have looked at the source for Crypt::CBC and found that
the Perl implementation does a conversion of the key into an
MD5 hash -- to override this behavior, I pass "-literal-key => 1"
when I create the cipher object in Perl.  I have also set
parameters that override the salt header in Perl and set the
padding to null bytes.

To analyze the problem, I wrote two command line test apps.
The client side app prompts for text input, encrypts the
string, converts it to hex, and prints it (it also does some
internal validation).  The server side app reads the hex encoded
input strings, decodes them using Crypt::CBC, and print the
decoded result.  The Perl side is not able to correctly
decode encrypted data from the Windows app.

For the encrypting side, I am running OpenSSL version 0.9.8i
on Windows Vista Ultimate.  The application is written in C
using Visual Studio 9.0.  On the server (Perl) side, I am
using Perl 5.8.8 with Crypt::CBC 2.30, Crypt::OpenSSL::AES
0.02, and FreeBSD 7.0 with OpenSSL 0.9.8e.

I have included copies of both the encrypting and decrypting
test apps below (these are to be run from the command line).
I would really appreciate any pointers or suggestions from the
group that would allow me to get these two AES CBC apps to
talk to each other.

Dave Stoddard

====================================
Client (Encrypting) Test Application
Windows Vista
OpenSSL 0.9.8i
Visual Studio C/C++ 9.0
====================================

# include <stdio.h>
# include <ctype.h>
# include <string.h>

# include "openssl/aes.h"

# define BLOCK_LEN      16
# define MAXBUF         65536
# define KEY            "abcdefghijklmnopqrstuvwxyz012345"
# define IV             "RandomIVRandomIV"

// function prototypes
int bin2hex (unsigned char *pinp, unsigned char *pout, unsigned int len);
int hex2bin (unsigned char *pinp, unsigned char *pout, unsigned int len);

int
main (int argc, char *argv[])
{
  unsigned long olen;
  unsigned char data[MAXBUF];   // command line input
  unsigned char dbuf[MAXBUF];   // decrypt output
  unsigned char ibuf[MAXBUF];   // encrypt input
  unsigned char obuf[MAXBUF];   // encrypt output
  unsigned char xbuf[MAXBUF];   // hex encrypt output
  unsigned char ybuf[MAXBUF];   // hex encrypt output
  unsigned char key[] = KEY;
  unsigned char iv[]  = IV;
  AES_KEY aeskeyEnc, aeskeyDec;

  // loop through user input
  while (1) {

    // read input
    printf ("input> ");
    gets_s (data,MAXBUF);

    // check for exit
    if (strcmp (data,"exit") == 0)
      break;
    if (strcmp (data,"quit") == 0)
      break;

    // printf ("input: %s (len = %d)\n", data, strlen(data));

    // prepare the input data with padding
    memset (ibuf, 0x00, sizeof (ibuf));
    memcpy_s (ibuf, sizeof (ibuf), data, strlen (data));

    // calc length of aes output block
    olen = ((int)(strlen (data) / BLOCK_LEN) * BLOCK_LEN) + 32;
 
    // init cipher keys 
    AES_set_encrypt_key (key, 256, &aeskeyEnc);
    AES_set_decrypt_key (key, 256, &aeskeyDec);

    // encrypt string
    memcpy_s (iv, sizeof (iv), IV, sizeof (IV));
    AES_cbc_encrypt (ibuf, obuf, olen, &aeskeyEnc, iv, AES_ENCRYPT);

    // convert encoded string to hex and display
    bin2hex (obuf,xbuf,olen);
    printf ("encode: %s (len = %d)\n", xbuf, (int) strlen (xbuf));

    // convert hex string to binary
    hex2bin (xbuf, ybuf, (int) strlen(xbuf));

    // compare binary values
    if (memcmp (obuf, ybuf, olen) != 0) {
      printf ("HEX FAILED!\n");
      return (0);
    }

    // decrypt string
    memcpy_s (iv, sizeof (iv), IV, sizeof (IV));
    AES_cbc_encrypt (ybuf, dbuf, olen, &aeskeyDec, iv, AES_DECRYPT);
    printf ("decode: %s (len = %d)\n", dbuf, strlen(dbuf));

    // compare binary values
    if (memcmp (data, dbuf, (unsigned int) strlen (data)) != 0) {
      printf ("DECODE FAILED!\n");
      return (0);
    }

    printf ("\n");
  } // while (1)

  return (0);
}

int
bin2hex (unsigned char *pcIbuf, unsigned char *pszObuf, unsigned int ilen)
{
  unsigned int  i;                      // loop iteration counter
  unsigned int  j = (ilen * 2) + 1;     // output buffer length
  unsigned char *p;

  p = pszObuf;          // point to start of output buffer

  for (i = 0; i < ilen; i++) {
    sprintf_s (p, j, "%2.2x", (unsigned char) pcIbuf [i]);
    p += 2;
  }
  *p = '\0';
  return (0);
}

int
hex2bin (unsigned char *pszIbuf, unsigned char *pcObuf, unsigned int ilen)
{
  unsigned int   i;                     // loop iteration variable
  unsigned int   j;                     // current character
  unsigned int   by = 0;                // byte value for conversion
  unsigned char  ch;                    // current character

  // process the list of characters
  for (i = 0; i < ilen; i++) {
    ch = toupper(*pszIbuf++);           // get next character

    // do the conversion
    if(ch >= '0' && ch <= '9')
      by = (by << 4) + ch - '0';
    else if(ch >= 'A' && ch <= 'F')
      by = (by << 4) + ch - 'A' + 10;
    else {                                      // error if not hexadecimal
      memcpy (pcObuf,"ERROR",5);
      return 0;
    }

    // store a byte for each pair of hexadecimal digits
    if (i & 1) {
      j = ((i + 1) / 2) - 1;
      pcObuf [j] = by & 0xff;
    }
  }

  return (j);
}

// end of client test app

================================
Server Decoding Test App in Perl
FreeBSD 7.0 UNIX
OpenSSL 0.9.8e
Perl 5.8.8
Crypt::CBC 2.30
Crypt::OpenSSL::AES 0.02
================================

#!/usr/bin/perl
use strict; 
use Crypt::CBC;
 
my $obj     = "";
my $len     = "";
my $key     = "abcdefghijklmnopqrstuvwxyz012345";
my $iv      = "RandomIVRandomIV";
my $meth    = "Crypt::OpenSSL::AES";
my $decdata = "";
 
print "coded hex input> ";
while (<STDIN>) {
  chomp;
  last if ($_ eq "exit");
  last if ($_ eq "quit");
 
  $obj = Crypt::CBC->new (
    -key         => $key,
    -padding     => "null",
    -header      => "none",
    -literal-key => 1,
    -iv          => $iv,
    -cipher      => $meth
  );
 
  # decrypt data
  $decdata   = $obj->decrypt_hex ($_);
  $len       = length ($decdata);
  print "decoded: $decdata (len = $len)\n";
 
  # input prompt
  print "\ncoded hex input> ";
}
 
exit 0;

# end of Perl app


______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to