1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 /*
25  * Base64 encoding and decoding as according to RFC1521.  Similar to uudecode.
26  *
27  * RFC 1521 requires inserting line breaks for long lines.  The basic web
28  * authentication scheme does not require them.  This implementation is
29  * intended for web-related use, and line breaks are not implemented.
30  *
31  * These routines return char*'s to malloc-ed strings.  The caller is
32  * responsible for freeing the strings.
33  */
34 #include "tscore/ink_platform.h"
35 #include "tscore/ink_base64.h"
36 #include "tscore/ink_assert.h"
37 
38 // TODO: The code here seems a bit klunky, and could probably be improved a bit.
39 
40 bool
ats_base64_encode(const unsigned char * inBuffer,size_t inBufferSize,char * outBuffer,size_t outBufSize,size_t * length)41 ats_base64_encode(const unsigned char *inBuffer, size_t inBufferSize, char *outBuffer, size_t outBufSize, size_t *length)
42 {
43   static const char _codes[66] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
44   char *obuf                   = outBuffer;
45   char in_tail[4];
46 
47   if (outBufSize < ATS_BASE64_ENCODE_DSTLEN(inBufferSize)) {
48     return false;
49   }
50 
51   while (inBufferSize > 2) {
52     *obuf++ = _codes[(inBuffer[0] >> 2) & 077];
53     *obuf++ = _codes[((inBuffer[0] & 03) << 4) | ((inBuffer[1] >> 4) & 017)];
54     *obuf++ = _codes[((inBuffer[1] & 017) << 2) | ((inBuffer[2] >> 6) & 017)];
55     *obuf++ = _codes[inBuffer[2] & 077];
56 
57     inBufferSize -= 3;
58     inBuffer += 3;
59   }
60 
61   /*
62    * We've done all the input groups of three chars.  We're left
63    * with 0, 1, or 2 input chars.  We have to add zero-bits to the
64    * right if we don't have enough input chars.
65    * If 0 chars left, we're done.
66    * If 1 char left, form 2 output chars, and add 2 pad chars to output.
67    * If 2 chars left, form 3 output chars, add 1 pad char to output.
68    */
69   if (inBufferSize == 0) {
70     *obuf = '\0';
71     if (length) {
72       *length = (obuf - outBuffer);
73     }
74   } else {
75     memset(in_tail, 0, sizeof(in_tail));
76     memcpy(in_tail, inBuffer, inBufferSize);
77 
78     *(obuf)     = _codes[(in_tail[0] >> 2) & 077];
79     *(obuf + 1) = _codes[((in_tail[0] & 03) << 4) | ((in_tail[1] >> 4) & 017)];
80     *(obuf + 2) = _codes[((in_tail[1] & 017) << 2) | ((in_tail[2] >> 6) & 017)];
81     *(obuf + 3) = _codes[in_tail[2] & 077];
82 
83     if (inBufferSize == 1) {
84       *(obuf + 2) = '=';
85     }
86     *(obuf + 3) = '=';
87     *(obuf + 4) = '\0';
88 
89     if (length) {
90       *length = (obuf + 4) - outBuffer;
91     }
92   }
93 
94   return true;
95 }
96 
97 bool
ats_base64_encode(const char * inBuffer,size_t inBufferSize,char * outBuffer,size_t outBufSize,size_t * length)98 ats_base64_encode(const char *inBuffer, size_t inBufferSize, char *outBuffer, size_t outBufSize, size_t *length)
99 {
100   return ats_base64_encode(reinterpret_cast<const unsigned char *>(inBuffer), inBufferSize, outBuffer, outBufSize, length);
101 }
102 
103 /*-------------------------------------------------------------------------
104   This is a reentrant, and malloc free implementation of ats_base64_decode.
105   -------------------------------------------------------------------------*/
106 #ifdef DECODE
107 #undef DECODE
108 #endif
109 
110 #define DECODE(x) printableToSixBit[(unsigned char)x]
111 #define MAX_PRINT_VAL 63
112 
113 /* Converts a printable character to it's six bit representation */
114 const unsigned char printableToSixBit[256] = {
115   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
116   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 62, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
117   64, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 63,
118   64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
119   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
120   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
121   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
122   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
123 
124 bool
ats_base64_decode(const char * inBuffer,size_t inBufferSize,unsigned char * outBuffer,size_t outBufSize,size_t * length)125 ats_base64_decode(const char *inBuffer, size_t inBufferSize, unsigned char *outBuffer, size_t outBufSize, size_t *length)
126 {
127   size_t inBytes        = 0;
128   size_t decodedBytes   = 0;
129   unsigned char *buf    = outBuffer;
130   int inputBytesDecoded = 0;
131 
132   // Make sure there is sufficient space in the output buffer
133   if (outBufSize < ATS_BASE64_DECODE_DSTLEN(inBufferSize)) {
134     return false;
135   }
136 
137   // Ignore any trailing ='s or other undecodable characters.
138   // TODO: Perhaps that ought to be an error instead?
139   while (inBytes < inBufferSize && printableToSixBit[static_cast<uint8_t>(inBuffer[inBytes])] <= MAX_PRINT_VAL) {
140     ++inBytes;
141   }
142 
143   for (size_t i = 0; i < inBytes; i += 4) {
144     buf[0] = static_cast<unsigned char>(DECODE(inBuffer[0]) << 2 | DECODE(inBuffer[1]) >> 4);
145     buf[1] = static_cast<unsigned char>(DECODE(inBuffer[1]) << 4 | DECODE(inBuffer[2]) >> 2);
146     buf[2] = static_cast<unsigned char>(DECODE(inBuffer[2]) << 6 | DECODE(inBuffer[3]));
147 
148     buf += 3;
149     inBuffer += 4;
150     decodedBytes += 3;
151     inputBytesDecoded += 4;
152   }
153 
154   // Check to see if we decoded a multiple of 4 four
155   //    bytes
156   if ((inBytes - inputBytesDecoded) & 0x3) {
157     if (DECODE(inBuffer[-2]) > MAX_PRINT_VAL) {
158       decodedBytes -= 2;
159     } else {
160       decodedBytes -= 1;
161     }
162   }
163   outBuffer[decodedBytes] = '\0';
164 
165   if (length) {
166     *length = decodedBytes;
167   }
168 
169   return true;
170 }
171