Title: Win32 base64 and DES
I'm having a problem with DES encryption combined with base64 encoding.

I've built the openssl 0.9.7i static libraries (with ssl) on Win32 and I've done so on Mac OS X 10.4.  On both the encrypt then decrypt loop fails once the data gets to large.

I'm able to use the code fine on openssl 0.9.7b.

Noticed in the change log that a fix was made to base64, maybe that is the problem.
--
 Changes between 0.9.7b and 0.9.7c  [30 Sep 2003]

  *) Various fixes to base64 BIO and non blocking I/O. On write
     flushes were not handled properly if the BIO retried. On read
     data was not being buffered properly and had various logic bugs.
     This also affects blocking I/O when the data being decoded is a
     certain size.
     [Steve Henson]
--

This looks like a bug to me.

-----------------------------

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

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/conf.h>

#undef SIZE
#define SIZE     (512)

#undef BSIZE
#define BSIZE  (8*1024)

#define IFDEBUG(code) code

static int MYENC_IS_INITED = 0;

void initOpenSsl()
{
    if(!MYENC_IS_INITED)
    {       //only add the algorithms once
          #if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WIN16) || defined(OPENSSL_SYS_WIN32)
                      printf("CRYPTO_malloc_init\n");
                CRYPTO_malloc_init();
           #endif

          OpenSSL_add_all_algorithms();
           //SSLeay_add_all_algorithms();
          MYENC_IS_INITED = 1;
    }
}

char* base64DESEncrypt (int enc, const char *pass, const char *data, size_t *dataSize)
{
       char* ret=NULL;
static const char magic[]="Salted__";
   char mbuf[sizeof magic-1];
      unsigned char *buff=NULL;
       int bsize=BSIZE;
        int inl;
        unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH];
    unsigned char salt[PKCS5_SALT_LEN];
     const char *str=pass;
   char *hkey=NULL,*hiv=NULL,*hsalt = NULL;
        int printkey=0,base64=0;
        int debug=0,nosalt=0;
   const EVP_CIPHER *cipher=NULL;
  EVP_CIPHER_CTX *ctx = NULL;
     BIO *in=NULL,*out=NULL,*b64=NULL,*benc=NULL,*rbio=NULL,*wbio=NULL;
      int bytesWritten;

       initOpenSsl();

  IFDEBUG(BIO *bio_err=NULL);
     #if TARGET_OS_WIN32
             IFDEBUG(
                                if((bio_err=BIO_new(BIO_s_file())) != NULL)
                                     BIO_set_fp(bio_err,stdout,BIO_NOCLOSE|BIO_FP_TEXT);
                     )
       #else
           IFDEBUG(
                                if((bio_err=BIO_new(BIO_s_file())) != NULL)
                                     BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
                     )
       #endif //TARGET_OS_WIN32

        cipher=EVP_get_cipherbyname("des");
     if(cipher == NULL)
      {
               IFDEBUG(BIO_printf(bio_err,"%s is an unknown cipher\n", "des"));
                goto end;
       }

       nosalt=0;       //use salt
      IFDEBUG(debug=1);
       base64=1;

       buff=(unsigned char *)OPENSSL_malloc(EVP_ENCODE_LENGTH(bsize));
if(buff == NULL)
        {
               IFDEBUG(BIO_printf(bio_err,"OPENSSL_malloc failure %ld\n",(long)EVP_ENCODE_LENGTH(bsize)));
             goto end;
       }

       in=BIO_new(BIO_s_mem());
        bytesWritten = BIO_write(in, data, *dataSize);
  if(BIO_flush(in) != 1)
  {
               IFDEBUG(BIO_printf(bio_err, "error flush in data\n");)
          goto end;
       }

       out=BIO_new(BIO_s_mem());

       if ((in == NULL) || (out == NULL))
      {
               IFDEBUG(ERR_print_errors(bio_err));
             goto end;
       }
       if (debug)
      {
               BIO_set_callback(in,BIO_debug_callback);
                BIO_set_callback(out,BIO_debug_callback);
               BIO_set_callback_arg(in,bio_err);
               BIO_set_callback_arg(out,bio_err);
      }

       rbio=in;
        wbio=out;

       if(base64)
      {
               if((b64=BIO_new(BIO_f_base64())) == NULL)
                       goto end;
               if (debug)
              {
                       BIO_set_callback(b64,BIO_debug_callback);
                       BIO_set_callback_arg(b64,bio_err);
              }
               if(enc)
                wbio=BIO_push(b64,wbio);
                else
                    rbio=BIO_push(b64,rbio);
        }

       if (cipher != NULL)
     {
               /* Note that str is NULL if a key was passed on the command
             * line, so we get no salt in that case. Is this a bug?
        */
             if (str != NULL)
                {
                       /* Salt handling: if encrypting generate a salt and
                     * write to output BIO. If decrypting read salt from
                    * input BIO.
                   */
                     unsigned char *sptr;
                    if(nosalt)
                              sptr = NULL;
                    else
                    {
                               if(enc)
                        {
                                       if(hsalt)
                                       {
                                               if(!set_hex(hsalt,salt,sizeof salt))
                                                {
                                                       IFDEBUG(BIO_printf(bio_err, "invalid hex salt value\n"));
                                                       goto end;
                                               }
                                       }
                                       else if (RAND_pseudo_bytes(salt, sizeof salt) < 0)
                                              goto end;
                                       /* If -P option then don't bother writing */
                                    if((printkey != 2)
                                              && (BIO_write(wbio,magic,
                                                       sizeof magic-1) != sizeof magic-1
                                                      || BIO_write(wbio,
                                                             (char *)salt,
                                                          sizeof salt) != sizeof salt))
                                  {
                                               IFDEBUG(BIO_printf(bio_err,"error writing output file\n"));
                                             goto end;
                                       }
                               }
                               else if(BIO_read(rbio,mbuf,sizeof mbuf) != sizeof mbuf
                                  || BIO_read(rbio,
                                                       (unsigned char *)salt,
                                        sizeof salt) != sizeof salt)
                            {
                                       IFDEBUG(BIO_printf(bio_err,"error reading input file\n"));
                                      goto end;
                               }
                               else if(memcmp(mbuf,magic,sizeof magic-1))
                              {
                                       IFDEBUG(BIO_printf(bio_err,"bad magic number\n"));
                                      goto end;
                               }

                               sptr = salt;
                    }

                       EVP_BytesToKey(cipher,
                                                          EVP_md5(),
                                                              sptr,
                                                           (unsigned char *)str,
                                                           strlen(str),
                                                            1,
                                                              key,
                                                            iv);
            }
               if ((hiv != NULL) && !set_hex(hiv,iv,sizeof iv))
                {
                       IFDEBUG(BIO_printf(bio_err,"invalid hex iv value\n"));
                  goto end;
               }
               if ((hiv == NULL) && (str == NULL))
             {
                       /* No IV was explicitly set and no IV was generated
                     * during EVP_BytesToKey. Hence the IV is undefined,
                    * making correct decryption impossible. */
                     IFDEBUG(BIO_printf(bio_err, "iv undefined\n"));
                goto end;
               }
               if ((hkey != NULL) && !set_hex(hkey,key,sizeof key))
            {
                       IFDEBUG(BIO_printf(bio_err,"invalid hex key value\n"));
                goto end;
               }

               if ((benc=BIO_new(BIO_f_cipher())) == NULL)
                     goto end;

               /* Since we may be changing parameters work on the encryption
           * context rather than calling BIO_set_cipher().
                */
             //old way
               //BIO_set_cipher(benc,cipher,key,iv,enc);
               //new way
               BIO_get_cipher_ctx(benc, &ctx);
        if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc))
             {
                       IFDEBUG(BIO_printf(bio_err, "Error setting cipher %s\n",
                                        EVP_CIPHER_name(cipher)));
                      IFDEBUG(ERR_print_errors(bio_err));
                     goto end;
               }
               if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc))
          {
                       BIO_printf(bio_err, "Error setting cipher %s\n",
                                        EVP_CIPHER_name(cipher));
                       ERR_print_errors(bio_err);
                      goto end;
               }

               if(debug)
               {
                       BIO_set_callback(benc,BIO_debug_callback);
                      BIO_set_callback_arg(benc,bio_err);
             }

       }

       /* Only encrypt/decrypt as we write the file */
if (benc != NULL)
               wbio=BIO_push(benc,wbio);

       for (;;)
        {
               inl=BIO_read(rbio,(char *)buff,bsize);
          if (inl <= 0) break;
            if (BIO_write(wbio,(char *)buff,inl) != inl)
            {
                       IFDEBUG(BIO_printf(bio_err,"error writing output file\n"));
                     goto end;
               }
       }
       if (!BIO_flush(wbio))
   {
               IFDEBUG(BIO_printf(bio_err,"bad decrypt\n"));
           goto end;
       }

       char *theBuf;
   *dataSize = BIO_get_mem_data(wbio, &theBuf);
    char *returnBuf = (char*)malloc((*dataSize)+1);
returnBuf[*dataSize] = NULL;
    memcpy(returnBuf, theBuf, *dataSize);

   ret=returnBuf;

end:
      IFDEBUG(ERR_print_errors(bio_err));
     if (buff != NULL) OPENSSL_free(buff);
   if (in != NULL) BIO_free(in);
   if (out != NULL) BIO_free_all(out);
     if (benc != NULL) BIO_free(benc);
       if (b64 != NULL) BIO_free(b64);

IFDEBUG(printf("base64DESEncrypt end\n"));
      return ret;
}

void doTest_helper(int size)
{
       char* key = "xxx";
      char *buf = (char*)malloc(sizeof(char)*(size+1));
       int i; for(i = 0; i < size; i++)
                buf[i] = ('a'+(i % 26));
        buf[size] = (char)NULL;

size_t dataSize = strlen(buf);
  char* encryptedStr = base64DESEncrypt(
                  myenc_ENCRYPT,
                  key,
                    buf,
                    &dataSize);

     char* decryptedStr = base64DESEncrypt(
          myenc_DECRYPT,
          key,
            encryptedStr,
           &dataSize);
     printf("decryptedStr:\n'%s'", decryptedStr);
    printf("\n\n=============================\n\n");
       
}

void doTest()
{
int i; for(i = 736; i < 2000; i+=10)
    {
               doTest_helper(i);
       }
}

Reply via email to