diff options
Diffstat (limited to 'common/zb32.c')
-rw-r--r-- | common/zb32.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/common/zb32.c b/common/zb32.c new file mode 100644 index 0000000..517321e --- /dev/null +++ b/common/zb32.c @@ -0,0 +1,120 @@ +/* zb32.c - z-base-32 functions + * Copyright (C) 2014 Werner Koch + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "util.h" +#include "zb32.h" + +/* Zooko's base32 variant. See RFC-6189 and + http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt + Caller must xfree the returned string. Returns NULL and sets ERRNO + on error. To avoid integer overflow DATALEN is limited to 2^16 + bytes. Note, that DATABITS is measured in bits!. */ +char * +zb32_encode (const void *data, unsigned int databits) +{ + static char const zb32asc[32] = {'y','b','n','d','r','f','g','8', + 'e','j','k','m','c','p','q','x', + 'o','t','1','u','w','i','s','z', + 'a','3','4','5','h','7','6','9' }; + const unsigned char *s; + char *output, *d; + size_t datalen; + + datalen = (databits + 7) / 8; + if (datalen > (1 << 16)) + { + errno = EINVAL; + return NULL; + } + + d = output = xtrymalloc (8 * (datalen / 5) + + 2 * (datalen % 5) + - ((datalen%5)>2) + + 1); + if (!output) + return NULL; + + /* I use straightforward code. The compiler should be able to do a + better job on optimization than me and it is easier to read. */ + for (s = data; datalen >= 5; s += 5, datalen -= 5) + { + *d++ = zb32asc[((s[0] ) >> 3) ]; + *d++ = zb32asc[((s[0] & 7) << 2) | (s[1] >> 6) ]; + *d++ = zb32asc[((s[1] & 63) >> 1) ]; + *d++ = zb32asc[((s[1] & 1) << 4) | (s[2] >> 4) ]; + *d++ = zb32asc[((s[2] & 15) << 1) | (s[3] >> 7) ]; + *d++ = zb32asc[((s[3] & 127) >> 2) ]; + *d++ = zb32asc[((s[3] & 3) << 3) | (s[4] >> 5) ]; + *d++ = zb32asc[((s[4] & 31) ) ]; + } + + switch (datalen) + { + case 4: + *d++ = zb32asc[((s[0] ) >> 3) ]; + *d++ = zb32asc[((s[0] & 7) << 2) | (s[1] >> 6) ]; + *d++ = zb32asc[((s[1] & 63) >> 1) ]; + *d++ = zb32asc[((s[1] & 1) << 4) | (s[2] >> 4) ]; + *d++ = zb32asc[((s[2] & 15) << 1) | (s[3] >> 7) ]; + *d++ = zb32asc[((s[3] & 127) >> 2) ]; + *d++ = zb32asc[((s[3] & 3) << 3) ]; + break; + case 3: + *d++ = zb32asc[((s[0] ) >> 3) ]; + *d++ = zb32asc[((s[0] & 7) << 2) | (s[1] >> 6) ]; + *d++ = zb32asc[((s[1] & 63) >> 1) ]; + *d++ = zb32asc[((s[1] & 1) << 4) | (s[2] >> 4) ]; + *d++ = zb32asc[((s[2] & 15) << 1) ]; + break; + case 2: + *d++ = zb32asc[((s[0] ) >> 3) ]; + *d++ = zb32asc[((s[0] & 7) << 2) | (s[1] >> 6) ]; + *d++ = zb32asc[((s[1] & 63) >> 1) ]; + *d++ = zb32asc[((s[1] & 1) << 4) ]; + break; + case 1: + *d++ = zb32asc[((s[0] ) >> 3) ]; + *d++ = zb32asc[((s[0] & 7) << 2) ]; + break; + default: + break; + } + *d = 0; + + /* Need to strip some bytes if not a multiple of 40. */ + output[(databits + 5 - 1) / 5] = 0; + return output; +} |