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) { 51fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *pos++ = base64_table[(in[0] >> 2) & 0x3f]; 52fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *pos++ = base64_table[(((in[0] & 0x03) << 4) | 53fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt (in[1] >> 4)) & 0x3f]; 54fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *pos++ = base64_table[(((in[1] & 0x0f) << 2) | 55fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt (in[2] >> 6)) & 0x3f]; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = base64_table[in[2] & 0x3f]; 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt in += 3; 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line_len += 4; 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (line_len >= 72) { 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = '\n'; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line_len = 0; 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - in) { 66fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *pos++ = base64_table[(in[0] >> 2) & 0x3f]; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - in == 1) { 68fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f]; 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = '='; 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 71fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *pos++ = base64_table[(((in[0] & 0x03) << 4) | 72fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt (in[1] >> 4)) & 0x3f]; 73fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f]; 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = '='; 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line_len += 4; 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (line_len) 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = '\n'; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos = '\0'; 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (out_len) 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *out_len = pos - out; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return out; 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * base64_decode - Base64 decode 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @src: Data to be decoded 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of the data to be decoded 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @out_len: Pointer to output length variable 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Allocated buffer of out_len bytes of decoded data, 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * or %NULL on failure 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Caller is responsible for freeing the returned buffer. 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned char * base64_decode(const unsigned char *src, size_t len, 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *out_len) 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt unsigned char dtable[256], *out, *pos, block[4], tmp; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, count, olen; 1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int pad = 0; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(dtable, 0x80, 256); 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < sizeof(base64_table) - 1; i++) 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dtable[base64_table[i]] = (unsigned char) i; 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dtable['='] = 0; 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count = 0; 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < len; i++) { 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dtable[src[i]] != 0x80) 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (count == 0 || count % 4) 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt olen = count / 4 * 3; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = out = os_malloc(olen); 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (out == NULL) 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count = 0; 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < len; i++) { 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = dtable[src[i]]; 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp == 0x80) 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (src[i] == '=') 1321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pad++; 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt block[count] = tmp; 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (count == 4) { 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = (block[0] << 2) | (block[1] >> 4); 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = (block[1] << 4) | (block[2] >> 2); 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = (block[2] << 6) | block[3]; 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count = 0; 1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pad) { 1411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (pad == 1) 1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos--; 1431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt else if (pad == 2) 1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos -= 2; 1451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt else { 1461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* Invalid padding */ 1471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(out); 1481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return NULL; 1491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt break; 1511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *out_len = pos - out; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return out; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 158