/* silcbase64.c Author: Pekka Riikonen Copyright (C) 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include "silc.h" static unsigned char pem_enc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* Encodes data into Base 64 encoding. Returns NULL terminated base 64 encoded data string. */ char *silc_base64_encode(SilcStack stack, unsigned char *data, SilcUInt32 len) { int i, j; SilcUInt32 bits, c, char_count; char *pem; char_count = 0; bits = 0; j = 0; pem = silc_scalloc(stack, ((len * 8 + 5) / 6) + 5, sizeof(*pem)); for (i = 0; i < len; i++) { c = data[i]; bits += c; char_count++; if (char_count == 3) { pem[j++] = pem_enc[bits >> 18]; pem[j++] = pem_enc[(bits >> 12) & 0x3f]; pem[j++] = pem_enc[(bits >> 6) & 0x3f]; pem[j++] = pem_enc[bits & 0x3f]; bits = 0; char_count = 0; } else { bits <<= 8; } } if (char_count != 0) { bits <<= 16 - (8 * char_count); pem[j++] = pem_enc[bits >> 18]; pem[j++] = pem_enc[(bits >> 12) & 0x3f]; if (char_count == 1) { pem[j++] = '='; pem[j] = '='; } else { pem[j++] = pem_enc[(bits >> 6) & 0x3f]; pem[j] = '='; } } return pem; } /* Same as above but puts newline ('\n') every 72 characters. */ char *silc_base64_encode_file(SilcStack stack, unsigned char *data, SilcUInt32 data_len) { int i, j; SilcUInt32 len, cols; char *pem, *pem2; pem = silc_base64_encode(stack, data, data_len); len = strlen(pem); pem2 = silc_scalloc(stack, len + (len / 72) + 1, sizeof(*pem2)); for (i = 0, j = 0, cols = 1; i < len; i++, cols++) { if (cols == 72) { pem2[i] = '\n'; cols = 0; len++; continue; } pem2[i] = pem[j++]; } silc_sfree(stack, pem); return pem2; } /* Decodes Base 64 into data. Returns the decoded data. */ unsigned char *silc_base64_decode(SilcStack stack, unsigned char *base64, SilcUInt32 base64_len, SilcUInt32 *ret_len) { int i, j; SilcUInt32 len, c, char_count, bits; unsigned char *data; static char ialpha[256], decoder[256]; for (i = 64 - 1; i >= 0; i--) { ialpha[pem_enc[i]] = 1; decoder[pem_enc[i]] = i; } char_count = 0; bits = 0; j = 0; if (!base64_len) len = strlen(base64); else len = base64_len; data = silc_scalloc(stack, ((len * 6) / 8), sizeof(*data)); for (i = 0; i < len; i++) { c = base64[i]; if (c == '=') break; if (c > 127 || !ialpha[c]) continue; bits += decoder[c]; char_count++; if (char_count == 4) { data[j++] = bits >> 16; data[j++] = (bits >> 8) & 0xff; data[j++] = bits & 0xff; bits = 0; char_count = 0; } else { bits <<= 6; } } switch(char_count) { case 1: silc_sfree(stack, data); return NULL; break; case 2: data[j++] = bits >> 10; break; case 3: data[j++] = bits >> 16; data[j++] = (bits >> 8) & 0xff; break; } if (ret_len) *ret_len = j; return data; }