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);
                                   unsigned char *out, unsigned long *outlen);
 \end{verbatim}
 \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}
 \mysection{Primality Testing}
 \index{Primality Testing}
 \index{Primality Testing}
 The library includes primality testing and random prime functions as well.  The primality tester will perform the test in
 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
 #define LTC_BASE64
 /* ... and it's URL safe version */
 /* ... and it's URL safe version */
 #define LTC_BASE64_URL
 #define LTC_BASE64_URL
+/* Base32 encoding/decoding */
+#define LTC_BASE32
 
 
 /* Keep LTC_NO_HKDF for compatibility reasons
 /* Keep LTC_NO_HKDF for compatibility reasons
  * superseeded by LTC_NO_MISC*/
  * 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);
                         unsigned char *out, unsigned long *outlen);
 #endif
 #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 <=== */
 /* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */
 #ifdef LTC_HKDF
 #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)
 #if defined(LTC_BASE64_URL)
     " BASE64-URL-SAFE "
     " BASE64-URL-SAFE "
 #endif
 #endif
+#if defined(LTC_BASE32)
+    " BASE32 "
+#endif
 #if defined(LTC_CRC32)
 #if defined(LTC_CRC32)
     " CRC32 "
     " CRC32 "
 #endif
 #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
 #ifdef LTC_BASE64
    DO(base64_test());
    DO(base64_test());
 #endif
 #endif
+#ifdef LTC_BASE32
+   DO(base32_test());
+#endif
 #ifdef LTC_ADLER32
 #ifdef LTC_ADLER32
    DO(adler32_test());
    DO(adler32_test());
 #endif
 #endif

+ 1 - 0
tests/tomcrypt_test.h

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