libclamav/conv.c
b2e7c931
 /*
  *  Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
  *
  *  Author: Shawn Webb
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  *
  *  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 should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
  */
 
 #if HAVE_CONF_H
 #include "clamav-config.h"
 #endif
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
 #include <math.h>
 
 #include <sys/types.h>
 
60d8d2c3
 #include "clamav.h"
b2e7c931
 #include <openssl/bio.h>
 #include <openssl/evp.h>
 
 #include "libclamav/conv.h"
 
 /** Get the expected decoded length of a base64-encoded string
  * @param[in] data Base64-encoded string
  * @param[in] len length of the string
  * @return The expected decoded length of the base64-encoded string
  */
 static size_t base64_len(const char *data, size_t len)
 {
     int padding=0;
     size_t i;
 
     if (!len)
         return 0;
 
     for (i=len-1; i > 0 && data[i] == '='; i--)
         padding++;
 
     return (size_t)((3*len)/4 - padding);
 }
 
 /** Decode a base64-encoded string
  * @param[in] data The base64-encoded string
  * @param[in] len Length of the base64-encoded string
  * @param[out] obuf If obuf is not set to NULL, store the decoded data in obuf. Otherwise, the decoded data is stored in a dynamically-allocated buffer.
  * @param[out] olen The length of the decoded data
  * @return The base64-decoded data
  */
30a75097
 void *cl_base64_decode(char *data, size_t len, void *obuf, size_t *olen, int oneline)
b2e7c931
 {
     BIO *bio, *b64;
cd94be7a
     void *buf;
b2e7c931
 
     buf = (obuf) ? obuf : malloc(base64_len(data, len)+1);
     if (!(buf))
         return NULL;
 
     b64 = BIO_new(BIO_f_base64());
     if (!(b64)) {
         if (!(obuf))
             free(buf);
 
         return NULL;
     }
 
     bio = BIO_new_mem_buf(data, len);
     if (!(bio)) {
         BIO_free(b64);
         if (!(obuf))
             free(buf);
 
         return NULL;
     }
 
     bio = BIO_push(b64, bio);
30a75097
     if (oneline)
         BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
b2e7c931
 
     *olen = BIO_read(bio, buf, base64_len(data, len));
 
     BIO_free_all(bio);
 
     return buf;
 }
 
 /** Base64-encode data
  * @param[in] data The data to be encoded
  * @param[in] len The length of the data
  * @return A pointer to the base64-encoded data. The data is stored in a dynamically-allocated buffer.
  */
 char *cl_base64_encode(void *data, size_t len)
 {
     BIO *bio, *b64;
     char *buf, *p;
     size_t elen;
 
     b64 = BIO_new(BIO_f_base64());
5f31c9b4
     if (!(b64))
         return NULL;
b2e7c931
     bio = BIO_new(BIO_s_mem());
5f31c9b4
     if (!(bio)) {
         BIO_free(b64);
         return NULL;
     }
b2e7c931
 
     bio = BIO_push(b64, bio);
     BIO_write(bio, data, len);
 
     BIO_flush(bio);
     elen = (size_t)BIO_get_mem_data(bio, &buf);
 
     /* Ensure we're dealing with a NULL-terminated string */
     p = (char *)malloc(elen+1);
24254d21
     if (NULL == p) {
         BIO_free(b64);
         return NULL;
     }
b2e7c931
     memcpy((void *)p, (void *)buf, elen);
     p[elen] = 0x00;
     buf = p;
 
     BIO_free_all(bio);
 
     return buf;
 }
 
 #if defined(CONV_SELF_TEST)
 
 int main(int argc, char *argv[])
 {
     char *plaintext, *encoded, *decoded;
     unsigned char *sha_plaintext, *sha_decoded;
     size_t len;
     int ret=0;
     unsigned int shalen;
 
     initialize_crypto();
 
     plaintext = (argv[1]) ? argv[1] : "Hello. This is dog";
     sha_plaintext = sha256(plaintext, strlen(plaintext), NULL, NULL);
     if (!(sha_plaintext)) {
         fprintf(stderr, "Could not generate sha256 of plaintext\n");
         return 1;
     }
 
     encoded = base64_encode(plaintext, strlen(plaintext));
     if (!(encoded)) {
         fprintf(stderr, "Could not base64 encode plaintest\n");
         return 1;
     }
     fprintf(stderr, "Base64 encoded: %s\n", encoded);
 
     decoded = base64_decode(encoded, strlen(encoded), NULL, &len);
     if (!(decoded)) {
         fprintf(stderr, "Could not base64 decoded string\n");
         return 1;
     }
 
     sha_decoded = sha256(decoded, len, NULL, &shalen);
     if (!(sha_decoded)) {
         fprintf(stderr, "Could not generate sha256 of decoded data\n");
         return 1;
     }
 
     if (memcmp(sha_plaintext, sha_decoded, shalen)) {
         fprintf(stderr, "Decoded does not match plaintext: %s\n", decoded);
         ret = 1;
     }
 
     free(sha_decoded);
     free(sha_plaintext);
     free(encoded);
     free(decoded);
 
     cleanup_crypto();
 
     return ret;
 }
 
 #endif