Postfix3.3.1
base64_code.c
[詳解]
1 /*++
2 /* NAME
3 /* base64_code 3
4 /* SUMMARY
5 /* encode/decode data, base 64 style
6 /* SYNOPSIS
7 /* #include <base64_code.h>
8 /*
9 /* VSTRING *base64_encode(result, in, len)
10 /* VSTRING *result;
11 /* const char *in;
12 /* ssize_t len;
13 /*
14 /* VSTRING *base64_decode(result, in, len)
15 /* VSTRING *result;
16 /* const char *in;
17 /* ssize_t len;
18 /*
19 /* VSTRING *base64_encode_opt(result, in, len, flags)
20 /* VSTRING *result;
21 /* const char *in;
22 /* ssize_t len;
23 /* int flags;
24 /*
25 /* VSTRING *base64_decode_opt(result, in, len, flags)
26 /* VSTRING *result;
27 /* const char *in;
28 /* ssize_t len;
29 /* int flags;
30 /* DESCRIPTION
31 /* base64_encode() takes a block of len bytes and encodes it as one
32 /* null-terminated string. The result value is the result argument.
33 /*
34 /* base64_decode() performs the opposite transformation. The result
35 /* value is the result argument. The result is null terminated, whether
36 /* or not that makes sense.
37 /*
38 /* base64_encode_opt() and base64_decode_opt() provide extended
39 /* interfaces. In both cases the flags arguments is the bit-wise
40 /* OR of zero or more the following:
41 /* .IP BASE64_FLAG_APPEND
42 /* Append the result, instead of overwriting the result buffer.
43 /* .PP
44 /* For convenience, BASE64_FLAG_NONE specifies none of the above.
45 /* DIAGNOSTICS
46 /* base64_decode () returns a null pointer when the input contains
47 /* characters not in the base 64 alphabet.
48 /* LICENSE
49 /* .ad
50 /* .fi
51 /* The Secure Mailer license must be distributed with this software.
52 /* AUTHOR(S)
53 /* Wietse Venema
54 /* IBM T.J. Watson Research
55 /* P.O. Box 704
56 /* Yorktown Heights, NY 10598, USA
57 /*--*/
58 
59 /* System library. */
60 
61 #include "sys_defs.h"
62 #include <ctype.h>
63 #include <string.h>
64 #include <limits.h>
65 
66 #ifndef UCHAR_MAX
67 #define UCHAR_MAX 0xff
68 #endif
69 
70 /* Utility library. */
71 
72 #include <msg.h>
73 #include <mymalloc.h>
74 #include <vstring.h>
75 #include <base64_code.h>
76 
77 /* Application-specific. */
78 
79 static unsigned char to_b64[] =
80 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
81 
82 #define UNSIG_CHAR_PTR(x) ((unsigned char *)(x))
83 
84 /* base64_encode - raw data to encoded */
85 
86 #undef base64_encode
87 
88 extern VSTRING *base64_encode(VSTRING *, const char *, ssize_t);
89 
90 VSTRING *base64_encode(VSTRING *result, const char *in, ssize_t len)
91 {
92  return (base64_encode_opt(result, in, len, BASE64_FLAG_NONE));
93 }
94 
95 VSTRING *base64_encode_opt(VSTRING *result, const char *in, ssize_t len,
96  int flags)
97 {
98  const unsigned char *cp;
99  ssize_t count;
100 
101  /*
102  * Encode 3 -> 4.
103  */
104  if ((flags & BASE64_FLAG_APPEND) == 0)
105  VSTRING_RESET(result);
106  for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 3, cp += 3) {
107  VSTRING_ADDCH(result, to_b64[cp[0] >> 2]);
108  if (count > 1) {
109  VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4 | cp[1] >> 4]);
110  if (count > 2) {
111  VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2 | cp[2] >> 6]);
112  VSTRING_ADDCH(result, to_b64[cp[2] & 0x3f]);
113  } else {
114  VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2]);
115  VSTRING_ADDCH(result, '=');
116  break;
117  }
118  } else {
119  VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4]);
120  VSTRING_ADDCH(result, '=');
121  VSTRING_ADDCH(result, '=');
122  break;
123  }
124  }
125  VSTRING_TERMINATE(result);
126  return (result);
127 }
128 
129 /* base64_decode - encoded data to raw */
130 
131 #undef base64_decode
132 
133 extern VSTRING *base64_decode(VSTRING *, const char *, ssize_t);
134 
135 VSTRING *base64_decode(VSTRING *result, const char *in, ssize_t len)
136 {
137  return (base64_decode_opt(result, in, len, BASE64_FLAG_NONE));
138 }
139 
140 VSTRING *base64_decode_opt(VSTRING *result, const char *in, ssize_t len,
141  int flags)
142 {
143  static unsigned char *un_b64 = 0;
144  const unsigned char *cp;
145  ssize_t count;
146  unsigned int ch0;
147  unsigned int ch1;
148  unsigned int ch2;
149  unsigned int ch3;
150 
151 #define CHARS_PER_BYTE (UCHAR_MAX + 1)
152 #define INVALID 0xff
153 
154  /*
155  * Sanity check.
156  */
157  if (len % 4)
158  return (0);
159 
160  /*
161  * Once: initialize the decoding lookup table on the fly.
162  */
163  if (un_b64 == 0) {
164  un_b64 = (unsigned char *) mymalloc(CHARS_PER_BYTE);
165  memset(un_b64, INVALID, CHARS_PER_BYTE);
166  for (cp = to_b64; cp < to_b64 + sizeof(to_b64) - 1; cp++)
167  un_b64[*cp] = cp - to_b64;
168  }
169 
170  /*
171  * Decode 4 -> 3.
172  */
173  if ((flags & BASE64_FLAG_APPEND) == 0)
174  VSTRING_RESET(result);
175  for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 4) {
176  if ((ch0 = un_b64[*cp++]) == INVALID
177  || (ch1 = un_b64[*cp++]) == INVALID)
178  return (0);
179  VSTRING_ADDCH(result, ch0 << 2 | ch1 >> 4);
180  if ((ch2 = *cp++) == '=')
181  break;
182  if ((ch2 = un_b64[ch2]) == INVALID)
183  return (0);
184  VSTRING_ADDCH(result, ch1 << 4 | ch2 >> 2);
185  if ((ch3 = *cp++) == '=')
186  break;
187  if ((ch3 = un_b64[ch3]) == INVALID)
188  return (0);
189  VSTRING_ADDCH(result, ch2 << 6 | ch3);
190  }
191  VSTRING_TERMINATE(result);
192  return (result);
193 }
194 
195 #ifdef TEST
196 
197  /*
198  * Proof-of-concept test program: convert to base 64 and back.
199  */
200 
201 #define STR(x) vstring_str(x)
202 #define LEN(x) VSTRING_LEN(x)
203 
204 int main(int unused_argc, char **unused_argv)
205 {
206  VSTRING *b1 = vstring_alloc(1);
207  VSTRING *b2 = vstring_alloc(1);
208  char test[256];
209  int n;
210 
211  for (n = 0; n < sizeof(test); n++)
212  test[n] = n;
213  base64_encode(b1, test, sizeof(test));
214  if (base64_decode(b2, STR(b1), LEN(b1)) == 0)
215  msg_panic("bad base64: %s", STR(b1));
216  if (LEN(b2) != sizeof(test))
217  msg_panic("bad decode length: %ld != %ld",
218  (long) LEN(b2), (long) sizeof(test));
219  for (n = 0; n < sizeof(test); n++)
220  if (STR(b2)[n] != test[n])
221  msg_panic("bad decode value %d != %d",
222  (unsigned char) STR(b2)[n], (unsigned char) test[n]);
223  vstring_free(b1);
224  vstring_free(b2);
225  return (0);
226 }
227 
228 #endif
#define BASE64_FLAG_APPEND
Definition: base64_code.h:26
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
int main(int argc, char **argv)
Definition: anvil.c:1010
VSTRING * base64_encode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
Definition: base64_code.c:95
#define LEN
Definition: cleanup_addr.c:106
#define BASE64_FLAG_NONE
Definition: base64_code.h:25
#define CHARS_PER_BYTE
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
#define VSTRING_RESET(vp)
Definition: vstring.h:77
#define STR(x)
Definition: anvil.c:518
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define UNSIG_CHAR_PTR(x)
Definition: base64_code.c:82
VSTRING * base64_decode(VSTRING *, const char *, ssize_t)
Definition: base64_code.c:135
#define INVALID
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
VSTRING * base64_encode(VSTRING *, const char *, ssize_t)
Definition: base64_code.c:90
VSTRING * base64_decode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
Definition: base64_code.c:140
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150