From a7c5fda40ac76c4a43af7a4ee5241514f890a2ee Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Wed, 15 Jul 2009 14:48:57 +0300 Subject: blob: base64 encoding and decoding and prefer sha1 checksums to be stored in base64 encoded format. --- src/apk_blob.h | 2 + src/blob.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 129 insertions(+), 17 deletions(-) diff --git a/src/apk_blob.h b/src/apk_blob.h index 170cf20..398056a 100644 --- a/src/apk_blob.h +++ b/src/apk_blob.h @@ -92,11 +92,13 @@ static inline const int apk_checksum_compare(const struct apk_checksum *a, void apk_blob_push_blob(apk_blob_t *to, apk_blob_t literal); void apk_blob_push_uint(apk_blob_t *to, unsigned int value, int radix); void apk_blob_push_csum(apk_blob_t *to, struct apk_checksum *csum); +void apk_blob_push_base64(apk_blob_t *to, apk_blob_t binary); void apk_blob_push_hexdump(apk_blob_t *to, apk_blob_t binary); void apk_blob_pull_char(apk_blob_t *b, int expected); unsigned int apk_blob_pull_uint(apk_blob_t *b, int radix); void apk_blob_pull_csum(apk_blob_t *b, struct apk_checksum *csum); +void apk_blob_pull_base64(apk_blob_t *b, apk_blob_t to); void apk_blob_pull_hexdump(apk_blob_t *b, apk_blob_t to); #endif diff --git a/src/blob.c b/src/blob.c index ed7f418..0b6efbf 100644 --- a/src/blob.c +++ b/src/blob.c @@ -186,14 +186,6 @@ void apk_blob_push_uint(apk_blob_t *to, unsigned int value, int radix) apk_blob_push_blob(to, APK_BLOB_PTR_PTR(ptr+1, &buf[sizeof(buf)-1])); } -static int checksum_char_to_id(char chr) -{ - switch (chr) { - case '1': return APK_CHECKSUM_SHA1; - } - return APK_CHECKSUM_NONE; -} - void apk_blob_push_csum(apk_blob_t *to, struct apk_checksum *csum) { switch (csum->type) { @@ -201,8 +193,8 @@ void apk_blob_push_csum(apk_blob_t *to, struct apk_checksum *csum) apk_blob_push_hexdump(to, APK_BLOB_CSUM(*csum)); break; case APK_CHECKSUM_SHA1: - apk_blob_push_blob(to, APK_BLOB_STR("X1")); - apk_blob_push_hexdump(to, APK_BLOB_CSUM(*csum)); + apk_blob_push_blob(to, APK_BLOB_STR("Q1")); + apk_blob_push_base64(to, APK_BLOB_CSUM(*csum)); break; default: *to = APK_BLOB_NULL; @@ -231,6 +223,42 @@ void apk_blob_push_hexdump(apk_blob_t *to, apk_blob_t binary) to->len -= binary.len * 2; } +static const char b64encode[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static inline void push_b64_chunk(unsigned char *to, const unsigned char *from, int len) +{ + to[0] = b64encode[from[0] >> 2]; + to[1] = b64encode[((from[0] & 0x03) << 4) | ((from[1] & 0xf0) >> 4)]; + to[2] = len < 2 ? '=' : b64encode[((from[1] & 0x0f) << 2) | + ((from[2] & 0xc0) >> 6)]; + to[3] = len < 3 ? '=' : b64encode[from[2] & 0x3f ]; +} + +void apk_blob_push_base64(apk_blob_t *to, apk_blob_t binary) +{ + unsigned char *src = (unsigned char *) binary.ptr; + unsigned char *dst = (unsigned char *) to->ptr; + int i, needed; + + if (unlikely(APK_BLOB_IS_NULL(*to))) + return; + + needed = ((binary.len + 2) / 3) * 4; + if (unlikely(to->len < needed)) { + *to = APK_BLOB_NULL; + return; + } + + for (i = 0; i < binary.len / 3; i++, src += 3, dst += 4) + push_b64_chunk(dst, src, 4); + i = binary.len % 3; + if (i != 0) + push_b64_chunk(dst, src, i); + to->ptr += needed; + to->len -= needed; +} + void apk_blob_pull_char(apk_blob_t *b, int expected) { if (unlikely(APK_BLOB_IS_NULL(*b))) @@ -265,6 +293,8 @@ unsigned int apk_blob_pull_uint(apk_blob_t *b, int radix) void apk_blob_pull_csum(apk_blob_t *b, struct apk_checksum *csum) { + int encoding; + if (unlikely(APK_BLOB_IS_NULL(*b))) return; @@ -273,18 +303,35 @@ void apk_blob_pull_csum(apk_blob_t *b, struct apk_checksum *csum) return; } - switch (b->ptr[0]) { - case 'X': - csum->type = checksum_char_to_id(b->ptr[1]); - b->ptr += 2; - b->len -= 2; + if (dx(b->ptr[0]) != -1) { + /* Assume MD5 for backwards compatibility */ + csum->type = APK_CHECKSUM_MD5; apk_blob_pull_hexdump(b, APK_BLOB_CSUM(*csum)); + return; + } + + encoding = b->ptr[0]; + switch (b->ptr[1]) { + case '1': + csum->type = APK_CHECKSUM_SHA1; break; default: - /* Assume MD5 for backwards compatibility */ - csum->type = APK_CHECKSUM_MD5; + *b = APK_BLOB_NULL; + return; + } + b->ptr += 2; + b->len -= 2; + + switch (encoding) { + case 'X': apk_blob_pull_hexdump(b, APK_BLOB_CSUM(*csum)); break; + case 'Q': + apk_blob_pull_base64(b, APK_BLOB_CSUM(*csum)); + break; + default: + *b = APK_BLOB_NULL; + break; } } @@ -314,3 +361,66 @@ void apk_blob_pull_hexdump(apk_blob_t *b, apk_blob_t to) err: *b = APK_BLOB_NULL; } + +static unsigned char b64decode[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +static inline int pull_b64_chunk(unsigned char *to, const unsigned char *from, int len) +{ + unsigned char tmp[4]; + int i; + + for (i = 0; i < 4; i++) { + if (unlikely(from[i] >= 0x80)) + return -1; + tmp[i] = b64decode[from[i]]; + if (unlikely(tmp[i] == 0xff)) + return -1; + } + + to[0] = (tmp[0] << 2 | tmp[1] >> 4); + if (len > 1) + to[1] = (tmp[1] << 4 | tmp[2] >> 2); + else if (unlikely(from[2] != '=')) + return -1; + if (len > 2) + to[2] = (((tmp[2] << 6) & 0xc0) | tmp[3]); + else if (unlikely(from[3] != '=')) + return -1; + return 0; +} + +void apk_blob_pull_base64(apk_blob_t *b, apk_blob_t to) +{ + unsigned char *src = (unsigned char *) b->ptr; + unsigned char *dst = (unsigned char *) to.ptr; + int i, needed; + + if (unlikely(APK_BLOB_IS_NULL(*b))) + return; + + needed = ((to.len + 2) / 3) * 4; + if (unlikely(b->len < needed)) { + *b = APK_BLOB_NULL; + return; + } + + for (i = 0; i < to.len / 3; i++, src += 4, dst += 3) + pull_b64_chunk(dst, src, 4); + i = to.len % 3; + if (i != 0) + pull_b64_chunk(dst, src, i); + b->ptr += needed; + b->len -= needed; +} -- cgit v1.2.3