5 * Catcrypt data encoding
7 * (c) 2004 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Header files ------------------------------------------------------*/
34 #include <mLib/alloc.h>
35 #include <mLib/base64.h>
36 #include <mLib/dstr.h>
37 #include <mLib/report.h>
42 /*----- Main code ---------------------------------------------------------*/
46 static enc *bin_init(FILE *fp, const char *msg)
47 { enc *e = CREATE(enc); return (e); }
49 static int bin_read(enc *e, void *p, size_t sz)
54 n = fread(p, 1, sz, e->fp);
55 if (!n || ferror(e->fp)) return (-1);
59 static int bin_write(enc *e, const void *p, size_t sz)
60 { if (sz && fwrite(p, 1, sz, e->fp) < sz) return (-1); return (0); }
62 static int bin_done(enc *e) { return (0); }
64 static void bin_destroy(enc *e) { DESTROY(e); }
68 typedef struct pem_encctx {
79 static enc *pem_encinit(FILE *fp, const char *msg)
81 pem_encctx *pe = CREATE(pem_encctx);
83 fprintf(fp, "-----BEGIN %s-----\n", msg);
84 pe->msg = xstrdup(msg);
91 static enc *pem_decinit(FILE *fp, const char *msg)
98 /* --- Go until I find a newline and `-----' --- */
103 if ((ch = getc(fp)) == EOF) goto fail;
105 case '\n': d = 0; break;
106 case '-': if (d >= 0) { d++; if (d == 5) goto banner; }; break;
107 default: d = -1; break;
111 /* --- See what the banner looks like --- */
116 if ((ch = getc(fp)) == EOF) goto fail;
117 if (ch == '-') { d++; continue; }
118 if (ch == '\n') break;
119 if (i + d + 1 >= sizeof(buf)) goto top;
120 while (d) { buf[i++] = '-'; d--; }
125 /* --- Check we have the right framing --- */
127 if (d != 5) goto top;
128 if (strncmp(buf, "BEGIN ", 6) != 0 ||
129 (msg && strcmp(buf + 6, msg) != 0))
134 pe = CREATE(pem_encctx);
136 pe->msg = xstrdup(buf + 6);
145 die(EXIT_FAILURE, "initial encapsulation boundary not found");
149 #define PEM_CHUNKSZ 4096
151 static int pem_read(enc *e, void *p, size_t sz)
153 pem_encctx *pe = (pem_encctx *)e;
154 char buf[PEM_CHUNKSZ];
161 n = pe->d.len - pe->n;
163 memcpy(pp, pe->d.buf + pe->n, n);
169 if (pe->f & PEMF_EOF) return (rc ? rc : -1);
173 if ((ch = getc(pe->e.fp)) == EOF) return (-1);
174 if ((pe->f & PEMF_NL) && ch == '-') {
175 ungetc(ch, pe->e.fp);
179 if (ch == '\n') { pe->f |= PEMF_NL; continue; }
182 if (n >= PEM_CHUNKSZ) break;
185 base64_decode(&pe->b, buf, n, &pe->d);
186 if (pe->f & PEMF_EOF)
187 base64_decode(&pe->b, 0, 0, &pe->d);
193 static int pem_write(enc *e, const void *p, size_t sz)
195 pem_encctx *pe = (pem_encctx *)e;
203 base64_encode(&pe->b, pp, n, &pe->d);
204 if (fwrite(pe->d.buf, 1, pe->d.len, pe->e.fp) < pe->d.len)
212 static int pem_encdone(enc *e)
214 pem_encctx *pe = (pem_encctx *)e;
216 base64_encode(&pe->b, 0, 0, &pe->d);
217 if (fwrite(pe->d.buf, 1, pe->d.len, pe->e.fp) < pe->d.len)
219 if (pe->b.lnlen) fputc('\n', pe->e.fp);
220 fprintf(pe->e.fp, "-----END %s-----\n", pe->msg);
224 static int pem_decdone(enc *e)
226 pem_encctx *pe = (pem_encctx *)e;
231 for (d = 0; d < 5; d++)
232 if ((ch = getc(pe->e.fp)) != '-') goto fail;
235 if ((ch = getc(pe->e.fp)) == EOF) goto fail;
236 if (ch == '-') { d++; continue; }
237 if (ch == '\n') break;
238 if (i + d + 1 >= sizeof(buf)) goto fail;
239 while (d) { buf[i++] = '-'; d--; }
242 if (d != 5) goto fail;
244 if (strncmp(buf, "END ", 4) != 0 || strcmp(buf + 4, pe->msg) != 0)
249 die(EXIT_FAILURE, "final encapsulation boundary not found");
253 static void pem_destroy(enc *e)
255 pem_encctx *pe = (pem_encctx *)e;
256 dstr_destroy(&pe->d);
261 /* --- Encoder table --- */
263 const encops enctab[] = {
264 { "binary", "rb", "wb",
270 pem_encinit, pem_decinit,
272 pem_encdone, pem_decdone,
277 /* --- @getenc@ --- *
279 * Arguments: @const char *enc@ = name of wanted encoding
281 * Returns: Pointer to encoder operations.
283 * Use: Finds a named encoder or decoder.
286 const encops *getenc(const char *enc)
290 for (eo = enctab; eo->name; eo++) {
291 if (strcmp(eo->name, enc) == 0)
294 die(EXIT_FAILURE, "couldn't find encoding `%s'", enc);
299 /* --- @initenc@ --- *
301 * Arguments: @const encops *eo@ = operations (from @getenc@)
302 * @FILE *fp@ = file handle to attach
303 * @const char *msg@ = banner message
304 * @int wantenc@ = nonzero if we want to encode
306 * Returns: The encoder object.
308 * Use: Initializes an encoder.
311 enc *initenc(const encops *eo, FILE *fp, const char *msg, int wantenc)
313 enc *e = (wantenc ? eo->initenc : eo->initdec)(fp, msg);
319 /* --- @freeenc@ --- *
321 * Arguments: @enc *e@ = encoder object
325 * Use: Frees an encoder object.
328 void freeenc(enc *e) { e->ops->destroy(e); }
330 /*----- That's all, folks -------------------------------------------------*/