Base64 Encode & Decode in C
Encode or decode below — it runs locally in your browser — then grab the canonical C code. C has no standard Base64 routine, so you either roll a small lookup table or link against OpenSSL. Both approaches are below.
Encode a string
Read the input three bytes (24 bits) at a time, split into four 6-bit values, and index a 64-character alphabet. The trailing 1 or 2 bytes are padded with =:
#include <stdint.h>
#include <stdlib.h>
static const char b64_table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* Returns a malloc'd, null-terminated Base64 string. Caller must free(). */
char *base64_encode(const uint8_t *in, size_t len) {
size_t out_len = 4 * ((len + 2) / 3); /* ceil(len/3) * 4 */
char *out = malloc(out_len + 1); /* +1 for '\0' */
if (!out) return NULL;
size_t i, j;
for (i = 0, j = 0; i + 2 < len; i += 3) {
uint32_t n = ((uint32_t)in[i] << 16)
| ((uint32_t)in[i + 1] << 8)
| (uint32_t)in[i + 2];
out[j++] = b64_table[(n >> 18) & 0x3F];
out[j++] = b64_table[(n >> 12) & 0x3F];
out[j++] = b64_table[(n >> 6) & 0x3F];
out[j++] = b64_table[ n & 0x3F];
}
size_t rem = len - i; /* trailing 1 or 2 bytes */
if (rem == 1) {
uint32_t n = (uint32_t)in[i] << 16;
out[j++] = b64_table[(n >> 18) & 0x3F];
out[j++] = b64_table[(n >> 12) & 0x3F];
out[j++] = '=';
out[j++] = '=';
} else if (rem == 2) {
uint32_t n = ((uint32_t)in[i] << 16) | ((uint32_t)in[i + 1] << 8);
out[j++] = b64_table[(n >> 18) & 0x3F];
out[j++] = b64_table[(n >> 12) & 0x3F];
out[j++] = b64_table[(n >> 6) & 0x3F];
out[j++] = '=';
}
out[j] = '\0';
return out;
}
Tip: C has no standard Base64 — use a lookup table or OpenSSL. Always size the output buffer as 4 * ((n + 2) / 3) + 1, and read input as uint8_t so high-bit bytes don't go negative.
Using OpenSSL (EVP)
If your project already links libcrypto, reuse its well-tested one-shot encoder and decoder instead of maintaining your own:
#include <openssl/evp.h>
#include <stdlib.h>
#include <string.h>
char *openssl_b64_encode(const unsigned char *in, int len) {
char *out = malloc(4 * ((len + 2) / 3) + 1);
if (!out) return NULL;
/* Writes the data plus a trailing '\0'. */
EVP_EncodeBlock((unsigned char *)out, in, len);
return out;
}
/* Returns decoded length. NOTE: EVP_DecodeBlock returns a multiple of 3 —
* subtract the number of trailing '=' yourself to drop padding bytes. */
int openssl_b64_decode(const char *in, unsigned char *out) {
int len = (int)strlen(in);
int n = EVP_DecodeBlock(out, (const unsigned char *)in, len);
if (n < 0) return -1;
if (len >= 2 && in[len - 1] == '=') n--;
if (len >= 2 && in[len - 2] == '=') n--;
return n;
}
URL-safe variant
For JWTs, URLs, and filenames, swap the last two alphabet characters — + and / become - and _ (RFC 4648 §5). The encoder is otherwise identical; just point it at the new table:
static const char b64_url_table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-_";
/* Pass url_safe = 1 to emit the RFC 4648 URL-safe alphabet. */
char *base64_encode_ex(const uint8_t *in, size_t len, int url_safe) {
const char *table = url_safe ? b64_url_table : b64_table;
/* ...identical loop, but index `table` instead of `b64_table`... */
/* (omit '=' padding entirely for unpadded URL-safe output) */
}
Frequently asked questions
Does C have a built-in Base64 function?
No. The C standard library (stdio.h, stdlib.h, string.h, etc.) has no Base64 routines. You write your own lookup-table implementation or link a library such as OpenSSL (EVP_EncodeBlock) or libb64.
How do I Base64 encode a string in C?
Define a 64-character alphabet, read three bytes at a time, and map each 6-bit group to a character. The base64_encode function above returns a malloc'd string you must free().
How do I size the output buffer?
Use 4 * ((len + 2) / 3) + 1 bytes — exact, including padding, plus 1 for the null terminator. Decoded length is at most (encoded_len / 4) * 3.
Should I use OpenSSL or a custom implementation?
If you already link libcrypto, use EVP_EncodeBlock/EVP_DecodeBlock. For embedded or dependency-free code, a small lookup table is portable.
Need image, file, or URL-safe modes?
The main base64.dev tool handles text, images, files, and URL-safe Base64 with auto-detect.
Open base64.dev →