From 62e431b4da1d3789ebf1decd5c2a208e893a3813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se> Date: Wed, 30 Oct 2002 21:48:01 +0100 Subject: [PATCH] * base64-decode.c (base64_decode_single): Return -1 on error. Also keep track of the number of padding characters ('=') seen. (base64_decode_update): New argument dst_length. Return -1 on error. (base64_decode_status): Renamed function... (base64_decode_final): ... to this. * base64.h (struct base64_decode_ctx): Deleted STATUS attribute. Added PADDING attribute. Rev: src/nettle/base64-decode.c:1.4 Rev: src/nettle/base64.h:1.11 --- base64-decode.c | 78 ++++++++++++++++++++++++------------------------- base64.h | 32 +++++++++++--------- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/base64-decode.c b/base64-decode.c index c332aa22..c1c0d2f0 100644 --- a/base64-decode.c +++ b/base64-decode.c @@ -57,30 +57,26 @@ decode_table[0x100] = void base64_decode_init(struct base64_decode_ctx *ctx) { - ctx->word = ctx->bits = 0; - ctx->status = BASE64_DECODE_OK; + ctx->word = ctx->bits = ctx->padding = 0; } -unsigned +int base64_decode_single(struct base64_decode_ctx *ctx, uint8_t *dst, uint8_t src) { int data; - if (ctx->status == BASE64_DECODE_ERROR) - return 0; - data = decode_table[src]; switch(data) { default: assert(data >= 0 && data < 0x40); - - if (ctx->status != BASE64_DECODE_OK) - goto invalid; - + + if (ctx->padding) + return -1; + ctx->word = ctx->word << 6 | data; ctx->bits += 6; @@ -93,56 +89,60 @@ base64_decode_single(struct base64_decode_ctx *ctx, else return 0; case TABLE_INVALID: - invalid: - ctx->status = BASE64_DECODE_ERROR; - /* Fall through */ - + return -1; + case TABLE_SPACE: return 0; case TABLE_END: - if (!ctx->bits) - goto invalid; + /* There can be at most two padding characters. */ + if (!ctx->bits || ctx->padding > 2) + return -1; + if (ctx->word & ( (1<<ctx->bits) - 1)) /* We shouldn't have any leftover bits */ - goto invalid; - - ctx->status = BASE64_DECODE_END; + return -1; + + ctx->padding++; ctx->bits -= 2; return 0; } } -unsigned +int base64_decode_update(struct base64_decode_ctx *ctx, + unsigned *dst_length, uint8_t *dst, - unsigned length, + unsigned src_length, const uint8_t *src) { unsigned done; unsigned i; - - if (ctx->status == BASE64_DECODE_ERROR) - return 0; - for (i = 0, done = 0; i<length; i++) - done += base64_decode_single(ctx, dst + done, src[i]); - - assert(done <= BASE64_DECODE_LENGTH(length)); + assert(*dst_length >= BASE64_DECODE_LENGTH(src_length)); + + for (i = 0, done = 0; i<src_length; i++) + switch(base64_decode_single(ctx, dst + done, src[i])) + { + case -1: + return 0; + case 1: + done++; + /* Fall through */ + case 0: + break; + default: + abort(); + } - return done; + assert(done <= BASE64_DECODE_LENGTH(src_length)); + + *dst_length = done; + return 1; } int -base64_decode_status(struct base64_decode_ctx *ctx) +base64_decode_final(struct base64_decode_ctx *ctx) { - switch (ctx->status) - { - case BASE64_DECODE_END: - case BASE64_DECODE_OK: - return ctx->bits == 0; - case BASE64_DECODE_ERROR: - return 0; - } - abort(); + return ctx->bits == 0; } diff --git a/base64.h b/base64.h index 3084bbff..9532e54f 100644 --- a/base64.h +++ b/base64.h @@ -95,36 +95,40 @@ base64_encode_group(uint8_t *dst, uint32_t group); struct base64_decode_ctx { - enum - { - BASE64_DECODE_OK, - BASE64_DECODE_ERROR, - BASE64_DECODE_END - } status; unsigned word; /* Leftover bits */ unsigned bits; /* Number buffered bits */ + + /* Number of padding characters encountered */ + unsigned padding; }; void base64_decode_init(struct base64_decode_ctx *ctx); -/* Decodes a single byte. Returns amount of output (always 0 or 1). - * FIXME: What to return on errors? */ -unsigned +/* Decodes a single byte. Returns amount of output (0 or 1), or -1 on + * errors. */ +int base64_decode_single(struct base64_decode_ctx *ctx, uint8_t *dst, uint8_t src); -/* Returns the number of output characters. DST should point to an - * area of size at least BASE64_DECODE_LENGTH(length). */ -unsigned +/* Returns 1 on success, 0 on error. DST should point to an area of + * size at least BASE64_DECODE_LENGTH(length), and for sanity + * checking, *DST_LENGTH should be initialized to the size of that + * area before the call. *DST_LENGTH is updated to the amount of + * decoded output. */ + +/* FIXME: Currently results in an assertion failure if *DST_LENGTH is + * too small. Return some error instead? */ +int base64_decode_update(struct base64_decode_ctx *ctx, + unsigned *dst_length, uint8_t *dst, - unsigned length, + unsigned src_length, const uint8_t *src); /* Returns 1 on success. */ int -base64_decode_status(struct base64_decode_ctx *ctx); +base64_decode_final(struct base64_decode_ctx *ctx); #endif /* NETTLE_BASE64_H_INCLUDED */ -- GitLab