Back to index

opendkim  2.6.4
base32.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>,
00003 ** Erik Ekman <yarrick@kryo.se>
00004 ** Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
00005 **
00006 ** Permission to use, copy, modify, and distribute this software for any
00007 ** purpose with or without fee is hereby granted, provided that the above
00008 ** copyright notice and this permission notice appear in all copies.
00009 **
00010 ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00011 ** WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00012 ** MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00013 ** ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00014 ** WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00015 ** ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00016 ** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00017 **
00018 ** Portions Copyright (c) 2010, 2011, The OpenDKIM Project.
00019 ** All rights reserved.
00020 */
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 
00026 #include "dkim.h"
00027 
00028 #define BLKSIZE_RAW 5
00029 #define BLKSIZE_ENC 8
00030 
00031 static const char cb32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
00032 
00033 /*
00034 **  DKIM_BASE32_ENCODE -- encode a string using base32
00035 **
00036 **  Parameters:
00037 **     buf -- destination buffer
00038 **     buflen -- in: bytes available at buf
00039 **                out: bytes used from "data"
00040 **     data -- pointer to data to encode
00041 **     size -- bytes at "data" to encode
00042 **
00043 **  Return value:
00044 **     Length of encoding.
00045 **
00046 **  Notes:
00047 **     buf should be at least a byte more than *buflen to hold the trailing
00048 **     '\0'.
00049 **
00050 **     *buflen is updated to count the number of bytes read from "data".
00051 */
00052 
00053 int 
00054 dkim_base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
00055 {
00056        unsigned int lastbits;
00057        unsigned int padding;
00058        int iout = 0;
00059        int iin = 0;
00060        unsigned char *udata;
00061 
00062        udata = (unsigned char *) data;
00063 
00064        for (;;)
00065        {
00066               if (iout >= *buflen || iin >= size)
00067                      break;
00068 
00069               buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)];
00070               iout++;
00071 
00072               if (iout >= *buflen || iin >= size)
00073               {
00074                      iout--;       /* previous char is useless */
00075                      break;
00076               }
00077 
00078               buf[iout] = cb32[((udata[iin] & 0x07) << 2) |
00079                               ((iin + 1 < size) ?
00080                                ((udata[iin + 1] & 0xc0) >> 6) : 0)];
00081               iin++;               /* 0 complete, iin = 1 */
00082               iout++;
00083 
00084               if (iout >= *buflen || iin >= size)
00085                      break;
00086               buf[iout] = cb32[((udata[iin] & 0x3e) >> 1)];
00087               iout++;
00088 
00089               if (iout >= *buflen || iin >= size)
00090               {
00091                      iout--;              /* previous char is useless */
00092                      break;
00093               }
00094               buf[iout] = cb32[((udata[iin] & 0x01) << 4) |
00095                               ((iin + 1 < size) ?
00096                                ((udata[iin + 1] & 0xf0) >> 4) : 0)];
00097               iin++;               /* 1 complete, iin = 2 */
00098               iout++;
00099 
00100               if (iout >= *buflen || iin >= size)
00101                      break;
00102               buf[iout] = cb32[((udata[iin] & 0x0f) << 1) |
00103                               ((iin + 1 < size) ?
00104                                ((udata[iin + 1] & 0x80) >> 7) : 0)];
00105               iin++;               /* 2 complete, iin = 3 */
00106               iout++;
00107 
00108               if (iout >= *buflen || iin >= size)
00109                      break;
00110               buf[iout] = cb32[((udata[iin] & 0x7c) >> 2)];
00111               iout++;
00112 
00113               if (iout >= *buflen || iin >= size)
00114               {
00115                      iout--;              /* previous char is useless */
00116                      break;
00117               }
00118               buf[iout] = cb32[((udata[iin] & 0x03) << 3) |
00119                               ((iin + 1 < size) ?
00120                                ((udata[iin + 1] & 0xe0) >> 5) : 0)];
00121               iin++;               /* 3 complete, iin = 4 */
00122               iout++;
00123 
00124               if (iout >= *buflen || iin >= size)
00125                      break;
00126               buf[iout] = cb32[((udata[iin] & 0x1f))];
00127               iin++;               /* 4 complete, iin = 5 */
00128               iout++;
00129        }
00130 
00131        /* append padding */
00132        lastbits = (size * 8) % 40;
00133        if (lastbits == 0)
00134               padding = 0;
00135        else if (lastbits == 8)
00136               padding = 6;
00137        else if (lastbits == 16)
00138               padding = 4;
00139        else if (lastbits == 24)
00140               padding = 3;
00141        else if (lastbits == 32)
00142               padding = 1;
00143 
00144        while (padding > 0 && iout < *buflen)
00145        {
00146               buf[iout++] = '=';
00147               padding--;
00148        }
00149 
00150        /* ensure NULL termination */
00151        buf[iout] = '\0';
00152 
00153        /* store number of bytes from data that was used */
00154        *buflen = iin;
00155 
00156        return iout;
00157 }
00158 
00159 #ifdef TEST
00160 #include <openssl/sha.h>
00161 
00162 int
00163 main(int argc, char **argv)
00164 {
00165        int x;
00166        size_t buflen;
00167        SHA_CTX sha;
00168        char buf[128];
00169        unsigned char shaout[SHA_DIGEST_LENGTH];
00170 
00171        memset(buf, '\0', sizeof buf);
00172        buflen = sizeof buf;
00173 
00174        SHA1_Init(&sha);
00175        SHA1_Update(&sha, argv[1], strlen(argv[1]));
00176        SHA1_Final(shaout, &sha);
00177 
00178        x = dkim_base32_encode(buf, &buflen, shaout, SHA_DIGEST_LENGTH);
00179 
00180        printf("%s (%d)\n", buf, x);
00181 
00182        return 0;
00183 }
00184 #endif /* TEST */