diff --git a/common/Makefile.am b/common/Makefile.am index f2242b6e9..880b01b76 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -52,6 +52,7 @@ common_sources = \ gettime.c \ yesno.c \ b64enc.c b64dec.c \ + zb32.c \ convert.c \ percent.c \ miscellaneous.c \ diff --git a/common/util.h b/common/util.h index becc9cfe0..48d02e0c1 100644 --- a/common/util.h +++ b/common/util.h @@ -182,6 +182,8 @@ gpg_error_t b64dec_proc (struct b64state *state, void *buffer, size_t length, gpg_error_t b64dec_finish (struct b64state *state); +/*-- zb32.c --*/ +char *zb32_encode (const void *data, unsigned int databits); /*-- sexputil.c */ diff --git a/common/zb32.c b/common/zb32.c new file mode 100644 index 000000000..05aa0eac8 --- /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 . + */ + +#include +#include +#include +#include +#include +#include + +#include "util.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; +}