diff mbox series

[04/12] lib/base64: RFC4648-compliant base64 encoding

Message ID 20211112125928.97318-5-hare@suse.de (mailing list archive)
State Not Applicable
Delegated to: Herbert Xu
Headers show
Series nvme: In-band authentication support | expand

Commit Message

Hannes Reinecke Nov. 12, 2021, 12:59 p.m. UTC
Add RFC4648-compliant base64 encoding and decoding routines, based on
the base64url encoding in fs/crypto/fname.c.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 include/linux/base64.h |  16 +++++++
 lib/Makefile           |   2 +-
 lib/base64.c           | 103 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 120 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/base64.h
 create mode 100644 lib/base64.c

Comments

Himanshu Madhani Nov. 15, 2021, 3:21 p.m. UTC | #1
On 11/12/21 06:59, Hannes Reinecke wrote:
> Add RFC4648-compliant base64 encoding and decoding routines, based on
> the base64url encoding in fs/crypto/fname.c.
> 
> Signed-off-by: Hannes Reinecke <hare@suse.de>
> ---
>   include/linux/base64.h |  16 +++++++
>   lib/Makefile           |   2 +-
>   lib/base64.c           | 103 +++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 120 insertions(+), 1 deletion(-)
>   create mode 100644 include/linux/base64.h
>   create mode 100644 lib/base64.c
> 
> diff --git a/include/linux/base64.h b/include/linux/base64.h
> new file mode 100644
> index 000000000000..660d4cb1ef31
> --- /dev/null
> +++ b/include/linux/base64.h
> @@ -0,0 +1,16 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * base64 encoding, lifted from fs/crypto/fname.c.
> + */
> +
> +#ifndef _LINUX_BASE64_H
> +#define _LINUX_BASE64_H
> +
> +#include <linux/types.h>
> +
> +#define BASE64_CHARS(nbytes)   DIV_ROUND_UP((nbytes) * 4, 3)
> +
> +int base64_encode(const u8 *src, int len, char *dst);
> +int base64_decode(const char *src, int len, u8 *dst);
> +
> +#endif /* _LINUX_BASE64_H */
> diff --git a/lib/Makefile b/lib/Makefile
> index 364c23f15578..ddc5cb4c6eb8 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -46,7 +46,7 @@ obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
>   	 bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
>   	 list_sort.o uuid.o iov_iter.o clz_ctz.o \
>   	 bsearch.o find_bit.o llist.o memweight.o kfifo.o \
> -	 percpu-refcount.o rhashtable.o \
> +	 percpu-refcount.o rhashtable.o base64.o \
>   	 once.o refcount.o usercopy.o errseq.o bucket_locks.o \
>   	 generic-radix-tree.o
>   obj-$(CONFIG_STRING_SELFTEST) += test_string.o
> diff --git a/lib/base64.c b/lib/base64.c
> new file mode 100644
> index 000000000000..60d46157da85
> --- /dev/null
> +++ b/lib/base64.c
> @@ -0,0 +1,103 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * base64.c - RFC4648-compliant base64 encoding
> + *
> + * Copyright (c) 2020 Hannes Reinecke, SUSE
> + *
> + * Based on the base64url routines from fs/crypto/fname.c
> + * (which are using the URL-safe base64 encoding),
> + * modified to use the standard coding table from RFC4648 section 4.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/export.h>
> +#include <linux/string.h>
> +#include <linux/base64.h>
> +
> +static const char base64_table[65] =
> +	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
> +
> +/**
> + * base64_encode() - base64-encode some binary data
> + * @src: the binary data to encode
> + * @srclen: the length of @src in bytes
> + * @dst: (output) the base64-encoded string.  Not NUL-terminated.
> + *
> + * Encodes data using base64 encoding, i.e. the "Base 64 Encoding" specified
> + * by RFC 4648, including the  '='-padding.
> + *
> + * Return: the length of the resulting base64url-encoded string in bytes.
> + */
> +int base64_encode(const u8 *src, int srclen, char *dst)
> +{
> +	u32 ac = 0;
> +	int bits = 0;
> +	int i;
> +	char *cp = dst;
> +
> +	for (i = 0; i < srclen; i++) {
> +		ac = (ac << 8) | src[i];
> +		bits += 8;
> +		do {
> +			bits -= 6;
> +			*cp++ = base64_table[(ac >> bits) & 0x3f];
> +		} while (bits >= 6);
> +	}
> +	if (bits) {
> +		*cp++ = base64_table[(ac << (6 - bits)) & 0x3f];
> +		bits -= 6;
> +	}
> +	while (bits < 0) {
> +		*cp++ = '=';
> +		bits += 2;
> +	}
> +	return cp - dst;
> +}
> +EXPORT_SYMBOL_GPL(base64_encode);
> +
> +/**
> + * base64_decode() - base64-decode a string
> + * @src: the string to decode.  Doesn't need to be NUL-terminated.
> + * @srclen: the length of @src in bytes
> + * @dst: (output) the decoded binary data
> + *
> + * Decodes a string using base64url encoding, i.e. the "Base 64 Encoding"
> + * specified by RFC 4648, including the  '='-padding.
> + *
> + * This implementation hasn't been optimized for performance.
> + *
> + * Return: the length of the resulting decoded binary data in bytes,
> + *	   or -1 if the string isn't a valid base64 string.
> + */
> +int base64_decode(const char *src, int srclen, u8 *dst)
> +{
> +	u32 ac = 0;
> +	int bits = 0;
> +	int i;
> +	u8 *bp = dst;
> +
> +	for (i = 0; i < srclen; i++) {
> +		const char *p = strchr(base64_table, src[i]);
> +
> +		if (src[i] == '=') {
> +			ac = (ac << 6);
> +			bits += 6;
> +			if (bits >= 8)
> +				bits -= 8;
> +			continue;
> +		}
> +		if (p == NULL || src[i] == 0)
> +			return -1;
> +		ac = (ac << 6) | (p - base64_table);
> +		bits += 6;
> +		if (bits >= 8) {
> +			bits -= 8;
> +			*bp++ = (u8)(ac >> bits);
> +		}
> +	}
> +	if (ac & ((1 << bits) - 1))
> +		return -1;
> +	return bp - dst;
> +}
> +EXPORT_SYMBOL_GPL(base64_decode);
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
diff mbox series

Patch

diff --git a/include/linux/base64.h b/include/linux/base64.h
new file mode 100644
index 000000000000..660d4cb1ef31
--- /dev/null
+++ b/include/linux/base64.h
@@ -0,0 +1,16 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * base64 encoding, lifted from fs/crypto/fname.c.
+ */
+
+#ifndef _LINUX_BASE64_H
+#define _LINUX_BASE64_H
+
+#include <linux/types.h>
+
+#define BASE64_CHARS(nbytes)   DIV_ROUND_UP((nbytes) * 4, 3)
+
+int base64_encode(const u8 *src, int len, char *dst);
+int base64_decode(const char *src, int len, u8 *dst);
+
+#endif /* _LINUX_BASE64_H */
diff --git a/lib/Makefile b/lib/Makefile
index 364c23f15578..ddc5cb4c6eb8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -46,7 +46,7 @@  obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
 	 bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
 	 list_sort.o uuid.o iov_iter.o clz_ctz.o \
 	 bsearch.o find_bit.o llist.o memweight.o kfifo.o \
-	 percpu-refcount.o rhashtable.o \
+	 percpu-refcount.o rhashtable.o base64.o \
 	 once.o refcount.o usercopy.o errseq.o bucket_locks.o \
 	 generic-radix-tree.o
 obj-$(CONFIG_STRING_SELFTEST) += test_string.o
diff --git a/lib/base64.c b/lib/base64.c
new file mode 100644
index 000000000000..60d46157da85
--- /dev/null
+++ b/lib/base64.c
@@ -0,0 +1,103 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * base64.c - RFC4648-compliant base64 encoding
+ *
+ * Copyright (c) 2020 Hannes Reinecke, SUSE
+ *
+ * Based on the base64url routines from fs/crypto/fname.c
+ * (which are using the URL-safe base64 encoding),
+ * modified to use the standard coding table from RFC4648 section 4.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/base64.h>
+
+static const char base64_table[65] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode() - base64-encode some binary data
+ * @src: the binary data to encode
+ * @srclen: the length of @src in bytes
+ * @dst: (output) the base64-encoded string.  Not NUL-terminated.
+ *
+ * Encodes data using base64 encoding, i.e. the "Base 64 Encoding" specified
+ * by RFC 4648, including the  '='-padding.
+ *
+ * Return: the length of the resulting base64url-encoded string in bytes.
+ */
+int base64_encode(const u8 *src, int srclen, char *dst)
+{
+	u32 ac = 0;
+	int bits = 0;
+	int i;
+	char *cp = dst;
+
+	for (i = 0; i < srclen; i++) {
+		ac = (ac << 8) | src[i];
+		bits += 8;
+		do {
+			bits -= 6;
+			*cp++ = base64_table[(ac >> bits) & 0x3f];
+		} while (bits >= 6);
+	}
+	if (bits) {
+		*cp++ = base64_table[(ac << (6 - bits)) & 0x3f];
+		bits -= 6;
+	}
+	while (bits < 0) {
+		*cp++ = '=';
+		bits += 2;
+	}
+	return cp - dst;
+}
+EXPORT_SYMBOL_GPL(base64_encode);
+
+/**
+ * base64_decode() - base64-decode a string
+ * @src: the string to decode.  Doesn't need to be NUL-terminated.
+ * @srclen: the length of @src in bytes
+ * @dst: (output) the decoded binary data
+ *
+ * Decodes a string using base64url encoding, i.e. the "Base 64 Encoding"
+ * specified by RFC 4648, including the  '='-padding.
+ *
+ * This implementation hasn't been optimized for performance.
+ *
+ * Return: the length of the resulting decoded binary data in bytes,
+ *	   or -1 if the string isn't a valid base64 string.
+ */
+int base64_decode(const char *src, int srclen, u8 *dst)
+{
+	u32 ac = 0;
+	int bits = 0;
+	int i;
+	u8 *bp = dst;
+
+	for (i = 0; i < srclen; i++) {
+		const char *p = strchr(base64_table, src[i]);
+
+		if (src[i] == '=') {
+			ac = (ac << 6);
+			bits += 6;
+			if (bits >= 8)
+				bits -= 8;
+			continue;
+		}
+		if (p == NULL || src[i] == 0)
+			return -1;
+		ac = (ac << 6) | (p - base64_table);
+		bits += 6;
+		if (bits >= 8) {
+			bits -= 8;
+			*bp++ = (u8)(ac >> bits);
+		}
+	}
+	if (ac & ((1 << bits) - 1))
+		return -1;
+	return bp - dst;
+}
+EXPORT_SYMBOL_GPL(base64_decode);