Postfix3.3.1
base32_code.c
[詳解]
1 /*++
2 /* NAME
3 /* base32_code 3
4 /* SUMMARY
5 /* encode/decode data, base 32 style
6 /* SYNOPSIS
7 /* #include <base32_code.h>
8 /*
9 /* VSTRING *base32_encode(result, in, len)
10 /* VSTRING *result;
11 /* const char *in;
12 /* ssize_t len;
13 /*
14 /* VSTRING *base32_decode(result, in, len)
15 /* VSTRING *result;
16 /* const char *in;
17 /* ssize_t len;
18 /* DESCRIPTION
19 /* base32_encode() takes a block of len bytes and encodes it as one
20 /* null-terminated string. The result value is the result argument.
21 /*
22 /* base32_decode() performs the opposite transformation. The result
23 /* value is the result argument. The result is null terminated, whether
24 /* or not that makes sense.
25 /* DIAGNOSTICS
26 /* base32_decode() returns a null pointer when the input contains
27 /* characters not in the base 32 alphabet.
28 /* SEE ALSO
29 /* RFC 4648; padding is strictly enforced
30 /* LICENSE
31 /* .ad
32 /* .fi
33 /* The Secure Mailer license must be distributed with this software.
34 /* AUTHOR(S)
35 /* Wietse Venema
36 /* IBM T.J. Watson Research
37 /* P.O. Box 704
38 /* Yorktown Heights, NY 10598, USA
39 /*--*/
40 
41 /* System library. */
42 
43 #include "sys_defs.h"
44 #include <ctype.h>
45 #include <string.h>
46 #include <limits.h>
47 
48 #ifndef UCHAR_MAX
49 #define UCHAR_MAX 0xff
50 #endif
51 
52 /* Utility library. */
53 
54 #include <msg.h>
55 #include <mymalloc.h>
56 #include <vstring.h>
57 #include <base32_code.h>
58 
59 /* Application-specific. */
60 
61 static unsigned char to_b32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
62 
63 #define UNSIG_CHAR_PTR(x) ((unsigned char *)(x))
64 
65 /* base32_encode - raw data to encoded */
66 
67 VSTRING *base32_encode(VSTRING *result, const char *in, ssize_t len)
68 {
69  const unsigned char *cp;
70  ssize_t count;
71  static int pad_count[] = {0, 6, 4, 3, 1};
72 
73  /*
74  * Encode 5 -> 8.
75  */
76  VSTRING_RESET(result);
77  for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 5, cp += 5) {
78  VSTRING_ADDCH(result, to_b32[cp[0] >> 3]);
79  if (count < 2) {
80  VSTRING_ADDCH(result, to_b32[(cp[0] & 0x7) << 2]);
81  break;
82  }
83  VSTRING_ADDCH(result, to_b32[(cp[0] & 0x7) << 2 | cp[1] >> 6]);
84  VSTRING_ADDCH(result, to_b32[(cp[1] & 0x3f) >> 1]);
85  if (count < 3) {
86  VSTRING_ADDCH(result, to_b32[(cp[1] & 0x1) << 4]);
87  break;
88  }
89  VSTRING_ADDCH(result, to_b32[(cp[1] & 0x1) << 4 | cp[2] >> 4]);
90  if (count < 4) {
91  VSTRING_ADDCH(result, to_b32[(cp[2] & 0xf) << 1]);
92  break;
93  }
94  VSTRING_ADDCH(result, to_b32[(cp[2] & 0xf) << 1 | cp[3] >> 7]);
95  VSTRING_ADDCH(result, to_b32[(cp[3] & 0x7f) >> 2]);
96  if (count < 5) {
97  VSTRING_ADDCH(result, to_b32[(cp[3] & 0x3) << 3]);
98  break;
99  }
100  VSTRING_ADDCH(result, to_b32[(cp[3] & 0x3) << 3 | cp[4] >> 5]);
101  VSTRING_ADDCH(result, to_b32[cp[4] & 0x1f]);
102  }
103  if (count > 0)
104  vstring_strncat(result, "======", pad_count[count]);
105  VSTRING_TERMINATE(result);
106  return (result);
107 }
108 
109 /* base32_decode - encoded data to raw */
110 
111 VSTRING *base32_decode(VSTRING *result, const char *in, ssize_t len)
112 {
113  static unsigned char *un_b32 = 0;
114  const unsigned char *cp;
115  ssize_t count;
116  unsigned int ch0;
117  unsigned int ch1;
118  unsigned int ch2;
119  unsigned int ch3;
120  unsigned int ch4;
121  unsigned int ch5;
122  unsigned int ch6;
123  unsigned int ch7;
124 
125 #define CHARS_PER_BYTE (UCHAR_MAX + 1)
126 #define INVALID 0xff
127 #if 1
128 #define ENFORCE_LENGTH(x) (x)
129 #define ENFORCE_PADDING(x) (x)
130 #define ENFORCE_NULL_BITS(x) (x)
131 #else
132 #define ENFORCE_LENGTH(x) (1)
133 #define ENFORCE_PADDING(x) (1)
134 #define ENFORCE_NULL_BITS(x) (1)
135 #endif
136 
137  /*
138  * Sanity check.
139  */
140  if (ENFORCE_LENGTH(len % 8))
141  return (0);
142 
143  /*
144  * Once: initialize the decoding lookup table on the fly.
145  */
146  if (un_b32 == 0) {
147  un_b32 = (unsigned char *) mymalloc(CHARS_PER_BYTE);
148  memset(un_b32, INVALID, CHARS_PER_BYTE);
149  for (cp = to_b32; cp < to_b32 + sizeof(to_b32) - 1; cp++)
150  un_b32[*cp] = cp - to_b32;
151  }
152 
153  /*
154  * Decode 8 -> 5.
155  */
156  VSTRING_RESET(result);
157  for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 8) {
158  if ((ch0 = un_b32[*cp++]) == INVALID
159  || (ch1 = un_b32[*cp++]) == INVALID)
160  return (0);
161  VSTRING_ADDCH(result, ch0 << 3 | ch1 >> 2);
162  if ((ch2 = *cp++) == '='
163  && ENFORCE_PADDING(strcmp((char *) cp, "=====") == 0)
164  && ENFORCE_NULL_BITS((ch1 & 0x3) == 0))
165  break;
166  if ((ch2 = un_b32[ch2]) == INVALID)
167  return (0);
168  if ((ch3 = un_b32[*cp++]) == INVALID)
169  return (0);
170  VSTRING_ADDCH(result, ch1 << 6 | ch2 << 1 | ch3 >> 4);
171  if ((ch4 = *cp++) == '='
172  && ENFORCE_PADDING(strcmp((char *) cp, "===") == 0)
173  && ENFORCE_NULL_BITS((ch3 & 0xf) == 0))
174  break;
175  if ((ch4 = un_b32[ch4]) == INVALID)
176  return (0);
177  VSTRING_ADDCH(result, ch3 << 4 | ch4 >> 1);
178  if ((ch5 = *cp++) == '='
179  && ENFORCE_PADDING(strcmp((char *) cp, "==") == 0)
180  && ENFORCE_NULL_BITS((ch4 & 0x1) == 0))
181  break;
182  if ((ch5 = un_b32[ch5]) == INVALID)
183  return (0);
184  if ((ch6 = un_b32[*cp++]) == INVALID)
185  return (0);
186  VSTRING_ADDCH(result, ch4 << 7 | ch5 << 2 | ch6 >> 3);
187  if ((ch7 = *cp++) == '='
188  && ENFORCE_NULL_BITS((ch6 & 0x7) == 0))
189  break;
190  if ((ch7 = un_b32[ch7]) == INVALID)
191  return (0);
192  VSTRING_ADDCH(result, ch6 << 5 | ch7);
193  }
194  VSTRING_TERMINATE(result);
195  return (result);
196 }
197 
198 #ifdef TEST
199 
200  /*
201  * Proof-of-concept test program: convert to base 32 and back.
202  */
203 
204 #define STR(x) vstring_str(x)
205 #define LEN(x) VSTRING_LEN(x)
206 
207 int main(int unused_argc, char **unused_argv)
208 {
209  VSTRING *b1 = vstring_alloc(1);
210  VSTRING *b2 = vstring_alloc(1);
211  VSTRING *test = vstring_alloc(1);
212  int i, j;
213 
214  /*
215  * Test all byte values (except null) on all byte positions.
216  */
217  for (j = 0; j < 256; j++)
218  for (i = 1; i < 256; i++)
219  VSTRING_ADDCH(test, i);
220  VSTRING_TERMINATE(test);
221 
222 #define DECODE(b,x,l) { \
223  if (base32_decode((b),(x),(l)) == 0) \
224  msg_panic("bad base32: %s", (x)); \
225  }
226 #define VERIFY(b,t,l) { \
227  if (memcmp((b), (t), (l)) != 0) \
228  msg_panic("bad test: %s", (b)); \
229  }
230 
231  /*
232  * Test all padding variants.
233  */
234  for (i = 1; i <= 8; i++) {
235  base32_encode(b1, STR(test), LEN(test));
236  DECODE(b2, STR(b1), LEN(b1));
237  VERIFY(STR(b2), STR(test), LEN(test));
238 
239  base32_encode(b1, STR(test), LEN(test));
240  base32_encode(b2, STR(b1), LEN(b1));
241  base32_encode(b1, STR(b2), LEN(b2));
242  DECODE(b2, STR(b1), LEN(b1));
243  DECODE(b1, STR(b2), LEN(b2));
244  DECODE(b2, STR(b1), LEN(b1));
245  VERIFY(STR(b2), STR(test), LEN(test));
246 
247  base32_encode(b1, STR(test), LEN(test));
248  base32_encode(b2, STR(b1), LEN(b1));
249  base32_encode(b1, STR(b2), LEN(b2));
250  base32_encode(b2, STR(b1), LEN(b1));
251  base32_encode(b1, STR(b2), LEN(b2));
252  DECODE(b2, STR(b1), LEN(b1));
253  DECODE(b1, STR(b2), LEN(b2));
254  DECODE(b2, STR(b1), LEN(b1));
255  DECODE(b1, STR(b2), LEN(b2));
256  DECODE(b2, STR(b1), LEN(b1));
257  VERIFY(STR(b2), STR(test), LEN(test));
258  vstring_truncate(test, LEN(test) - 1);
259  }
260  vstring_free(test);
261  vstring_free(b1);
262  vstring_free(b2);
263  return (0);
264 }
265 
266 #endif
int main(int argc, char **argv)
Definition: anvil.c:1010
VSTRING * vstring_strncat(VSTRING *vp, const char *src, ssize_t len)
Definition: vstring.c:471
VSTRING * vstring_truncate(VSTRING *vp, ssize_t len)
Definition: vstring.c:415
#define LEN
Definition: cleanup_addr.c:106
VSTRING * base32_decode(VSTRING *result, const char *in, ssize_t len)
Definition: base32_code.c:111
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
#define CHARS_PER_BYTE
#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: base32_code.c:63
#define ENFORCE_NULL_BITS(x)
#define ENFORCE_LENGTH(x)
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
VSTRING * base32_encode(VSTRING *result, const char *in, ssize_t len)
Definition: base32_code.c:67
#define INVALID
#define ENFORCE_PADDING(x)
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150