RFC 4648 (https://tools.ietf.org/html/rfc4648) standardizes two
Base-64 alphabets. Nettle currently only supports the traditional
base-64 alphabet from section 4.

There is growing use amongst new protocol definitions and extensions,
particularly in the HTTP area for the URL-safe extension alphabet
instead of the classical Base-64 alphabet.

The attached patch implements a proposed API/ABI extension adding
support for RFC 4648 section 5 "Base 64 Encoding with URL and Filename
Safe Alphabet"

For the standardized alphabets external code simply calls the init()
function relevant to the alphabet it is needing to encode/decode with.
The library internally uses the context to select which lookup table to
use for later base64 function calls.

For custom or non-standard alphabets a pointer to the alphabet lookup
table is included in the encode/decode contexts. External code can
memset() a context to empty and provide the alphabet lookup table pointer.


Amos Jeffries
Treehouse Networks Ltd.

PS, I have also removed the dead code wrappend in "#if 0" rather than
updating it.
diff --git a/Makefile.in b/Makefile.in
index 2a940f9..48cce47 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -81,6 +81,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
                 arctwo.c arctwo-meta.c blowfish.c \
                 base16-encode.c base16-decode.c base16-meta.c \
                 base64-encode.c base64-decode.c base64-meta.c \
+                base64url-encode.c base64url-decode.c \
                 buffer.c buffer-init.c \
                 camellia-crypt-internal.c camellia-table.c \
                 camellia-absorb.c camellia-invert-key.c \
diff --git a/base64-decode.c b/base64-decode.c
index f622baa..69a1133 100644
--- a/base64-decode.c
+++ b/base64-decode.c
@@ -43,7 +43,7 @@
 #define TABLE_END -3
 
 static const signed char
-decode_table[0x100] =
+default_decode_table[0x100] =
 {
   /* White space is HT, VT, FF, CR, LF and SPC */
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, 
@@ -68,6 +68,7 @@ void
 base64_decode_init(struct base64_decode_ctx *ctx)
 {
   ctx->word = ctx->bits = ctx->padding = 0;
+  ctx->alphabet = default_decode_table;
 }
 
 int
@@ -76,8 +77,7 @@ base64_decode_single(struct base64_decode_ctx *ctx,
                     uint8_t src)
 {
   int data;
-  
-  data = decode_table[src];
+  data = ctx->alphabet[src];
 
   switch(data)
     {
diff --git a/base64-encode.c b/base64-encode.c
index 313c512..2bc2908 100644
--- a/base64-encode.c
+++ b/base64-encode.c
@@ -38,16 +38,24 @@
 
 #include "base64.h"
 
-static const uint8_t encode_table[64] =
+static const uint8_t default_encode_table[64] =
   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   "abcdefghijklmnopqrstuvwxyz"
   "0123456789+/";
 
-#define ENCODE(x) (encode_table[0x3F & (x)])
+#define ENCODE(x) (ctx->alphabet[0x3F & (x)])
 
 void
 base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src)
 {
+  struct base64_encode_ctx ctx;
+  base64_encode_init(&ctx);
+  _base64_encode_raw(&cxt, dst, length, src);
+}
+
+static void
+_base64_encode_raw(struct base64_encode_ctx *ctx, uint8_t *dst, size_t length, 
const uint8_t *src)
+{
   const uint8_t *in = src + length;
   uint8_t *out = dst + BASE64_ENCODE_RAW_LENGTH(length);
 
@@ -87,53 +95,12 @@ base64_encode_raw(uint8_t *dst, size_t length, const 
uint8_t *src)
   assert(out == dst);
 }
 
-#if 0
-unsigned 
-base64_encode(uint8_t *dst,
-             unsigned src_length,
-             const uint8_t *src)
-{
-  unsigned dst_length = BASE64_ENCODE_RAW_LENGTH(src_length);
-  unsigned n = src_length / 3;
-  unsigned left_over  = src_length % 3;
-  unsigned done = 0;
-  
-  if (left_over)
-    {
-      const uint8_t *in = src + n * 3;
-      uint8_t *out = dst + dst_length;
-
-      switch(left_over)
-       {
-       case 1:
-         *--out = '=';
-         *--out = ENCODE(in[0] << 4);
-         break;
-         
-       case 2:
-         *--out = ENCODE( in[1] << 2);
-         *--out = ENCODE((in[0] << 4) | (in[1] >> 4));
-         break;
-
-       default:
-         abort();
-       }
-      *--out = ENCODE(in[0] >> 2);
-
-      done = 4;
-    }
-  base64_encode_raw(n, dst, src);
-  done += n * 4;
-
-  assert(done == dst_length);
-
-  return done;
-}
-#endif
-
 void
 base64_encode_group(uint8_t *dst, uint32_t group)
 {
+  struct base64_encode ctx;
+  base64_encode_init(&ctx);
+
   *dst++ = ENCODE(group >> 18);
   *dst++ = ENCODE(group >> 12);
   *dst++ = ENCODE(group >> 6);
@@ -144,6 +111,7 @@ void
 base64_encode_init(struct base64_encode_ctx *ctx)
 {
   ctx->word = ctx->bits = 0;
+  ctx->alphabet = default_encode_table;
 }
 
 /* Encodes a single byte. */
@@ -196,7 +164,7 @@ base64_encode_update(struct base64_encode_ctx *ctx,
     {
       assert(!(bulk % 3));
       
-      base64_encode_raw(dst + done, bulk, src);
+      _base64_encode_raw(ctx, dst + done, bulk, src);
       done += BASE64_ENCODE_RAW_LENGTH(bulk);
       src += bulk;
       left = left_over;
diff --git a/base64.h b/base64.h
index a6fb823..21381d2 100644
--- a/base64.h
+++ b/base64.h
@@ -42,12 +42,14 @@ extern "C" {
 
 /* Name mangling */
 #define base64_encode_init nettle_base64_encode_init
+#define base64url_encode_init nettle_base64url_encode_init
 #define base64_encode_single nettle_base64_encode_single
 #define base64_encode_update nettle_base64_encode_update
 #define base64_encode_final nettle_base64_encode_final
 #define base64_encode_raw nettle_base64_encode_raw
 #define base64_encode_group nettle_base64_encode_group
 #define base64_decode_init nettle_base64_decode_init
+#define base64url_decode_init nettle_base64url_decode_init
 #define base64_decode_single nettle_base64_decode_single
 #define base64_decode_update nettle_base64_decode_update
 #define base64_decode_final nettle_base64_decode_final
@@ -73,11 +75,17 @@ struct base64_encode_ctx
 {
   unsigned word;   /* Leftover bits */
   unsigned bits;  /* Number of bits, always 0, 2, or 4. */
+  const uint8_t *alphabet; /* which alphabet to use for encoding */
 };
 
+/* initialize encoding context for base-64 */
 void
 base64_encode_init(struct base64_encode_ctx *ctx);
 
+/* initialize encoding context for base-64 with URL safe extended alphabet */
+void
+base64url_encode_init(struct base64_encode_ctx *ctx);
+
 /* Encodes a single byte. Returns amount of output (always 1 or 2). */
 size_t
 base64_encode_single(struct base64_encode_ctx *ctx,
@@ -123,11 +131,17 @@ struct base64_decode_ctx
 
   /* Number of padding characters encountered */
   unsigned padding;
+  const signed char *alphabet; /* which alphabet to use for encoding */
 };
 
+/* initialize encoding context for base-64 */
 void
 base64_decode_init(struct base64_decode_ctx *ctx);
 
+/* initialize encoding context for base-64 with URL safe extended alphabet */
+void
+base64url_decode_init(struct base64_decode_ctx *ctx);
+
 /* Decodes a single byte. Returns amount of output (0 or 1), or -1 on
  * errors. */
 int
diff --git a/base64url-decode.c b/base64url-decode.c
index e69de29..5b1a802 100644
--- a/base64url-decode.c
+++ b/base64url-decode.c
@@ -0,0 +1,65 @@
+/* base64url-decode.c
+
+   Copyright (C) 2015 Niels Möller
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "base64.h"
+
+static const signed char
+urlextended_decode_table[0x100] =
+{
+  /* White space is HT, VT, FF, CR, LF and SPC */
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1,
+  -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
+  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+void
+base64url_decode_init(struct base64_decode_ctx *ctx)
+{
+  ctx->word = ctx->bits = ctx->padding = 0;
+  ctx->alphabet = urlextended_decode_table;
+}
diff --git a/base64url-encode.c b/base64url-encode.c
index e69de29..1f1eab7 100644
--- a/base64url-encode.c
+++ b/base64url-encode.c
@@ -0,0 +1,48 @@
+/* base64url-encode.c
+
+   Copyright (C) 2015 Niels Möller
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "base64.h"
+
+static const uint8_t urlextended_encode_table[64] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "abcdefghijklmnopqrstuvwxyz"
+  "0123456789-_";
+
+void
+base64url_encode_init(struct base64_encode_ctx *ctx)
+{
+  ctx->word = ctx->bits = 0;
+  ctx->alphabet = urlextended_encode_table;
+}
_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs

Reply via email to