xref: /linux/lib/base64.c (revision 001c6df098834eb5eaa36a2b121bd6a675b38aa9)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * base64.c - RFC4648-compliant base64 encoding
4   *
5   * Copyright (c) 2020 Hannes Reinecke, SUSE
6   *
7   * Based on the base64url routines from fs/crypto/fname.c
8   * (which are using the URL-safe base64 encoding),
9   * modified to use the standard coding table from RFC4648 section 4.
10   */
11  
12  #include <linux/kernel.h>
13  #include <linux/types.h>
14  #include <linux/export.h>
15  #include <linux/string.h>
16  #include <linux/base64.h>
17  
18  static const char base64_table[65] =
19  	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
20  
21  /**
22   * base64_encode() - base64-encode some binary data
23   * @src: the binary data to encode
24   * @srclen: the length of @src in bytes
25   * @dst: (output) the base64-encoded string.  Not NUL-terminated.
26   *
27   * Encodes data using base64 encoding, i.e. the "Base 64 Encoding" specified
28   * by RFC 4648, including the  '='-padding.
29   *
30   * Return: the length of the resulting base64-encoded string in bytes.
31   */
32  int base64_encode(const u8 *src, int srclen, char *dst)
33  {
34  	u32 ac = 0;
35  	int bits = 0;
36  	int i;
37  	char *cp = dst;
38  
39  	for (i = 0; i < srclen; i++) {
40  		ac = (ac << 8) | src[i];
41  		bits += 8;
42  		do {
43  			bits -= 6;
44  			*cp++ = base64_table[(ac >> bits) & 0x3f];
45  		} while (bits >= 6);
46  	}
47  	if (bits) {
48  		*cp++ = base64_table[(ac << (6 - bits)) & 0x3f];
49  		bits -= 6;
50  	}
51  	while (bits < 0) {
52  		*cp++ = '=';
53  		bits += 2;
54  	}
55  	return cp - dst;
56  }
57  EXPORT_SYMBOL_GPL(base64_encode);
58  
59  /**
60   * base64_decode() - base64-decode a string
61   * @src: the string to decode.  Doesn't need to be NUL-terminated.
62   * @srclen: the length of @src in bytes
63   * @dst: (output) the decoded binary data
64   *
65   * Decodes a string using base64 encoding, i.e. the "Base 64 Encoding"
66   * specified by RFC 4648, including the  '='-padding.
67   *
68   * This implementation hasn't been optimized for performance.
69   *
70   * Return: the length of the resulting decoded binary data in bytes,
71   *	   or -1 if the string isn't a valid base64 string.
72   */
73  int base64_decode(const char *src, int srclen, u8 *dst)
74  {
75  	u32 ac = 0;
76  	int bits = 0;
77  	int i;
78  	u8 *bp = dst;
79  
80  	for (i = 0; i < srclen; i++) {
81  		const char *p = strchr(base64_table, src[i]);
82  
83  		if (src[i] == '=') {
84  			ac = (ac << 6);
85  			bits += 6;
86  			if (bits >= 8)
87  				bits -= 8;
88  			continue;
89  		}
90  		if (p == NULL || src[i] == 0)
91  			return -1;
92  		ac = (ac << 6) | (p - base64_table);
93  		bits += 6;
94  		if (bits >= 8) {
95  			bits -= 8;
96  			*bp++ = (u8)(ac >> bits);
97  		}
98  	}
99  	if (ac & ((1 << bits) - 1))
100  		return -1;
101  	return bp - dst;
102  }
103  EXPORT_SYMBOL_GPL(base64_decode);
104