diff mbox series

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

Message ID 20210716110428.9727-5-hare@suse.de
State Superseded
Headers show
Series nvme: In-band authentication support | expand

Commit Message

Hannes Reinecke July 16, 2021, 11:04 a.m. UTC
Add RFC4648-compliant base64 encoding and decoding routines.

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

Comments

Sagi Grimberg July 17, 2021, 6:16 a.m. UTC | #1
> Add RFC4648-compliant base64 encoding and decoding routines.


Looks good to me (although didn't look in the logic itself).
Can you maybe mention where was this taken from?
Hannes Reinecke July 17, 2021, 2 p.m. UTC | #2
On 7/17/21 8:16 AM, Sagi Grimberg wrote:
> 

>> Add RFC4648-compliant base64 encoding and decoding routines.

> 

> Looks good to me (although didn't look in the logic itself).

> Can you maybe mention where was this taken from?


Umm ... yeah, I guess I can; I _think_ I've copied it from base64 
routines in fs/crypto/fname.c, but I'll check.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare@suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Felix Imendörffer
Eric Biggers July 17, 2021, 2:12 p.m. UTC | #3
On Sat, Jul 17, 2021 at 04:00:20PM +0200, Hannes Reinecke wrote:
> On 7/17/21 8:16 AM, Sagi Grimberg wrote:

> > 

> > > Add RFC4648-compliant base64 encoding and decoding routines.

> > 

> > Looks good to me (although didn't look in the logic itself).

> > Can you maybe mention where was this taken from?

> 

> Umm ... yeah, I guess I can; I _think_ I've copied it from base64 routines

> in fs/crypto/fname.c, but I'll check.

> 


Note that it wasn't simply a copy, as you changed the variant of base64 that is
implemented.  So please make sure that you are very clear about which variant of
base64 it is, and update all the comments accordingly.

- Eric
Eric Biggers July 17, 2021, 2:20 p.m. UTC | #4
On Fri, Jul 16, 2021 at 01:04:21PM +0200, Hannes Reinecke wrote:
> +/**

> + * base64_decode() - base64-decode some bytes

> + * @src: the base64-encoded string to decode

> + * @len: number of bytes to decode

> + * @dst: (output) the decoded bytes.

> + *

> + * Decodes the base64-encoded bytes @src according to RFC 4648.

> + *

> + * Return: number of decoded bytes

> + */

> +int base64_decode(const char *src, int len, u8 *dst)

> +{

> +        int i, bits = 0, pad = 0;

> +        u32 ac = 0;

> +        size_t dst_len = 0;

> +

> +        for (i = 0; i < len; i++) {

> +                int c, p = -1;

> +

> +                if (src[i] == '=') {

> +                        pad++;

> +                        if (i + 1 < len && src[i + 1] == '=')

> +                                pad++;

> +                        break;

> +                }

> +                for (c = 0; c < strlen(lookup_table); c++) {

> +                        if (src[i] == lookup_table[c]) {

> +                                p = c;

> +                                break;

> +                        }

> +                }

> +                if (p < 0)

> +                        break;

> +                ac = (ac << 6) | p;

> +                bits += 6;

> +                if (bits < 24)

> +                        continue;

> +                while (bits) {

> +                        bits -= 8;

> +                        dst[dst_len++] = (ac >> bits) & 0xff;

> +                }

> +                ac = 0;

> +        }

> +        dst_len -= pad;

> +        return dst_len;

> +}

> +EXPORT_SYMBOL_GPL(base64_decode);


This should return an error if the input isn't valid base64.

- Eric
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 6d765d5fb8ac..92a428aa0e5f 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..a8929a3a04fe
--- /dev/null
+++ b/lib/base64.c
@@ -0,0 +1,111 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * base64.c - RFC4648-compliant base64 encoding
+ *
+ * Copyright (c) 2020 Hannes Reinecke, SUSE
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/base64.h>
+
+static const char lookup_table[65] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode() - base64-encode some bytes
+ * @src: the bytes to encode
+ * @len: number of bytes to encode
+ * @dst: (output) the base64-encoded string.  Not NUL-terminated.
+ *
+ * Encodes the input string using characters from the set [A-Za-z0-9+,].
+ * The encoded string is roughly 4/3 times the size of the input string.
+ *
+ * Return: length of the encoded string
+ */
+int base64_encode(const u8 *src, int len, char *dst)
+{
+	int i, bits = 0;
+	u32 ac = 0;
+	char *cp = dst;
+
+	for (i = 0; i < len; i++) {
+		ac = (ac << 8) | src[i];
+		bits += 8;
+		if (bits < 24)
+			continue;
+		do {
+			bits -= 6;
+			*cp++ = lookup_table[(ac >> bits) & 0x3f];
+		} while (bits);
+		ac = 0;
+	}
+	if (bits) {
+		int more = 0;
+
+		if (bits < 16)
+			more = 2;
+		ac = (ac << (2 + more));
+		bits += (2 + more);
+		do {
+			bits -= 6;
+			*cp++ = lookup_table[(ac >> bits) & 0x3f];
+		} while (bits);
+		*cp++ = '=';
+		if (more)
+			*cp++ = '=';
+	}
+
+	return cp - dst;
+}
+EXPORT_SYMBOL_GPL(base64_encode);
+
+/**
+ * base64_decode() - base64-decode some bytes
+ * @src: the base64-encoded string to decode
+ * @len: number of bytes to decode
+ * @dst: (output) the decoded bytes.
+ *
+ * Decodes the base64-encoded bytes @src according to RFC 4648.
+ *
+ * Return: number of decoded bytes
+ */
+int base64_decode(const char *src, int len, u8 *dst)
+{
+        int i, bits = 0, pad = 0;
+        u32 ac = 0;
+        size_t dst_len = 0;
+
+        for (i = 0; i < len; i++) {
+                int c, p = -1;
+
+                if (src[i] == '=') {
+                        pad++;
+                        if (i + 1 < len && src[i + 1] == '=')
+                                pad++;
+                        break;
+                }
+                for (c = 0; c < strlen(lookup_table); c++) {
+                        if (src[i] == lookup_table[c]) {
+                                p = c;
+                                break;
+                        }
+                }
+                if (p < 0)
+                        break;
+                ac = (ac << 6) | p;
+                bits += 6;
+                if (bits < 24)
+                        continue;
+                while (bits) {
+                        bits -= 8;
+                        dst[dst_len++] = (ac >> bits) & 0xff;
+                }
+                ac = 0;
+        }
+        dst_len -= pad;
+        return dst_len;
+}
+EXPORT_SYMBOL_GPL(base64_decode);