/*- * Copyright (c) 2017 Taylor R. Campbell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Base32 encoding of octet strings, safe for URLs, domain labels, and * human eyeball distinction to avoid confusing 0/O and 1/l/I. * Specified in * * S. Josefsson, `The Base16, Base32, and Base64 Data Encodings', * IETF RFC 4648, October 2006. */ #define _POSIX_C_SOURCE 200809L #include "base32enc.h" #include #include #include /* * base32enc_size(s) * * Return the size in bytes of the base32 encoding of a string of * s octets. */ size_t base32enc_size(size_t s) { return 8*((s + 4)/5); } /* * base32enc(target, tlen, source, slen) * * Encode slen bytes of data at source as NUL-terminated base32 in * the buffer target which has tlen bytes. tlen must be at least * base32enc_size(slen) + 1. */ void base32enc(char *target, size_t tlen, const void *source, size_t slen) { static const char b32[] = "abcdefghijklmnopqrstuvwxyz234567"; char *t = target; const uint8_t *s = source; /* Require enough room in target buffer. */ assert(tlen >= base32enc_size(slen) + 1); /* Map 5-octet chunks to 8-character chunks. */ while (5 <= slen) { assert(8 <= tlen); t[0] = b32[ (s[0] & 0xf8) >> 3]; t[1] = b32[(s[0] & 0x07) << 2 | (s[1] & 0xc0) >> 6]; t[2] = b32[ (s[1] & 0x3e) >> 1]; t[3] = b32[(s[1] & 0x01) << 4 | (s[2] & 0xf0) >> 4]; t[4] = b32[(s[2] & 0x0f) << 1 | (s[3] & 0x80) >> 7]; t[5] = b32[ (s[3] & 0x7c) >> 2]; t[6] = b32[(s[3] & 0x03) << 3 | (s[4] & 0xe0) >> 5]; t[7] = b32[(s[4] & 0x1f) << 0 ]; s += 5, slen -= 5; t += 8, tlen -= 8; } /* Map trailing chunk with padding if need be. */ if (0 < slen) { uint8_t s0, s1, s2, s3, s4; assert(8 <= tlen); assert(slen == 1 || slen == 2 || slen == 3 || slen == 4); s0 = s[0]; s1 = (slen <= 1? 0 : s[1]); s2 = (slen <= 2? 0 : s[2]); s3 = (slen <= 3? 0 : s[3]); s4 = 0; t[0] = b32[ (s0 & 0xf8) >> 3]; t[1] = b32[(s0 & 0x07) << 2 | (s1 & 0xc0) >> 6]; t[2] = (slen <= 1? '=' : b32[ (s1 & 0x3e) >> 1]); t[3] = (slen <= 1? '=' : b32[(s1 & 0x01) << 4 | (s2 & 0xf0) >> 4]); t[4] = (slen <= 2? '=' : b32[(s2 & 0x0f) << 1 | (s3 & 0x80) >> 7]); t[5] = (slen <= 3? '=' : b32[ (s3 & 0x7c) >> 2]); t[6] = (slen <= 3? '=' : b32[(s3 & 0x03) << 3 | (s4 & 0xe0) >> 5]); t[7] = (slen <= 4? '=' : b32[(s4 & 0x1f) << 0 ]); s += slen, slen -= slen; t += 8, tlen -= 8; } /* NUL-terminate. */ *t++ = '\0', tlen--; /* We had better have encoded the size we promised. */ assert((size_t)(t - target) == base32enc_size((size_t)(s - (const uint8_t *)source)) + 1); }