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 -------------------------------------------------*/