1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ 2 /* vi: set expandtab shiftwidth=4 tabstop=4: */ 3 /** 4 * \file 5 * <PRE> 6 * MODP_B64 - High performance base64 encoder/decoder 7 * Version 1.3 -- 17-Mar-2006 8 * http://modp.com/release/base64 9 * 10 * Copyright © 2005, 2006 Nick Galbreath -- nickg [at] modp [dot] com 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions are 15 * met: 16 * 17 * Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * Neither the name of the modp.com nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * This is the standard "new" BSD license: 41 * http://www.opensource.org/licenses/bsd-license.php 42 * </PRE> 43 */ 44 45 /* public header */ 46 #include "modp_b64.h" 47 48 /* 49 * If you are ripping this out of the library, comment out the next 50 * line and uncomment the next lines as approrpiate 51 */ 52 //#include "config.h" 53 54 /* if on motoral, sun, ibm; uncomment this */ 55 /* #define WORDS_BIGENDIAN 1 */ 56 /* else for Intel, Amd; uncomment this */ 57 /* #undef WORDS_BIGENDIAN */ 58 59 #include "modp_b64_data.h" 60 61 #define BADCHAR 0x01FFFFFF 62 63 /** 64 * you can control if we use padding by commenting out this 65 * next line. However, I highly recommend you use padding and not 66 * using it should only be for compatability with a 3rd party. 67 * Also, 'no padding' is not tested! 68 */ 69 #define DOPAD 1 70 71 /* 72 * if we aren't doing padding 73 * set the pad character to NULL 74 */ 75 #ifndef DOPAD 76 #undef CHARPAD 77 #define CHARPAD '\0' 78 #endif 79 80 int modp_b64_encode(char* dest, const char* str, int len) 81 { 82 int i; 83 uint8_t* p = (uint8_t*) dest; 84 85 /* unsigned here is important! */ 86 uint8_t t1, t2, t3; 87 88 for (i = 0; i < len - 2; i += 3) { 89 t1 = str[i]; t2 = str[i+1]; t3 = str[i+2]; 90 *p++ = e0[t1]; 91 *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; 92 *p++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; 93 *p++ = e2[t3]; 94 } 95 96 switch (len - i) { 97 case 0: 98 break; 99 case 1: 100 t1 = str[i]; 101 *p++ = e0[t1]; 102 *p++ = e1[(t1 & 0x03) << 4]; 103 *p++ = CHARPAD; 104 *p++ = CHARPAD; 105 break; 106 default: /* case 2 */ 107 t1 = str[i]; t2 = str[i+1]; 108 *p++ = e0[t1]; 109 *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; 110 *p++ = e2[(t2 & 0x0F) << 2]; 111 *p++ = CHARPAD; 112 } 113 114 *p = '\0'; 115 return p - (uint8_t*)dest; 116 } 117 118 #ifdef WORDS_BIGENDIAN /* BIG ENDIAN -- SUN / IBM / MOTOROLA */ 119 int modp_b64_decode(char* dest, const char* src, int len) 120 { 121 if (len == 0) return 0; 122 123 #ifdef DOPAD 124 /* if padding is used, then the message must be at least 125 4 chars and be a multiple of 4. 126 there can be at most 2 pad chars at the end */ 127 if (len < 4 || (len % 4 != 0)) return -1; 128 if (src[len-1] == CHARPAD) { 129 len--; 130 if (src[len -1] == CHARPAD) { 131 len--; 132 } 133 } 134 #endif /* DOPAD */ 135 136 int i; 137 int leftover = len % 4; 138 int chunks = (leftover == 0) ? len / 4 - 1 : len /4; 139 140 uint8_t* p = (uint8_t*) dest; 141 uint32_t x = 0; 142 uint32_t* destInt = (uint32_t*) p; 143 uint32_t* srcInt = (uint32_t*) src; 144 uint32_t y = *srcInt++; 145 for (i = 0; i < chunks; ++i) { 146 x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] | 147 d2[y >> 8 & 0xff] | d3[y & 0xff]; 148 149 if (x >= BADCHAR) return -1; 150 *destInt = x << 8; 151 p += 3; 152 destInt = (uint32_t*)p; 153 y = *srcInt++; 154 } 155 156 switch (leftover) { 157 case 0: 158 x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] | 159 d2[y >> 8 & 0xff] | d3[y & 0xff]; 160 if (x >= BADCHAR) return -1; 161 *p++ = ((uint8_t*)&x)[1]; 162 *p++ = ((uint8_t*)&x)[2]; 163 *p = ((uint8_t*)&x)[3]; 164 return (chunks+1)*3; 165 case 1: 166 x = d3[y >> 24]; 167 *p = (uint8_t)x; 168 break; 169 case 2: 170 x = d3[y >> 24] *64 + d3[(y >> 16) & 0xff]; 171 *p = (uint8_t)(x >> 4); 172 break; 173 default: /* case 3 */ 174 x = (d3[y >> 24] *64 + d3[(y >> 16) & 0xff])*64 + 175 d3[(y >> 8) & 0xff]; 176 *p++ = (uint8_t) (x >> 10); 177 *p = (uint8_t) (x >> 2); 178 break; 179 } 180 181 if (x >= BADCHAR) return -1; 182 return 3*chunks + (6*leftover)/8; 183 } 184 185 #else /* LITTLE ENDIAN -- INTEL AND FRIENDS */ 186 187 int modp_b64_decode(char* dest, const char* src, int len) 188 { 189 if (len == 0) return 0; 190 191 #ifdef DOPAD 192 /* 193 * if padding is used, then the message must be at least 194 * 4 chars and be a multiple of 4 195 */ 196 if (len < 4 || (len % 4 != 0)) return -1; /* error */ 197 /* there can be at most 2 pad chars at the end */ 198 if (src[len-1] == CHARPAD) { 199 len--; 200 if (src[len -1] == CHARPAD) { 201 len--; 202 } 203 } 204 #endif 205 206 int i; 207 int leftover = len % 4; 208 int chunks = (leftover == 0) ? len / 4 - 1 : len /4; 209 210 uint8_t* p = (uint8_t*)dest; 211 uint32_t x = 0; 212 uint32_t* destInt = (uint32_t*) p; 213 uint32_t* srcInt = (uint32_t*) src; 214 uint32_t y = *srcInt++; 215 for (i = 0; i < chunks; ++i) { 216 x = d0[y & 0xff] | 217 d1[(y >> 8) & 0xff] | 218 d2[(y >> 16) & 0xff] | 219 d3[(y >> 24) & 0xff]; 220 221 if (x >= BADCHAR) return -1; 222 *destInt = x ; 223 p += 3; 224 destInt = (uint32_t*)p; 225 y = *srcInt++;} 226 227 228 switch (leftover) { 229 case 0: 230 x = d0[y & 0xff] | 231 d1[(y >> 8) & 0xff] | 232 d2[(y >> 16) & 0xff] | 233 d3[(y >> 24) & 0xff]; 234 235 if (x >= BADCHAR) return -1; 236 *p++ = ((uint8_t*)(&x))[0]; 237 *p++ = ((uint8_t*)(&x))[1]; 238 *p = ((uint8_t*)(&x))[2]; 239 return (chunks+1)*3; 240 break; 241 case 1: /* with padding this is an impossible case */ 242 x = d0[y & 0xff]; 243 *p = *((uint8_t*)(&x)); // i.e. first char/byte in int 244 break; 245 case 2: // * case 2, 1 output byte */ 246 x = d0[y & 0xff] | d1[y >> 8 & 0xff]; 247 *p = *((uint8_t*)(&x)); // i.e. first char 248 break; 249 default: /* case 3, 2 output bytes */ 250 x = d0[y & 0xff] | 251 d1[y >> 8 & 0xff ] | 252 d2[y >> 16 & 0xff]; /* 0x3c */ 253 *p++ = ((uint8_t*)(&x))[0]; 254 *p = ((uint8_t*)(&x))[1]; 255 break; 256 } 257 258 if (x >= BADCHAR) return -1; 259 260 return 3*chunks + (6*leftover)/8; 261 } 262 263 #endif /* if bigendian / else / endif */ 264