Matter SDK Coverage Report
Current view: top level - lib/support - Base64.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 54.8 % 146 80
Test Date: 2025-01-17 19:00:11 Functions: 42.9 % 14 6

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 Project CHIP Authors
       4              :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : /**
      20              :  *    @file
      21              :  *      Base-64 utility functions.
      22              :  *
      23              :  */
      24              : 
      25              : #include "Base64.h"
      26              : 
      27              : #include <ctype.h>
      28              : #include <stdint.h>
      29              : 
      30              : namespace chip {
      31              : 
      32              : // Convert a value in the range 0..63 to its equivalent base64 character.
      33              : // Return '=' for any value >= 64.
      34        19440 : static char Base64ValToChar(uint8_t val)
      35              : {
      36        19440 :     if (val < 26)
      37         8545 :         return static_cast<char>('A' + val);
      38        10895 :     val = static_cast<uint8_t>(val - 26);
      39        10895 :     if (val < 26)
      40         6639 :         return static_cast<char>('a' + val);
      41         4256 :     val = static_cast<uint8_t>(val - 26);
      42         4256 :     if (val < 10)
      43         2316 :         return static_cast<char>('0' + val);
      44         1940 :     if (val == 10)
      45          277 :         return '+';
      46         1663 :     if (val == 11)
      47          248 :         return '/';
      48         1415 :     return '=';
      49              : }
      50              : 
      51              : // Convert a base64 character to a value in the range 0..63, or UINT8_MAX if the character is invalid.
      52         5600 : static uint8_t Base64CharToVal(uint8_t c)
      53              : {
      54         5600 :     if (c == 43)
      55           40 :         return 62;
      56         5560 :     if (c == 47)
      57           49 :         return 63;
      58              :     // NOTE: c < 48 will fall through to return UINT8_MAX below.
      59         5511 :     c = static_cast<uint8_t>(c - 48);
      60         5511 :     if (c < 10)
      61          534 :         return static_cast<uint8_t>(c + 52);
      62              :     // NOTE: c < 17 here will fall through to return UINT8_MAX below.
      63         4977 :     c = static_cast<uint8_t>(c - 17);
      64         4977 :     if (c < 26)
      65         3273 :         return c;
      66              :     // NOTE: c < 32 here will fall through to return UINT8_MAX below.
      67         1704 :     c = static_cast<uint8_t>(c - 32);
      68         1704 :     if (c < 26)
      69         1703 :         return static_cast<uint8_t>(c + 26);
      70            1 :     return UINT8_MAX;
      71              : }
      72              : 
      73              : // Convert a value in the range 0..63 to its equivalent base64url character (see RFC-4648, section 5).
      74              : // Return '=' for any value >= 64.
      75            0 : static char Base64URLValToChar(uint8_t val)
      76              : {
      77            0 :     if (val < 26)
      78            0 :         return static_cast<char>('A' + val);
      79            0 :     val = static_cast<uint8_t>(val - 26);
      80            0 :     if (val < 26)
      81            0 :         return static_cast<char>('a' + val);
      82            0 :     val = static_cast<uint8_t>(val - 26);
      83            0 :     if (val < 10)
      84            0 :         return static_cast<char>('0' + val);
      85            0 :     if (val == 10)
      86            0 :         return '-';
      87            0 :     if (val == 11)
      88            0 :         return '_';
      89            0 :     return '=';
      90              : }
      91              : 
      92              : // Convert a base64url character to a value in the range 0..63, or UINT8_MAX if the character is invalid.
      93            0 : static uint8_t Base64URLCharToVal(uint8_t c)
      94              : {
      95            0 :     if (c == 45)
      96            0 :         return 62;
      97            0 :     if (c == 95)
      98            0 :         return 63;
      99              :     // NOTE: c < 48 will fall through to return UINT8_MAX below.
     100            0 :     c = static_cast<uint8_t>(c - 48);
     101            0 :     if (c < 10)
     102            0 :         return static_cast<uint8_t>(c + 52);
     103              :     // NOTE: c < 17 here will fall through to return UINT8_MAX below.
     104            0 :     c = static_cast<uint8_t>(c - 17);
     105            0 :     if (c < 26)
     106            0 :         return c;
     107              :     // NOTE: c < 32 here will fall through to return UINT8_MAX below.
     108            0 :     c = static_cast<uint8_t>(c - 32);
     109            0 :     if (c < 26)
     110            0 :         return static_cast<uint8_t>(c + 26);
     111            0 :     return UINT8_MAX;
     112              : }
     113              : 
     114          736 : uint16_t Base64Encode(const uint8_t * in, uint16_t inLen, char * out, Base64ValToCharFunct valToCharFunct)
     115              : {
     116          736 :     char * outStart = out;
     117              : 
     118         5596 :     while (inLen > 0)
     119              :     {
     120              :         uint8_t val1, val2, val3, val4;
     121              : 
     122         4860 :         val1 = static_cast<uint8_t>(*in >> 2);
     123         4860 :         val2 = static_cast<uint8_t>((*in << 4) & 0x3F);
     124         4860 :         in++;
     125         4860 :         inLen--;
     126         4860 :         if (inLen > 0)
     127              :         {
     128         4162 :             val2 = static_cast<uint8_t>(val2 | *in >> 4);
     129         4162 :             val3 = static_cast<uint8_t>((*in << 2) & 0x3F);
     130         4162 :             in++;
     131         4162 :             inLen--;
     132         4162 :             if (inLen > 0)
     133              :             {
     134         4143 :                 val3 = static_cast<uint8_t>(val3 | *in >> 6);
     135         4143 :                 val4 = static_cast<uint8_t>(*in & 0x3F);
     136         4143 :                 in++;
     137         4143 :                 inLen--;
     138              :             }
     139              :             else
     140           19 :                 val4 = UINT8_MAX;
     141              :         }
     142              :         else
     143          698 :             val3 = val4 = UINT8_MAX;
     144              : 
     145         4860 :         *out++ = valToCharFunct(val1);
     146         4860 :         *out++ = valToCharFunct(val2);
     147         4860 :         *out++ = valToCharFunct(val3);
     148         4860 :         *out++ = valToCharFunct(val4);
     149              :     }
     150              : 
     151          736 :     return static_cast<uint16_t>(out - outStart);
     152              : }
     153              : 
     154          736 : uint16_t Base64Encode(const uint8_t * in, uint16_t inLen, char * out)
     155              : {
     156          736 :     return Base64Encode(in, inLen, out, Base64ValToChar);
     157              : }
     158              : 
     159            0 : uint16_t Base64URLEncode(const uint8_t * in, uint16_t inLen, char * out)
     160              : {
     161            0 :     return Base64Encode(in, inLen, out, Base64URLValToChar);
     162              : }
     163              : 
     164            0 : uint32_t Base64Encode32(const uint8_t * in, uint32_t inLen, char * out, Base64ValToCharFunct valToCharFunct)
     165              : {
     166            0 :     uint32_t outLen = 0;
     167              : 
     168              :     // Maximum number of input bytes to convert to base-64 in a single call to Base64Encode.
     169              :     // Number is the largest multiple of 3 bytes where the resulting number of base-64 characters
     170              :     // fits within a uint16_t.
     171              :     enum
     172              :     {
     173              :         kMaxConvert = (UINT16_MAX / 4) * 3
     174              :     };
     175              : 
     176              :     while (true)
     177              :     {
     178            0 :         uint16_t inChunkLen = (inLen > kMaxConvert) ? static_cast<uint16_t>(kMaxConvert) : static_cast<uint16_t>(inLen);
     179              : 
     180            0 :         uint16_t outChunkLen = Base64Encode(in, inChunkLen, out, valToCharFunct);
     181              : 
     182            0 :         inLen -= inChunkLen;
     183            0 :         outLen += outChunkLen;
     184              : 
     185            0 :         if (inLen == 0)
     186            0 :             break;
     187              : 
     188            0 :         in += inChunkLen;
     189            0 :         out += outChunkLen;
     190            0 :     }
     191              : 
     192            0 :     return outLen;
     193              : }
     194              : 
     195            0 : uint32_t Base64Encode32(const uint8_t * in, uint32_t inLen, char * out)
     196              : {
     197            0 :     return Base64Encode32(in, inLen, out, Base64ValToChar);
     198              : }
     199              : 
     200           35 : uint16_t Base64Decode(const char * in, uint16_t inLen, uint8_t * out, Base64CharToValFunct charToValFunct)
     201              : {
     202           35 :     uint8_t * outStart = out;
     203              : 
     204              :     // isgraph() returns false for space and ctrl chars
     205         1418 :     while (inLen > 0 && isgraph(*in))
     206              :     {
     207         1411 :         if (inLen == 1)
     208            0 :             goto fail;
     209              : 
     210         1411 :         uint8_t a = charToValFunct(static_cast<uint8_t>(*in++));
     211         1411 :         uint8_t b = charToValFunct(static_cast<uint8_t>(*in++));
     212         1411 :         inLen     = static_cast<uint16_t>(inLen - 2);
     213              : 
     214         1411 :         if (a == UINT8_MAX || b == UINT8_MAX)
     215            0 :             goto fail;
     216              : 
     217         1411 :         *out++ = static_cast<uint8_t>((a << 2) | (b >> 4));
     218              : 
     219         1411 :         if (inLen == 0 || *in == '=')
     220              :             break;
     221              : 
     222         1394 :         uint8_t c = charToValFunct(static_cast<uint8_t>(*in++));
     223         1394 :         inLen--;
     224              : 
     225         1394 :         if (c == UINT8_MAX)
     226            0 :             goto fail;
     227              : 
     228         1394 :         *out++ = static_cast<uint8_t>((b << 4) | (c >> 2));
     229              : 
     230         1394 :         if (inLen == 0 || *in == '=')
     231              :             break;
     232              : 
     233         1384 :         uint8_t d = charToValFunct(static_cast<uint8_t>(*in++));
     234         1384 :         inLen--;
     235              : 
     236         1384 :         if (d == UINT8_MAX)
     237            1 :             goto fail;
     238              : 
     239         1383 :         *out++ = static_cast<uint8_t>((c << 6) | d);
     240              :     }
     241              : 
     242           34 :     return static_cast<uint16_t>(out - outStart);
     243              : 
     244            1 : fail:
     245            1 :     return UINT16_MAX;
     246              : }
     247              : 
     248           35 : uint16_t Base64Decode(const char * in, uint16_t inLen, uint8_t * out)
     249              : {
     250           35 :     return Base64Decode(in, inLen, out, Base64CharToVal);
     251              : }
     252              : 
     253            0 : uint16_t Base64URLDecode(const char * in, uint16_t inLen, uint8_t * out)
     254              : {
     255            0 :     return Base64Decode(in, inLen, out, Base64URLCharToVal);
     256              : }
     257              : 
     258            0 : uint32_t Base64Decode32(const char * in, uint32_t inLen, uint8_t * out, Base64CharToValFunct charToValFunct)
     259              : {
     260            0 :     uint32_t outLen = 0;
     261              : 
     262              :     // Maximum number of base-64 characters to convert in a single call to Base64Decode.
     263              :     // Number is the largest multiple of 4 characters that fits in a uint16_t.
     264              :     enum
     265              :     {
     266              :         kMaxConvert = (UINT16_MAX / 4) * 4
     267              :     };
     268              : 
     269              :     while (true)
     270              :     {
     271            0 :         uint16_t inChunkLen = (inLen > kMaxConvert) ? static_cast<uint16_t>(kMaxConvert) : static_cast<uint16_t>(inLen);
     272              : 
     273            0 :         uint16_t outChunkLen = Base64Decode(in, inChunkLen, out, charToValFunct);
     274            0 :         if (outChunkLen == UINT16_MAX)
     275            0 :             return UINT32_MAX;
     276              : 
     277            0 :         inLen -= inChunkLen;
     278            0 :         outLen += outChunkLen;
     279              : 
     280            0 :         if (inLen == 0)
     281            0 :             break;
     282              : 
     283            0 :         in += inChunkLen;
     284            0 :         out += outChunkLen;
     285            0 :     }
     286              : 
     287            0 :     return outLen;
     288              : }
     289              : 
     290            0 : uint32_t Base64Decode32(const char * in, uint32_t inLen, uint8_t * out)
     291              : {
     292            0 :     return Base64Decode32(in, inLen, out, Base64CharToVal);
     293              : }
     294              : 
     295              : } // namespace chip
     296              : 
     297              : #ifdef TEST
     298              : 
     299              : #include <stdio.h>
     300              : #include <string.h>
     301              : 
     302              : void TestBase64(const char * test, bool base64URL = false)
     303              : {
     304              :     uint8_t buf[256];
     305              :     char buf2[256];
     306              :     uint16_t len;
     307              : 
     308              :     strcpy((char *) buf, test);
     309              : 
     310              :     len = (base64URL) ? nl::Base64URLDecode((char *) buf, strlen((char *) buf), buf)
     311              :                       : nl::Base64Decode((char *) buf, strlen((char *) buf), buf);
     312              :     printf("%s: ", test);
     313              :     if (len != UINT16_MAX)
     314              :     {
     315              :         printf("(%d) ", len);
     316              :         for (uint16_t i = 0; i < len; i++)
     317              :             printf("%c", buf[i]);
     318              : 
     319              :         len = (base64URL) ? nl::Base64URLEncode(buf, len, buf2) : nl::Base64Encode(buf, len, buf2);
     320              :         printf(" (%d) ", len);
     321              :         for (uint16_t i = 0; i < len; i++)
     322              :             printf("%c", buf2[i]);
     323              :     }
     324              :     else
     325              :         printf("ERROR");
     326              :     printf("\n");
     327              : }
     328              : 
     329              : int main(int argc, char * argv[])
     330              : {
     331              :     TestBase64("");
     332              :     TestBase64("Zg==");
     333              :     TestBase64("Zm8=");
     334              :     TestBase64("Zm9v");
     335              :     TestBase64("Zm9vYg==");
     336              :     TestBase64("Zm9vYmE=");
     337              :     TestBase64("Zm9vYmFy");
     338              :     TestBase64("QmFzZTY0D+8xMjM0D/8=");
     339              : 
     340              :     TestBase64("Zg");
     341              :     TestBase64("Zm8");
     342              :     TestBase64("Zm9vYg");
     343              :     TestBase64("Zm9vYmE");
     344              : 
     345              :     TestBase64("QmFzZTY0D-8xMjM0D_8=", true);
     346              : 
     347              :     // Error cases
     348              :     TestBase64("Z");
     349              :     TestBase64("Z\x019vYmFy");
     350              :     TestBase64("Zm9vY");
     351              :     TestBase64("Zm9vY;");
     352              :     TestBase64("Zm9 vYg");
     353              : }
     354              : 
     355              : #endif // TEST
        

Generated by: LCOV version 2.0-1