Quelle pgp-armor.c
Sprache: unbekannt
/*
* pgp - armor . c
* PGP ascii - armor .
*
* Copyright ( c ) 2005 Marko Kreen
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1 . Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2 . Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
* contrib / pgcrypto / pgp - armor . c
*/
#include "postgres.h"
#include "pgp.h"
#include "px.h"
/*
* BASE64 - duplicated : (
*/
static const unsigned char _base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
static int
pg_base64_encode(const uint8 *src, unsigned len, uint8 *dst)
{
uint8 *p,
*lend = dst + 76 ;
const uint8 *s,
*end = src + len;
int pos = 2 ;
unsigned long buf = 0 ;
s = src;
p = dst;
while (s < end)
{
buf |= *s << (pos << 3 );
pos--;
s++;
/*
* write it out
*/
if (pos < 0 )
{
*p++ = _base64[(buf >> 18 ) & 0 x3f];
*p++ = _base64[(buf >> 12 ) & 0 x3f];
*p++ = _base64[(buf >> 6 ) & 0 x3f];
*p++ = _base64[buf & 0 x3f];
pos = 2 ;
buf = 0 ;
}
if (p >= lend)
{
*p++ = '\n' ;
lend = p + 76 ;
}
}
if (pos != 2 )
{
*p++ = _base64[(buf >> 18 ) & 0 x3f];
*p++ = _base64[(buf >> 12 ) & 0 x3f];
*p++ = (pos == 0 ) ? _base64[(buf >> 6 ) & 0 x3f] : '=' ;
*p++ = '=' ;
}
return p - dst;
}
/* probably should use lookup table */
static int
pg_base64_decode(const uint8 *src, unsigned len, uint8 *dst)
{
const uint8 *srcend = src + len,
*s = src;
uint8 *p = dst;
char c;
unsigned b = 0 ;
unsigned long buf = 0 ;
int pos = 0 ,
end = 0 ;
while (s < srcend)
{
c = *s++;
if (c >= 'A' && c <= 'Z' )
b = c - 'A' ;
else if (c >= 'a' && c <= 'z' )
b = c - 'a' + 26 ;
else if (c >= '0' && c <= '9' )
b = c - '0' + 52 ;
else if (c == '+' )
b = 62 ;
else if (c == '/' )
b = 63 ;
else if (c == '=' )
{
/*
* end sequence
*/
if (!end)
{
if (pos == 2 )
end = 1 ;
else if (pos == 3 )
end = 2 ;
else
return PXE_PGP_CORRUPT_ARMOR;
}
b = 0 ;
}
else if (c == ' ' || c == '\t' || c == '\n' || c == '\r' )
continue ;
else
return PXE_PGP_CORRUPT_ARMOR;
/*
* add it to buffer
*/
buf = (buf << 6 ) + b;
pos++;
if (pos == 4 )
{
*p++ = (buf >> 16 ) & 255 ;
if (end == 0 || end > 1 )
*p++ = (buf >> 8 ) & 255 ;
if (end == 0 || end > 2 )
*p++ = buf & 255 ;
buf = 0 ;
pos = 0 ;
}
}
if (pos != 0 )
return PXE_PGP_CORRUPT_ARMOR;
return p - dst;
}
static unsigned
pg_base64_enc_len(unsigned srclen)
{
/*
* 3 bytes will be converted to 4 , linefeed after 76 chars
*/
return (srclen + 2 ) / 3 * 4 + srclen / (76 * 3 / 4 );
}
static unsigned
pg_base64_dec_len(unsigned srclen)
{
return (srclen * 3 ) >> 2 ;
}
/*
* PGP armor
*/
static const char *const armor_header = "-----BEGIN PGP MESSAGE-----\n" ;
static const char *const armor_footer = "\n-----END PGP MESSAGE-----\n" ;
/* CRC24 implementation from rfc2440 */
#define CRC24_INIT 0 x00b704ceL
#define CRC24_POLY 0 x01864cfbL
static long
crc24(const uint8 *data, unsigned len)
{
unsigned crc = CRC24_INIT;
int i;
while (len--)
{
crc ^= (*data++) << 16 ;
for (i = 0 ; i < 8 ; i++)
{
crc <<= 1 ;
if (crc & 0 x1000000)
crc ^= CRC24_POLY;
}
}
return crc & 0 xffffffL;
}
void
pgp_armor_encode(const uint8 *src, unsigned len, StringInfo dst,
int num_headers, char **keys, char **values)
{
int n;
int res;
unsigned b64len;
unsigned crc = crc24(src, len);
appendStringInfoString(dst, armor_header);
for (n = 0 ; n < num_headers; n++)
appendStringInfo(dst, "%s: %s\n" , keys[n], values[n]);
appendStringInfoChar(dst, '\n' );
/* make sure we have enough room to pg_base64_encode() */
b64len = pg_base64_enc_len(len);
enlargeStringInfo(dst, (int ) b64len);
res = pg_base64_encode(src, len, (uint8 *) dst->data + dst->len);
if (res > b64len)
elog(FATAL, "overflow - encode estimate too small" );
dst->len += res;
if (*(dst->data + dst->len - 1 ) != '\n' )
appendStringInfoChar(dst, '\n' );
appendStringInfoChar(dst, '=' );
appendStringInfoChar(dst, _base64[(crc >> 18 ) & 0 x3f]);
appendStringInfoChar(dst, _base64[(crc >> 12 ) & 0 x3f]);
appendStringInfoChar(dst, _base64[(crc >> 6 ) & 0 x3f]);
appendStringInfoChar(dst, _base64[crc & 0 x3f]);
appendStringInfoString(dst, armor_footer);
}
static const uint8 *
find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
{
const uint8 *p = data;
if (!strlen)
return NULL;
if (data_end - data < strlen)
return NULL;
while (p < data_end)
{
p = memchr(p, str[0 ], data_end - p);
if (p == NULL)
return NULL;
if (p + strlen > data_end)
return NULL;
if (memcmp(p, str, strlen) == 0 )
return p;
p++;
}
return NULL;
}
static int
find_header(const uint8 *data, const uint8 *datend,
const uint8 **start_p, int is_end)
{
const uint8 *p = data;
static const char *start_sep = "-----BEGIN" ;
static const char *end_sep = "-----END" ;
const char *sep = is_end ? end_sep : start_sep;
/* find header line */
while (1 )
{
p = find_str(p, datend, sep, strlen(sep));
if (p == NULL)
return PXE_PGP_CORRUPT_ARMOR;
/* it must start at beginning of line */
if (p == data || *(p - 1 ) == '\n' )
break ;
p += strlen(sep);
}
*start_p = p;
p += strlen(sep);
/* check if header text ok */
for (; p < datend && *p != '-' ; p++)
{
/* various junk can be there, but definitely not line-feed */
if (*p >= ' ' )
continue ;
return PXE_PGP_CORRUPT_ARMOR;
}
if (datend - p < 5 || memcmp(p, sep, 5 ) != 0 )
return PXE_PGP_CORRUPT_ARMOR;
p += 5 ;
/* check if at end of line */
if (p < datend)
{
if (*p != '\n' && *p != '\r' )
return PXE_PGP_CORRUPT_ARMOR;
if (*p == '\r' )
p++;
if (p < datend && *p == '\n' )
p++;
}
return p - *start_p;
}
int
pgp_armor_decode(const uint8 *src, int len, StringInfo dst)
{
const uint8 *p = src;
const uint8 *data_end = src + len;
long crc;
const uint8 *base64_start,
*armor_end;
const uint8 *base64_end = NULL;
uint8 buf[4 ];
int hlen;
int blen;
int res = PXE_PGP_CORRUPT_ARMOR;
/* armor start */
hlen = find_header(src, data_end, &p, 0 );
if (hlen <= 0 )
goto out;
p += hlen;
/* armor end */
hlen = find_header(p, data_end, &armor_end, 1 );
if (hlen <= 0 )
goto out;
/* skip comments - find empty line */
while (p < armor_end && *p != '\n' && *p != '\r' )
{
p = memchr(p, '\n' , armor_end - p);
if (!p)
goto out;
/* step to start of next line */
p++;
}
base64_start = p;
/* find crc pos */
for (p = armor_end; p >= base64_start; p--)
if (*p == '=' )
{
base64_end = p - 1 ;
break ;
}
if (base64_end == NULL)
goto out;
/* decode crc */
if (pg_base64_decode(p + 1 , 4 , buf) != 3 )
goto out;
crc = (((long ) buf[0 ]) << 16 ) + (((long ) buf[1 ]) << 8 ) + (long ) buf[2 ];
/* decode data */
blen = (int ) pg_base64_dec_len(len);
enlargeStringInfo(dst, blen);
res = pg_base64_decode(base64_start, base64_end - base64_start, (uint8 *) dst->data);
if (res > blen)
elog(FATAL, "overflow - decode estimate too small" );
if (res >= 0 )
{
if (crc24((uint8 *) dst->data, res) == crc)
dst->len += res;
else
res = PXE_PGP_CORRUPT_ARMOR;
}
out:
return res;
}
/*
* Extracts all armor headers from an ASCII - armored input .
*
* Returns 0 on success , or PXE_ * error code on error . On success , the
* number of headers and their keys and values are returned in * nheaders ,
* * nkeys and * nvalues .
*/
int
pgp_extract_armor_headers(const uint8 *src, unsigned len,
int *nheaders, char ***keys, char ***values)
{
const uint8 *data_end = src + len;
const uint8 *p;
const uint8 *base64_start;
const uint8 *armor_start;
const uint8 *armor_end;
Size armor_len;
char *line;
char *nextline;
char *eol,
*colon;
int hlen;
char *buf;
int hdrlines;
int n;
/* armor start */
hlen = find_header(src, data_end, &armor_start, 0 );
if (hlen <= 0 )
return PXE_PGP_CORRUPT_ARMOR;
armor_start += hlen;
/* armor end */
hlen = find_header(armor_start, data_end, &armor_end, 1 );
if (hlen <= 0 )
return PXE_PGP_CORRUPT_ARMOR;
/* Count the number of armor header lines. */
hdrlines = 0 ;
p = armor_start;
while (p < armor_end && *p != '\n' && *p != '\r' )
{
p = memchr(p, '\n' , armor_end - p);
if (!p)
return PXE_PGP_CORRUPT_ARMOR;
/* step to start of next line */
p++;
hdrlines++;
}
base64_start = p;
/*
* Make a modifiable copy of the part of the input that contains the
* headers . The returned key / value pointers will point inside the buffer .
*/
armor_len = base64_start - armor_start;
buf = palloc(armor_len + 1 );
memcpy(buf, armor_start, armor_len);
buf[armor_len] = '\0' ;
/* Allocate return arrays */
*keys = (char **) palloc(hdrlines * sizeof (char *));
*values = (char **) palloc(hdrlines * sizeof (char *));
/*
* Split the header lines at newlines and " : " separators , and collect
* pointers to the keys and values in the return arrays .
*/
n = 0 ;
line = buf;
for (;;)
{
/* find end of line */
eol = strchr(line, '\n' );
if (!eol)
break ;
nextline = eol + 1 ;
/* if the line ends in CR + LF, strip the CR */
if (eol > line && *(eol - 1 ) == '\r' )
eol--;
*eol = '\0' ;
/* find colon+space separating the key and value */
colon = strstr(line, ": " );
if (!colon)
return PXE_PGP_CORRUPT_ARMOR;
*colon = '\0' ;
/* shouldn't happen, we counted the number of lines beforehand */
if (n >= hdrlines)
elog(ERROR, "unexpected number of armor header lines" );
(*keys)[n] = line;
(*values)[n] = colon + 2 ;
n++;
/* step to start of next line */
line = nextline;
}
if (n != hdrlines)
elog(ERROR, "unexpected number of armor header lines" );
*nheaders = n;
return 0 ;
}
Messung V0.5 in Prozent C=98 H=92 G=94
[zur Elbe Produktseite wechseln0.15QuellennavigatorsAnalyse erneut starten2026-08-08]
2026-08-25