> From: owner-openssl-us...@openssl.org On Behalf Of Vinay Kumar L
> Sent: Tuesday, 01 March, 2011 23:42
> Thanks for your reply, but OpenSSL Base64 decoding api returns NULL
> on passing Base64 encoded data. The code snippet is as follows:
I very much doubt it returns NULL. NULL in C is a null POINTER
(pedantically, a null pointer CONSTANT). Your code will return
a string of zero characters, i.e. an empty string.
In general this is sometimes called a null STRING but in C
that's confusing because a null string is not a null pointer.
(And FWIW in SQL a NULL value is not an empty string either,
although some user tools will DISPLAY it as such.)
Also, the byte that terminates a C (narrow) string is a null
character or null byte, sometimes called NUL (note 3 letters).
But this character is not IN the string, it is AFTER the string.
> int main(int argc, char **argv)
> {
> char *output = unbase64("dGVzdGVuY29kaW5nCg==",
strlen("dGVzdGVuY29kaW5nCg=="));
Your real problem is that the ENCODING should have terminating newline.
See below. (The encoded/decoded DATA can include a newline or not,
which as you have already seen changes the encoding, but often
isn't even characters so the concept of newline doesn't apply.)
> printf("Unbase64: %s\n", output);
> free(output);
> }
In C99 or C++ you must have at least a declaration of the function
before the call. (You can have the definition which is also a
declaration, by arranging your code 'bottom up'.)
But in C89, the implicit declaration is 'returns int'. You should
be unable to assign it to a char* without at least a warning.
And even if you add a cast, it still won't work on some systems
because the calling sequence is actually different. (Pedantically,
initialization isn't assignment but it's sufficiently like.)
In C (both C89 and C99) you can choose whether to use a prototype
declaration (with parameter types) or a nonprototype aka "K&R1"
declaration without. Prototypes are Better(tm).
> char *unbase64(unsigned char *input, int length)
With a nonprototype (including implicit) declaration this is wrong.
strlen() returns size_t, not int. On SOME systems size_t and int are
actually the same size (and passed compatibly) and this 'accidentally'
works. On some systems it doesn't work at all. (With a prototype
it will be converted as long as the value is in range. If you have
data long enough its length fits in size_t but not int, use size_t.)
Technically unsigned-char* is not the same type as plain-char*,
which is the value of the string literal above -- even on systems
where plain-char is unsigned. In practice this will always work.
However, since (valid) b64 data is always in a limited character set
that is a subset of the 'basic execution' set, it usually makes sense
to store it in array of plain-char, and pass it as pointer to same.
OTOH the data encoded into and decoded from b64 is often binary
(although your example isn't) so in general treating it as
array of and pointer to unsigned-char is usually better.
> {
> BIO *b64, *bmem;
>
> char *buffer = (char *)malloc(length);
Should check for failed allocation (returned null pointer) before using,
but I'll assume this is only test/example code. The cast is not needed
in C if you have #include'd as required; without that correct
declaration the cast doesn't actually solve the problem on some systems,
it just silences the warning because you lied to the compiler.
In C++ the cast is needed if you use malloc but you shouldn't use malloc.
> memset(buffer, 0, length);
Don't need this if you add just one null terminator in the right place.
If you actually do need zero-fill, calloc() may be less inefficient.
> b64 = BIO_new(BIO_f_base64());
> bmem = BIO_new_mem_buf(input, length);
> bmem = BIO_push(b64, bmem);
> BIO_read(bmem, buffer, length);
You should use the return value of BIO_read.
For the data above, the return value is zero, because by default
b64BIO requires input to have the line terminators specified
by PEM (always at the end, plus in the middle if 'too long')
and similarly inserts them on output (which you don't have here).
You can change this with
BIO_set_flags (b64,BIO_FLAGS_BASE64_NO_NL)
When successful, the return value is the number of bytes decoded,
which is convenient for a number of things; in your case you want
to treat the data as a null-terminated string, so that's the
right place to insert a single null-character terminator.
> BIO_free_all(bmem);
> return buffer;
> }
__
OpenSSL Project http://www.openssl.org
User Support Mailing Listopenssl-users@openssl.org
Automated List Manager