summaryrefslogtreecommitdiff
path: root/beecrypt/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'beecrypt/base64.c')
-rw-r--r--beecrypt/base64.c203
1 files changed, 202 insertions, 1 deletions
diff --git a/beecrypt/base64.c b/beecrypt/base64.c
index 31bd90c1c..a35627acf 100644
--- a/beecrypt/base64.c
+++ b/beecrypt/base64.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2000 Virtual Unlimited B.V.
+ * Copyright (c) 2000-2001 Virtual Unlimited B.V.
*
* Author: Bob Deblier <bob@virtualunlimited.com>
*
@@ -37,12 +37,213 @@ static int _debug = 0;
#if HAVE_STRING_H
# include <string.h>
#endif
+#if HAVE_CTYPE_H
+# include <ctype.h>
+#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdio.h>
+static const char* to_b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* encode 64 characters per line */
+#define CHARS_PER_LINE 64
+
+char* b64enc(const memchunk* chunk)
+{
+ int div = chunk->size / 3;
+ int rem = chunk->size % 3;
+ int chars = div*4 + rem + 1;
+ int newlines = (chars + CHARS_PER_LINE - 1) / CHARS_PER_LINE;
+
+ const byte* data = chunk->data;
+ char* string = (char*) malloc(chars + newlines + 1);
+
+ if (string)
+ {
+ register char* buf = string;
+
+ chars = 0;
+
+ while (div > 0)
+ {
+ buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
+ buf[1] = to_b64[((data[0] << 4) & 0x30) | ((data[1] >> 4) & 0xf)];
+ buf[2] = to_b64[((data[1] << 2) & 0x3c) | ((data[2] >> 6) & 0x3)];
+ buf[3] = to_b64[ data[2] & 0x3f];
+ data += 3;
+ buf += 4;
+ div--;
+ chars += 4;
+ if (chars == CHARS_PER_LINE)
+ {
+ chars = 0;
+ *(buf++) = '\n';
+ }
+ }
+
+ switch (rem)
+ {
+ case 2:
+ buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
+ buf[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)];
+ buf[2] = to_b64[ (data[1] << 2) & 0x3c];
+ buf[3] = '=';
+ buf += 4;
+ chars += 4;
+ break;
+ case 1:
+ buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
+ buf[1] = to_b64[ (data[0] << 4) & 0x30];
+ buf[2] = '=';
+ buf[3] = '=';
+ buf += 4;
+ chars += 4;
+ break;
+ }
+
+ /* *(buf++) = '\n'; This would result in a buffer overrun */
+ *buf = '\0';
+ }
+
+ return string;
+}
+
+memchunk* b64dec(const char* string)
+{
+ /* return a decoded memchunk, or a null pointer in case of failure */
+
+ memchunk* rc = 0;
+
+ if (string)
+ {
+ register int length = strlen(string);
+
+ /* do a format verification first */
+ if (length > 0)
+ {
+ register int count = 0, rem = 0;
+ register const char* tmp = string;
+
+ while (length > 0)
+ {
+ register int skip = strspn(tmp, to_b64);
+ count += skip;
+ length -= skip;
+ tmp += skip;
+ if (length > 0)
+ {
+ register int i, vrfy = strcspn(tmp, to_b64);
+
+ for (i = 0; i < vrfy; i++)
+ {
+ if (isspace(tmp[i]))
+ continue;
+
+ if (tmp[i] == '=')
+ {
+ /* we should check if we're close to the end of the string */
+ rem = count % 4;
+
+ /* rem must be either 2 or 3, otherwise no '=' should be here */
+ if (rem < 2)
+ return 0;
+
+ /* end-of-message recognized */
+ break;
+ }
+ else
+ {
+ /* Transmission error; RFC tells us to ignore this, but:
+ * - the rest of the message is going to even more corrupt since we're sliding bits out of place
+ * If a message is corrupt, it should be dropped. Period.
+ */
+
+ return 0;
+ }
+ }
+
+ length -= vrfy;
+ tmp += vrfy;
+ }
+ }
+
+ rc = memchunkAlloc((count / 4) * 3 + (rem ? (rem - 1) : 0));
+
+ if (rc)
+ {
+ if (count > 0)
+ {
+ register int i, qw = 0, tw = 0;
+ register byte* data = rc->data;
+
+ length = strlen(tmp = string);
+
+ for (i = 0; i < length; i++)
+ {
+ register char ch = string[i];
+ register byte bits;
+
+ if (isspace(ch))
+ continue;
+
+ if ((ch >= 'A') && (ch <= 'Z'))
+ {
+ bits = (byte) (ch - 'A');
+ }
+ else if ((ch >= 'a') && (ch <= 'z'))
+ {
+ bits = (byte) (ch - 'a' + 26);
+ }
+ else if ((ch >= '0') && (ch <= '9'))
+ {
+ bits = (byte) (ch - '0' + 52);
+ }
+ else if (ch == '+')
+ {
+ bits = 62;
+ }
+ else if (ch == '/')
+ {
+ bits = 63;
+ }
+ else if (ch == '=')
+ break;
+
+ switch (qw++)
+ {
+ case 0:
+ data[tw+0] = (bits << 2) & 0xfc;
+ break;
+ case 1:
+ data[tw+0] |= (bits >> 4) & 0x03;
+ data[tw+1] = (bits << 4) & 0xf0;
+ break;
+ case 2:
+ data[tw+1] |= (bits >> 2) & 0x0f;
+ data[tw+2] = (bits << 6) & 0xc0;
+ break;
+ case 3:
+ data[tw+2] |= bits & 0x3f;
+ break;
+ }
+
+ if (qw == 4)
+ {
+ qw = 0;
+ tw += 3;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
int b64encode_chars_per_line = B64ENCODE_CHARS_PER_LINE;
const char * b64encode_eolstr = B64ENCODE_EOLSTR;