162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * base64.c - RFC4648-compliant base64 encoding 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020 Hannes Reinecke, SUSE 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on the base64url routines from fs/crypto/fname.c 862306a36Sopenharmony_ci * (which are using the URL-safe base64 encoding), 962306a36Sopenharmony_ci * modified to use the standard coding table from RFC4648 section 4. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/export.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/base64.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic const char base64_table[65] = 1962306a36Sopenharmony_ci "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/** 2262306a36Sopenharmony_ci * base64_encode() - base64-encode some binary data 2362306a36Sopenharmony_ci * @src: the binary data to encode 2462306a36Sopenharmony_ci * @srclen: the length of @src in bytes 2562306a36Sopenharmony_ci * @dst: (output) the base64-encoded string. Not NUL-terminated. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Encodes data using base64 encoding, i.e. the "Base 64 Encoding" specified 2862306a36Sopenharmony_ci * by RFC 4648, including the '='-padding. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Return: the length of the resulting base64-encoded string in bytes. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ciint base64_encode(const u8 *src, int srclen, char *dst) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci u32 ac = 0; 3562306a36Sopenharmony_ci int bits = 0; 3662306a36Sopenharmony_ci int i; 3762306a36Sopenharmony_ci char *cp = dst; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci for (i = 0; i < srclen; i++) { 4062306a36Sopenharmony_ci ac = (ac << 8) | src[i]; 4162306a36Sopenharmony_ci bits += 8; 4262306a36Sopenharmony_ci do { 4362306a36Sopenharmony_ci bits -= 6; 4462306a36Sopenharmony_ci *cp++ = base64_table[(ac >> bits) & 0x3f]; 4562306a36Sopenharmony_ci } while (bits >= 6); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci if (bits) { 4862306a36Sopenharmony_ci *cp++ = base64_table[(ac << (6 - bits)) & 0x3f]; 4962306a36Sopenharmony_ci bits -= 6; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci while (bits < 0) { 5262306a36Sopenharmony_ci *cp++ = '='; 5362306a36Sopenharmony_ci bits += 2; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci return cp - dst; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(base64_encode); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/** 6062306a36Sopenharmony_ci * base64_decode() - base64-decode a string 6162306a36Sopenharmony_ci * @src: the string to decode. Doesn't need to be NUL-terminated. 6262306a36Sopenharmony_ci * @srclen: the length of @src in bytes 6362306a36Sopenharmony_ci * @dst: (output) the decoded binary data 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * Decodes a string using base64 encoding, i.e. the "Base 64 Encoding" 6662306a36Sopenharmony_ci * specified by RFC 4648, including the '='-padding. 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * This implementation hasn't been optimized for performance. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Return: the length of the resulting decoded binary data in bytes, 7162306a36Sopenharmony_ci * or -1 if the string isn't a valid base64 string. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ciint base64_decode(const char *src, int srclen, u8 *dst) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci u32 ac = 0; 7662306a36Sopenharmony_ci int bits = 0; 7762306a36Sopenharmony_ci int i; 7862306a36Sopenharmony_ci u8 *bp = dst; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci for (i = 0; i < srclen; i++) { 8162306a36Sopenharmony_ci const char *p = strchr(base64_table, src[i]); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (src[i] == '=') { 8462306a36Sopenharmony_ci ac = (ac << 6); 8562306a36Sopenharmony_ci bits += 6; 8662306a36Sopenharmony_ci if (bits >= 8) 8762306a36Sopenharmony_ci bits -= 8; 8862306a36Sopenharmony_ci continue; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci if (p == NULL || src[i] == 0) 9162306a36Sopenharmony_ci return -1; 9262306a36Sopenharmony_ci ac = (ac << 6) | (p - base64_table); 9362306a36Sopenharmony_ci bits += 6; 9462306a36Sopenharmony_ci if (bits >= 8) { 9562306a36Sopenharmony_ci bits -= 8; 9662306a36Sopenharmony_ci *bp++ = (u8)(ac >> bits); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci if (ac & ((1 << bits) - 1)) 10062306a36Sopenharmony_ci return -1; 10162306a36Sopenharmony_ci return bp - dst; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(base64_decode); 104