From b47087824bbcfa324a64b299b388a938886fc004 Mon Sep 17 00:00:00 2001 From: Jeff Connelly Date: Thu, 15 May 2008 01:02:54 -0700 Subject: [PATCH] Work on base64 decoder (incomplete). --- b64.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ libotp.c | 42 ++++++--- libotp.h | 2 +- try.c | 6 +- 4 files changed, 330 insertions(+), 16 deletions(-) create mode 100644 b64.c diff --git a/b64.c b/b64.c new file mode 100644 index 0000000..0d23616 --- /dev/null +++ b/b64.c @@ -0,0 +1,296 @@ +/* Based on: + * + * from http://base64.sourceforge.net/ + * ********************************************************************\ + +MODULE NAME: b64.c + +AUTHOR: Bob Trower 08/04/01 + +PROJECT: Crypt Data Packaging + +COPYRIGHT: Copyright (c) Trantor Standard Systems Inc., 2001 + +NOTE: This source code may be used as you wish, subject to + the MIT license. See the LICENCE section below. + +DESCRIPTION: + This little utility implements the Base64 + Content-Transfer-Encoding standard described in + RFC1113 (http://www.faqs.org/rfcs/rfc1113.html). + + This is the coding scheme used by MIME to allow + binary data to be transferred by SMTP mail. + + Groups of 3 bytes from a binary stream are coded as + groups of 4 bytes in a text stream. + + The input stream is 'padded' with zeros to create + an input that is an even multiple of 3. + + A special character ('=') is used to denote padding so + that the stream can be decoded back to its exact size. + + Encoded output is formatted in lines which should + be a maximum of 72 characters to conform to the + specification. This program defaults to 72 characters, + but will allow more or less through the use of a + switch. The program enforces a minimum line size + of 4 characters. + + Example encoding: + + The stream 'ABCD' is 32 bits long. It is mapped as + follows: + + ABCD + + A (65) B (66) C (67) D (68) (None) (None) + 01000001 01000010 01000011 01000100 + + 16 (Q) 20 (U) 9 (J) 3 (D) 17 (R) 0 (A) NA (=) NA (=) + 010000 010100 001001 000011 010001 000000 000000 000000 + + + QUJDRA== + + Decoding is the process in reverse. A 'decode' lookup + table has been created to avoid string scans. + +DESIGN GOALS: Specifically: + Code is a stand-alone utility to perform base64 + encoding/decoding. It should be genuinely useful + when the need arises and it meets a need that is + likely to occur for some users. + Code acts as sample code to show the author's + design and coding style. + + Generally: + This program is designed to survive: + Everything you need is in a single source file. + It compiles cleanly using a vanilla ANSI C compiler. + It does its job correctly with a minimum of fuss. + The code is not overly clever, not overly simplistic + and not overly verbose. + Access is 'cut and paste' from a web page. + Terms of use are reasonable. + +VALIDATION: Non-trivial code is never without errors. This + file likely has some problems, since it has only + been tested by the author. It is expected with most + source code that there is a period of 'burn-in' when + problems are identified and corrected. That being + said, it is possible to have 'reasonably correct' + code by following a regime of unit test that covers + the most likely cases and regression testing prior + to release. This has been done with this code and + it has a good probability of performing as expected. + + Unit Test Cases: + + case 0:empty file: + CASE0.DAT -> -> + (Zero length target file created + on both encode and decode.) + + case 1:One input character: + CASE1.DAT A -> QQ== -> A + + case 2:Two input characters: + CASE2.DAT AB -> QUJD -> AB + + case 3:Three input characters: + CASE3.DAT ABC -> QUJD -> ABC + + case 4:Four input characters: + case4.dat ABCD -> QUJDRA== -> ABCD + + case 5:All chars from 0 to ff, LINE_SIZE set to 50: + + AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj + JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH + SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P + kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz + tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX + 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7 + /P3+/w== + + case 6:Mime Block from e-mail: + (Data same as test case 5) + + case 7: Large files: + Tested 28 MB file in/out. + + case 8: Random Binary Integrity: + This binary program (b64.exe) was encoded to base64, + back to binary and then executed. + + case 9 Stress: + All files in a working directory encoded/decoded + and compared with file comparison utility to + ensure that multiple runs do not cause problems + such as exhausting file handles, tmp storage, etc. + + ------------- + + Syntax, operation and failure: + All options/switches tested. Performs as + expected. + + case 10: + No Args -- Shows Usage Screen + Return Code 1 (Invalid Syntax) + case 11: + One Arg (invalid) -- Shows Usage Screen + Return Code 1 (Invalid Syntax) + case 12: + One Arg Help (-?) -- Shows detailed Usage Screen. + Return Code 0 (Success -- help request is valid). + case 13: + One Arg Help (-h) -- Shows detailed Usage Screen. + Return Code 0 (Success -- help request is valid). + case 14: + One Arg (valid) -- Uses stdin/stdout (filter) + Return Code 0 (Sucess) + case 15: + Two Args (invalid file) -- shows system error. + Return Code 2 (File Error) + case 16: + Encode non-existent file -- shows system error. + Return Code 2 (File Error) + case 17: + Out of disk space -- shows system error. + Return Code 3 (File I/O Error) + + ------------- + + Compile/Regression test: + gcc compiled binary under Cygwin + Microsoft Visual Studio under Windows 2000 + Microsoft Version 6.0 C under Windows 2000 + +DEPENDENCIES: None + +LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall + be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +VERSION HISTORY: + Bob Trower 08/04/01 -- Create Version 0.00.00B + +\******************************************************************* */ + +#include +#include +#include +#include + +#define LINE_SIZE 72 + +/* +** Translation Table as described in RFC1113 +*/ +static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* +** Translation Table to decode (created by author) +*/ +static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + +/* +** encodeblock +** +** encode 3 8-bit binary bytes as 4 '6-bit' characters +*/ +void encodeblock( unsigned char in[3], unsigned char out[4], int len ) +{ + out[0] = cb64[ in[0] >> 2 ]; + out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; + out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='); + out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '='); +} + +/* +** decodeblock +** +** decode 4 '6-bit' characters into 3 8-bit binary bytes +*/ +void decodeblock( unsigned char in[4], unsigned char out[3] ) +{ + out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4); + out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2); + out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]); +} + +/* Decode base64. Caller frees. */ +char *b64_decode(char *in) +{ + char *out; + unsigned int at, out_at; + + + /* Get some space for the output. Needs less, but keep it simple. */ + out = malloc(strlen(in)); + if (!out) { + perror("malloc"); + exit(EX_UNAVAILABLE); + } + + memset(out, 0, strlen(in)); + + at = out_at = 0; + do { + unsigned int i; + unsigned char in4[4]; + + /* Read 4 base64-encoded characters */ + i = 0; + do + { + char c; + + c = in[at++]; + if (isalpha(c) || isdigit(c)) + { + printf("in4 = %c\n", c); + in4[i++] = c; + } + } while (i < 4); + decodeblock(in4, (unsigned char *)(out + out_at)); + out_at += 3; + printf("\n"); + } while(at < strlen(in)); + + return out; +} + +int main() +{ + char *s; + int i; + + /* TODO: fix this! */ + printf("|%s|\n", b64_decode("aXQgd29ya3M=")); +} + diff --git a/libotp.c b/libotp.c index f7400fe..1449a64 100644 --- a/libotp.c +++ b/libotp.c @@ -156,13 +156,27 @@ void free_pads() } } -/** Unpackage a message packaged for transport. */ -void unpackage(char *input) +void free_message(MESSAGE *msg) { - MESSAGE msg; + free(msg->cipher_text); + free(msg); +} + +/** Unpackage a message packaged for transport. + * + * Caller must free_message(). */ +MESSAGE *unpackage(char *input) +{ + MESSAGE *msg; unsigned int at; char *s, *end; + msg = malloc(sizeof(MESSAGE)); + if (!msg) { + perror("malloc"); + exit(EX_UNAVAILABLE); + } + /** Format offset = strtoul(s, &s, 10); - printf("offset=%ld\n", msg.offset); + printf("offset=%ld\n", msg->offset); /* Move after mandatory comma. */ if (s[0] != ',') { @@ -205,7 +219,7 @@ void unpackage(char *input) } ++s; - memset(msg.pad_name, 0, PAD_NAME_LENGTH); + memset(msg->pad_name, 0, PAD_NAME_LENGTH); /* Includes pad name? */ if (s[0] != '\n' && s[0] != '\r') { @@ -214,7 +228,7 @@ void unpackage(char *input) i = 0; /* v0.7+ message, includes pad name */ while(s[0] != '\n' && s[0] != '\r' && s[0] != ',' && s < end) { - msg.pad_name[i] = s[0]; + msg->pad_name[i] = s[0]; ++s; ++i; if (i > PAD_NAME_LENGTH) { @@ -225,20 +239,20 @@ void unpackage(char *input) } } - printf("Pad name: |%s|\n", msg.pad_name); + printf("Pad name: |%s|\n", msg->pad_name); /* Go to next line */ - while(s[0] == '\n' || s[0] == '\r' || s[0] == ',' && (s < end)) + while((s[0] == '\n' || s[0] == '\r' || s[0] == ',') && (s < end)) ++s; printf("s=%s\n", s); /* Extract base64 data from end of message. */ - msg.cipher_text = strdup(s); - msg.cipher_text[end - s] = 0; + msg->cipher_text = strdup(s); + msg->cipher_text[end - s] = 0; - printf("b64_data=<%s>\n", msg.cipher_text); - - /* TODO: free(msg.cipher_text); */ + printf("b64_data=<%s>\n", msg->cipher_text); + + return msg; } diff --git a/libotp.h b/libotp.h index 49c2e76..f176642 100644 --- a/libotp.h +++ b/libotp.h @@ -34,4 +34,4 @@ unsigned long read_offset(PAD *p); void write_offset(PAD *p, unsigned long offset); void load_pad(char *local_filename); void free_pads(); -void unpackage(); +MESSAGE *unpackage(); diff --git a/try.c b/try.c index 6f322d8..3c89d34 100644 --- a/try.c +++ b/try.c @@ -11,6 +11,8 @@ extern PAD *pads; int main() { + MESSAGE *m; + load_pad("/Volumes/Not Backed Up/otp/otp-dazzlement"); load_pad("/Volumes/Not Backed Up/otp/otp-dazzlement"); load_pad("/Volumes/Not Backed Up/otp/otp-dazzlement"); @@ -19,10 +21,12 @@ int main() write_offset(pads, 1213475); printf("offset=%ld\n", read_offset(pads)); - unpackage("--EMOTP_BEGIN--1213434,\n" + m = unpackage("--EMOTP_BEGIN--1213434,\n" "gK1O22FPbxLmxrROfFHDCsM1LTsOAjjbRlHVM1p+WG+s6yslYVfzvtc=\n" "--EMOTP_END--\n"); + free_message(m); + unpackage("--EMOTP_BEGIN--978,dc,\n" "hUZm1q0gX7pa6Alzbo9OZiT8wA==\n" "--EMOTP_END--\n"); -- 2.11.4.GIT