/* ** Copyright (c) 2005 Sendmail, Inc. and its suppliers. ** All rights reserved. ** ** $Id: base64.c,v 1.3 2005/05/18 20:31:36 msk Exp $ */ #ifndef lint static char base64_c_id[] = "@(#)$Id: base64.c,v 1.3 2005/05/18 20:31:36 msk Exp $"; #endif /* !lint */ /* system includes */ #include #include /* libdkim includes */ #include "base64.h" /* base64 alphabet */ static unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* base64 decode stuff */ static int decoder[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #ifndef NULL # define NULL 0 #endif /* ! NULL */ /* ** DKIM_BASE64_DECODE -- decode a base64 blob ** ** Parameters: ** str -- string to decide ** buf -- where to write it ** buflen -- bytes available at "buf" ** ** Return value: ** >= 0 -- success; length of what was decoded is returned ** -1 -- corrupt ** -2 -- not enough space at "buf" */ int dkim_base64_decode(u_char *str, u_char *buf, size_t buflen) { int n = 0; int bits = 0; int char_count = 0; u_char *c; assert(str != NULL); assert(buf != NULL); for (c = str; *c != '=' && *c != '\0'; c++) { /* end padding */ if (*c == '=' || *c == '\0') break; /* skip stuff not part of the base64 alphabet (RFC2045) */ if (!((*c >= 'A' && *c <= 'Z') || (*c >= 'a' && *c <= 'z') || (*c >= '0' && *c <= '9') || (*c == '+') || (*c == '/'))) continue; /* everything else gets decoded */ bits += decoder[(int) *c]; char_count++; if (n + 3 > buflen) return -2; if (char_count == 4) { buf[n++] = (bits >> 16); buf[n++] = ((bits >> 8) & 0xff); buf[n++] = (bits & 0xff); bits = 0; char_count = 0; } else { bits <<= 6; } } /* XXX -- don't bother checking for proper termination (for now) */ /* process trailing data, if any */ switch (char_count) { case 0: break; case 1: /* base64 decoding incomplete; at least two bits missing */ break; case 2: if (n + 1 > buflen) return -2; buf[n++] = (bits >> 10); break; case 3: if (n + 2 > buflen) return -2; buf[n++] = (bits >> 16); buf[n++] = ((bits >> 8) & 0xff); break; } return n; } /* ** DKIM_BASE64_ENCODE -- encode base64 data ** ** Parameters: ** data -- data to encode ** datalen -- bytes at "data" to encode ** buf -- where to write the encoding ** buflen -- bytes available at "buf" ** ** Return value: ** >= 0 -- success; number of bytes written to "buf" returned ** -1 -- failure (not enough space at "buf") */ int dkim_base64_encode(u_char *data, size_t datalen, u_char *buf, size_t buflen) { int bits; int c; int char_count; size_t n; assert(data != NULL); assert(buf != NULL); bits = 0; char_count = 0; n = 0; for (c = 0; c < datalen; c++) { bits += data[c]; char_count++; if (char_count == 3) { if (n + 4 > buflen) return -1; buf[n++] = alphabet[bits >> 18]; buf[n++] = alphabet[(bits >> 12) & 0x3f]; buf[n++] = alphabet[(bits >> 6) & 0x3f]; buf[n++] = alphabet[bits & 0x3f]; bits = 0; char_count = 0; } else { bits <<= 8; } } if (char_count != 0) { if (n + 4 > buflen) return -1; bits <<= 16 - (8 * char_count); buf[n++] = alphabet[bits >> 18]; buf[n++] = alphabet[(bits >> 12) & 0x3f]; if (char_count == 1) { buf[n++] = '='; buf[n++] = '='; } else { buf[n++] = alphabet[(bits >> 6) & 0x3f]; buf[n++] = '='; } } return n; }