Implement base64 without openssl
This commit is contained in:
parent
8b8cfbe119
commit
4699dced14
246
common/base64.c
246
common/base64.c
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (C) 2017 Koichiro Iwao, all xrdp contributors
|
||||
* Copyright (C) 2022 Matt Burt, all xrdp contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -26,57 +26,229 @@
|
||||
|
||||
#include "string_calls.h"
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "base64.h"
|
||||
|
||||
size_t
|
||||
base64_decoded_bytes(const char *src)
|
||||
/*
|
||||
* Values for invalid and padding characters, used in the charmap
|
||||
* for converting base64 to binary
|
||||
*
|
||||
* Thse value are specially chosen to make it easy to detect padding or
|
||||
* invalid characters by or-ing together the values looked up in
|
||||
* a base64 quantum */
|
||||
#define E_INVALID 0x40
|
||||
#define E_PAD 0x80
|
||||
|
||||
/* Determine the character set on this platform */
|
||||
#if ('a' == 0x61 && 'z' == 0x7a ) && \
|
||||
('A' == 0x41 && 'Z' == 0x5a ) && \
|
||||
('0' == 0x30 && '9' == 0x39 )
|
||||
# define PLATFORM_IS_ASCII 1
|
||||
#else
|
||||
# error "Unrecognised character set on this platform"
|
||||
#endif /* character set check */
|
||||
|
||||
|
||||
/*
|
||||
* Define a table to map the base64 character values to bit values.
|
||||
*/
|
||||
#ifdef PLATFORM_IS_ASCII
|
||||
#define CHARMAP_BASE 0x28
|
||||
#define E_IV E_INVALID /* For table alignment */
|
||||
const unsigned char charmap[] =
|
||||
{
|
||||
size_t len;
|
||||
size_t padding;
|
||||
/* 0x28 */ E_IV, E_IV, E_IV, 0x3e, E_IV, E_IV, E_IV, 0x3f,
|
||||
/* 0x30 */ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
/* 0x38 */ 0x3c, 0x3d, E_IV, E_IV, E_IV, E_PAD, E_IV, E_IV,
|
||||
/* 0x40 */ E_IV, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
/* 0x48 */ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
/* 0x50 */ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
/* 0x58 */ 0x17, 0x18, 0x19, E_IV, E_IV, E_IV, E_IV, E_IV,
|
||||
/* 0x60 */ E_IV, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
||||
/* 0x68 */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
/* 0x70 */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||
/* 0x78 */ 0x31, 0x32, 0x33
|
||||
};
|
||||
#undef E_IV
|
||||
#endif /* PLATFORM_IS_ASCII */
|
||||
|
||||
len = g_strlen(src);
|
||||
padding = 0;
|
||||
|
||||
if (src[len - 1] == '=')
|
||||
/**
|
||||
* Lookup a value in the charmap
|
||||
*
|
||||
* @param x - byte to lookup. Only referenced once so can safely have
|
||||
* side effects.
|
||||
* @param dest - destination to assign result to.
|
||||
*/
|
||||
#define CM_LOOKUP(x,dest) \
|
||||
{ \
|
||||
unsigned int t = (unsigned int)(x) - CHARMAP_BASE;\
|
||||
dest = (t < sizeof(charmap)) ? charmap[t] : E_INVALID; \
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
base64_decode(const char *src, char *dst, size_t dst_len, size_t *actual_len)
|
||||
{
|
||||
*actual_len = 0;
|
||||
size_t src_len;
|
||||
size_t src_i = 0;
|
||||
size_t dst_i = 0;
|
||||
unsigned int a; /* Four characters of base64 quantum */
|
||||
unsigned int b;
|
||||
unsigned int c;
|
||||
unsigned int d;
|
||||
unsigned int v;
|
||||
|
||||
#define OUTPUT_CHAR(x) \
|
||||
{ \
|
||||
if (dst_i < dst_len) \
|
||||
{ \
|
||||
dst[dst_i] = (x);\
|
||||
} \
|
||||
++dst_i; \
|
||||
}
|
||||
|
||||
src_len = g_strlen(src);
|
||||
|
||||
while (src_i < src_len)
|
||||
{
|
||||
padding++;
|
||||
|
||||
if (src[len - 2] == '=')
|
||||
if ((src_len - src_i) >= 4)
|
||||
{
|
||||
padding++;
|
||||
/* Usual case - full quantum */
|
||||
CM_LOOKUP(src[src_i++], a);
|
||||
CM_LOOKUP(src[src_i++], b);
|
||||
CM_LOOKUP(src[src_i++], c);
|
||||
CM_LOOKUP(src[src_i++], d);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add padding on the end to make up the full quantum */
|
||||
CM_LOOKUP(src[src_i++], a);
|
||||
b = E_PAD;
|
||||
c = E_PAD;
|
||||
d = E_PAD;
|
||||
if ((src_len - src_i) > 0)
|
||||
{
|
||||
CM_LOOKUP(src[src_i++], b);
|
||||
}
|
||||
if ((src_len - src_i) > 0)
|
||||
{
|
||||
CM_LOOKUP(src[src_i++], c);
|
||||
}
|
||||
}
|
||||
|
||||
return len * 3 / 4 - padding;
|
||||
/*
|
||||
* Bitwise-or the translated quantum values together, so that
|
||||
* any invalid or padding characters can be detected with a
|
||||
* single test */
|
||||
v = a | b | c | d;
|
||||
|
||||
if ((v & E_INVALID) != 0)
|
||||
{
|
||||
return -1; /* At least one invalid character */
|
||||
}
|
||||
|
||||
if ((v & E_PAD) == 0)
|
||||
{
|
||||
/* No padding - a full quantum */
|
||||
v = (a << 18) | (b << 12) | (c << 6) | d;
|
||||
OUTPUT_CHAR(v >> 16);
|
||||
OUTPUT_CHAR((v >> 8) & 0xff);
|
||||
OUTPUT_CHAR(v & 0xff);
|
||||
}
|
||||
else if (((a | b | c) & E_PAD) == 0)
|
||||
{
|
||||
/* No padding in the first 3 chars, so the padding must
|
||||
* be at the end */
|
||||
v = (a << 10) | (b << 4) | (c >> 2);
|
||||
OUTPUT_CHAR(v >> 8);
|
||||
OUTPUT_CHAR(v & 0xff);
|
||||
}
|
||||
else if (((a | b) & E_PAD) == 0 && c == d)
|
||||
{
|
||||
/* No padding in first two chars, so if the last two chars are
|
||||
* equal, they must both be padding */
|
||||
v = (a << 2) | (b >> 4);
|
||||
OUTPUT_CHAR(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Illegal padding */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*actual_len = dst_i;
|
||||
return 0;
|
||||
|
||||
#undef OUTPUT_CHAR
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
char *
|
||||
base64_decode(char *dst, const char *src, size_t len)
|
||||
size_t
|
||||
base64_encode(const char *src, size_t src_len, char *dst, size_t dst_len)
|
||||
{
|
||||
BIO *b64;
|
||||
BIO *bio;
|
||||
char *b64str;
|
||||
size_t estimated_decoded_bytes;
|
||||
size_t decoded_bytes;
|
||||
char *p = dst;
|
||||
size_t src_i = 0;
|
||||
size_t max_src_len;
|
||||
unsigned int v;
|
||||
static const char *b64chr =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/=";
|
||||
|
||||
b64str = g_strdup(src);
|
||||
estimated_decoded_bytes = base64_decoded_bytes(b64str);
|
||||
dst[estimated_decoded_bytes] = '\0';
|
||||
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
bio = BIO_new_mem_buf(b64str, len);
|
||||
bio = BIO_push(b64, bio);
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||
decoded_bytes = BIO_read(bio, dst, len);
|
||||
BIO_free_all(bio);
|
||||
|
||||
/* if input is corrupt, return empty string */
|
||||
if (estimated_decoded_bytes != decoded_bytes)
|
||||
/* Each three octets of the source results in four bytes at the output,
|
||||
* plus we need a terminator. So we can work out the maximum number of
|
||||
* source octets we can process */
|
||||
if (dst_len == 0)
|
||||
{
|
||||
g_strncpy(dst, "", sizeof(""));
|
||||
max_src_len = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
max_src_len = (dst_len - 1) / 4 * 3;
|
||||
}
|
||||
|
||||
return dst;
|
||||
if (src_len > max_src_len)
|
||||
{
|
||||
src_len = max_src_len;
|
||||
}
|
||||
|
||||
while (src_i < src_len)
|
||||
{
|
||||
switch (src_len - src_i)
|
||||
{
|
||||
case 1:
|
||||
v = (unsigned int)(unsigned char)src[src_i++] << 4;
|
||||
*p++ = b64chr[v >> 6];
|
||||
*p++ = b64chr[v & 0x3f];
|
||||
*p++ = b64chr[64];
|
||||
*p++ = b64chr[64];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
v = (unsigned int)(unsigned char)src[src_i++] << 10;
|
||||
v |= (unsigned int)(unsigned char)src[src_i++] << 2;
|
||||
*p++ = b64chr[v >> 12];
|
||||
*p++ = b64chr[(v >> 6) & 0x3f];
|
||||
*p++ = b64chr[v & 0x3f];
|
||||
*p++ = b64chr[64];
|
||||
break;
|
||||
|
||||
default:
|
||||
v = (unsigned int)(unsigned char)src[src_i++] << 16;
|
||||
v |= (unsigned int)(unsigned char)src[src_i++] << 8;
|
||||
v |= (unsigned int)(unsigned char)src[src_i++];
|
||||
*p++ = b64chr[v >> 18];
|
||||
*p++ = b64chr[(v >> 12) & 0x3f];
|
||||
*p++ = b64chr[(v >> 6) & 0x3f];
|
||||
*p++ = b64chr[v & 0x3f];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
|
||||
return src_len;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (C) 2017 Koichiro Iwao, all xrdp contributors
|
||||
* Copyright (C) 2021 Koichiro Iwao, all xrdp contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -17,16 +17,66 @@
|
||||
/**
|
||||
* @file common/base64.h
|
||||
* @brief Base64 encoder / decoder
|
||||
*
|
||||
* Base-64 is described in RFC4648. The following notes apply to this
|
||||
* implementation:-
|
||||
* - The only supported characters are [A-Za-z0-9+/=]. At present,
|
||||
* embedded linefeeds and URL encodings are not supported.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(SSL_CALLS_H)
|
||||
#define SSL_CALLS_H
|
||||
#if !defined(BASE64_CALLS_H)
|
||||
#define BASE64_CALLS_H
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
size_t
|
||||
base64_decoded_bytes(const char *src);
|
||||
char *
|
||||
base64_decode(char *dst, const char *src, size_t len);
|
||||
/*
|
||||
* Decodes a base64 string
|
||||
*
|
||||
* @param src Pointer to null-terminated source
|
||||
* @param dst Pointer to output buffer
|
||||
* @param dst_len Length of above. No more than this is written to the
|
||||
* output buffer
|
||||
* @param actual_len Pointer to value to receive actual length of decoded data
|
||||
* @return 0 for success, 1 for an invalid input string
|
||||
*
|
||||
* The following notes apply to this implementation:-
|
||||
* - Embedded padding is supported, provided it only occurs at the end
|
||||
* of a quantum as described in RFC4648(4). This allows concatenated
|
||||
* encodings to be fed into the decoder.
|
||||
* - Padding of the last quantum is assumed if not provided.
|
||||
* - Excess padding of the last quantum is ignored.
|
||||
*
|
||||
* Only dst_len bytes at most are written to the output. The length
|
||||
* returned in actual_len however represents how much buffer is needed for
|
||||
* a correct result. This may be more than dst_len, and enables the caller
|
||||
* to detect a potential buffer overflow
|
||||
*/
|
||||
int
|
||||
base64_decode(const char *src, char *dst, size_t dst_len, size_t *actual_len);
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Encodes a buffer as base64
|
||||
*
|
||||
* @param src Pointer to source
|
||||
* @param src_len Length of above.
|
||||
* @param dst Pointer to output buffer for null-terminated string
|
||||
* @param dst_len Length of above. No more than this is written to the
|
||||
* output buffer
|
||||
* @return Number of source characters processed
|
||||
*
|
||||
* The following notes apply to this implementation:-
|
||||
* - Padding of the last quantum is always written if the number of
|
||||
* source bytes is not divisible by 3.
|
||||
*
|
||||
* The number of source characters processed is always returned. If
|
||||
* the destination buffer is too small for all the output plus a
|
||||
* terminator, the returned value from this procedure will be less than
|
||||
* src_len. In this case no padding characters will have been written,
|
||||
* and the remaining characters can be converted with more calls to
|
||||
* this procedure.
|
||||
*/
|
||||
size_t
|
||||
base64_encode(const char *src, size_t src_len, char *dst, size_t dst_len);
|
||||
|
||||
#endif /* BASE64_CALLS_H */
|
||||
|
@ -6,6 +6,8 @@ AM_CPPFLAGS = \
|
||||
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
|
||||
$(top_srcdir)/tap-driver.sh
|
||||
|
||||
PACKAGE_STRING = "libcommon"
|
||||
|
||||
TESTS = test_common
|
||||
check_PROGRAMS = test_common
|
||||
|
||||
@ -14,7 +16,8 @@ test_common_SOURCES = \
|
||||
test_common_main.c \
|
||||
test_string_calls.c \
|
||||
test_os_calls.c \
|
||||
test_ssl_calls.c
|
||||
test_ssl_calls.c \
|
||||
test_base64.c
|
||||
|
||||
test_common_CFLAGS = \
|
||||
@CHECK_CFLAGS@ \
|
||||
|
400
tests/common/test_base64.c
Normal file
400
tests/common/test_base64.c
Normal file
@ -0,0 +1,400 @@
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "base64.h"
|
||||
|
||||
#include "test_common.h"
|
||||
/*
|
||||
* These are the example test strings in RFC4648(10)
|
||||
*/
|
||||
static const char *rfc4648_ex1_text = "";
|
||||
static const char *rfc4648_ex1_b64 = "";
|
||||
static const char *rfc4648_ex2_text = "f";
|
||||
static const char *rfc4648_ex2_b64 = "Zg==";
|
||||
static const char *rfc4648_ex3_text = "fo";
|
||||
static const char *rfc4648_ex3_b64 = "Zm8=";
|
||||
static const char *rfc4648_ex4_text = "foo";
|
||||
static const char *rfc4648_ex4_b64 = "Zm9v";
|
||||
static const char *rfc4648_ex5_text = "foob";
|
||||
static const char *rfc4648_ex5_b64 = "Zm9vYg==";
|
||||
static const char *rfc4648_ex6_text = "fooba";
|
||||
static const char *rfc4648_ex6_b64 = "Zm9vYmE=";
|
||||
static const char *rfc4648_ex7_text = "foobar";
|
||||
static const char *rfc4648_ex7_b64 = "Zm9vYmFy";
|
||||
|
||||
/* Every single valid base64 character, except padding */
|
||||
static const char *all_b64 =
|
||||
"ABCDEFGHIJKL"
|
||||
"MNOPQRSTUVWX"
|
||||
"YZabcdefghij"
|
||||
"klmnopqrstuv"
|
||||
"wxyz01234567"
|
||||
"89+/";
|
||||
|
||||
/* What we should get as binary if we decode this */
|
||||
static const char all_b64_decoded[] =
|
||||
{
|
||||
'\x00', '\x10', '\x83', '\x10', '\x51', '\x87', '\x20', '\x92', '\x8b',
|
||||
'\x30', '\xd3', '\x8f', '\x41', '\x14', '\x93', '\x51', '\x55', '\x97',
|
||||
'\x61', '\x96', '\x9b', '\x71', '\xd7', '\x9f', '\x82', '\x18', '\xa3',
|
||||
'\x92', '\x59', '\xa7', '\xa2', '\x9a', '\xab', '\xb2', '\xdb', '\xaf',
|
||||
'\xc3', '\x1c', '\xb3', '\xd3', '\x5d', '\xb7', '\xe3', '\x9e', '\xbb',
|
||||
'\xf3', '\xdf', '\xbf'
|
||||
};
|
||||
|
||||
static void
|
||||
test_rfc4648_to_b64(const char *plaintext, size_t len, const char *b64)
|
||||
{
|
||||
char buff[256];
|
||||
size_t result;
|
||||
|
||||
result = base64_encode(plaintext, len, buff, sizeof(buff));
|
||||
ck_assert_int_eq(result, len);
|
||||
ck_assert_str_eq(buff, b64);
|
||||
|
||||
}
|
||||
|
||||
/* Text-only encoder wrapper */
|
||||
static void
|
||||
test_rfc4648_to_b64_text(const char *plaintext, const char *b64)
|
||||
{
|
||||
test_rfc4648_to_b64(plaintext, g_strlen(plaintext), b64);
|
||||
}
|
||||
|
||||
/* Text-only decoder wrapper for valid base64 */
|
||||
static void
|
||||
test_rfc4648_from_b64_text(const char *b64, const char *text)
|
||||
{
|
||||
char buff[256];
|
||||
size_t actual_len;
|
||||
int result;
|
||||
|
||||
result = base64_decode(b64, buff, sizeof(buff), &actual_len);
|
||||
ck_assert_int_eq(result, 0);
|
||||
ck_assert_int_lt(actual_len, sizeof(buff));
|
||||
buff[actual_len] = '\0';
|
||||
ck_assert_str_eq(buff, text);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex1_to)
|
||||
{
|
||||
test_rfc4648_to_b64_text(rfc4648_ex1_text, rfc4648_ex1_b64);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex1_from)
|
||||
{
|
||||
test_rfc4648_from_b64_text(rfc4648_ex1_b64, rfc4648_ex1_text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex2_to)
|
||||
{
|
||||
test_rfc4648_to_b64_text(rfc4648_ex2_text, rfc4648_ex2_b64);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex2_from)
|
||||
{
|
||||
test_rfc4648_from_b64_text(rfc4648_ex2_b64, rfc4648_ex2_text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex3_to)
|
||||
{
|
||||
test_rfc4648_to_b64_text(rfc4648_ex3_text, rfc4648_ex3_b64);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex3_from)
|
||||
{
|
||||
test_rfc4648_from_b64_text(rfc4648_ex3_b64, rfc4648_ex3_text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex4_to)
|
||||
{
|
||||
test_rfc4648_to_b64_text(rfc4648_ex4_text, rfc4648_ex4_b64);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex4_from)
|
||||
{
|
||||
test_rfc4648_from_b64_text(rfc4648_ex4_b64, rfc4648_ex4_text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex5_to)
|
||||
{
|
||||
test_rfc4648_to_b64_text(rfc4648_ex5_text, rfc4648_ex5_b64);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex5_from)
|
||||
{
|
||||
test_rfc4648_from_b64_text(rfc4648_ex5_b64, rfc4648_ex5_text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex6_to)
|
||||
{
|
||||
test_rfc4648_to_b64_text(rfc4648_ex6_text, rfc4648_ex6_b64);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex6_from)
|
||||
{
|
||||
test_rfc4648_from_b64_text(rfc4648_ex6_b64, rfc4648_ex6_text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex7_to)
|
||||
{
|
||||
test_rfc4648_to_b64_text(rfc4648_ex7_text, rfc4648_ex7_b64);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_rfc4648_ex7_from)
|
||||
{
|
||||
test_rfc4648_from_b64_text(rfc4648_ex7_b64, rfc4648_ex7_text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_all_valid_from)
|
||||
{
|
||||
char buff[256];
|
||||
size_t actual_len;
|
||||
int result;
|
||||
char *str_result;
|
||||
char *str_expected;
|
||||
|
||||
result = base64_decode(all_b64, buff, sizeof(buff), &actual_len);
|
||||
ck_assert_int_eq(result, 0);
|
||||
ck_assert_int_eq(actual_len, sizeof(all_b64_decoded));
|
||||
str_result = bin_to_hex(buff, actual_len);
|
||||
str_expected = bin_to_hex(all_b64_decoded, sizeof(all_b64_decoded));
|
||||
ck_assert_str_eq(str_result, str_expected);
|
||||
free(str_result);
|
||||
free(str_expected);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_all_valid_to)
|
||||
{
|
||||
char buff[256];
|
||||
size_t result;
|
||||
|
||||
result = base64_encode(all_b64_decoded, sizeof(all_b64_decoded),
|
||||
buff, sizeof(buff));
|
||||
ck_assert_int_eq(result, sizeof(all_b64_decoded));
|
||||
ck_assert_str_eq(buff, all_b64);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_all_invalid)
|
||||
{
|
||||
char buff[256];
|
||||
size_t actual_len;
|
||||
char valid[256] = {0};
|
||||
char encoded[5] = { "T0sh" }; /* Decodes to 'OK!' */
|
||||
int result;
|
||||
|
||||
/* Make a note of all the valid b64 characters */
|
||||
unsigned int i = 0;
|
||||
unsigned char c;
|
||||
while ((c = all_b64[i]) != '\0')
|
||||
{
|
||||
valid[c] = 1;
|
||||
++i;
|
||||
}
|
||||
|
||||
/* Check the decoder's working on a simple string...*/
|
||||
result = base64_decode(encoded, buff, sizeof(buff), &actual_len);
|
||||
ck_assert_int_eq(result, 0);
|
||||
ck_assert_int_eq(actual_len, 3);
|
||||
buff[actual_len] = '\0';
|
||||
ck_assert_str_eq(buff, "OK!");
|
||||
|
||||
/* Now replace the 1st character with all invalid characters in turn,
|
||||
* and check they're rejected */
|
||||
for (i = 0 ; i < 256; ++i)
|
||||
{
|
||||
if (i != '\0' && !valid[i]) /* Don't try the string terminator char! */
|
||||
{
|
||||
encoded[0] = i;
|
||||
result = base64_decode(encoded, buff, sizeof(buff), &actual_len);
|
||||
if (result == 0)
|
||||
{
|
||||
ck_abort_msg("Character 0x%02x was not rejected", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_small_buffer_encode)
|
||||
{
|
||||
char buff[10 * 4 + 1]; /* Enough space for 10 quanta */
|
||||
|
||||
size_t result;
|
||||
|
||||
result = base64_encode(all_b64_decoded, sizeof(all_b64_decoded),
|
||||
buff, sizeof(buff));
|
||||
/* Should have read 10 lots of 24 bits from the input */
|
||||
ck_assert_int_eq(result, 10 * 3);
|
||||
ck_assert_str_eq(buff, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_small_buffer_decode)
|
||||
{
|
||||
char buff[10]; /* Enough space for 10 chars */
|
||||
|
||||
size_t actual_len;
|
||||
int result;
|
||||
char *str_result;
|
||||
char *str_expected;
|
||||
|
||||
result = base64_decode(all_b64, buff, sizeof(buff), &actual_len);
|
||||
ck_assert_int_eq(result, 0);
|
||||
ck_assert_int_eq(actual_len, sizeof(all_b64_decoded));
|
||||
str_result = bin_to_hex(buff, sizeof(buff));
|
||||
str_expected = bin_to_hex(all_b64_decoded, sizeof(buff));
|
||||
ck_assert_str_eq(str_result, str_expected);
|
||||
free(str_result);
|
||||
free(str_expected);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_add_pad_one)
|
||||
{
|
||||
/* Check that a missing trailing '=' is added when decoding */
|
||||
test_rfc4648_from_b64_text("Zm8", "fo"); /* RFC4648 example 3 */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_add_pad_two)
|
||||
{
|
||||
/* Check that two missing trailing '=' chars are added when decoding */
|
||||
test_rfc4648_from_b64_text("Zg", "f"); /* RFC4648 example 2 */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_bad_pad)
|
||||
{
|
||||
char buff[16];
|
||||
size_t actual_len;
|
||||
|
||||
/* Check all bad quanta with padding chars */
|
||||
static const char *bad_pad[] =
|
||||
{
|
||||
"=AAA",
|
||||
"A=AA",
|
||||
"AA=A",
|
||||
"==AA",
|
||||
"=A=A",
|
||||
"=AA=",
|
||||
"A==A",
|
||||
"A=A=",
|
||||
"===A",
|
||||
"A===",
|
||||
NULL
|
||||
};
|
||||
const char **p;
|
||||
|
||||
for (p = bad_pad ; *p != NULL ; ++p)
|
||||
{
|
||||
int result = base64_decode(*p, buff, sizeof(buff), &actual_len);
|
||||
if (result == 0)
|
||||
{
|
||||
ck_abort_msg("Padding '%s' was not rejected", *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_b64_concat_pad)
|
||||
{
|
||||
const char *src =
|
||||
"VGVzdA==" /* Test */
|
||||
"IA==" /* <space> */
|
||||
"Y29uY2F0ZW5hdGVk" /* concatenated */
|
||||
"IA==" /* <space> */
|
||||
"cGFkZGluZw=="; /*padding */
|
||||
const char *expected = "Test concatenated padding";
|
||||
char buff[64];
|
||||
size_t actual_len;
|
||||
int result;
|
||||
|
||||
result = base64_decode(src, buff, sizeof(buff), &actual_len);
|
||||
ck_assert_int_eq(result, 0);
|
||||
ck_assert_int_eq(actual_len, g_strlen(expected));
|
||||
buff[actual_len] = '\0';
|
||||
ck_assert_str_eq(buff, expected);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
Suite *
|
||||
make_suite_test_base64(void)
|
||||
{
|
||||
Suite *s;
|
||||
TCase *tc_b64;
|
||||
|
||||
s = suite_create("base64");
|
||||
|
||||
tc_b64 = tcase_create("base64");
|
||||
suite_add_tcase(s, tc_b64);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex1_to);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex1_from);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex2_to);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex2_from);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex3_to);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex3_from);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex4_to);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex4_from);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex5_to);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex5_from);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex6_to);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex6_from);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex7_to);
|
||||
tcase_add_test(tc_b64, test_b64_rfc4648_ex7_from);
|
||||
tcase_add_test(tc_b64, test_b64_all_valid_from);
|
||||
tcase_add_test(tc_b64, test_b64_all_valid_to);
|
||||
tcase_add_test(tc_b64, test_b64_all_invalid);
|
||||
tcase_add_test(tc_b64, test_b64_small_buffer_encode);
|
||||
tcase_add_test(tc_b64, test_b64_small_buffer_decode);
|
||||
tcase_add_test(tc_b64, test_b64_add_pad_one);
|
||||
tcase_add_test(tc_b64, test_b64_add_pad_two);
|
||||
tcase_add_test(tc_b64, test_b64_bad_pad);
|
||||
tcase_add_test(tc_b64, test_b64_concat_pad);
|
||||
|
||||
return s;
|
||||
}
|
@ -4,8 +4,12 @@
|
||||
|
||||
#include <check.h>
|
||||
|
||||
char *
|
||||
bin_to_hex(const char *input, int length);
|
||||
|
||||
Suite *make_suite_test_string(void);
|
||||
Suite *make_suite_test_os_calls(void);
|
||||
Suite *make_suite_test_ssl_calls(void);
|
||||
Suite *make_suite_test_base64(void);
|
||||
|
||||
#endif /* TEST_COMMON_H */
|
||||
|
@ -10,6 +10,36 @@
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
/**
|
||||
* Converts a binary buffer to a hexadecimal representation
|
||||
*
|
||||
* Result must be free'd after use
|
||||
*/
|
||||
char *
|
||||
bin_to_hex(const char *input, int length)
|
||||
{
|
||||
int i;
|
||||
char *result = (char *)malloc(length * 2 + 1);
|
||||
if (result != NULL)
|
||||
{
|
||||
char *p = result;
|
||||
const char *hexdigit = "0123456789abcdef";
|
||||
for (i = 0 ; i < length ; ++i)
|
||||
{
|
||||
int c = input[i];
|
||||
if (c < 0)
|
||||
{
|
||||
c += 256;
|
||||
}
|
||||
*p++ = hexdigit[ c / 16];
|
||||
*p++ = hexdigit[ c % 16];
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
int number_failed;
|
||||
@ -18,6 +48,7 @@ int main (void)
|
||||
sr = srunner_create (make_suite_test_string());
|
||||
srunner_add_suite(sr, make_suite_test_os_calls());
|
||||
srunner_add_suite(sr, make_suite_test_ssl_calls());
|
||||
srunner_add_suite(sr, make_suite_test_base64());
|
||||
// srunner_add_suite(sr, make_list_suite());
|
||||
|
||||
srunner_set_tap(sr, "-");
|
||||
|
@ -9,32 +9,6 @@
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
static
|
||||
char *bin_to_hex(const char *input, int length)
|
||||
{
|
||||
int i;
|
||||
char *result = (char *)g_malloc(length * 2 + 1, 0);
|
||||
if (result != NULL)
|
||||
{
|
||||
char *p = result;
|
||||
const char *hexdigit = "0123456789abcdef";
|
||||
for (i = 0 ; i < length ; ++i)
|
||||
{
|
||||
int c = input[i];
|
||||
if (c < 0)
|
||||
{
|
||||
c += 256;
|
||||
}
|
||||
*p++ = hexdigit[ c / 16];
|
||||
*p++ = hexdigit[ c % 16];
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
START_TEST(test_rc4_enc_ok)
|
||||
{
|
||||
const char *key = "16_byte_key-----";
|
||||
|
@ -346,6 +346,7 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
|
||||
struct xrdp_cfg_globals *globals;
|
||||
char resultIP[256];
|
||||
char *plain; /* base64 decoded string */
|
||||
size_t plain_length; /* length of decoded base64 string */
|
||||
size_t base64_length; /* length of base64 string */
|
||||
|
||||
globals = &self->xrdp_config->cfg_globals;
|
||||
@ -379,8 +380,9 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
|
||||
{
|
||||
base64_length = g_strlen(value + BASE64PREFIX_LEN);
|
||||
plain = (char *)g_malloc(base64_length, 0);
|
||||
base64_decode(plain, value + BASE64PREFIX_LEN, base64_length);
|
||||
g_strncpy(value, plain, g_strlen(plain));
|
||||
base64_decode(value + BASE64PREFIX_LEN,
|
||||
plain, base64_length, &plain_length);
|
||||
g_strncpy(value, plain, plain_length);
|
||||
g_free(plain);
|
||||
}
|
||||
else if (g_strncmp(ASK, value, ASK_LEN) == 0)
|
||||
@ -421,7 +423,9 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
|
||||
{
|
||||
base64_length = g_strlen(value + ASK_LEN + BASE64PREFIX_LEN);
|
||||
plain = (char *)g_malloc(base64_length, 0);
|
||||
base64_decode(plain, value + ASK_LEN + BASE64PREFIX_LEN, base64_length);
|
||||
base64_decode(value + ASK_LEN + BASE64PREFIX_LEN,
|
||||
plain, base64_length, &plain_length);
|
||||
plain[plain_length] = '\0';
|
||||
g_strncpy(b->caption1, plain, 255);
|
||||
g_free(plain);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user