Skip to content

Commit 47aeb21

Browse files
committed
lib/plumcore-cryptolib: Add Base64 routines
1 parent b516cd5 commit 47aeb21

File tree

2 files changed

+205
-0
lines changed

2 files changed

+205
-0
lines changed

lib/plumcore-cryptolib/src/base64.c

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* Base64 encoding/decoding
3+
*
4+
* Code taken from https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64,
5+
* suspected public domain as the site states.
6+
*/
7+
8+
#include <stdint.h>
9+
10+
#include "base64.h"
11+
#include <stddef.h>
12+
13+
14+
const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
15+
16+
base64_ret_t base64encode(const void *buf, size_t len, char *result, size_t resultSize) {
17+
const uint8_t *data = (const uint8_t *)buf;
18+
size_t resultIndex = 0;
19+
size_t x = 0;
20+
uint32_t n = 0;
21+
int padCount = len % 3;
22+
uint8_t n0 = 0;
23+
uint8_t n1 = 0;
24+
uint8_t n2 = 0;
25+
uint8_t n3 = 0;
26+
27+
/* Increment over the length of the string, three characters at a time. */
28+
for (x = 0; x < len; x += 3) {
29+
/* These three 8-bit (ASCII) characters become one 24-bit number.
30+
* Parenthesis needed, compiler depending on flags can do the shifting before conversion to uint32_t,
31+
* resulting to 0 */
32+
n = ((uint32_t)data[x]) << 16;
33+
34+
if((x + 1) < len) {
35+
/* Parenthesis needed, compiler depending on flags can do the shifting before conversion
36+
* to uint32_t, resulting to 0 */
37+
n += ((uint32_t)data[x + 1]) << 8;
38+
}
39+
40+
if((x + 2) < len) {
41+
n += data[x + 2];
42+
}
43+
44+
/* This 24-bit number gets separated into four 6-bit numbers. */
45+
n0 = (uint8_t)(n >> 18) & 63;
46+
n1 = (uint8_t)(n >> 12) & 63;
47+
n2 = (uint8_t)(n >> 6) & 63;
48+
n3 = (uint8_t)n & 63;
49+
50+
/* If we have one byte available, then its encoding is spread out over two characters. */
51+
if(resultIndex >= resultSize) {
52+
return BASE64_RET_BUF_SMALL;
53+
}
54+
result[resultIndex++] = base64chars[n0];
55+
if(resultIndex >= resultSize) {
56+
return BASE64_RET_BUF_SMALL;
57+
}
58+
result[resultIndex++] = base64chars[n1];
59+
60+
/* if we have only two bytes available, then their encoding is spread out over three chars */
61+
if((x+1) < len) {
62+
if (resultIndex >= resultSize) {
63+
return BASE64_RET_BUF_SMALL;
64+
}
65+
result[resultIndex++] = base64chars[n2];
66+
}
67+
68+
/* if we have all three bytes available, then their encoding is spread out over four characters */
69+
if((x+2) < len) {
70+
if (resultIndex >= resultSize) {
71+
return BASE64_RET_BUF_SMALL;
72+
}
73+
result[resultIndex++] = base64chars[n3];
74+
}
75+
}
76+
77+
/* create and add padding that is required if we did not have a multiple of 3
78+
* number of characters available */
79+
if (padCount > 0) {
80+
for (; padCount < 3; padCount++) {
81+
if (resultIndex >= resultSize) {
82+
return BASE64_RET_BUF_SMALL;
83+
}
84+
result[resultIndex++] = '=';
85+
}
86+
}
87+
88+
if (resultIndex >= resultSize) {
89+
/* indicate failure: buffer too small */
90+
return BASE64_RET_BUF_SMALL;
91+
}
92+
93+
result[resultIndex] = 0;
94+
return BASE64_RET_OK;
95+
}
96+
97+
98+
#define B64_WHITESPACE 64
99+
#define B64_EQUALS 65
100+
#define B64_INVALID 66
101+
102+
static const unsigned char d[] = {
103+
52,53,54,55,56,57,58,59,60,61,66,66,66,65,66,66,
104+
66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
105+
15,16,17,18,19,20,21,22,23,24,25,66,66,66,66,66,
106+
66,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
107+
41,42,43,44,45,46,47,48,49,50,51,66,66,66,66,66,
108+
};
109+
110+
111+
static unsigned char b64fromchar(unsigned char c) {
112+
if (c >= 128) {
113+
return B64_INVALID;
114+
} else if (c == '\n') {
115+
return B64_WHITESPACE;
116+
} else if (c == 43) {
117+
return 62;
118+
} else if (c == 47) {
119+
return 63;
120+
} else if (c < 48) {
121+
return B64_INVALID;
122+
} else {
123+
return d[c - 48];
124+
}
125+
}
126+
127+
128+
base64_ret_t base64decode(const char *in, size_t inLen, unsigned char *out, size_t *outLen) {
129+
const char *end = in + inLen;
130+
char iter = 0;
131+
uint32_t buf = 0;
132+
size_t len = 0;
133+
134+
while (in < end) {
135+
unsigned char c = b64fromchar(*in++);
136+
137+
switch (c) {
138+
case B64_WHITESPACE:
139+
/* Skip whitespace. */
140+
continue;
141+
case B64_INVALID:
142+
/* Invalid input, return error. */
143+
return BASE64_RET_INVALID;
144+
case B64_EQUALS:
145+
/* Pad character, end of data. */
146+
in = end;
147+
continue;
148+
default:
149+
buf = buf << 6 | c;
150+
iter++;
151+
/* If the buffer is full, split it into bytes. */
152+
if (iter == 4) {
153+
if ((len += 3) > *outLen) {
154+
return BASE64_RET_BUF_OVERFLOW;
155+
}
156+
*(out++) = (buf >> 16) & 255;
157+
*(out++) = (buf >> 8) & 255;
158+
*(out++) = buf & 255;
159+
buf = 0; iter = 0;
160+
}
161+
}
162+
}
163+
164+
if (iter == 3) {
165+
if ((len += 2) > *outLen) {
166+
return BASE64_RET_BUF_OVERFLOW;
167+
}
168+
*(out++) = (buf >> 10) & 255;
169+
*(out++) = (buf >> 2) & 255;
170+
} else if (iter == 2) {
171+
if (++len > *outLen) {
172+
return BASE64_RET_BUF_OVERFLOW;
173+
}
174+
*(out++) = (buf >> 4) & 255;
175+
}
176+
177+
/* Modify to reflect the actual output size. */
178+
*outLen = len;
179+
return BASE64_RET_OK;
180+
}
181+

lib/plumcore-cryptolib/src/base64.h

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Base64 encoding/decoding
3+
*
4+
* Code taken from https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64,
5+
* suspected public domain as the site states.
6+
*/
7+
8+
#pragma once
9+
10+
#include <stdint.h>
11+
#include <stddef.h>
12+
13+
14+
typedef enum {
15+
BASE64_RET_OK = 0,
16+
BASE64_RET_BUF_SMALL,
17+
BASE64_RET_INVALID,
18+
BASE64_RET_BUF_OVERFLOW,
19+
} base64_ret_t;
20+
21+
22+
base64_ret_t base64encode(const void *buf, size_t len, char *result, size_t resultSize);
23+
base64_ret_t base64decode(const char *in, size_t inLen, unsigned char *out, size_t *outLen);
24+

0 commit comments

Comments
 (0)