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