Index: ossp-pkg/str/ChangeLog RCS File: /v/ossp/cvs/ossp-pkg/str/ChangeLog,v rcsdiff -q -kk '-r1.31' '-r1.32' -u '/v/ossp/cvs/ossp-pkg/str/ChangeLog,v' 2>/dev/null --- ChangeLog 2001/08/16 12:16:51 1.31 +++ ChangeLog 2001/08/16 12:21:21 1.32 @@ -11,6 +11,10 @@ Changes between 0.9.4 and 0.9.5 (14-Jul-2000 to 16-Aug-2001): + *) Let str_base64(STR_BASE64_DECODE, ...) correctly honor + the specified maximum size of the input string. + [Peter Simons ] + *) Upgraded to GNU Autoconf 2.52 and GNU Libtool 1.4 [Ralf S. Engelschall] Index: ossp-pkg/str/str_base64.c RCS File: /v/ossp/cvs/ossp-pkg/str/str_base64.c,v co -q -kk -p'1.3' '/v/ossp/cvs/ossp-pkg/str/str_base64.c,v' | diff -u /dev/null - -L'ossp-pkg/str/str_base64.c' 2>/dev/null --- ossp-pkg/str/str_base64.c +++ - 2024-05-15 06:49:31.099078225 +0200 @@ -0,0 +1,365 @@ +/* +** Str - String Library +** Copyright (c) 1999-2000 Ralf S. Engelschall +** +** This file is part of Str, a string handling and manipulation +** library which can be found at http://www.engelschall.com/sw/str/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** 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. +** +** str_convert.c: string to byte conversions and vice versa +*/ + +#include "str_p.h" + +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include + +/* + * Encoding (Base256->Base64): + * Base256: 3 bytes, |11111111| |22222222| |33333333| + * Base64: 4 bytes, |XX111111| |XX112222| |XX222233| |XX333333| + * + * Decoding (Base64->Base256): + * Base64: 4 bytes, |XX111111| |XX222222| |XX333333| |XX444444| + * Base256: 3 bytes, |11111122| |22223333| |33444444| + * + * - + * + * The following encoding technique is taken from RFC 1521 by Borenstein + * and Freed. It is reproduced here in a slightly edited form for + * convenience. + * + * A 65-character subset of US-ASCII is used, enabling 6 bits to be + * represented per printable character. (The extra 65th character, "=", + * is used to signify a special processing function.) + * + * The encoding process represents 24-bit groups of input bits as output + * strings of 4 encoded characters. Proceeding from left to right, a + * 24-bit input group is formed by concatenating 3 8-bit input groups. + * These 24 bits are then treated as 4 concatenated 6-bit groups, each + * of which is translated into a single digit in the base64 alphabet. + * + * Each 6-bit group is used as an index into an array of 64 printable + * characters. The character referenced by the index is placed in the + * output string. + * + * Table 1: The Base64 Alphabet + * + * Value Encoding Value Encoding Value Encoding Value Encoding + * 0 A 17 R 34 i 51 z + * 1 B 18 S 35 j 52 0 + * 2 C 19 T 36 k 53 1 + * 3 D 20 U 37 l 54 2 + * 4 E 21 V 38 m 55 3 + * 5 F 22 W 39 n 56 4 + * 6 G 23 X 40 o 57 5 + * 7 H 24 Y 41 p 58 6 + * 8 I 25 Z 42 q 59 7 + * 9 J 26 a 43 r 60 8 + * 10 K 27 b 44 s 61 9 + * 11 L 28 c 45 t 62 + + * 12 M 29 d 46 u 63 / + * 13 N 30 e 47 v + * 14 O 31 f 48 w (pad) = + * 15 P 32 g 49 x + * 16 Q 33 h 50 y + * + * Special processing is performed if fewer than 24 bits are available + * at the end of the data being encoded. A full encoding quantum is + * always completed at the end of a quantity. When fewer than 24 input + * bits are available in an input group, zero bits are added (on the + * right) to form an integral number of 6-bit groups. Padding at the + * end of the data is performed using the '=' character. + * + * Since all base64 input is an integral number of octets, only the + * following cases can arise: + * + * (1) the final quantum of encoding input is an integral + * multiple of 24 bits; here, the final unit of encoded + * output will be an integral multiple of 4 characters + * with no "=" padding, + * (2) the final quantum of encoding input is exactly 16 bits; + * here, the final unit of encoded output will be three + * characters followed by one "=" padding character, or + * (3) the final quantum of encoding input is exactly 8 bits; + * here, the final unit of encoded output will be two + * characters followed by two "=" padding characters. + */ + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* encoding: binary -> base64 */ +static int +base64_encode( + char *dst, str_size_t dstlen, + unsigned char const *src, str_size_t srclen, + int strict) +{ + str_size_t dstpos; + unsigned char input[3]; + unsigned char output[4]; + int ocnt; + str_size_t i; + + if (srclen == 0) + return -1; + if (dst == NULL) { + /* just calculate required length of dst */ + dstlen = (((srclen + 2) / 3) * 4); + if (strict) + dstlen += (dstlen / 72); + return dstlen; + } + + /* bulk encoding */ + dstpos = 0; + ocnt = 0; + while (srclen >= 3) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclen -= 3; + + output[0] = (input[0] >> 2); + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = (input[2] & 0x3f); + + if (dstpos + 4 > dstlen) + return -1; + dst[dstpos++] = Base64[output[0]]; + dst[dstpos++] = Base64[output[1]]; + dst[dstpos++] = Base64[output[2]]; + dst[dstpos++] = Base64[output[3]]; + if (strict) + if (++ocnt % (72/4) == 0) + dst[dstpos++] = '\n'; + } + + /* now worry about padding with remaining 1 or 2 bytes */ + if (srclen != 0) { + input[0] = input[1] = input[2] = NUL; + for (i = 0; i < srclen; i++) + input[i] = *src++; + + output[0] = (input[0] >> 2); + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (dstpos + 4 > dstlen) + return -1; + dst[dstpos++] = Base64[output[0]]; + dst[dstpos++] = Base64[output[1]]; + if (srclen == 1) + dst[dstpos++] = Pad64; + else + dst[dstpos++] = Base64[output[2]]; + dst[dstpos++] = Pad64; + } + + if (dstpos >= dstlen) + return -1; + dst[dstpos] = NUL; + + return dstpos; +} + +/* decoding: base64 -> binary */ +static int +base64_decode( + unsigned char *dst, str_size_t dstlen, + char const *src, str_size_t srclen) +{ + int dstidx, state, ch = 0; + unsigned char res; + char *pos; + + if (srclen == 0) + srclen = strlen(src); + state = 0; + dstidx = 0; + res = 0; + while (srclen-- > 0) { + ch = *src++; + if (isascii(ch) && isspace(ch)) /* Skip whitespace anywhere */ + continue; + if (ch == Pad64) + break; + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character */ + return -1; + switch (state) { + case 0: + if (dst != NULL) { + if ((str_size_t)dstidx >= dstlen) + return -1; + dst[dstidx] = ((pos - Base64) << 2); + } + state = 1; + break; + case 1: + if (dst != NULL) { + if ((str_size_t)dstidx >= dstlen) + return -1; + dst[dstidx] |= ((pos - Base64) >> 4); + res = (((pos - Base64) & 0x0f) << 4); + } + dstidx++; + state = 2; + break; + case 2: + if (dst != NULL) { + if ((str_size_t)dstidx >= dstlen) + return -1; + dst[dstidx] = res | ((pos - Base64) >> 2); + res = ((pos - Base64) & 0x03) << 6; + } + dstidx++; + state = 3; + break; + case 3: + if (dst != NULL) { + if ((str_size_t)dstidx >= dstlen) + return -1; + dst[dstidx] = res | (pos - Base64); + } + dstidx++; + state = 0; + break; + default: + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return -1; + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + while (srclen-- > 0) { + ch = *src++; + if (!(isascii(ch) && isspace(ch))) + break; + } + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return -1; + /* FALLTHROUGH */ + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + while (srclen-- > 0) { + ch = *src++; + if (!(isascii(ch) && isspace(ch))) + return -1; + } + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (dst != NULL && res != 0) + return -1; + default: + break; + } + } + else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return -1; + } + + return dstidx; +} + +/* + * The API Function + */ +int str_base64(char *s, str_size_t n, unsigned char *ucp, str_size_t ulen, int mode) +{ + int rv; + + if (mode & STR_BASE64_ENCODE) + rv = base64_encode(s, n, ucp, ulen, mode & STR_BASE64_STRICT ? TRUE : FALSE); + else if (mode & STR_BASE64_DECODE) + rv = base64_decode(ucp, ulen, s, n); + else + return -1; + return rv; +} +