18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Base64 encoding/decoding (RFC1341) 31f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "os.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base64.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const unsigned char base64_table[65] = 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * base64_encode - Base64 encode 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @src: Data to be encoded 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of the data to be encoded 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @out_len: Pointer to output length variable, or %NULL if not used 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Allocated buffer of out_len bytes of encoded data, 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * or %NULL on failure 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Caller is responsible for freeing the returned buffer. Returned buffer is 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * nul terminated to make it easier to use as a C string. The nul terminator is 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * not included in out_len. 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned char * base64_encode(const unsigned char *src, size_t len, 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *out_len) 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *out, *pos; 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const unsigned char *end, *in; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t olen; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int line_len; 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt olen += olen / 72; /* line feeds */ 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt olen++; /* nul termination */ 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (olen < len) 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; /* integer overflow */ 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt out = os_malloc(olen); 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (out == NULL) 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = src + len; 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt in = src; 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = out; 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line_len = 0; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (end - in >= 3) { 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[in[0] >> 2]; 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[in[2] & 0x3f]; 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt in += 3; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line_len += 4; 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (line_len >= 72) { 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = '\n'; 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line_len = 0; 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - in) { 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[in[0] >> 2]; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - in == 1) { 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[(in[0] & 0x03) << 4]; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = '='; 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[((in[0] & 0x03) << 4) | 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (in[1] >> 4)]; 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[(in[1] & 0x0f) << 2]; 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = '='; 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line_len += 4; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (line_len) 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = '\n'; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos = '\0'; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (out_len) 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *out_len = pos - out; 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return out; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * base64_decode - Base64 decode 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @src: Data to be decoded 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of the data to be decoded 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @out_len: Pointer to output length variable 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Allocated buffer of out_len bytes of decoded data, 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * or %NULL on failure 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Caller is responsible for freeing the returned buffer. 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned char * base64_decode(const unsigned char *src, size_t len, 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *out_len) 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt unsigned char dtable[256], *out, *pos, block[4], tmp; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, count, olen; 1021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int pad = 0; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(dtable, 0x80, 256); 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < sizeof(base64_table) - 1; i++) 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dtable[base64_table[i]] = (unsigned char) i; 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dtable['='] = 0; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count = 0; 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < len; i++) { 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dtable[src[i]] != 0x80) 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (count == 0 || count % 4) 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt olen = count / 4 * 3; 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = out = os_malloc(olen); 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (out == NULL) 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count = 0; 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < len; i++) { 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = dtable[src[i]]; 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp == 0x80) 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (src[i] == '=') 1301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pad++; 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt block[count] = tmp; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (count == 4) { 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = (block[0] << 2) | (block[1] >> 4); 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = (block[1] << 4) | (block[2] >> 2); 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = (block[2] << 6) | block[3]; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count = 0; 1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pad) { 1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pad == 1) 1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos--; 1411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt else if (pad == 2) 1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos -= 2; 1431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt else { 1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Invalid padding */ 1451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(out); 1461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return NULL; 1471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt break; 1491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *out_len = pos - out; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return out; 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 156