Blame SOURCES/Add-libkrb5support-hex-functions-and-tests.patch

d7027e
From 868cbb573b512eac4561046fe7540c37406637fb Mon Sep 17 00:00:00 2001
d7027e
From: Greg Hudson <ghudson@mit.edu>
d7027e
Date: Mon, 19 Feb 2018 00:51:44 -0500
d7027e
Subject: [PATCH] Add libkrb5support hex functions and tests
d7027e
d7027e
(cherry picked from commit 720dea558da0062d3cea4385327161e62cf09a5e)
d7027e
[rharwood@redhat.com: gitignore, backport around no utf16]
d7027e
---
d7027e
 src/include/k5-hex.h                          |  53 ++++++
d7027e
 src/util/support/Makefile.in                  |  13 +-
d7027e
 src/util/support/deps                         |   6 +
d7027e
 src/util/support/hex.c                        | 116 ++++++++++++
d7027e
 src/util/support/libkrb5support-fixed.exports |   2 +
d7027e
 src/util/support/t_hex.c                      | 169 ++++++++++++++++++
d7027e
 6 files changed, 357 insertions(+), 2 deletions(-)
d7027e
 create mode 100644 src/include/k5-hex.h
d7027e
 create mode 100644 src/util/support/hex.c
d7027e
 create mode 100644 src/util/support/t_hex.c
d7027e
d7027e
diff --git a/src/include/k5-hex.h b/src/include/k5-hex.h
d7027e
new file mode 100644
d7027e
index 000000000..75bd2cb19
d7027e
--- /dev/null
d7027e
+++ b/src/include/k5-hex.h
d7027e
@@ -0,0 +1,53 @@
d7027e
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
d7027e
+/* include/k5-hex.h - libkrb5support hex encoding/decoding declarations */
d7027e
+/*
d7027e
+ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
d7027e
+ * All rights reserved.
d7027e
+ *
d7027e
+ * Redistribution and use in source and binary forms, with or without
d7027e
+ * modification, are permitted provided that the following conditions
d7027e
+ * are met:
d7027e
+ *
d7027e
+ * * Redistributions of source code must retain the above copyright
d7027e
+ *   notice, this list of conditions and the following disclaimer.
d7027e
+ *
d7027e
+ * * Redistributions in binary form must reproduce the above copyright
d7027e
+ *   notice, this list of conditions and the following disclaimer in
d7027e
+ *   the documentation and/or other materials provided with the
d7027e
+ *   distribution.
d7027e
+ *
d7027e
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
d7027e
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
d7027e
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
d7027e
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
d7027e
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
d7027e
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
d7027e
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
d7027e
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
d7027e
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
d7027e
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
d7027e
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
d7027e
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
d7027e
+ */
d7027e
+
d7027e
+#ifndef K5_HEX_H
d7027e
+#define K5_HEX_H
d7027e
+
d7027e
+#include "k5-platform.h"
d7027e
+
d7027e
+/*
d7027e
+ * Encode len bytes in hex, placing the result in allocated storage in
d7027e
+ * *hex_out.  Use uppercase hex digits if uppercase is non-zero.  Return 0 on
d7027e
+ * success, ENOMEM on error.
d7027e
+ */
d7027e
+int k5_hex_encode(const void *bytes, size_t len, int uppercase,
d7027e
+                  char **hex_out);
d7027e
+
d7027e
+/*
d7027e
+ * Decode hex bytes, placing the result in allocated storage in *bytes_out and
d7027e
+ * *len_out.  Null-terminate the result (primarily for decoding passwords in
d7027e
+ * libkdb_ldap).  Return 0 on success, ENOMEM or EINVAL on error.
d7027e
+ */
d7027e
+int k5_hex_decode(const char *hex, uint8_t **bytes_out, size_t *len_out);
d7027e
+
d7027e
+#endif /* K5_HEX_H */
d7027e
diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
d7027e
index 9326742d7..b3576f0b7 100644
d7027e
--- a/src/util/support/Makefile.in
d7027e
+++ b/src/util/support/Makefile.in
d7027e
@@ -82,6 +82,7 @@ STLIBOBJS= \
d7027e
 	path.o \
d7027e
 	base64.o \
d7027e
 	json.o \
d7027e
+	hex.o \
d7027e
 	bcmp.o \
d7027e
 	strerror_r.o \
d7027e
 	dir_filenames.o \
d7027e
@@ -108,6 +109,7 @@ LIBOBJS= \
d7027e
 	$(OUTPRE)path.$(OBJEXT) \
d7027e
 	$(OUTPRE)base64.$(OBJEXT) \
d7027e
 	$(OUTPRE)json.$(OBJEXT) \
d7027e
+	$(OUTPRE)hex.$(OBJEXT) \
d7027e
 	$(OUTPRE)bcmp.$(OBJEXT) \
d7027e
 	$(OUTPRE)strerror_r.$(OBJEXT) \
d7027e
 	$(OUTPRE)dir_filenames.$(OBJEXT) \
d7027e
@@ -139,10 +141,12 @@ SRCS=\
d7027e
 	$(srcdir)/t_unal.c \
d7027e
 	$(srcdir)/t_path.c \
d7027e
 	$(srcdir)/t_json.c \
d7027e
+	$(srcdir)/t_hex.c \
d7027e
 	$(srcdir)/zap.c \
d7027e
 	$(srcdir)/path.c \
d7027e
 	$(srcdir)/base64.c \
d7027e
 	$(srcdir)/json.c \
d7027e
+	$(srcdir)/hex.c \
d7027e
 	$(srcdir)/bcmp.c \
d7027e
 	$(srcdir)/strerror_r.c \
d7027e
 	$(srcdir)/dir_filenames.c \
d7027e
@@ -218,13 +222,16 @@ T_JSON_OBJS= t_json.o json.o base64.o k5buf.o $(PRINTF_ST_OBJ)
d7027e
 t_json: $(T_JSON_OBJS)
d7027e
 	$(CC_LINK) -o $@ $(T_JSON_OBJS)
d7027e
 
d7027e
+t_hex: t_hex.o hex.o
d7027e
+	$(CC_LINK) -o $@ t_hex.o hex.o
d7027e
+
d7027e
 t_unal: t_unal.o
d7027e
 	$(CC_LINK) -o t_unal t_unal.o
d7027e
 
d7027e
 t_utf8: t_utf8.o utf8.o
d7027e
 	$(CC_LINK) -o t_utf8 t_utf8.o utf8.o
d7027e
 
d7027e
-TEST_PROGS= t_k5buf t_path t_path_win t_base64 t_json t_unal t_utf8
d7027e
+TEST_PROGS= t_k5buf t_path t_path_win t_base64 t_json t_hex t_unal t_utf8
d7027e
 
d7027e
 check-unix: $(TEST_PROGS)
d7027e
 	./t_k5buf
d7027e
@@ -232,13 +239,15 @@ check-unix: $(TEST_PROGS)
d7027e
 	./t_path_win
d7027e
 	./t_base64
d7027e
 	./t_json
d7027e
+	./t_hex
d7027e
 	./t_unal
d7027e
 	./t_utf8
d7027e
 
d7027e
 clean:
d7027e
 	$(RM) t_k5buf.o t_k5buf t_unal.o t_unal path_win.o path_win
d7027e
 	$(RM) t_path_win.o t_path_win t_path.o t_path t_base64.o t_base64
d7027e
-	$(RM) t_json.o t_json libkrb5support.exports t_utf8.o t_utf8
d7027e
+	$(RM) t_json.o t_json t_hex.o t_hex libkrb5support.exports
d7027e
+	$(RM) t_utf8.o t_utf8
d7027e
 
d7027e
 @lib_frag@
d7027e
 @libobj_frag@
d7027e
diff --git a/src/util/support/deps b/src/util/support/deps
d7027e
index 4dff014f4..551843357 100644
d7027e
--- a/src/util/support/deps
d7027e
+++ b/src/util/support/deps
d7027e
@@ -62,6 +62,9 @@ t_path.so t_path.po $(OUTPRE)t_path.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
d7027e
   t_path.c
d7027e
 t_json.so t_json.po $(OUTPRE)t_json.$(OBJEXT): $(top_srcdir)/include/k5-json.h \
d7027e
   t_json.c
d7027e
+t_hex.so t_hex.po $(OUTPRE)t_hex.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
d7027e
+  $(top_srcdir)/include/k5-hex.h $(top_srcdir)/include/k5-platform.h \
d7027e
+  $(top_srcdir)/include/k5-thread.h t_hex.c
d7027e
 zap.so zap.po $(OUTPRE)zap.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
d7027e
   $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
d7027e
   zap.c
d7027e
@@ -75,6 +78,9 @@ json.so json.po $(OUTPRE)json.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
d7027e
   $(top_srcdir)/include/k5-base64.h $(top_srcdir)/include/k5-buf.h \
d7027e
   $(top_srcdir)/include/k5-json.h $(top_srcdir)/include/k5-platform.h \
d7027e
   $(top_srcdir)/include/k5-thread.h json.c
d7027e
+hex.so hex.po $(OUTPRE)hex.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
d7027e
+  $(top_srcdir)/include/k5-hex.h $(top_srcdir)/include/k5-platform.h \
d7027e
+  $(top_srcdir)/include/k5-thread.h hex.c
d7027e
 bcmp.so bcmp.po $(OUTPRE)bcmp.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
d7027e
   $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
d7027e
   bcmp.c
d7027e
diff --git a/src/util/support/hex.c b/src/util/support/hex.c
d7027e
new file mode 100644
d7027e
index 000000000..4407ff9ff
d7027e
--- /dev/null
d7027e
+++ b/src/util/support/hex.c
d7027e
@@ -0,0 +1,116 @@
d7027e
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
d7027e
+/* util/support/hex.c - hex encoding/decoding implementation */
d7027e
+/*
d7027e
+ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
d7027e
+ * All rights reserved.
d7027e
+ *
d7027e
+ * Redistribution and use in source and binary forms, with or without
d7027e
+ * modification, are permitted provided that the following conditions
d7027e
+ * are met:
d7027e
+ *
d7027e
+ * * Redistributions of source code must retain the above copyright
d7027e
+ *   notice, this list of conditions and the following disclaimer.
d7027e
+ *
d7027e
+ * * Redistributions in binary form must reproduce the above copyright
d7027e
+ *   notice, this list of conditions and the following disclaimer in
d7027e
+ *   the documentation and/or other materials provided with the
d7027e
+ *   distribution.
d7027e
+ *
d7027e
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
d7027e
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
d7027e
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
d7027e
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
d7027e
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
d7027e
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
d7027e
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
d7027e
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
d7027e
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
d7027e
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
d7027e
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
d7027e
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
d7027e
+ */
d7027e
+
d7027e
+#include <k5-platform.h>
d7027e
+#include <k5-hex.h>
d7027e
+#include <ctype.h>
d7027e
+
d7027e
+static inline char
d7027e
+hex_digit(uint8_t bval, int uppercase)
d7027e
+{
d7027e
+    assert(bval >= 0 && bval <= 0xF);
d7027e
+    if (bval < 10)
d7027e
+        return '0' + bval;
d7027e
+    else if (uppercase)
d7027e
+        return 'A' + (bval - 10);
d7027e
+    else
d7027e
+        return 'a' + (bval - 10);
d7027e
+}
d7027e
+
d7027e
+int
d7027e
+k5_hex_encode(const void *bytes, size_t len, int uppercase, char **hex_out)
d7027e
+{
d7027e
+    size_t i;
d7027e
+    const uint8_t *p = bytes;
d7027e
+    char *hex;
d7027e
+
d7027e
+    *hex_out = NULL;
d7027e
+
d7027e
+    hex = malloc(len * 2 + 1);
d7027e
+    if (hex == NULL)
d7027e
+        return ENOMEM;
d7027e
+
d7027e
+    for (i = 0; i < len; i++) {
d7027e
+        hex[i * 2] = hex_digit(p[i] >> 4, uppercase);
d7027e
+        hex[i * 2 + 1] = hex_digit(p[i] & 0xF, uppercase);
d7027e
+    }
d7027e
+    hex[len * 2] = '\0';
d7027e
+
d7027e
+    *hex_out = hex;
d7027e
+    return 0;
d7027e
+}
d7027e
+
d7027e
+/* Decode a hex digit.  Return 0-15 on success, -1 on invalid input. */
d7027e
+static inline int
d7027e
+decode_hexchar(unsigned char c)
d7027e
+{
d7027e
+    if (isdigit(c))
d7027e
+        return c - '0';
d7027e
+    if (c >= 'A' && c <= 'F')
d7027e
+        return c - 'A' + 10;
d7027e
+    if (c >= 'a' && c <= 'f')
d7027e
+        return c - 'a' + 10;
d7027e
+    return -1;
d7027e
+}
d7027e
+
d7027e
+int
d7027e
+k5_hex_decode(const char *hex, uint8_t **bytes_out, size_t *len_out)
d7027e
+{
d7027e
+    size_t hexlen, i;
d7027e
+    int h1, h2;
d7027e
+    uint8_t *bytes;
d7027e
+
d7027e
+    *bytes_out = NULL;
d7027e
+    *len_out = 0;
d7027e
+
d7027e
+    hexlen = strlen(hex);
d7027e
+    if (hexlen % 2 != 0)
d7027e
+        return EINVAL;
d7027e
+    bytes = malloc(hexlen / 2 + 1);
d7027e
+    if (bytes == NULL)
d7027e
+        return ENOMEM;
d7027e
+
d7027e
+    for (i = 0; i < hexlen / 2; i++) {
d7027e
+        h1 = decode_hexchar(hex[i * 2]);
d7027e
+        h2 = decode_hexchar(hex[i * 2 + 1]);
d7027e
+        if (h1 == -1 || h2 == -1) {
d7027e
+            free(bytes);
d7027e
+            return EINVAL;
d7027e
+        }
d7027e
+        bytes[i] = h1 * 16 + h2;
d7027e
+    }
d7027e
+    bytes[i] = 0;
d7027e
+
d7027e
+    *bytes_out = bytes;
d7027e
+    *len_out = hexlen / 2;
d7027e
+    return 0;
d7027e
+}
d7027e
diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
d7027e
index 2cdcddfe0..6193d7331 100644
d7027e
--- a/src/util/support/libkrb5support-fixed.exports
d7027e
+++ b/src/util/support/libkrb5support-fixed.exports
d7027e
@@ -16,6 +16,8 @@ k5_get_error
d7027e
 k5_free_error
d7027e
 k5_clear_error
d7027e
 k5_set_error_info_callout_fn
d7027e
+k5_hex_decode
d7027e
+k5_hex_encode
d7027e
 k5_json_array_add
d7027e
 k5_json_array_create
d7027e
 k5_json_array_fmt
d7027e
diff --git a/src/util/support/t_hex.c b/src/util/support/t_hex.c
d7027e
new file mode 100644
d7027e
index 000000000..a586a1bc8
d7027e
--- /dev/null
d7027e
+++ b/src/util/support/t_hex.c
d7027e
@@ -0,0 +1,169 @@
d7027e
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
d7027e
+/* util/support/t_hex.c - Test hex encoding and decoding */
d7027e
+/*
d7027e
+ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
d7027e
+ * All rights reserved.
d7027e
+ *
d7027e
+ * Redistribution and use in source and binary forms, with or without
d7027e
+ * modification, are permitted provided that the following conditions
d7027e
+ * are met:
d7027e
+ *
d7027e
+ * * Redistributions of source code must retain the above copyright
d7027e
+ *   notice, this list of conditions and the following disclaimer.
d7027e
+ *
d7027e
+ * * Redistributions in binary form must reproduce the above copyright
d7027e
+ *   notice, this list of conditions and the following disclaimer in
d7027e
+ *   the documentation and/or other materials provided with the
d7027e
+ *   distribution.
d7027e
+ *
d7027e
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
d7027e
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
d7027e
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
d7027e
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
d7027e
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
d7027e
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
d7027e
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
d7027e
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
d7027e
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
d7027e
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
d7027e
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
d7027e
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
d7027e
+ */
d7027e
+
d7027e
+#include <k5-platform.h>
d7027e
+#include <k5-hex.h>
d7027e
+
d7027e
+struct {
d7027e
+    const char *hex;
d7027e
+    const char *binary;
d7027e
+    size_t binary_len;
d7027e
+    int uppercase;
d7027e
+} tests[] = {
d7027e
+    /* Invalid hex strings */
d7027e
+    { "1" },
d7027e
+    { "123" },
d7027e
+    { "0/" },
d7027e
+    { "/0" },
d7027e
+    { "0:" },
d7027e
+    { ":0" },
d7027e
+    { "0@" },
d7027e
+    { "@0" },
d7027e
+    { "0G" },
d7027e
+    { "G0" },
d7027e
+    { "0`" },
d7027e
+    { "`0" },
d7027e
+    { "0g" },
d7027e
+    { "g0" },
d7027e
+    { " 00 " },
d7027e
+    { "0\x01" },
d7027e
+
d7027e
+    { "", "", 0 },
d7027e
+    { "00", "\x00", 1 },
d7027e
+    { "01", "\x01", 1 },
d7027e
+    { "10", "\x10", 1 },
d7027e
+    { "01ff", "\x01\xFF", 2 },
d7027e
+    { "A0B0C0", "\xA0\xB0\xC0", 3, 1 },
d7027e
+    { "1a2b3c4d5e6f", "\x1A\x2B\x3C\x4D\x5E\x6F", 6 },
d7027e
+    { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
d7027e
+      "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
d7027e
+      "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32 },
d7027e
+
d7027e
+    /* All byte values, lowercase */
d7027e
+    { "0001020304050607", "\x00\x01\x02\x03\x04\x05\x06\x07", 8 },
d7027e
+    { "08090a0b0c0d0e0f", "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", 8 },
d7027e
+    { "1011121314151617", "\x10\x11\x12\x13\x14\x15\x16\x17", 8 },
d7027e
+    { "18191a1b1c1d1e1f", "\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 8 },
d7027e
+    { "2021222324252627", "\x20\x21\x22\x23\x24\x25\x26\x27", 8 },
d7027e
+    { "28292a2b2c2d2e2f", "\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F", 8 },
d7027e
+    { "3031323334353637", "\x30\x31\x32\x33\x34\x35\x36\x37", 8 },
d7027e
+    { "38393a3b3c3d3e3f", "\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F", 8 },
d7027e
+    { "4041424344454647", "\x40\x41\x42\x43\x44\x45\x46\x47", 8 },
d7027e
+    { "48494a4b4c4d4e4f", "\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F", 8 },
d7027e
+    { "5051525354555657", "\x50\x51\x52\x53\x54\x55\x56\x57", 8 },
d7027e
+    { "58595a5b5c5d5e5f", "\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F", 8 },
d7027e
+    { "6061626364656667", "\x60\x61\x62\x63\x64\x65\x66\x67", 8 },
d7027e
+    { "68696a6b6c6d6e6f", "\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F", 8 },
d7027e
+    { "7071727374757677", "\x70\x71\x72\x73\x74\x75\x76\x77", 8 },
d7027e
+    { "78797a7b7c7d7e7f", "\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F", 8 },
d7027e
+    { "8081828384858687", "\x80\x81\x82\x83\x84\x85\x86\x87", 8 },
d7027e
+    { "88898a8b8c8d8e8f", "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F", 8 },
d7027e
+    { "9091929394959697", "\x90\x91\x92\x93\x94\x95\x96\x97", 8 },
d7027e
+    { "98999a9b9c9d9e9f", "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F", 8 },
d7027e
+    { "a0a1a2a3a4a5a6a7", "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", 8 },
d7027e
+    { "a8a9aaabacadaeaf", "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF", 8 },
d7027e
+    { "b0b1b2b3b4b5b6b7", "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7", 8 },
d7027e
+    { "b8b9babbbcbdbebf", "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF", 8 },
d7027e
+    { "c0c1c2c3c4c5c6c7", "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7", 8 },
d7027e
+    { "c8c9cacbcccdcecf", "\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", 8 },
d7027e
+    { "d0d1d2d3d4d5d6d7", "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7", 8 },
d7027e
+    { "d8d9dadbdcdddedf", "\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF", 8 },
d7027e
+    { "e0e1e2e3e4e5e6e7", "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7", 8 },
d7027e
+    { "e8e9eaebecedeeef", "\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF", 8 },
d7027e
+    { "f0f1f2f3f4f5f6f7", "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7", 8 },
d7027e
+    { "f8f9fafbfcfdfeff", "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF", 8 },
d7027e
+
d7027e
+    /* All byte values, uppercase */
d7027e
+    { "0001020304050607", "\x00\x01\x02\x03\x04\x05\x06\x07", 8, 1 },
d7027e
+    { "08090A0B0C0D0E0F", "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", 8, 1 },
d7027e
+    { "1011121314151617", "\x10\x11\x12\x13\x14\x15\x16\x17", 8, 1 },
d7027e
+    { "18191A1B1C1D1E1F", "\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 8, 1 },
d7027e
+    { "2021222324252627", "\x20\x21\x22\x23\x24\x25\x26\x27", 8, 1 },
d7027e
+    { "28292A2B2C2D2E2F", "\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F", 8, 1 },
d7027e
+    { "3031323334353637", "\x30\x31\x32\x33\x34\x35\x36\x37", 8, 1 },
d7027e
+    { "38393A3B3C3D3E3F", "\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F", 8, 1 },
d7027e
+    { "4041424344454647", "\x40\x41\x42\x43\x44\x45\x46\x47", 8, 1 },
d7027e
+    { "48494A4B4C4D4E4F", "\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F", 8, 1 },
d7027e
+    { "5051525354555657", "\x50\x51\x52\x53\x54\x55\x56\x57", 8, 1 },
d7027e
+    { "58595A5B5C5D5E5F", "\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F", 8, 1 },
d7027e
+    { "6061626364656667", "\x60\x61\x62\x63\x64\x65\x66\x67", 8, 1 },
d7027e
+    { "68696A6B6C6D6E6F", "\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F", 8, 1 },
d7027e
+    { "7071727374757677", "\x70\x71\x72\x73\x74\x75\x76\x77", 8, 1 },
d7027e
+    { "78797A7B7C7D7E7F", "\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F", 8, 1 },
d7027e
+    { "8081828384858687", "\x80\x81\x82\x83\x84\x85\x86\x87", 8, 1 },
d7027e
+    { "88898A8B8C8D8E8F", "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F", 8, 1 },
d7027e
+    { "9091929394959697", "\x90\x91\x92\x93\x94\x95\x96\x97", 8, 1 },
d7027e
+    { "98999A9B9C9D9E9F", "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F", 8, 1 },
d7027e
+    { "A0A1A2A3A4A5A6A7", "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", 8, 1 },
d7027e
+    { "A8A9AAABACADAEAF", "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF", 8, 1 },
d7027e
+    { "B0B1B2B3B4B5B6B7", "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7", 8, 1 },
d7027e
+    { "B8B9BABBBCBDBEBF", "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF", 8, 1 },
d7027e
+    { "C0C1C2C3C4C5C6C7", "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7", 8, 1 },
d7027e
+    { "C8C9CACBCCCDCECF", "\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", 8, 1 },
d7027e
+    { "D0D1D2D3D4D5D6D7", "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7", 8, 1 },
d7027e
+    { "D8D9DADBDCDDDEDF", "\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF", 8, 1 },
d7027e
+    { "E0E1E2E3E4E5E6E7", "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7", 8, 1 },
d7027e
+    { "E8E9EAEBECEDEEEF", "\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF", 8, 1 },
d7027e
+    { "F0F1F2F3F4F5F6F7", "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7", 8, 1 },
d7027e
+    { "F8F9FAFBFCFDFEFF", "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF", 8, 1 },
d7027e
+};
d7027e
+
d7027e
+int main()
d7027e
+{
d7027e
+    size_t i;
d7027e
+    char *hex;
d7027e
+    int ret;
d7027e
+    uint8_t *bytes;
d7027e
+    size_t len;
d7027e
+
d7027e
+    for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
d7027e
+        if (tests[i].binary == NULL) {
d7027e
+            ret = k5_hex_decode(tests[i].hex, &bytes, &len;;
d7027e
+            assert(ret == EINVAL && bytes == NULL && len == 0);
d7027e
+            continue;
d7027e
+        }
d7027e
+
d7027e
+        ret = k5_hex_decode(tests[i].hex, &bytes, &len;;
d7027e
+        assert(ret == 0);
d7027e
+        assert(len == tests[i].binary_len);
d7027e
+        assert(memcmp(bytes, tests[i].binary, len) == 0);
d7027e
+        assert(bytes[len] == 0);
d7027e
+        free(bytes);
d7027e
+
d7027e
+        ret = k5_hex_encode((uint8_t *)tests[i].binary, tests[i].binary_len,
d7027e
+                            tests[i].uppercase, &hex;;
d7027e
+        assert(ret == 0);
d7027e
+        assert(strcmp(tests[i].hex, hex) == 0);
d7027e
+        free(hex);
d7027e
+    }
d7027e
+    return 0;
d7027e
+}