Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Base64 handling
0003  *
0004  * @file exbase64.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 #include <ndrx_config.h>
0035 #include <string.h>
0036 #include <stdio.h>
0037 #include <stdlib.h>
0038 #include <memory.h>
0039 #include <time.h>
0040 #include <sys/time.h>
0041 #include <unistd.h>
0042 #include <stdarg.h>
0043 
0044 #include <ndrstandard.h>
0045 #include <ndebug.h>
0046 #include <nstdutil.h>
0047 #include <sys_unix.h>
0048 #include <exbase64.h>
0049 /*---------------------------Externs------------------------------------*/
0050 /*---------------------------Macros-------------------------------------*/
0051 /*---------------------------Enums--------------------------------------*/
0052 /*---------------------------Typedefs-----------------------------------*/
0053 /*---------------------------Globals------------------------------------*/
0054 /*---------------------------Statics------------------------------------*/
0055 /*---------------------------Prototypes---------------------------------*/
0056 static char M_encoding_table_xa[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
0057                                 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
0058                                 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
0059                                 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
0060                                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
0061                                 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
0062                                 'w', 'x', 'y', 'z', '0', '1', '2', '3',
0063                                 '4', '5', '6', '7', '8', '9', '+', '_'};
0064 
0065 static char M_encoding_table_normal[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
0066                                 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
0067                                 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
0068                                 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
0069                                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
0070                                 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
0071                                 'w', 'x', 'y', 'z', '0', '1', '2', '3',
0072                                 '4', '5', '6', '7', '8', '9', '+', '/'};
0073 
0074 /* built by build_decoding_table(M_encoding_table_xa); */
0075 static char M_decoding_table_xa[] =
0076 {
0077 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0078 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0079 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
0080 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0081 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0082 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x3f,
0083 0x00, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0084 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00,
0085 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0086 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0087 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0088 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0089 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0090 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0092 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0093 };
0094 
0095 /* built by build_decoding_table(M_encoding_table_normal); */
0096 static char M_decoding_table_normal[] =
0097 {
0098 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0099 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f,
0101 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0102 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0103 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
0104 0x00, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0105 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00,
0106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0114 };
0115 
0116 static int mod_table[] = {0, 2, 1};
0117 
0118 /*---------------------------Prototypes---------------------------------*/
0119 exprivate char * build_decoding_table(char *encoding_table);
0120 
0121 /* private void base64_cleanup(void); */
0122 
0123 exprivate char * ndrx_b64encode(const unsigned char *data,
0124                     size_t input_length,
0125                     size_t *output_length,
0126                     char *encoded_data, 
0127                     char *encoding_table);
0128 
0129 
0130 exprivate unsigned char *ndrx_b64decode(unsigned char *data,
0131                              size_t input_length,
0132                              size_t *output_length,
0133                              char *decoded_data,
0134                              char *encoding_table);
0135 
0136 /**
0137  * XA Version of Base64 encode
0138  * EOS is installed in output data
0139  * @param data
0140  * @param input_length
0141  * @param output_length includes EOS byte
0142  * @param encoded_data
0143  * @return 
0144  */
0145 expublic char * ndrx_xa_base64_encode(unsigned char *data,
0146                     size_t input_length,
0147                     size_t *output_length,
0148                     char *encoded_data)
0149 {
0150     return ndrx_b64encode(data, input_length, output_length, 
0151             encoded_data, M_encoding_table_xa);
0152 }
0153 
0154 /**
0155  * XA Version of base64 decode
0156  * @param data input data
0157  * @param input_length input len
0158  * @param output_length output data len (ptr to). Only output len, no len checking.
0159  * @param decoded_data decoded output data
0160  * @return NULL in case of error
0161  */
0162 expublic unsigned char *ndrx_xa_base64_decode(unsigned char *data,
0163                              size_t input_length,
0164                              size_t *output_length,
0165                              char *decoded_data)
0166 {
0167     return ndrx_b64decode((unsigned char *)data, input_length, output_length, 
0168             decoded_data, (char *)M_decoding_table_xa);
0169 }
0170 
0171 
0172 /**
0173  * Standard Version of Base64 encode
0174  * EOS is installed in output data
0175  * @param data
0176  * @param input_length
0177  * @param output_length includes EOS byte
0178  * @param encoded_data
0179  * @return 
0180  */
0181 char * ndrx_base64_encode(unsigned char *data,
0182                     size_t input_length,
0183                     size_t *output_length,
0184                     char *encoded_data) 
0185 {
0186     return ndrx_b64encode(data, input_length, output_length, 
0187             encoded_data, M_encoding_table_normal);
0188 }
0189 
0190 /**
0191  * Standard Version of base64 decode
0192  * @param data
0193  * @param input_length
0194  * @param output_length
0195  * @param decoded_data
0196  * @return 
0197  */
0198 unsigned char *ndrx_base64_decode(const char *data,
0199                              size_t input_length,
0200                              size_t *output_length,
0201                              char *decoded_data)
0202 {
0203     return ndrx_b64decode((unsigned char *)data, input_length, output_length, 
0204             decoded_data, (char *)M_decoding_table_normal);
0205 }
0206 
0207 /**
0208  * Encode the data
0209  * Output string contains EOS
0210  * @param data
0211  * @param input_length
0212  * @param output_length includes the EOS
0213  * @return 
0214  */
0215 exprivate char * ndrx_b64encode(const unsigned char *data,
0216                     size_t input_length,
0217                     size_t *output_length,
0218                     char *encoded_data, 
0219                     char *encoding_table) 
0220 {
0221     int i;
0222     int j;
0223     size_t tmp_len;
0224     
0225     /* Ensure position for EOS */
0226     tmp_len = 4 * ((input_length + 2) / 3);
0227     
0228     if (*output_length > 0 && *output_length < (tmp_len+1) /*  +1 for EOS */ )
0229     {
0230         NDRX_LOG(log_error, "Failed to encode data len incl EOS %d but buffer sz %d",
0231                 (int)(tmp_len+1), (int)*output_length);
0232         return NULL;
0233     }
0234     
0235     *output_length = tmp_len;
0236 
0237     /*
0238     char *encoded_data = NDRX_MALLOC(*output_length);
0239     if (encoded_data == NULL) return NULL;*/
0240     
0241     /* TODO: Check output buffer size!!!! */
0242 
0243     for (i = 0, j = 0; i < input_length;) 
0244     {
0245 
0246         uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
0247         uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
0248         uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
0249 
0250         uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
0251 
0252         encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
0253         encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
0254         encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
0255         encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
0256     }
0257 
0258     for (i = 0; i < mod_table[input_length % 3]; i++)
0259         encoded_data[*output_length - 1 - i] = '=';
0260 
0261     encoded_data[*output_length] = EXEOS;
0262     
0263     /* we wrote to output including EOS.. */
0264     (*output_length)++;
0265     
0266     return encoded_data;
0267 }
0268 
0269 
0270 /**
0271  * Decode the data
0272  * @param data
0273  * @param input_length
0274  * @param output_length
0275  * @return 
0276  */
0277 exprivate unsigned char *ndrx_b64decode(unsigned char *data,
0278                              size_t input_length,
0279                              size_t *output_length,
0280                              char *decoded_data,
0281                              char *decoding_table)
0282 {
0283 
0284     int i;
0285     int j;
0286     size_t tmp_len;
0287 
0288     if (input_length % 4 != 0) 
0289     {
0290         NDRX_LOG(log_error, "Invalid input_length: %d!", input_length);
0291         return NULL;
0292     }
0293     
0294     if (input_length <= 0)
0295     {
0296         NDRX_LOG(log_error, "Invalid input length %d <= 0!", input_length);
0297         return NULL;
0298     }
0299 
0300     tmp_len = input_length / 4 * 3;
0301     
0302     /* strip off padding if any.. */
0303     if (data[input_length - 1] == '=') tmp_len--;
0304     if (data[input_length - 2] == '=') tmp_len--;
0305     
0306     if (*output_length > 0 && *output_length < tmp_len)
0307     {
0308         NDRX_LOG(log_error, "Output buffer too short: Output buffer size: %d, "
0309                 "but data output size: %d", (int)*output_length, (int)tmp_len);
0310         return NULL;
0311     }
0312 
0313     *output_length = tmp_len;
0314     
0315     /*
0316     unsigned char *decoded_data = NDRX_MALLOC(*output_length);
0317     if (decoded_data == NULL) return NULL;
0318 */
0319     for (i = 0, j = 0; i < input_length;) {
0320 
0321         uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
0322         uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
0323         uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
0324         uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
0325 
0326         uint32_t triple = (sextet_a << 3 * 6)
0327         + (sextet_b << 2 * 6)
0328         + (sextet_c << 1 * 6)
0329         + (sextet_d << 0 * 6);
0330 
0331         if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
0332         if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
0333         if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
0334     }
0335 
0336     return (unsigned char *)decoded_data;
0337 }
0338 
0339 #if 0
0340 /**
0341  * Build encoding table
0342  */
0343 exprivate char * build_decoding_table(char *encoding_table)
0344 {
0345     int i;
0346     char *ptr = NDRX_MALLOC(256);
0347 
0348     memset(ptr, 0, 256);
0349 
0350     for (i = 0; i < 64; i++)
0351         ptr[(unsigned char) encoding_table[i]] = i;
0352     
0353     fprintf(stderr, "START\n");
0354     for (i=0; i< 256; i++)
0355     {
0356         fprintf(stderr, "0x%02x, ", ptr[i]);
0357 
0358         if (0==(i+1)%16)
0359         {
0360             fprintf(stderr, "\n");
0361         }
0362 
0363     }
0364     fprintf(stderr, "END\n");
0365     return ptr;
0366 }
0367 #endif
0368 
0369 #if 0
0370 /**
0371  * Cleanup table
0372  */
0373 exprivate void base64_cleanup(void)
0374 {
0375     NDRX_FREE(decoding_table);
0376 }
0377 #endif
0378 
0379 /* vim: set ts=4 sw=4 et smartindent: */