LCOV - code coverage report
Current view: top level - src - b64.c (source / functions) Hit Total Coverage
Test: oc-runner-0.0.51.5.29c69 Code Coverage Lines: 87 111 78.4 %
Date: 2018-10-15 12:44:38 Functions: 5 7 71.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //
       2             : //  b64.c
       3             : //  cjose_cjson
       4             : //
       5             : //  Created by Danny Goossen on 22/1/18.
       6             : //  Copyright (c) 2018 Danny Goossen. All rights reserved.
       7             : //
       8             : 
       9             : #include "b64.h"
      10             : /*
      11             :  * Copyrights
      12             :  *
      13             :  * Portions created or assigned to Cisco Systems, Inc. are
      14             :  * Copyright (c) 2014-2016 Cisco Systems, Inc.  All Rights Reserved.
      15             :  */
      16             : 
      17             : #include <errno.h>
      18             : #include <string.h>
      19             : #include <stdlib.h>
      20             : #include <assert.h>
      21             : #include "utils.h"
      22             : #include "jose_error.h"
      23             : 
      24             : // defines
      25             : #define B64_BYTE1(ptr) (((*ptr) & 0xfc) >> 2)
      26             : #define B64_BYTE2(ptr) ((((*ptr) & 0x03) << 4) | ((*(ptr + 1) & 0xf0) >> 4))
      27             : #define B64_BYTE3(ptr) (((*(ptr + 1) & 0x0f) << 2) | ((*(ptr + 2) & 0xc0) >> 6))
      28             : #define B64_BYTE4(ptr) (*(ptr + 2) & 0x3f)
      29             : 
      30             : // internal data
      31             : 
      32             : static const char *ALPHABET_B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      33             : static const char *ALPHABET_B64U = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
      34             : 
      35             : static const uint8_t TEBAHPLA_B64[]
      36             : = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      37             :    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      38             :    0xff, 0xff, 0xff, 0x3e, 0xff, 0x3e, 0xff, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
      39             :    0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
      40             :    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x1a, 0x1b, 0x1c,
      41             :    0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
      42             :    0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      43             :    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      44             :    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      45             :    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      46             :    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      47             :    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      48             :    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
      49             : 
      50             : // internal functions
      51             : 
      52           3 : static inline bool _decode(const char *input, size_t inlen, uint8_t **output, size_t *outlen, bool url, jose_err *err)
      53             : {
      54           3 :    if ((NULL == input) || (NULL == output) || (NULL == outlen))
      55             :    {
      56           0 :       JOSE_ERROR(err, JOSE_ERR_INVALID_ARG);
      57             :       return false;
      58             :    }
      59             :    
      60             :    // return empty string on 0 length input
      61           3 :    if (0 == inlen)
      62             :    {
      63           2 :       uint8_t *retVal = calloc(1,sizeof(uint8_t));
      64           2 :       if (NULL == retVal)
      65             :       {
      66           0 :          JOSE_ERROR(err, JOSE_ERR_NO_MEMORY);
      67             :          return false;
      68             :       }
      69             :       
      70           2 :       retVal[0] = 0;
      71           2 :       *output = retVal;
      72           2 :       *outlen = 0;
      73           2 :       return true;
      74             :    }
      75             :    
      76             :    // extra validation -- inlen is a multiple of 4
      77           1 :    if ((!url && 0 != (inlen % 4)) || (inlen % 4 == 1))
      78             :    {
      79           0 :       JOSE_ERROR(err, JOSE_ERR_INVALID_ARG);
      80             :       return false;
      81             :    }
      82             :    
      83             :    // rlen takes a best guess on size;
      84             :    // might be too large for base64url, but never too small.
      85           1 :    size_t rlen = ((inlen * 3) >> 2) + 3 +1;
      86           1 :    uint8_t *buffer = calloc(sizeof(uint8_t),  rlen);
      87           1 :    if (!buffer)
      88             :    {
      89           0 :       JOSE_ERROR(err, JOSE_ERR_NO_MEMORY);
      90             :       return false;
      91             :    }
      92             :    
      93             :    size_t idx = 0;
      94             :    size_t pos = 0;
      95             :    size_t shift = 0;
      96             :    uint32_t packed = 0;
      97          39 :    while (inlen > idx)
      98             :    {
      99             :       uint8_t val;
     100          39 :       val = input[idx];
     101          39 :       if ('=' == val)
     102             :       {
     103             :          break;
     104             :       }
     105          38 :       else if (url && ('+' == val || '/' == val))
     106             :       {
     107           0 :          JOSE_ERROR(err, JOSE_ERR_INVALID_ARG);
     108             :          goto b64_decode_failed;
     109             :       }
     110          38 :       else if (!url && ('-' == val || '_' == val))
     111             :       {
     112           0 :          JOSE_ERROR(err, JOSE_ERR_INVALID_ARG);
     113             :          goto b64_decode_failed;
     114             :       }
     115             :       
     116          38 :       val = TEBAHPLA_B64[val];
     117          38 :       if (0xff == val)
     118             :       {
     119           0 :          JOSE_ERROR(err, JOSE_ERR_INVALID_ARG);
     120           0 :          if (buffer) free(buffer);
     121             :          return false;
     122             :       }
     123          38 :       idx++;
     124             :       
     125          38 :       packed = packed | (val << (18 - (6 * shift++)));
     126          38 :       if (4 == shift)
     127             :       {
     128           9 :          buffer[pos++] = (packed >> 16) & 0xff;
     129           9 :          buffer[pos++] = (packed >> 8) & 0xff;
     130           9 :          buffer[pos++] = packed & 0xff;
     131           9 :          shift = 0;
     132           9 :          packed = 0;
     133             :       }
     134             :    }
     135             :    
     136           1 :    assert(shift != 1);
     137           1 :    assert(shift != 4);
     138             :    
     139           1 :    if (shift == 3)
     140             :    {
     141           0 :       buffer[pos++] = (packed >> 16) & 0xff;
     142           0 :       buffer[pos++] = (packed >> 8) & 0xff;
     143             :    }
     144             :    
     145           1 :    if (shift == 2)
     146             :    {
     147           1 :       buffer[pos++] = (packed >> 16) & 0xff;
     148             :    }
     149             :    
     150           1 :    *output = buffer;
     151           1 :    buffer[pos]='\0';
     152           1 :    *outlen = pos;
     153           1 :    assert(((*outlen) +1) <= rlen);
     154             :    return true;
     155             :    
     156             : b64_decode_failed:
     157           0 :    if (buffer)
     158             :    {
     159           0 :       free(buffer);
     160             :    }
     161             :    return false;
     162             : }
     163             : 
     164           6 : static inline bool _encode(const uint8_t *input, size_t inlen, char **output, size_t *outlen, const char *alphabet, jose_err *err)
     165             : {
     166           6 :    if ((inlen > 0 && NULL == input) || (NULL == output) || (NULL == outlen))
     167             :    {
     168           0 :       JOSE_ERROR(err, JOSE_ERR_INVALID_ARG);
     169             :       return false;
     170             :    }
     171             :    
     172             :    // return empty string on 0 length input
     173           6 :    if (!inlen)
     174             :    {
     175           3 :       char *retVal = calloc(1,1);
     176           3 :       if (!retVal)
     177             :       {
     178           0 :          JOSE_ERROR(err, JOSE_ERR_NO_MEMORY);
     179             :          return false;
     180             :       }
     181           3 :       retVal[0] = '\0';
     182           3 :       *output = retVal;
     183           3 :       *outlen = 0;
     184           3 :       return true;
     185             :    }
     186             :    
     187           3 :    const bool padit = (ALPHABET_B64 == alphabet);
     188           3 :    size_t rlen = (((inlen + 2) / 3) << 2);
     189             :    char *base;
     190             :    
     191           3 :    base = calloc(sizeof(char) , (rlen + 1));
     192           3 :    if (NULL == base)
     193             :    {
     194           0 :       JOSE_ERROR(err, JOSE_ERR_NO_MEMORY);
     195             :       return false;
     196             :    }
     197             :    
     198             :    size_t pos = 0, idx = 0;
     199          30 :    while ((idx + 2) < inlen)
     200             :    {
     201          27 :       base[pos++] = alphabet[0x3f & (input[idx] >> 2)];
     202          27 :       base[pos++] = alphabet[(0x3f & (input[idx] << 4)) | (0x3f & (input[idx + 1] >> 4))];
     203          27 :       base[pos++] = alphabet[(0x3f & (input[idx + 1] << 2)) | (0x3f & (input[idx + 2] >> 6))];
     204          27 :       base[pos++] = alphabet[0x3f & input[idx + 2]];
     205          27 :       idx += 3;
     206             :    }
     207             :    
     208           3 :    if (idx < inlen)
     209             :    {
     210           3 :       if ((inlen - 1) == idx)
     211             :       {
     212           3 :          base[pos++] = alphabet[0x3f & (input[idx] >> 2)];
     213           3 :          base[pos++] = alphabet[0x3f & (input[idx] << 4)];
     214           3 :          if (padit)
     215             :          {
     216           3 :             base[pos++] = '=';
     217           3 :             base[pos++] = '=';
     218             :          }
     219             :       }
     220             :       else
     221             :       {
     222           0 :          base[pos++] = alphabet[0x3f & (input[idx] >> 2)];
     223           0 :          base[pos++] = alphabet[(0x3f & (input[idx] << 4)) | (0x3f & (input[idx + 1] >> 4))];
     224           0 :          base[pos++] = alphabet[0x3f & (input[idx + 1] << 2)];
     225           0 :          if (padit)
     226             :          {
     227           0 :             base[pos++] = '=';
     228             :          }
     229             :       }
     230           3 :       rlen = pos;
     231             :    }
     232           3 :    base[rlen] = '\0';
     233             :    
     234           3 :    *output = base;
     235           3 :    *outlen = rlen;
     236           3 :    return true;
     237             : }
     238             : 
     239             : // interface functions
     240             : 
     241           3 : bool base64_encode(const uint8_t *input, size_t inlen, char **output, size_t *outlen, jose_err *err)
     242             : {
     243           6 :    return _encode(input, inlen, output, outlen, ALPHABET_B64, err);
     244             : }
     245           0 : bool base64url_encode(const uint8_t *input, size_t inlen, char **output, size_t *outlen, jose_err *err)
     246             : {
     247           0 :    return _encode(input, inlen, output, outlen, ALPHABET_B64U, err);
     248             : }
     249             : 
     250           3 : bool base64_decode(const char *input, size_t inlen, uint8_t **output, size_t *outlen, jose_err *err)
     251             : {
     252           3 :    return _decode(input, inlen, output, outlen, false, err);
     253             : }
     254           0 : bool base64url_decode(const char *input, size_t inlen, uint8_t **output, size_t *outlen, jose_err *err)
     255             : {
     256           0 :    return _decode(input, inlen, output, outlen, true, err);
     257             : }
     258             : 
     259             : 
     260             : 
     261           4 : char * Base64Encode_v(const char * prefix, const char * message, ...)
     262             : {
     263           4 :         if (!message|| strlen(message)==0) return NULL;
     264             :         
     265           3 :         char * contents=CSPRINTF(message);
     266             :         
     267             :         //debug("base64 input (%d b): %s\n",strlen(contents),contents);
     268           3 :         char * result=NULL;
     269             :         size_t len_out;
     270           3 :         base64_encode((uint8_t *)contents,strlen(contents), &result, &len_out, NULL);
     271           3 :         if (contents) free(contents);
     272             :         //debug("base64 output (%d b): %s\n",strlen(result),result);
     273           3 :         size_t prefix_len=0;
     274           3 :         char *tmp=NULL;
     275           3 :         if (prefix)
     276             :         {
     277           1 :                 prefix_len=strlen(prefix);
     278           1 :             tmp=calloc(1,len_out+prefix_len+1);
     279           1 :             sprintf(tmp,"%s%.*s",prefix,(int)(len_out),result);
     280           1 :             if (result) free(result);
     281             :         }
     282           2 :         else tmp=result;
     283           3 :         return (tmp);
     284             : }
     285             : 
     286             : 

Generated by: LCOV version 1.13