include base64 encoder
authorEugene Crosser <crosser@average.org>
Sun, 8 Dec 2013 17:59:01 +0000 (21:59 +0400)
committerEugene Crosser <crosser@average.org>
Sun, 8 Dec 2013 17:59:01 +0000 (21:59 +0400)
Makefile.am
base64.c [new file with mode: 0644]
base64.h [new file with mode: 0644]
test_base64.c [new file with mode: 0644]

index e14ead904685e3a46addc71335f77a463d18b422..934ed22a14ce564f2ef77e373e39b861ffcd6704 100644 (file)
@@ -7,11 +7,11 @@ libdir = $(PAMDIR)
 DEFS = -DDEBUG_PAM -DPAM_DEBUG @DEFS@
 
 noinst_HEADERS = pcsc_cr.h token.h crypto_if.h crypto.h serial.h authobj.h \
-               authfile.h
+               authfile.h base64.h
 
 noinst_LTLIBRARIES = libpcsc_cr.la
 libpcsc_cr_la_SOURCES = authfile.c authobj.c serial.c crypto.c pcsc_cr.c \
-                       ykneo.c
+                       ykneo.c base64.c
 EXTRA_libpcsc_cr_la_SOURCES = ossl_crypto.c tom_crypto.c gnu_crypto.c
 libpcsc_cr_la_LIBADD = @CRYPTO_OBJS@
 libpcsc_cr_la_DEPENDENCIES = @CRYPTO_OBJS@
@@ -24,15 +24,16 @@ pam_pcsc_cr_la_LIBADD = libpcsc_cr.la
 bin_PROGRAMS = pam_cr_setup
 pam_cr_setup_LDADD = libpcsc_cr.la
 
-check_PROGRAMS = test_auth test_serial test_crypto test_chalresp
+check_PROGRAMS = test_auth test_serial test_crypto test_chalresp test_base64
 test_auth_LDADD = libpcsc_cr.la
 test_serial_LDADD = libpcsc_cr.la
 test_crypto_LDADD = libpcsc_cr.la
 test_chalresp_LDADD = libpcsc_cr.la
+test_base64_LDADD = libpcsc_cr.la
 
 EXTRA_DIST = autogen.sh README.md README_CR
 
-TESTS = test_auth test_serial test_crypto test_chalresp
+TESTS = test_auth test_serial test_crypto test_chalresp test_base64
 XFAIL_TESTS = test_chalresp
 
 html: README.html
diff --git a/base64.c b/base64.c
new file mode 100644 (file)
index 0000000..d90a927
--- /dev/null
+++ b/base64.c
@@ -0,0 +1,262 @@
+/*
+cencoder.c - c source to a base64 encoding algorithm implementation
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+/*
+  Modified by Eugene Crosser to fit pam_pcsc_cr project, 2013
+*/
+
+#include <string.h>
+#include <base64.h>
+/*
+cencode.h - c header for a base64 encoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+/*
+  Modified by Eugene Crosser to fit pam_pcsc_cr project, 2013
+*/
+
+typedef enum
+{
+       step_A, step_B, step_C
+} base64_encodestep;
+
+typedef struct
+{
+       base64_encodestep step;
+       char result;
+       int stepcount;
+} base64_encodestate;
+
+/*
+cdecode.h - c header for a base64 decoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+typedef enum
+{
+       step_a, step_b, step_c, step_d
+} base64_decodestep;
+
+typedef struct
+{
+       base64_decodestep step;
+       char plainchar;
+} base64_decodestate;
+
+static void base64_init_encodestate(base64_encodestate* state_in)
+{
+       state_in->step = step_A;
+       state_in->result = 0;
+       state_in->stepcount = 0;
+}
+
+static char base64_encode_value(char value_in)
+{
+       static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+       if (value_in > 63) return '=';
+       return encoding[(int)value_in];
+}
+
+static int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
+{
+       const char* plainchar = plaintext_in;
+       const char* const plaintextend = plaintext_in + length_in;
+       char* codechar = code_out;
+       char result;
+       char fragment;
+       
+       result = state_in->result;
+       
+       switch (state_in->step)
+       {
+               while (1)
+               {
+       case step_A:
+                       if (plainchar == plaintextend)
+                       {
+                               state_in->result = result;
+                               state_in->step = step_A;
+                               return codechar - code_out;
+                       }
+                       fragment = *plainchar++;
+                       result = (fragment & 0x0fc) >> 2;
+                       *codechar++ = base64_encode_value(result);
+                       result = (fragment & 0x003) << 4;
+       case step_B:
+                       if (plainchar == plaintextend)
+                       {
+                               state_in->result = result;
+                               state_in->step = step_B;
+                               return codechar - code_out;
+                       }
+                       fragment = *plainchar++;
+                       result |= (fragment & 0x0f0) >> 4;
+                       *codechar++ = base64_encode_value(result);
+                       result = (fragment & 0x00f) << 2;
+       case step_C:
+                       if (plainchar == plaintextend)
+                       {
+                               state_in->result = result;
+                               state_in->step = step_C;
+                               return codechar - code_out;
+                       }
+                       fragment = *plainchar++;
+                       result |= (fragment & 0x0c0) >> 6;
+                       *codechar++ = base64_encode_value(result);
+                       result  = (fragment & 0x03f) >> 0;
+                       *codechar++ = base64_encode_value(result);
+                       
+                       ++(state_in->stepcount);
+               }
+       }
+       /* control should not reach here */
+       return codechar - code_out;
+}
+
+static int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
+{
+       char* codechar = code_out;
+       
+       switch (state_in->step)
+       {
+       case step_B:
+               *codechar++ = base64_encode_value(state_in->result);
+               *codechar++ = '=';
+               *codechar++ = '=';
+               break;
+       case step_C:
+               *codechar++ = base64_encode_value(state_in->result);
+               *codechar++ = '=';
+               break;
+       case step_A:
+               break;
+       }
+       *codechar++ = '\n';
+       
+       return codechar - code_out;
+}
+
+/*
+cdecoder.c - c source to a base64 decoding algorithm implementation
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+static int base64_decode_value(char value_in)
+{
+       static const char 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};
+       static const char decoding_size = sizeof(decoding);
+       value_in -= 43;
+       if (value_in < 0 || value_in >= decoding_size) return -1;
+       return decoding[(int)value_in];
+}
+
+static void base64_init_decodestate(base64_decodestate* state_in)
+{
+       state_in->step = step_a;
+       state_in->plainchar = 0;
+}
+
+static int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
+{
+       const char* codechar = code_in;
+       char* plainchar = plaintext_out;
+       char fragment;
+       
+       *plainchar = state_in->plainchar;
+       
+       switch (state_in->step)
+       {
+               while (1)
+               {
+       case step_a:
+                       do {
+                               if (codechar == code_in+length_in)
+                               {
+                                       state_in->step = step_a;
+                                       state_in->plainchar = *plainchar;
+                                       return plainchar - plaintext_out;
+                               }
+                               fragment = (char)base64_decode_value(*codechar++);
+                       } while (fragment < 0);
+                       *plainchar    = (fragment & 0x03f) << 2;
+       case step_b:
+                       do {
+                               if (codechar == code_in+length_in)
+                               {
+                                       state_in->step = step_b;
+                                       state_in->plainchar = *plainchar;
+                                       return plainchar - plaintext_out;
+                               }
+                               fragment = (char)base64_decode_value(*codechar++);
+                       } while (fragment < 0);
+                       *plainchar++ |= (fragment & 0x030) >> 4;
+                       *plainchar    = (fragment & 0x00f) << 4;
+       case step_c:
+                       do {
+                               if (codechar == code_in+length_in)
+                               {
+                                       state_in->step = step_c;
+                                       state_in->plainchar = *plainchar;
+                                       return plainchar - plaintext_out;
+                               }
+                               fragment = (char)base64_decode_value(*codechar++);
+                       } while (fragment < 0);
+                       *plainchar++ |= (fragment & 0x03c) >> 2;
+                       *plainchar    = (fragment & 0x003) << 6;
+       case step_d:
+                       do {
+                               if (codechar == code_in+length_in)
+                               {
+                                       state_in->step = step_d;
+                                       state_in->plainchar = *plainchar;
+                                       return plainchar - plaintext_out;
+                               }
+                               fragment = (char)base64_decode_value(*codechar++);
+                       } while (fragment < 0);
+                       *plainchar++   |= (fragment & 0x03f);
+               }
+       }
+       /* control should not reach here */
+       return plainchar - plaintext_out;
+}
+
+int b64_encode(const char *src, const int ssize,
+               char *const b64, int *const bsize)
+{
+       base64_encodestate s;
+       int cnt1, cnt2;
+       char *c = b64;
+
+       /* FIXME check size */
+       base64_init_encodestate(&s);
+       cnt1 = base64_encode_block(src, ssize, c, &s);
+       c += cnt1;
+       cnt2 = base64_encode_blockend(c, &s);
+       c += cnt2;
+       *c = 0;
+       *bsize = cnt1 + cnt2;
+       return 0;
+}
+
+int b64_decode(const char *b64, char *const dst, int *const dsize)
+{
+       base64_decodestate s;
+       int cnt;
+
+       /* FIXME check size */
+       base64_init_decodestate(&s);
+       cnt = base64_decode_block(b64, strlen(b64), dst, &s);
+       *dsize = cnt;
+       return 0;
+}
diff --git a/base64.h b/base64.h
new file mode 100644 (file)
index 0000000..f1fe1f1
--- /dev/null
+++ b/base64.h
@@ -0,0 +1,17 @@
+/*
+This is an addition to the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+/*
+  Modified by Eugene Crosser to fit pam_pcsc_cr project, 2013
+*/
+
+#ifndef BASE64_H
+#define BASE64_H
+
+int b64_encode(const char *src, const int ssize,
+               char *const b64, int *const bsize);
+int b64_decode(const char *b64, char *const dst, int *const dsize);
+
+#endif /* BASE64_H */
diff --git a/test_base64.c b/test_base64.c
new file mode 100644 (file)
index 0000000..83fbf57
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2013 Eugene Crosser
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must
+    not claim that you wrote the original software. If you use this
+    software in a product, an acknowledgment in the product documentation
+    would be appreciated but is not required.
+
+    2. Altered source versions must be plainly marked as such, and must
+    not be misrepresented as being the original software.
+
+    3. This notice may not be removed or altered from any source
+    distribution.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "base64.h"
+
+static char src[40] = "Quick brown fox jumps over the lazy dog";
+
+int main(int argc, char *argv[])
+{
+       char b64[80];
+       char dst[40];
+       int bsize, dsize;
+
+       printf("src=\"%s\" (%d)\n", src, (int)sizeof(src));
+       bsize = sizeof(b64);
+       if (b64_encode(src, sizeof(src), b64, &bsize)) {
+               fprintf(stderr, "encode error\n");
+               return 1;
+       }
+       printf("b64=\"%s\" (%d)\n", b64, bsize);
+       dsize = sizeof(dst);
+       if (b64_decode(b64, dst, &dsize)) {
+               fprintf(stderr, "decode error\n");
+               return 1;
+       }
+       printf("dst=\"%s\" (%d)\n", dst, dsize);
+       return !(dsize == sizeof(src) && !memcmp(src, dst, dsize));
+}