Base64 encoding and decoding functions.
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 3 Jul 2011 20:13:58 +0000 (22:13 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 3 Jul 2011 20:13:58 +0000 (22:13 +0200)
src/utils.c
src/utils.h

index 6ea904a59d15a63803faee04c448e8e43665b4ad..6b44556afcacb5b7082b56c666e8a85247df077e 100644 (file)
@@ -24,6 +24,7 @@
 #include "utils.h"
 
 static const char hexadecimals[] = "0123456789ABCDEF";
+static const char base64imals[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 static int charhex2bin(char c) {
        if(isdigit(c))
@@ -32,6 +33,14 @@ static int charhex2bin(char c) {
                return toupper(c) - 'A' + 10;
 }
 
+static int charb64decode(char c) {
+       if(c > 'a')
+               return c - 'a' + 26;
+       else if(c > 'A')
+               return c - 'A';
+       else
+               return c - '0';
+}
 
 void hex2bin(char *src, char *dst, int length) {
        int i;
@@ -47,6 +56,65 @@ void bin2hex(char *src, char *dst, int length) {
        }
 }
 
+int b64decode(const char *src, char *dst, int length) {
+       uint32_t triplet = 0;
+       unsigned char *udst;
+
+       for(int i = 0; i < length; i++) {
+               triplet |= charb64decode(src[i]) << (6 * (i % 4));
+               if((i % 4) == 3) {
+                       udst[0] = triplet & 0xff; triplet >>= 8;
+                       udst[1] = triplet & 0xff; triplet >>= 8;
+                       udst[2] = triplet;
+                       triplet = 0;
+                       udst += 3;
+               }
+       }
+       if((length % 4) == 3) {
+               udst[0] = triplet & 0xff; triplet >>= 8;
+               udst[1] = triplet & 0xff;
+               return length / 4 * 3 + 2;
+       } else if((length % 4) == 2) {
+               udst[0] = triplet & 0xff;
+               return length / 4 * 3 + 1;
+       } else {
+               return length / 4 * 3;
+       }
+}
+
+int b64encode(const char *src, char *dst, int length) {
+       uint32_t triplet;
+       const unsigned char *usrc = src;
+       int origlen = length;
+
+       while(length > 0) {
+               if(length >= 3) {
+                       triplet = usrc[0] | usrc[1] << 8 | usrc[2] << 16;
+                       dst[0] = base64imals[triplet & 63]; triplet >>= 6;
+                       dst[1] = base64imals[triplet & 63]; triplet >>= 6;
+                       dst[2] = base64imals[triplet & 63]; triplet >>= 6;
+                       dst[3] = base64imals[triplet];
+                       dst += 4; usrc += 3; length -= 3;
+               } else if(length >=2) {
+                       triplet = usrc[0] | usrc[1] << 8;
+                       dst[0] = base64imals[triplet & 63]; triplet >>= 6;
+                       dst[1] = base64imals[triplet & 63]; triplet >>= 6;
+                       dst[2] = base64imals[triplet];
+                       dst[3] = 0;
+                       return origlen / 3 * 4 + 3;
+               } else {
+                       triplet = usrc[0];
+                       dst[0] = base64imals[triplet & 63]; triplet >>= 6;
+                       dst[1] = base64imals[triplet];
+                       dst[2] = 0;
+                       return origlen / 3 * 4 + 2;
+               }
+       }
+
+       *dst = 0;
+       return origlen / 4 * 3;
+}
+
 #if defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
 #ifdef HAVE_CYGWIN
 #include <w32api/windows.h>
index 6f00e5a28cffb42a6196e127aea6f639eefa8bb1..4e0b55fc58f0515ae979f45f5c9c841b150f088c 100644 (file)
@@ -24,6 +24,9 @@
 extern void hex2bin(char *src, char *dst, int length);
 extern void bin2hex(char *src, char *dst, int length);
 
+extern int b64encode(const char *src, char *dst, int length);
+extern int b64decode(const char *src, char *dst, int length);
+
 #ifdef HAVE_MINGW
 extern const char *winerror(int);
 #define strerror(x) ((x)>0?strerror(x):winerror(GetLastError()))