5 * Copyright (c) 2005 Marko Kreen
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * BASE64 - duplicated :(
42 static const unsigned char _base64
[] =
43 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
46 b64_encode(const uint8
*src
, unsigned len
, uint8
*dst
)
53 unsigned long buf
= 0;
60 buf
|= *s
<< (pos
<< 3);
69 *p
++ = _base64
[(buf
>> 18) & 0x3f];
70 *p
++ = _base64
[(buf
>> 12) & 0x3f];
71 *p
++ = _base64
[(buf
>> 6) & 0x3f];
72 *p
++ = _base64
[buf
& 0x3f];
85 *p
++ = _base64
[(buf
>> 18) & 0x3f];
86 *p
++ = _base64
[(buf
>> 12) & 0x3f];
87 *p
++ = (pos
== 0) ? _base64
[(buf
>> 6) & 0x3f] : '=';
94 /* probably should use lookup table */
96 b64_decode(const uint8
*src
, unsigned len
, uint8
*dst
)
98 const uint8
*srcend
= src
+ len
,
103 unsigned long buf
= 0;
110 if (c
>= 'A' && c
<= 'Z')
112 else if (c
>= 'a' && c
<= 'z')
114 else if (c
>= '0' && c
<= '9')
132 return PXE_PGP_CORRUPT_ARMOR
;
136 else if (c
== ' ' || c
== '\t' || c
== '\n' || c
== '\r')
139 return PXE_PGP_CORRUPT_ARMOR
;
144 buf
= (buf
<< 6) + b
;
148 *p
++ = (buf
>> 16) & 255;
149 if (end
== 0 || end
> 1)
150 *p
++ = (buf
>> 8) & 255;
151 if (end
== 0 || end
> 2)
159 return PXE_PGP_CORRUPT_ARMOR
;
164 b64_enc_len(unsigned srclen
)
167 * 3 bytes will be converted to 4, linefeed after 76 chars
169 return (srclen
+ 2) * 4 / 3 + srclen
/ (76 * 3 / 4);
173 b64_dec_len(unsigned srclen
)
175 return (srclen
* 3) >> 2;
182 static const char *armor_header
= "-----BEGIN PGP MESSAGE-----\n\n";
183 static const char *armor_footer
= "\n-----END PGP MESSAGE-----\n";
185 /* CRC24 implementation from rfc2440 */
186 #define CRC24_INIT 0x00b704ceL
187 #define CRC24_POLY 0x01864cfbL
189 crc24(const uint8
*data
, unsigned len
)
191 unsigned crc
= CRC24_INIT
;
196 crc
^= (*data
++) << 16;
197 for (i
= 0; i
< 8; i
++)
204 return crc
& 0xffffffL
;
208 pgp_armor_encode(const uint8
*src
, unsigned len
, uint8
*dst
)
212 unsigned crc
= crc24(src
, len
);
214 n
= strlen(armor_header
);
215 memcpy(pos
, armor_header
, n
);
218 n
= b64_encode(src
, len
, pos
);
221 if (*(pos
- 1) != '\n')
225 pos
[3] = _base64
[crc
& 0x3f];
227 pos
[2] = _base64
[crc
& 0x3f];
229 pos
[1] = _base64
[crc
& 0x3f];
231 pos
[0] = _base64
[crc
& 0x3f];
234 n
= strlen(armor_footer
);
235 memcpy(pos
, armor_footer
, n
);
242 find_str(const uint8
*data
, const uint8
*data_end
, const char *str
, int strlen
)
244 const uint8
*p
= data
;
248 if (data_end
- data
< strlen
)
252 p
= memchr(p
, str
[0], data_end
- p
);
255 if (p
+ strlen
> data_end
)
257 if (memcmp(p
, str
, strlen
) == 0)
265 find_header(const uint8
*data
, const uint8
*datend
,
266 const uint8
**start_p
, int is_end
)
268 const uint8
*p
= data
;
269 static const char *start_sep
= "-----BEGIN";
270 static const char *end_sep
= "-----END";
271 const char *sep
= is_end
? end_sep
: start_sep
;
273 /* find header line */
276 p
= find_str(p
, datend
, sep
, strlen(sep
));
278 return PXE_PGP_CORRUPT_ARMOR
;
279 /* it must start at beginning of line */
280 if (p
== data
|| *(p
- 1) == '\n')
287 /* check if header text ok */
288 for (; p
< datend
&& *p
!= '-'; p
++)
290 /* various junk can be there, but definitely not line-feed */
293 return PXE_PGP_CORRUPT_ARMOR
;
295 if (datend
- p
< 5 || memcmp(p
, sep
, 5) != 0)
296 return PXE_PGP_CORRUPT_ARMOR
;
299 /* check if at end of line */
302 if (*p
!= '\n' && *p
!= '\r')
303 return PXE_PGP_CORRUPT_ARMOR
;
306 if (p
< datend
&& *p
== '\n')
313 pgp_armor_decode(const uint8
*src
, unsigned len
, uint8
*dst
)
315 const uint8
*p
= src
;
316 const uint8
*data_end
= src
+ len
;
318 const uint8
*base64_start
,
320 const uint8
*base64_end
= NULL
;
323 int res
= PXE_PGP_CORRUPT_ARMOR
;
326 hlen
= find_header(src
, data_end
, &p
, 0);
332 hlen
= find_header(p
, data_end
, &armor_end
, 1);
336 /* skip comments - find empty line */
337 while (p
< armor_end
&& *p
!= '\n' && *p
!= '\r')
339 p
= memchr(p
, '\n', armor_end
- p
);
343 /* step to start of next line */
349 for (p
= armor_end
; p
>= base64_start
; p
--)
355 if (base64_end
== NULL
)
359 if (b64_decode(p
+ 1, 4, buf
) != 3)
361 crc
= (((long) buf
[0]) << 16) + (((long) buf
[1]) << 8) + (long) buf
[2];
364 res
= b64_decode(base64_start
, base64_end
- base64_start
, dst
);
367 if (res
>= 0 && crc24(dst
, res
) != crc
)
368 res
= PXE_PGP_CORRUPT_ARMOR
;
374 pgp_armor_enc_len(unsigned len
)
376 return b64_enc_len(len
) + strlen(armor_header
) + strlen(armor_footer
) + 16;
380 pgp_armor_dec_len(unsigned len
)
382 return b64_dec_len(len
);