2 * armor.c - Routines to (de)armor OpenPGP packet streams.
4 * Jonathan McDowell <noodles@earth.li>
6 * Copyright 2002 Project Purple
13 #include "keystructs.h"
16 #define ARMOR_WIDTH 64
18 #define CRC24_INIT 0xb704ceL
19 #define CRC24_POLY 0x1864cfbL
24 static unsigned char encode64(unsigned char c) {
27 } else if (c >= 26 && c <= 51) {
29 } else if (c >= 52 && c <= 61) {
45 static unsigned char decode64(unsigned char c) {
46 if (c >= 'A' && c <= 'Z') {
48 } else if (c >= 'a' && c <= 'z') {
50 } else if (c >= '0' && c <= '9') {
52 } else if (c == '+') {
54 } else if (c == '/') {
56 } else if (c == '=' || c == '-') {
66 void putstring(int (*putchar_func)(void *ctx, unsigned char c),
72 assert(putchar_func != NULL);
73 assert(string != NULL);
75 for (i = 0; string[i] != 0; i++) {
76 putchar_func(ctx, string[i]);
81 * @lastoctet: The last octet we got.
82 * @curoctet: The current octet we're expecting (0, 1 or 2).
83 * @count: The number of octets we've seen.
84 * @crc24: A running CRC24 of the data we've seen.
85 * @putchar_func: The function to output a character.
86 * @ctx: Context for putchar_func.
88 struct armor_context {
89 unsigned char lastoctet;
93 int (*putchar_func)(void *ctx, unsigned char c);
97 static void armor_init(struct armor_context *ctx)
102 ctx->crc24 = CRC24_INIT;
105 static void armor_finish(struct armor_context *state)
107 switch (state->curoctet++) {
111 state->putchar_func(state->ctx,
112 encode64((state->lastoctet & 3) << 4));
113 state->putchar_func(state->ctx, '=');
114 state->putchar_func(state->ctx, '=');
117 state->putchar_func(state->ctx,
118 encode64((state->lastoctet & 0xF) << 2));
119 state->putchar_func(state->ctx, '=');
123 state->crc24 &= 0xffffffL;
124 state->putchar_func(state->ctx, '\n');
125 state->putchar_func(state->ctx, '=');
126 state->putchar_func(state->ctx, encode64(state->crc24 >> 18));
127 state->putchar_func(state->ctx, encode64((state->crc24 >> 12) & 0x3F));
128 state->putchar_func(state->ctx, encode64((state->crc24 >> 6) & 0x3F));
129 state->putchar_func(state->ctx, encode64(state->crc24 & 0x3F));
130 state->putchar_func(state->ctx, '\n');
134 static int armor_putchar(void *ctx, unsigned char c)
136 struct armor_context *state;
140 state = (struct armor_context *) ctx;
142 switch (state->curoctet++) {
144 state->putchar_func(state->ctx, encode64(c >> 2));
148 state->putchar_func(state->ctx,
149 encode64(((state->lastoctet & 3) << 4) + (c >> 4)));
153 state->putchar_func(state->ctx,
154 encode64(((state->lastoctet & 0xF) << 2) + (c >> 6)));
155 state->putchar_func(state->ctx, encode64(c & 0x3F));
159 state->curoctet %= 3;
160 state->lastoctet = c;
162 state->crc24 ^= c << 16;
163 for (i = 0; i < 8; i++) {
165 if (state->crc24 & 0x1000000) {
166 state->crc24 ^= CRC24_POLY;
170 if ((state->count % ARMOR_WIDTH) == 0) {
171 state->putchar_func(state->ctx, '\n');
178 * @lastoctet: The last octet we got.
179 * @curoctet: The current octet we're expecting (0, 1 or 2).
180 * @count: The number of octets we've seen.
181 * @crc24: A running CRC24 of the data we've seen.
182 * @putchar_func: The function to output a character.
183 * @ctx: Context for putchar_func.
185 struct dearmor_context {
186 unsigned char lastoctet;
190 int (*getchar_func)(void *ctx, size_t count, unsigned char *c);
194 static void dearmor_init(struct dearmor_context *ctx)
199 ctx->crc24 = CRC24_INIT;
202 static void dearmor_finish(struct dearmor_context *state)
204 // Check the checksum,
206 state->crc24 &= 0xffffffL;
207 // state->putchar_func(state->ctx, '\n');
208 // state->putchar_func(state->ctx, '=');
209 // state->putchar_func(state->ctx, encode64(state->crc24 >> 18));
210 // state->putchar_func(state->ctx, encode64((state->crc24 >> 12) & 0x3F));
211 // state->putchar_func(state->ctx, encode64((state->crc24 >> 6) & 0x3F));
212 // state->putchar_func(state->ctx, encode64(state->crc24 & 0x3F));
217 static int dearmor_getchar(void *ctx, unsigned char *c)
219 struct dearmor_context *state;
224 state = (struct dearmor_context *) ctx;
229 state->getchar_func(state->ctx, 1, &tmpc);
230 tmpc = decode64(tmpc);
234 switch (state->curoctet++) {
236 state->lastoctet = tmpc;
239 state->getchar_func(state->ctx, 1, &tmpc);
240 tmpc = decode64(tmpc);
242 *c = (state->lastoctet << 2) + (tmpc >> 4);
245 *c = ((state->lastoctet & 0xF) << 4) + (tmpc >> 2);
248 *c = ((state->lastoctet & 3) << 6) + tmpc;
252 state->curoctet %= 3;
253 state->lastoctet = tmpc;
256 state->crc24 ^= *c << 16;
257 for (i = 0; i < 8; i++) {
259 if (state->crc24 & 0x1000000) {
260 state->crc24 ^= CRC24_POLY;
268 static int dearmor_getchar_c(void *ctx, size_t count, unsigned char *c)
272 for (i = 0; i < count && rc == 0; i++) {
273 rc = dearmor_getchar(ctx, &c[i]);
280 * armor_openpgp_stream - Takes a list of OpenPGP packets and armors it.
281 * @putchar_func: The function to output the next armor character.
282 * @ctx: The context pointer for putchar_func.
283 * @packets: The list of packets to output.
285 * This function ASCII armors a list of OpenPGP packets and outputs it
286 * using putchar_func.
288 int armor_openpgp_stream(int (*putchar_func)(void *ctx, unsigned char c),
290 struct openpgp_packet_list *packets)
292 struct armor_context armor_ctx;
298 putstring(putchar_func, ctx, "-----BEGIN PGP PUBLIC KEY BLOCK-----\n");
299 putstring(putchar_func, ctx, "Version: onak 0.0.1\n\n");
301 armor_init(&armor_ctx);
302 armor_ctx.putchar_func = putchar_func;
304 write_openpgp_stream(armor_putchar, &armor_ctx, packets);
305 armor_finish(&armor_ctx);
310 putstring(putchar_func, ctx, "-----END PGP PUBLIC KEY BLOCK-----\n");
316 * dearmor_openpgp_stream - Reads & decodes an ACSII armored OpenPGP msg.
317 * @getchar_func: The function to get the next character from the stream.
318 * @ctx: The context pointer for getchar_func.
319 * @packets: The list of packets.
321 * This function uses getchar_func to read characters from an ASCII
322 * armored OpenPGP stream and outputs the data as a linked list of
325 int dearmor_openpgp_stream(int (*getchar_func)(void *ctx, size_t count,
328 struct openpgp_packet_list **packets)
330 struct dearmor_context dearmor_ctx;
331 unsigned char curchar;
336 * Look for armor header. We want "-----BEGIN.*\n", then some headers
337 * with :s in them, then a blank line, then the data.
340 while (state != 4 && !getchar_func(ctx, 1, &curchar)) {
343 if (curchar == '\n') {
349 if (curchar == '-') {
354 } else if (curchar != '\n') {
359 if (curchar == 'B') {
367 if (curchar == '\n') {
372 } else if (curchar != '\r') {
380 dearmor_init(&dearmor_ctx);
381 dearmor_ctx.getchar_func = getchar_func;
382 dearmor_ctx.ctx = ctx;
383 read_openpgp_stream(dearmor_getchar_c, &dearmor_ctx, packets);
384 dearmor_finish(&dearmor_ctx);
385 // TODO: Look for armor footer