Thursday, July 17, 2008

[HACKERS] Patch to eliminate duplicate b64 code from pgcrypto

Index: contrib/pgcrypto/pgp-armor.c
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/pgcrypto/pgp-armor.c,v
retrieving revision 1.3
diff -c -r1.3 pgp-armor.c
*** contrib/pgcrypto/pgp-armor.c 15 Oct 2005 02:49:06 -0000 1.3
--- contrib/pgcrypto/pgp-armor.c 17 Jul 2008 22:37:27 -0000
***************
*** 30,181 ****
*/

#include "postgres.h"

#include "px.h"
#include "mbuf.h"
#include "pgp.h"

/*
- * BASE64 - duplicated :(
- */
-
- static const unsigned char _base64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
- static int
- b64_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) & 0x3f];
- *p++ = _base64[(buf >> 12) & 0x3f];
- *p++ = _base64[(buf >> 6) & 0x3f];
- *p++ = _base64[buf & 0x3f];
-
- pos = 2;
- buf = 0;
- }
- if (p >= lend)
- {
- *p++ = '\n';
- lend = p + 76;
- }
- }
- if (pos != 2)
- {
- *p++ = _base64[(buf >> 18) & 0x3f];
- *p++ = _base64[(buf >> 12) & 0x3f];
- *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
- *p++ = '=';
- }
-
- return p - dst;
- }
-
- /* probably should use lookup table */
- static int
- b64_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
- b64_enc_len(unsigned srclen)
- {
- /*
- * 3 bytes will be converted to 4, linefeed after 76 chars
- */
- return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
- }
-
- static unsigned
- b64_dec_len(unsigned srclen)
- {
- return (srclen * 3) >> 2;
- }
-
- /*
* PGP armor
*/

--- 30,42 ----
*/

#include "postgres.h"
+ #include "utils/builtins.h"

#include "px.h"
#include "mbuf.h"
#include "pgp.h"

/*
* PGP armor
*/

***************
*** 215,234 ****
memcpy(pos, armor_header, n);
pos += n;

! n = b64_encode(src, len, pos);
pos += n;

if (*(pos - 1) != '\n')
*pos++ = '\n';

*pos++ = '=';
! pos[3] = _base64[crc & 0x3f];
crc >>= 6;
! pos[2] = _base64[crc & 0x3f];
crc >>= 6;
! pos[1] = _base64[crc & 0x3f];
crc >>= 6;
! pos[0] = _base64[crc & 0x3f];
pos += 4;

n = strlen(armor_footer);
--- 76,95 ----
memcpy(pos, armor_header, n);
pos += n;

! n = b64_encode((char *) src, len, (char *) pos);
pos += n;

if (*(pos - 1) != '\n')
*pos++ = '\n';

*pos++ = '=';
! pos[3] = b64_char(crc);
crc >>= 6;
! pos[2] = b64_char(crc);
crc >>= 6;
! pos[1] = b64_char(crc);
crc >>= 6;
! pos[0] = b64_char(crc);
pos += 4;

n = strlen(armor_footer);
***************
*** 356,367 ****
goto out;

/* decode crc */
! if (b64_decode(p + 1, 4, buf) != 3)
goto out;
crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];

/* decode data */
! res = b64_decode(base64_start, base64_end - base64_start, dst);

/* check crc */
if (res >= 0 && crc24(dst, res) != crc)
--- 217,229 ----
goto out;

/* decode crc */
! if (b64_decode((char *) (p + 1), 4, (char *) buf) != 3)
goto out;
crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];

/* decode data */
! res = b64_decode((char *) base64_start, base64_end - base64_start,
! (char *) dst);

/* check crc */
if (res >= 0 && crc24(dst, res) != crc)
***************
*** 373,383 ****
unsigned
pgp_armor_enc_len(unsigned len)
{
! return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16;
}

unsigned
pgp_armor_dec_len(unsigned len)
{
! return b64_dec_len(len);
}
--- 235,246 ----
unsigned
pgp_armor_enc_len(unsigned len)
{
! return b64_enc_len(NULL, len) + strlen(armor_header) +
! strlen(armor_footer) + 16;
}

unsigned
pgp_armor_dec_len(unsigned len)
{
! return b64_dec_len(NULL, len);
}
Index: src/backend/utils/adt/encode.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/encode.c,v
retrieving revision 1.22
diff -c -r1.22 encode.c
*** src/backend/utils/adt/encode.c 25 Mar 2008 22:42:44 -0000 1.22
--- src/backend/utils/adt/encode.c 17 Jul 2008 22:37:28 -0000
***************
*** 214,220 ****
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
};

! static unsigned
b64_encode(const char *src, unsigned len, char *dst)
{
char *p,
--- 214,226 ----
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
};

! char
! b64_char(unsigned src)
! {
! return _base64[src & 0x3f];
! }
!
! unsigned
b64_encode(const char *src, unsigned len, char *dst)
{
char *p,
***************
*** 261,267 ****
return p - dst;
}

! static unsigned
b64_decode(const char *src, unsigned len, char *dst)
{
const char *srcend = src + len,
--- 267,273 ----
return p - dst;
}

! unsigned
b64_decode(const char *src, unsigned len, char *dst)
{
const char *srcend = src + len,
***************
*** 330,343 ****
}


! static unsigned
b64_enc_len(const char *src, unsigned srclen)
{
/* 3 bytes will be converted to 4, linefeed after 76 chars */
return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
}

! static unsigned
b64_dec_len(const char *src, unsigned srclen)
{
return (srclen * 3) >> 2;
--- 336,349 ----
}


! unsigned
b64_enc_len(const char *src, unsigned srclen)
{
/* 3 bytes will be converted to 4, linefeed after 76 chars */
return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
}

! unsigned
b64_dec_len(const char *src, unsigned srclen)
{
return (srclen * 3) >> 2;
Index: src/include/utils/builtins.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.318
diff -c -r1.318 builtins.h
*** src/include/utils/builtins.h 3 Jul 2008 20:58:47 -0000 1.318
--- src/include/utils/builtins.h 17 Jul 2008 22:37:28 -0000
***************
*** 677,684 ****
extern Datum byteaGetBit(PG_FUNCTION_ARGS);
extern Datum byteaSetByte(PG_FUNCTION_ARGS);
extern Datum byteaSetBit(PG_FUNCTION_ARGS);
- extern Datum binary_encode(PG_FUNCTION_ARGS);
- extern Datum binary_decode(PG_FUNCTION_ARGS);
extern Datum byteaeq(PG_FUNCTION_ARGS);
extern Datum byteane(PG_FUNCTION_ARGS);
extern Datum bytealt(PG_FUNCTION_ARGS);
--- 677,682 ----
***************
*** 692,697 ****
--- 690,704 ----
extern Datum bytea_substr_no_len(PG_FUNCTION_ARGS);
extern Datum pg_column_size(PG_FUNCTION_ARGS);

+ /* encode.c */
+ extern Datum binary_encode(PG_FUNCTION_ARGS);
+ extern Datum binary_decode(PG_FUNCTION_ARGS);
+ extern char b64_char(unsigned src);
+ extern unsigned b64_encode(const char *src, unsigned len, char *dst);
+ extern unsigned b64_decode(const char *src, unsigned len, char *dst);
+ extern unsigned b64_enc_len(const char *src, unsigned srclen);
+ extern unsigned b64_dec_len(const char *src, unsigned srclen);
+
/* version.c */
extern Datum pgsql_version(PG_FUNCTION_ARGS);

I am attaching a patch to eliminate duplicate b64_encode and decode
functions from pgcrypto, and to expose those functions for use by
add-ins (I want to use them in Veil).

The patch was made against CVS head today. It compiles and tests
successfully. Though I was unable to run pgrypto regression tests, I
did give the b64 encoding a sanity check.

I also added a b64_char() function that is now used from pgcrypto. This
allowed me to remove the duplicate _base64 character array.

I hope this is the correct place to submit the patch. The wiki
(http://wiki.postgresql.org/wiki/Submitting_a_Patch) refers to
pgsql-patches but I believe that is now deprecated.


__
Marc

No comments: