lib/base64: RFC4648-compliant base64 encoding
authorHannes Reinecke <hare@suse.de>
Mon, 27 Jun 2022 09:51:59 +0000 (11:51 +0200)
committerJens Axboe <axboe@kernel.dk>
Tue, 2 Aug 2022 23:14:47 +0000 (17:14 -0600)
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>
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Cc: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
include/linux/base64.h [new file with mode: 0644]
lib/Makefile
lib/base64.c [new file with mode: 0644]

diff --git a/include/linux/base64.h b/include/linux/base64.h
new file mode 100644 (file)
index 0000000..660d4cb
--- /dev/null
@@ -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 */
index f99bf61..20d2caf 100644 (file)
@@ -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 (file)
index 0000000..b736a7a
--- /dev/null
@@ -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 base64-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 base64 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);