/munge-0.5.10/src/munged/base64.c
C | 445 lines | 297 code | 66 blank | 82 comment | 66 complexity | a7857d28c42d88f8ed2c1ab4149f933b MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
- /*****************************************************************************
- * $Id: base64.c 890 2011-01-20 01:54:21Z chris.m.dunlap $
- *****************************************************************************
- * Written by Chris Dunlap <cdunlap@llnl.gov>.
- * Copyright (C) 2007-2011 Lawrence Livermore National Security, LLC.
- * Copyright (C) 2002-2007 The Regents of the University of California.
- * UCRL-CODE-155910.
- *
- * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE).
- * For details, see <http://munge.googlecode.com/>.
- *
- * MUNGE is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version. Additionally for the MUNGE library (libmunge), you
- * can redistribute it and/or modify it under the terms of 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.
- *
- * MUNGE 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
- * and GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * and GNU Lesser General Public License along with MUNGE. If not, see
- * <http://www.gnu.org/licenses/>.
- *****************************************************************************/
- #if HAVE_CONFIG_H
- # include <config.h>
- #endif /* HAVE_CONFIG_H */
- #include <assert.h>
- #include <string.h>
- #include "base64.h"
- /*****************************************************************************
- * Notes
- *****************************************************************************/
- /*
- * For details on base64 encoding/decoding, refer to
- * rfc2440 (OpenPGP Message Format) sections 6.3-6.5.
- *
- * Why am I not using OpenSSL's base64 encoding/decoding functions?
- * Because they have the following fucked functionality:
- * For base64-encoding, use of the context results in output that is broken
- * into 64-character lines; however, EVP_EncodeBlock() output is not broken.
- * For base64-decoding, use of the context returns the correct length of the
- * resulting output; however, EVP_DecodeBlock() returns a length that may
- * be up to two characters too long.
- * Finally, data base64-encoded via a context has to be decoded via a context,
- * and data base64-encoded w/o a context has to be decoded w/o a context.
- * So fuck it, I wrote my own. :-P
- */
- /*****************************************************************************
- * Constants
- *****************************************************************************/
- #define BASE64_MAGIC 0xDEADBEEF
- #define BASE64_ERR 0xFF
- #define BASE64_IGN 0xFE
- #define BASE64_PAD 0xFD
- #define BASE64_PAD_CHAR '='
- /*****************************************************************************
- * Static Variables
- *****************************************************************************/
- static const unsigned char bin2asc[] = \
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- static const unsigned char asc2bin[256] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe,
- 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
- 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
- 0xff, 0xfd, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
- 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
- 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff
- };
- /*****************************************************************************
- * Extern Functions
- *****************************************************************************/
- int
- base64_init (base64_ctx *x)
- {
- assert (x != NULL);
- x->num = 0;
- x->pad = 0;
- assert (x->magic = BASE64_MAGIC);
- assert (!(x->finalized = 0));
- return (0);
- }
- int
- base64_encode_update (base64_ctx *x, void *vdst, int *dstlen,
- const void *vsrc, int srclen)
- {
- int n;
- int num_read;
- int num_write;
- unsigned char *dst = (unsigned char *) vdst;
- unsigned char *src = (unsigned char *) vsrc;
- assert (x != NULL);
- assert (x->magic == BASE64_MAGIC);
- assert (x->finalized != 1);
- assert (dst != NULL);
- assert (dstlen != NULL);
- assert (src != NULL);
- num_write = 0;
- if (srclen <= 0) {
- return (0);
- }
- /* Encode leftover data if context buffer can be filled.
- */
- if ((x->num > 0) && (srclen >= (num_read = 3 - x->num))) {
- memcpy (&x->buf[x->num], src, num_read);
- src += num_read;
- srclen -= num_read;
- base64_encode_block (dst, &n, x->buf, 3);
- x->num = 0;
- dst += n;
- num_write += n;
- }
- /* Encode maximum amount of data w/o requiring a pad.
- */
- if (srclen >= 3) {
- num_read = (srclen / 3) * 3;
- base64_encode_block (dst, &n, src, num_read);
- src += num_read;
- srclen -= num_read;
- num_write += n;
- }
- /* Save leftover data for the next update() or final().
- */
- if (srclen > 0) {
- memcpy (&x->buf[x->num], src, srclen);
- x->num += srclen;
- }
- *dstlen = num_write;
- return (0);
- }
- int
- base64_encode_final (base64_ctx *x, void *dst, int *dstlen)
- {
- assert (x != NULL);
- assert (x->magic == BASE64_MAGIC);
- assert (x->finalized != 1);
- assert (dst != NULL);
- assert (dstlen != NULL);
- /* Encode leftover data from the previous update().
- */
- if (x->num > 0) {
- base64_encode_block (dst, dstlen, x->buf, x->num);
- x->num = 0;
- }
- else {
- *dstlen = 0;
- }
- assert (x->finalized = 1);
- return (0);
- }
- int
- base64_decode_update (base64_ctx *x, void *dst, int *dstlen,
- const void *src, int srclen)
- {
- /* Context [x] should only be NULL when called via base64_decode_block().
- */
- int i = 0;
- int err = 0;
- int pad = 0;
- unsigned char *pdst;
- const unsigned char *psrc;
- const unsigned char *psrc_last;
- unsigned char c;
- assert ((x == NULL) || (x->magic == BASE64_MAGIC));
- assert ((x == NULL) || (x->finalized != 1));
- assert (dst != NULL);
- assert (dstlen != NULL);
- assert (src != NULL);
- pdst = dst;
- psrc = src;
- psrc_last = psrc + srclen;
- /* Restore context.
- */
- if (x != NULL) {
- i = x->num;
- pad = x->pad;
- *pdst = x->buf[0];
- }
- while (psrc < psrc_last) {
- c = asc2bin[*psrc++];
- if (c == BASE64_IGN) {
- continue;
- }
- if ((c == BASE64_PAD) && (pad < 2)) {
- pad++;
- continue;
- }
- if ((c == BASE64_ERR) || (pad > 0)) {
- err++;
- break;
- }
- switch (i) {
- case 0:
- *pdst = (c << 2) & 0xfc;
- break;
- case 1:
- *pdst++ |= (c >> 4) & 0x03;
- *pdst = (c << 4) & 0xf0;
- break;
- case 2:
- *pdst++ |= (c >> 2) & 0x0f;
- *pdst = (c << 6) & 0xc0;
- break;
- case 3:
- *pdst++ |= (c ) & 0x3f;
- break;
- }
- i = (i + 1) % 4;
- }
- /* Save context.
- */
- if (x != NULL) {
- x->num = i;
- x->pad = pad;
- x->buf[0] = *pdst;
- }
- /* Check for the correct amount of padding.
- */
- else if (!err) {
- err = (((i + pad) % 4) != 0);
- }
- *pdst = '\0';
- *dstlen = pdst - (unsigned char *) dst;
- return (err ? -1 : 0);
- }
- int
- base64_decode_final (base64_ctx *x, void *dst, int *dstlen)
- {
- int rc = 0;
- assert (x != NULL);
- assert (x->magic == BASE64_MAGIC);
- assert (x->finalized != 1);
- if (((x->num + x->pad) % 4) != 0) {
- rc = -1;
- }
- *dstlen = 0;
- assert (x->finalized = 1);
- return (rc);
- }
- int
- base64_cleanup (base64_ctx *x)
- {
- assert (x != NULL);
- assert (x->magic == BASE64_MAGIC);
- memset (x, 0, sizeof (*x));
- assert (x->magic = ~BASE64_MAGIC);
- return (0);
- }
- int
- base64_encode_block (void *dst, int *dstlen, const void *src, int srclen)
- {
- unsigned char *pdst;
- const unsigned char *psrc;
- int n;
- pdst = dst;
- psrc = src;
- n = 0;
- while (srclen >= 3) {
- *pdst++ = bin2asc[ (psrc[0] >> 2) & 0x3f];
- *pdst++ = bin2asc[((psrc[0] << 4) & 0x30) | ((psrc[1] >> 4) & 0x0f)];
- *pdst++ = bin2asc[((psrc[1] << 2) & 0x3c) | ((psrc[2] >> 6) & 0x03)];
- *pdst++ = bin2asc[ (psrc[2] ) & 0x3f];
- psrc += 3;
- srclen -= 3;
- n += 4;
- }
- if (srclen == 2) {
- *pdst++ = bin2asc[ (psrc[0] >> 2) & 0x3f];
- *pdst++ = bin2asc[((psrc[0] << 4) & 0x30) | ((psrc[1] >> 4) & 0x0f)];
- *pdst++ = bin2asc[ (psrc[1] << 2) & 0x3c];
- *pdst++ = '=';
- n += 4;
- }
- else if (srclen == 1) {
- *pdst++ = bin2asc[ (psrc[0] >> 2) & 0x3f];
- *pdst++ = bin2asc[ (psrc[0] << 4) & 0x30];
- *pdst++ = '=';
- *pdst++ = '=';
- n += 4;
- }
- *pdst = '\0';
- *dstlen = n;
- return (0);
- }
- int
- base64_decode_block (void *dst, int *dstlen, const void *src, int srclen)
- {
- return (base64_decode_update (NULL, dst, dstlen, src, srclen));
- }
- int
- base64_encode_length (int srclen)
- {
- /* When encoding, 3 bytes are encoded into 4 characters.
- * Add 2 bytes to ensure a partial 3-byte chunk will be accounted for
- * during integer division, then add 1 byte for the terminating NUL.
- */
- return (((srclen + 2) / 3) * 4) + 1;
- }
- int
- base64_decode_length (int srclen)
- {
- /* When decoding, 4 characters are decoded into 3 bytes.
- * Add 3 bytes to ensure a partial 4-byte chunk will be accounted for
- * during integer division, then add 1 byte for the terminating NUL.
- */
- return (((srclen + 3) / 4) * 3) + 1;
- }
- /*****************************************************************************
- * Table Initialization Routines
- *****************************************************************************/
- #ifdef BASE64_INIT
- #include <ctype.h>
- #include <stdio.h>
- #include <stdlib.h>
- #define BASE64_DEF_COLS 12
- void base64_build_table (unsigned char *data, int len);
- void base64_print_table (unsigned char *data, int len, char *name, int col);
- int
- main (int argc, char *argv[])
- {
- int col;
- unsigned char a2b[256];
- col = (argc > 1) ? atoi (argv[1]) : BASE64_DEF_COLS;
- base64_build_table (a2b, sizeof (a2b));
- base64_print_table (a2b, sizeof (a2b), "asc2bin", col);
- exit (EXIT_SUCCESS);
- }
- void
- base64_build_table (unsigned char *data, int len)
- {
- int i;
- for (i = 0; i < len; i++)
- data[i] = (isspace (i)) ? BASE64_IGN : BASE64_ERR;
- for (i = strlen (bin2asc) - 1; i >= 0; i--)
- data[bin2asc[i]] = i;
- data[BASE64_PAD_CHAR] = BASE64_PAD;
- return;
- }
- void
- base64_print_table (unsigned char *data, int len, char *name, int col)
- {
- int i;
- int n;
- if (col < 1) {
- col = BASE64_DEF_COLS;
- }
- printf ("static const unsigned char %s[%d] = {", name, len);
- for (i=0, n=len-1; ; i++) {
- if ((i % col) == 0)
- printf ("\n ");
- printf ("0x%02x", data[i]);
- if (i == n)
- break;
- printf (", ");
- }
- printf ("\n};\n");
- return;
- }
- #endif /* BASE64_INIT */