r2677 - trunk/libminisip/source/zrtp

werner at minisip.org werner at minisip.org
Sun Jul 2 21:12:59 CEST 2006


Author: werner
Date: 2006-07-02 21:12:58 +0200 (Sun, 02 Jul 2006)
New Revision: 2677

Added:
   trunk/libminisip/source/zrtp/Base32.cxx
Log:
A base32 presentation mode for binary data. Optimized for easy human reading of binary data

Added: trunk/libminisip/source/zrtp/Base32.cxx
===================================================================
--- trunk/libminisip/source/zrtp/Base32.cxx	2006-07-02 19:12:23 UTC (rev 2676)
+++ trunk/libminisip/source/zrtp/Base32.cxx	2006-07-02 19:12:58 UTC (rev 2677)
@@ -0,0 +1,295 @@
+/**
+ *
+ * Copyright (c) 2002 Bryce "Zooko" Wilcox-O'Hearn Permission is hereby
+ * granted, free of charge, to any person obtaining a copy of this software to
+ * deal in this software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of this software, and to permit persons to whom this software
+ * is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THIS SOFTWARE.
+ *
+ * Converted into C++ by:
+ *
+ *	@author Werner Dittmann <Werner.Dittmann at t-online.de>
+ */
+#include <libminisip/zrtp/Base32.h>
+
+int divceil(int a, int b) {
+    int c;
+    if (a>0) {
+	if (b>0) c=a+b-1;
+	else c=a;
+    } else {
+	if (b>0) c=a;
+	else c=a+b+1;
+    }
+    return c/b;
+}
+
+//                                         1         2         3
+//                               01234567890123456789012345678901
+static const char* const chars= "ybndrfg8ejkmcpqxot1uwisza345h769";
+
+/* 
+ * revchars: index into this table with the ASCII value of the char.  
+ * The result is the value of that quintet. 
+ */
+static const uint8_t revchars[]= { 
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255,  18, 255,  25,  26,  27,  30,  29,
+    7,  31, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255,  24,   1,  12,   3,   8,   5,   6,
+    28,  21,   9,  10, 255,  11,   2,  16,  
+    13,  14,   4,  22,  17,  19, 255,  20,  
+    15,   0,  23, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255
+};
+
+    
+Base32::Base32(const string encoded): 
+    binaryResult(NULL), resultLength(0) {
+        
+    a2b_l(encoded, encoded.size(), (encoded.size()*5/8)*8);          
+}
+    
+Base32::Base32(const string encoded, int32_t noOfBits): 
+    binaryResult(NULL), resultLength(0) {
+        
+    a2b_l(encoded, divceil(noOfBits, 5), noOfBits);
+}
+    
+Base32::Base32(const uint8_t* data, int32_t noOfBits): 
+    binaryResult(NULL), resultLength(0) {
+        
+    b2a_l(data, (noOfBits+7)/8, noOfBits);
+}
+
+Base32::~Base32() {
+    if (binaryResult != NULL && binaryResult != smallBuffer) {
+	delete [] binaryResult;
+    }
+    binaryResult = NULL;
+}
+    
+const uint8_t* Base32::getDecoded(int32_t &length) {
+    length = resultLength;
+    return binaryResult;
+}
+
+void Base32::b2a_l(const uint8_t* os, int32_t len, 
+		   const size_t lengthinbits) {
+        
+    /* if lengthinbits is not a multiple of 8 then this is allocating
+     * space for 0, 1, or 2 extra quintets that will be truncated at the
+     * end of this function if they are not needed
+     */                                 
+    string result(divceil(len*8, 5), ' '); 
+
+    /* pointer into the result buffer, initially pointing to the
+     * "one-past-the-end" quintet 
+     */
+    int32_t resp = result.size();
+        
+    /* pointer into the os buffer, initially pointing to the
+     * "one-past-the-end" octet
+     */
+    const uint8_t* osp = os + len;
+        
+    /* Now this is a real live Duff's device.  You gotta love it. */
+
+    unsigned long x = 0;	// to hold up to 32 bits worth of the input
+    switch ((osp - os) % 5) {
+
+	case 0:
+	    do {
+		x = *--osp;
+		result[--resp] = chars[x % 32]; /* The least sig 5 bits go into the final quintet. */
+		x /= 32;	/* ... now we have 3 bits worth in x... */
+		case 4:
+		    x |= ((unsigned long)(*--osp)) << 3; /* ... now we have 11 bits worth in x... */
+		    result[--resp] = chars[x % 32];
+		    x /= 32; /* ... now we have 6 bits worth in x... */
+		    result[--resp] = chars[x % 32];
+		    x /= 32; /* ... now we have 1 bits worth in x... */
+		case 3:
+		    x |= ((unsigned long)(*--osp)) << 1; /* The 8 bits from the 2-indexed octet.
+							    So now we have 9 bits worth in x... */
+		    result[--resp] = chars[x % 32];
+		    x /= 32; /* ... now we have 4 bits worth in x... */
+		case 2:
+		    x |= ((unsigned long)(*--osp)) << 4; /* The 8 bits from the 1-indexed octet.  
+							    So now we have 12 bits worth in x... */
+		    result[--resp] = chars[x%32];
+		    x /= 32; /* ... now we have 7 bits worth in x... */
+		    result[--resp] = chars[x%32];
+		    x /= 32; /* ... now we have 2 bits worth in x... */
+		case 1:
+		    x |= ((unsigned long)(*--osp)) << 2; /* The 8 bits from the 0-indexed octet.  
+							    So now we have 10 bits worth in x... */
+		    result[--resp] = chars[x%32];
+		    x /= 32; /* ... now we have 5 bits worth in x... */
+		    result[--resp] = chars[x];
+	    } while (osp > os);
+    } /* switch ((osp - os.buf) % 5) */
+
+    /* truncate any unused trailing zero quintets */
+    encoded = result.substr(0, divceil(lengthinbits, 5));
+    return;
+}
+
+void Base32::a2b_l(const string cs, size_t size, const size_t lengthinbits ) {
+    unsigned long x=0;                         // to hold up to 32 bits worth of the input
+    
+    int32_t len = divceil(size*5, 8);
+    
+    /* if lengthinbits is not a multiple of 5 then this is
+       allocating space for 0 or 1 extra octets that will be
+       truncated at the end of this function if they are 
+       not needed */
+    
+    if (len < 128) {
+        binaryResult = smallBuffer;
+    }
+    else {
+        binaryResult = new unsigned char[len];
+    }
+    
+    /* pointer into the result buffer, initially pointing to 
+       the "one-past-the-end" octet */
+    uint8_t* resp = binaryResult + len;
+        
+    /* index into the input buffer, initially pointing to the
+       "one-past-the-end" character */    
+    int32_t csp = size;
+          
+    /* Now this is a real live Duff's device.  You gotta love it. */
+    switch (csp % 8) {
+	case 0:
+	    do {
+		x = revchars[cs[--csp]]; /* 5 bits... */
+		case 7:
+		    x |= revchars[cs[--csp]] << 5; /* 10 bits... */
+		    *--resp = x % 256;
+		    x /= 256; /* 2 bits... */
+		case 6:
+		    x |= revchars[cs[--csp]] << 2; /* 7 bits... */
+		case 5:
+		    x |= revchars[cs[--csp]] << 7; /* 12 bits... */
+		    *--resp = x % 256;
+		    x /= 256; /* 4 bits... */
+		case 4:
+		    x |= revchars[cs[--csp]] << 4; /* 9 bits... */
+		    *--resp = x % 256;
+		    x /= 256; /* 1 bit... */
+		case 3:
+		    x |= revchars[cs[--csp]] << 1; /* 6 bits... */
+		case 2:
+		    x |= revchars[cs[--csp]] << 6; /* 11 bits... */
+		    *--resp = x % 256;
+		    x /= 256; /* 3 bits... */
+		case 1:
+		    x |= revchars[cs[--csp]] << 3; /* 8 bits... */
+		    *--resp = x % 256;
+	    } while (csp);
+    } /* switch ((csp - cs.buf) % 8) */
+
+    /* truncate any unused trailing zero octets */
+    resultLength = divceil(lengthinbits, 8);
+    return;
+}
+
+#ifdef UNIT_TEST
+#include <math.h>
+
+
+uint8_t* randz(const size_t len)
+{
+    uint8_t* result = (uint8_t*)malloc(len);
+    size_t i;
+    for (i=0; i<len; i++) {
+        result[i] = rand() % 256;
+    }    
+    return result;
+}
+
+int main(int argc, char *argv[]) {
+    
+    int32_t resLen;
+    string a;
+    const uint8_t* zrecovered;
+    uint8_t ones[] = {1, 1, 1, 1, 1};
+    
+    // Encode all bits of the 5 one bytes (= 40 bits)
+    a = Base32(ones, 5*8).getEncoded();
+    
+    // The string should be: "yryonyeb"
+    cout << "Encoded 5 ones: '" << a << "', Expected: 'yryonyeb'" << endl;
+    
+    // Now decode all bits and check
+    Base32 *y = new Base32(a);
+    zrecovered = y->getDecoded(resLen);
+    if (resLen != 5 && memcmp(ones, zrecovered, 5)) {
+        printf("Failed basic 5 ones recovery test.\n");
+        return -1;
+    }
+    delete y;
+    
+    a = Base32(ones, 15).getEncoded();
+    cout << "Encoded 5 ones, 15 bits only: '" << a << "', Expected: 'yry'" << endl;
+    // now decode 15 bits (out of 40 possible)
+    y = new Base32(a, 15);
+    zrecovered = y->getDecoded(resLen);
+    printf("Decoded 15 bits, result length: %d (should be 2)\n", resLen);
+    printf("Decoded bytes: %x %x (should be 1 0)\n", zrecovered[0], zrecovered[1]);
+    delete y;
+    
+    for (int i = 0; i < 2; i++) {
+        uint8_t* z = randz(16);
+        a = Base32(z, 16*8).getEncoded();
+//        cout << "Result: " << a << endl;
+        assert (a.size() == Base32::b2alen(16*8));
+        Base32 *x = new Base32(a);
+        zrecovered = x->getDecoded(resLen);
+        if (resLen != 16 && memcmp(z, zrecovered, 16)) {
+            printf("Failed basic recovery test.\n");
+            return -1;
+        }
+        delete x;
+        free((void*)z);
+    }
+}
+#endif



More information about the Minisip-devel mailing list