Browse Source

base32_decode + base32_encode

Karel Miko 8 years ago
parent
commit
8674eb3097

+ 39 - 0
doc/crypt.tex

@@ -6365,6 +6365,45 @@ int base64url_strict_decode(const unsigned char *in,  unsigned long len,
                                   unsigned char *out, unsigned long *outlen);
 \end{verbatim}
 
+\mysection{Base32 Encoding and Decoding}
+
+The library provides functions to encode and decode a Base32 coding scheme. The supported mappings are:
+
+\begin{center}
+\begin{tabular}{|c|c|c|}
+     \hline \textbf{alphabet\_idx} & \textbf{Mapping} & \textbf{Name} \\
+     \hline 0 & \textit{ABCDEFGHIJKLMNOPQRSTUVWXYZ234567} & RFC-4648 \\
+     \hline 1 & \textit{0123456789ABCDEFGHIJKLMNOPQRSTUV} & Base32hex \\
+     \hline 2 & \textit{YBNDRFG8EJKMCPQXOT1UWISZA345H769} & ZBase32 \\
+     \hline 3 & \textit{0123456789ABCDEFGHJKMNPQRSTVWXYZ} & Crockford \\
+     \hline
+\end{tabular}
+\end{center}
+
+To encode a binary string in base32 call:
+
+\index{base32\_encode()}
+\begin{verbatim}
+int base32_encode(const unsigned char *in,
+                        unsigned long  len,
+                        unsigned char *out,
+                        unsigned long *outlen,
+                        unsigned int   alphabet_idx);
+\end{verbatim}
+
+Where \textit{in} is the binary string, \textit{out} is where the ASCII output is placed and \textit{alphabet\_idx} is the alphabet index from the table above.
+
+To decode a base32 string call:
+
+\index{base32\_decode()}
+\begin{verbatim}
+int base32_decode(const unsigned char *in,
+                        unsigned long  len,
+                        unsigned char *out,
+                        unsigned long *outlen,
+                        unsigned int   alphabet_idx);
+\end{verbatim}
+
 \mysection{Primality Testing}
 \index{Primality Testing}
 The library includes primality testing and random prime functions as well.  The primality tester will perform the test in

+ 2 - 0
src/headers/tomcrypt_custom.h

@@ -444,6 +444,8 @@
 #define LTC_BASE64
 /* ... and it's URL safe version */
 #define LTC_BASE64_URL
+/* Base32 encoding/decoding */
+#define LTC_BASE32
 
 /* Keep LTC_NO_HKDF for compatibility reasons
  * superseeded by LTC_NO_MISC*/

+ 10 - 0
src/headers/tomcrypt_misc.h

@@ -30,6 +30,16 @@ int base64url_strict_decode(const unsigned char *in,  unsigned long len,
                         unsigned char *out, unsigned long *outlen);
 #endif
 
+/* ---- BASE32 Routines ---- */
+#ifdef LTC_BASE32
+int base32_encode(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        unsigned int alphabet_idx);
+int base32_decode(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        unsigned int alphabet_idx);
+#endif
+
 /* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */
 #ifdef LTC_HKDF
 

+ 119 - 0
src/misc/base32/base32_decode.c

@@ -0,0 +1,119 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BASE32
+
+/**
+   Base32 decode a buffer
+   @param in       The Base32 data to decode
+   @param inlen    The length of the Base32 data
+   @param out      [out] The destination of the binary decoded data
+   @param outlen   [in/out] The max size and resulting size of the decoded data
+   @return CRYPT_OK if successful
+*/
+int base32_decode(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        unsigned int alphabet_idx)
+{
+   unsigned long x;
+   int y = 0;
+   ulong64 t = 0;
+   unsigned char c, *map;
+   unsigned char tables[4][43] = {
+      {  /* alphabet_idx 0 = rfc4648 ABCDEFGHIJKLMNOPQRSTUVWXYZ234567 */
+         99/*0*/,99/*1*/,26/*2*/,27/*3*/,28/*4*/,29/*5*/,30/*6*/,31/*7*/,99/*8*/,99/*9*/,
+         99/*:*/,99/*;*/,99/*<*/,99/*=*/,99/*>*/,99/*?*/,99/*@*/,
+          0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, 7/*H*/, 8/*I*/, 9/*J*/,10/*K*/,11/*L*/,12/*M*/,
+         13/*N*/,14/*O*/,15/*P*/,16/*Q*/,17/*R*/,18/*S*/,19/*T*/,20/*U*/,21/*V*/,22/*W*/,23/*X*/,24/*Y*/,25/*Z*/
+      },
+      {  /* alphabet_idx 1 = base32hex 0123456789ABCDEFGHIJKLMNOPQRSTUV */
+           0/*0*/, 1/*1*/, 2/*2*/, 3/*3*/, 4/*4*/, 5/*5*/, 6/*6*/, 7/*7*/, 8/*8*/, 9/*9*/,
+          99/*:*/,99/*;*/,99/*<*/,99/*=*/,99/*>*/,99/*?*/,99/*@*/,
+          10/*A*/,11/*B*/,12/*C*/,13/*D*/,14/*E*/,15/*F*/,16/*G*/,17/*H*/,18/*I*/,19/*J*/,20/*K*/,21/*L*/,22/*M*/,
+          23/*N*/,24/*O*/,25/*P*/,26/*Q*/,27/*R*/,28/*S*/,29/*T*/,30/*U*/,31/*V*/,99/*W*/,99/*X*/,99/*Y*/,99/*Z*/
+      },
+      {  /* alphabet_idx 2 = zbase32 YBNDRFG8EJKMCPQXOT1UWISZA345H769 */
+         99/*0*/,18/*1*/,99/*2*/,25/*3*/,26/*4*/,27/*5*/,30/*6*/,29/*7*/, 7/*8*/,31/*9*/,
+         99/*:*/,99/*;*/,99/*<*/,99/*=*/,99/*>*/,99/*?*/,99/*@*/,
+         24/*A*/, 1/*B*/,12/*C*/, 3/*D*/, 8/*E*/, 5/*F*/, 6/*G*/,28/*H*/,21/*I*/, 9/*J*/,10/*K*/,99/*L*/,11/*M*/,
+          2/*N*/,16/*O*/,13/*P*/,14/*Q*/, 4/*R*/,22/*S*/,17/*T*/,19/*U*/,99/*V*/,20/*W*/,15/*X*/, 0/*Y*/,23/*Z*/
+      },
+      {  /* alphabet_idx 3 = crockford 0123456789ABCDEFGHJKMNPQRSTVWXYZ + O=>0 + IL=>1 */
+          0/*0*/, 1/*1*/, 2/*2*/, 3/*3*/, 4/*4*/, 5/*5*/, 6/*6*/, 7/*7*/, 8/*8*/, 9/*9*/,
+         99/*:*/,99/*;*/,99/*<*/,99/*=*/,99/*>*/,99/*?*/,99/*@*/,
+         10/*A*/,11/*B*/,12/*C*/,13/*D*/,14/*E*/,15/*F*/,16/*G*/,17/*H*/, 1/*I*/,18/*J*/,19/*K*/, 1/*L*/,20/*M*/,
+         21/*N*/, 0/*O*/,22/*P*/,23/*Q*/,24/*R*/,25/*S*/,26/*T*/,99/*U*/,27/*V*/,28/*W*/,29/*X*/,30/*Y*/,31/*Z*/
+      }
+   };
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(alphabet_idx < 4);
+
+   /* ignore all trailing = */
+   while (inlen > 0 && in[inlen-1] == '=') inlen--;
+
+   /* no input, nothing to do */
+   if (inlen == 0) {
+      *outlen = 0;
+      return CRYPT_OK;
+   }
+
+   /* check the size of output buffer */
+   x = (inlen * 5) / 8;
+   if (*outlen < x) {
+      *outlen = x;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   *outlen = x;
+
+   /* check input data length */
+   x = inlen % 8;
+   if (x == 1 || x == 3 || x == 6) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   map = tables[alphabet_idx];
+   for (x = 0; x < inlen; x++) {
+      c = in[x];
+      /* convert to upper case */
+      if ((c >= 'a') && (c <= 'z')) c -= 32;
+      /* '0' = 48 .. 'Z' = 90 */
+      if (c < 48 || c > 90 || map[c-48] > 31) {
+         return CRYPT_INVALID_PACKET;
+      }
+      t = (t<<5)|map[c-48];
+      if (++y == 8) {
+         *out++ = (unsigned char)((t>>32) & 255);
+         *out++ = (unsigned char)((t>>24) & 255);
+         *out++ = (unsigned char)((t>>16) & 255);
+         *out++ = (unsigned char)((t>> 8) & 255);
+         *out++ = (unsigned char)( t      & 255);
+         y = 0;
+         t = 0;
+      }
+   }
+   if (y > 0) {
+      t = t << (5 * (8 - y));
+      if (y >= 2) *out++ = (unsigned char)((t>>32) & 255);
+      if (y >= 4) *out++ = (unsigned char)((t>>24) & 255);
+      if (y >= 5) *out++ = (unsigned char)((t>>16) & 255);
+      if (y >= 7) *out++ = (unsigned char)((t>> 8) & 255);
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 93 - 0
src/misc/base32/base32_encode.c

@@ -0,0 +1,93 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BASE32
+
+/**
+   Base32 encode a buffer
+   @param in       The input buffer to encode
+   @param inlen    The length of the input buffer
+   @param out      [out] The destination of the Base32 encoded data
+   @param outlen   [in/out] The max size and resulting size of the encoded data
+   @return CRYPT_OK if successful
+*/
+int base32_encode(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        unsigned int alphabet_idx)
+{
+   unsigned long i, x;
+   unsigned char *codes;
+   const char *alphabet[4] = {
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",     /* alphabet_idx 0 = rfc4648   */
+      "0123456789ABCDEFGHIJKLMNOPQRSTUV",     /* alphabet_idx 1 = base32hex */
+      "ybndrfg8ejkmcpqxot1uwisza345h769",     /* alphabet_idx 2 = zbase32   */
+      "0123456789ABCDEFGHJKMNPQRSTVWXYZ"      /* alphabet_idx 3 = crockford */
+   };
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(alphabet_idx < 4);
+
+   /* no input, nothing to do */
+   if (inlen == 0) {
+      *outlen = 0;
+      return CRYPT_OK;
+   }
+
+   /* check the size of output buffer */
+   x = (8 * inlen + 4) / 5;
+   if (*outlen < x) {
+      *outlen = x;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   *outlen = x;
+
+   codes = (unsigned char*)alphabet[alphabet_idx];
+   x = 5 * (inlen / 5);
+   for (i = 0; i < x; i += 5) {
+      *out++ = codes[(in[0] >> 3) & 0x1F];
+      *out++ = codes[(((in[0] & 0x7) << 2) + (in[1] >> 6)) & 0x1F];
+      *out++ = codes[(in[1] >> 1) & 0x1F];
+      *out++ = codes[(((in[1] & 0x1) << 4) + (in[2] >> 4)) & 0x1F];
+      *out++ = codes[(((in[2] & 0xF) << 1) + (in[3] >> 7)) & 0x1F];
+      *out++ = codes[(in[3] >> 2) & 0x1F];
+      *out++ = codes[(((in[3] & 0x3) << 3) + (in[4] >> 5)) & 0x1F];
+      *out++ = codes[in[4] & 0x1F];
+      in += 5;
+   }
+   if (i < inlen) {
+      unsigned a = in[0];
+      unsigned b = (i+1 < inlen) ? in[1] : 0;
+      unsigned c = (i+2 < inlen) ? in[2] : 0;
+      unsigned d = (i+3 < inlen) ? in[3] : 0;
+      *out++ = codes[(a >> 3) & 0x1F];
+      *out++ = codes[(((a & 0x7) << 2) + (b >> 6)) & 0x1F];
+      if (i+1 < inlen) {
+         *out++ = codes[(b >> 1) & 0x1F];
+         *out++ = codes[(((b & 0x1) << 4) + (c >> 4)) & 0x1F];
+      }
+      if (i+2 < inlen) {
+         *out++ = codes[(((c & 0xF) << 1) + (d >> 7)) & 0x1F];
+         *out++ = codes[(d >> 2) & 0x1F];
+      }
+      if (i+3 < inlen) {
+         *out++ = codes[((d & 0x3) << 3) & 0x1F];
+      }
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 3 - 0
src/misc/crypt/crypt.c

@@ -399,6 +399,9 @@ const char *crypt_build_settings =
 #if defined(LTC_BASE64_URL)
     " BASE64-URL-SAFE "
 #endif
+#if defined(LTC_BASE32)
+    " BASE32 "
+#endif
 #if defined(LTC_CRC32)
     " CRC32 "
 #endif

+ 60 - 0
tests/base32_test.c

@@ -0,0 +1,60 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include  <tomcrypt_test.h>
+
+#ifdef LTC_BASE32
+
+int base32_test(void)
+{
+   unsigned char in[100], out[160], tmp[100];
+   unsigned char testin[] = { 0x61,0xc2,0xcb,0xbc,0x5e,0x6d,0x2a,0x7a,0x1a,0x19,0x1a,0xae,0xc9,0x02,0xd4,0xbf,0x7d };
+   const char *testout[4] = {
+      "MHBMXPC6NUVHUGQZDKXMSAWUX56Q",
+      "C71CNF2UDKL7K6GP3ANCI0MKNTUG",
+      "c8bczxn6pwi8wgo3dkzc1yswz76o",
+      "C71CQF2YDMN7M6GS3AQCJ0PMQXYG"
+   };
+   unsigned long x, l1, l2;
+   int idx;
+
+   for (idx = 0; idx < 4; idx++) {
+      for (x = 0; x < 100; x++) {
+         yarrow_read(in, x, &yarrow_prng);
+         l1 = sizeof(out);
+         DO(base32_encode(in, x, out, &l1, idx));
+         l2 = sizeof(tmp);
+         DO(base32_decode(out, l1, tmp, &l2, idx));
+         if (compare_testvector(tmp, l2, in, x, "random base32", idx * 100 + x)) {
+            return CRYPT_FAIL_TESTVECTOR;
+         }
+      }
+   }
+
+   for (idx = 0; idx < 4; idx++) {
+      l1 = sizeof(out);
+      DO(base32_encode(testin, sizeof(testin), out, &l1, idx));
+      if (compare_testvector(out, l1, testout[idx], strlen(testout[idx]), "testout base32", idx)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+      l2 = sizeof(tmp);
+      DO(base32_decode(out, l1, tmp, &l2, idx));
+      if (compare_testvector(tmp, l2, testin, sizeof(testin), "testin base32", idx)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 3 - 0
tests/misc_test.c

@@ -19,6 +19,9 @@ int misc_test(void)
 #ifdef LTC_BASE64
    DO(base64_test());
 #endif
+#ifdef LTC_BASE32
+   DO(base32_test());
+#endif
 #ifdef LTC_ADLER32
    DO(adler32_test());
 #endif

+ 1 - 0
tests/tomcrypt_test.h

@@ -38,6 +38,7 @@ int dsa_test(void);
 int der_test(void);
 int misc_test(void);
 int base64_test(void);
+int base32_test(void);
 int file_test(void);
 int multi_test(void);
 int prng_test(void);