summaryrefslogtreecommitdiff
path: root/rpmio/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'rpmio/base64.c')
-rw-r--r--rpmio/base64.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/rpmio/base64.c b/rpmio/base64.c
new file mode 100644
index 0000000..6b006e1
--- /dev/null
+++ b/rpmio/base64.c
@@ -0,0 +1,255 @@
+/* base64 encoder/decoder based on public domain implementation
+ * by Chris Venter */
+
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include "rpmio/base64.h"
+
+
+static char base64_encode_value(char value_in)
+{
+ static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ if (value_in > 63) return '=';
+ return encoding[(int)value_in];
+}
+
+static char *base64_encode_block(const char *plaintext_in, int length_in, char *codechar)
+{
+ const char *plainchar = plaintext_in;
+ const char *const plaintextend = plaintext_in + length_in;
+ char result;
+ char fragment;
+
+ while (1) {
+ if (plainchar == plaintextend) {
+ return codechar;
+ }
+ fragment = *plainchar++;
+ result = (fragment & 0x0fc) >> 2;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x003) << 4;
+ if (plainchar == plaintextend)
+ {
+ *codechar++ = base64_encode_value(result);
+ *codechar++ = '=';
+ *codechar++ = '=';
+ return codechar;
+ }
+ fragment = *plainchar++;
+ result |= (fragment & 0x0f0) >> 4;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x00f) << 2;
+ if (plainchar == plaintextend)
+ {
+ *codechar++ = base64_encode_value(result);
+ *codechar++ = '=';
+ return codechar;
+ }
+ fragment = *plainchar++;
+ result |= (fragment & 0x0c0) >> 6;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x03f) >> 0;
+ *codechar++ = base64_encode_value(result);
+ }
+ /* control should not reach here */
+ return codechar;
+}
+
+#define BASE64_DEFAULT_LINE_LENGTH 64
+
+char *b64encode(const void *data, size_t len, int linelen)
+{
+ size_t encodedlen;
+ const char *dataptr = data;
+ char *output;
+ char *outptr;
+
+ if (data == NULL)
+ return NULL;
+
+ if (linelen < 0)
+ linelen = BASE64_DEFAULT_LINE_LENGTH;
+
+ linelen /= 4;
+ encodedlen = ((len + 2) / 3) * 4;
+ if (linelen > 0) {
+ encodedlen += encodedlen/(linelen * 4) + 1;
+ }
+ ++encodedlen; /* for zero termination */
+
+ output = malloc(encodedlen);
+ if (output == NULL)
+ return NULL;
+
+ outptr = output;
+ while (len > 0) {
+ if (linelen > 0 && len > linelen * 3) {
+ outptr = base64_encode_block(dataptr, linelen * 3, outptr);
+ len -= linelen * 3;
+ dataptr += linelen * 3;
+ } else {
+ outptr = base64_encode_block(dataptr, len, outptr);
+ len = 0;
+ }
+ if (linelen > 0) {
+ *outptr++ = '\n';
+ }
+ }
+ *outptr = '\0';
+ return output;
+}
+
+static int base64_decode_value(unsigned char value_in)
+{
+ static const int decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
+ value_in -= 43;
+ if (value_in > sizeof(decoding)/sizeof(int))
+ return -1;
+ return decoding[value_in];
+}
+
+static size_t base64_decode_block(const char *code_in, const size_t length_in, char *plaintext_out)
+{
+ const char *codechar = code_in;
+ char *plainchar = plaintext_out;
+ int fragment;
+
+ *plainchar = 0;
+
+ while (1)
+ {
+ do {
+ if (codechar == code_in+length_in)
+ {
+ return plainchar - plaintext_out;
+ }
+ fragment = base64_decode_value(*codechar++);
+ } while (fragment < 0);
+ *plainchar = (char)((fragment & 0x03f) << 2);
+
+ do {
+ if (codechar == code_in+length_in)
+ {
+ return plainchar - plaintext_out;
+ }
+ fragment = base64_decode_value(*codechar++);
+ } while (fragment < 0);
+ *plainchar++ |= (char)((fragment & 0x030) >> 4);
+ *plainchar = (char)((fragment & 0x00f) << 4);
+
+ do {
+ if (codechar == code_in+length_in)
+ {
+ return plainchar - plaintext_out;
+ }
+ fragment = base64_decode_value(*codechar++);
+ } while (fragment < 0);
+ *plainchar++ |= (char)((fragment & 0x03c) >> 2);
+ *plainchar = (char)((fragment & 0x003) << 6);
+
+ do {
+ if (codechar == code_in+length_in)
+ {
+ return plainchar - plaintext_out;
+ }
+ fragment = base64_decode_value(*codechar++);
+ } while (fragment < 0);
+ *plainchar++ |= (char)(fragment & 0x03f);
+ }
+ /* control should not reach here */
+ return plainchar - plaintext_out;
+}
+
+int b64decode(const char *in, void **out, size_t *outlen)
+{
+ size_t outcnt = 0;
+ const char *inptr = in;
+
+ *out = NULL;
+
+ if (in == NULL) {
+ return 1;
+ }
+
+ while (*inptr != '\0') {
+ /* assume all ASCII control chars as whitespace */
+ if (*inptr > 32) {
+ if (base64_decode_value(*inptr) != -1) {
+ ++outcnt;
+ } else {
+ return 3;
+ }
+ }
+ ++inptr;
+ }
+
+ if (outcnt % 4 != 0)
+ return 2;
+
+ outcnt = (outcnt / 4) * 3;
+
+ *out = malloc(outcnt + 1); /* base64_decode_block can write one extra character */
+
+ if (*out == NULL)
+ return 4;
+
+ *outlen = base64_decode_block(in, inptr - in, *out);
+
+ return 0;
+}
+
+#define CRC24_INIT 0xb704ce
+#define CRC24_POLY 0x1864cfb
+
+char *b64crc(const unsigned char *data, size_t len)
+{
+ uint32_t crc = CRC24_INIT;
+ int i;
+
+ while (len--) {
+ crc ^= (*data++) << 16;
+ for (i = 0; i < 8; i++) {
+ crc <<= 1;
+ if (crc & 0x1000000)
+ crc ^= CRC24_POLY;
+ }
+ }
+ crc = htonl(crc & 0xffffff);
+ data = (unsigned char *)&crc;
+ ++data;
+ return b64encode(data, 3, 0);
+}
+
+#ifdef BASE64_TEST
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+ static char tst[]="wtrt8122čLýáj\x20s ~ýhž\t4\x02šjjmBvž^%$RTš#á.íěj\x1hčýčŤc+";
+ char *encoded;
+ void *decoded;
+ size_t size;
+ int err;
+ printf("Original: %lu\n%s\n", sizeof(tst)-1, tst);
+ encoded = b64encode(tst, sizeof(tst)-1, 64);
+ printf("Encoded: %lu\n%s\n", strlen(encoded), encoded);
+ if ((err = b64decode(encoded, &decoded, &size)) != 0) {
+ fprintf(stderr, "Error in decode: %d\n", err);
+ return 1;
+ }
+ printf("Decoded:\n%.*s\n", (int)size, (char *)decoded);
+ if (size != sizeof(tst)-1) {
+ fprintf(stderr, "Size differs orig: %lu new: %lu\n", sizeof(tst)-1, size);
+ return 1;
+ }
+ if (memcmp(tst, decoded, size) != 0) {
+ fprintf(stderr, "Decoded data differs.\n");
+ return 1;
+ }
+ fprintf(stderr, "OK\n");
+ return 0;
+}
+#endif
+