211 lines
5.4 KiB
C
211 lines
5.4 KiB
C
|
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||
|
* Use of this source code is governed by a BSD-style license that can be
|
||
|
* found in the LICENSE file.
|
||
|
*
|
||
|
* Test Base-32 encoding/decoding
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include "common.h"
|
||
|
#include "base32.h"
|
||
|
#include "test_util.h"
|
||
|
#include "util.h"
|
||
|
|
||
|
static int test_crc5(void)
|
||
|
{
|
||
|
uint32_t seen;
|
||
|
int i, j, c;
|
||
|
int errors = 0;
|
||
|
|
||
|
/*
|
||
|
* For every current CRC value and symbol, new CRC value is unique.
|
||
|
* This guarantees a single-character typo will be detected.
|
||
|
*/
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
seen = 0;
|
||
|
for (j = 0; j < 32; j++)
|
||
|
seen |= 1 << crc5_sym(j, i);
|
||
|
TEST_ASSERT(seen == 0xffffffff);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Do the same in the opposite order, to make sure a subsequent
|
||
|
* character doesn't obscure a previous typo.
|
||
|
*/
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
seen = 0;
|
||
|
for (j = 0; j < 32; j++)
|
||
|
seen |= 1 << crc5_sym(i, j);
|
||
|
TEST_ASSERT(seen == 0xffffffff);
|
||
|
}
|
||
|
|
||
|
/* Transposing different symbols generates distinct CRCs */
|
||
|
for (c = 0; c < 32; c++) {
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
for (j = i + 1; j < 32; j++) {
|
||
|
if (crc5_sym(j, crc5_sym(i, c)) ==
|
||
|
crc5_sym(i, crc5_sym(j, c)))
|
||
|
errors++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
TEST_ASSERT(errors == 0);
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static int enctest(const void *src, int srcbits, int crc_every,
|
||
|
const char *enc)
|
||
|
{
|
||
|
char dest[32];
|
||
|
|
||
|
if (base32_encode(dest, sizeof(dest), src, srcbits, crc_every))
|
||
|
return -1;
|
||
|
if (strlen(dest) != strlen(enc) || strncmp(dest, enc, strlen(dest))) {
|
||
|
fprintf(stderr, "expected encode: \"%s\"\n", enc);
|
||
|
fprintf(stderr, "got encode: \"%s\"\n", dest);
|
||
|
return -2;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#define ENCTEST(a, b, c, d) TEST_ASSERT(enctest(a, b, c, d) == 0)
|
||
|
|
||
|
static int test_encode(void)
|
||
|
{
|
||
|
const uint8_t src1[5] = {0xff, 0x00, 0xff, 0x00, 0xff};
|
||
|
char enc[32];
|
||
|
|
||
|
/* Test for enough space; error produces null string */
|
||
|
*enc = 1;
|
||
|
TEST_ASSERT(base32_encode(enc, 3, src1, 15, 0) == EC_ERROR_INVAL);
|
||
|
TEST_ASSERT(*enc == 0);
|
||
|
|
||
|
/* Empty source */
|
||
|
ENCTEST("\x00", 0, 0, "");
|
||
|
|
||
|
/* Single symbol uses top 5 bits */
|
||
|
ENCTEST("\x07", 5, 0, "A");
|
||
|
ENCTEST("\xb8", 5, 0, "Z");
|
||
|
ENCTEST("\xc0", 5, 0, "2");
|
||
|
ENCTEST("\xf8", 5, 0, "9");
|
||
|
|
||
|
/* Multiples of 5 bits use top bits */
|
||
|
ENCTEST("\x08\x86", 10, 0, "BC");
|
||
|
ENCTEST("\x08\x86", 15, 0, "BCD");
|
||
|
|
||
|
/* Multiples of 8 bits pad with 0 bits */
|
||
|
ENCTEST("\xff", 8, 0, "96");
|
||
|
ENCTEST("\x08\x87", 16, 0, "BCDS");
|
||
|
|
||
|
/* Multiples of 40 bits use all the bits */
|
||
|
ENCTEST("\xff\x00\xff\x00\xff", 40, 0, "96AR8AH9");
|
||
|
|
||
|
/* CRC requires exact multiple of symbol count */
|
||
|
ENCTEST("\xff\x00\xff\x00\xff", 40, 4, "96ARU8AH9D");
|
||
|
ENCTEST("\xff\x00\xff\x00\xff", 40, 8, "96AR8AH9L");
|
||
|
TEST_ASSERT(
|
||
|
base32_encode(enc, 16, (uint8_t *)"\xff\x00\xff\x00\xff", 40, 6)
|
||
|
== EC_ERROR_INVAL);
|
||
|
/* But what matters is symbol count, not bit count */
|
||
|
ENCTEST("\xff\x00\xff\x00\xfe", 39, 4, "96ARU8AH8P");
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static int cmpbytes(const uint8_t *expect, const uint8_t *got, int len,
|
||
|
const char *desc)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if (!memcmp(expect, got, len))
|
||
|
return 0;
|
||
|
|
||
|
fprintf(stderr, "expected %s:", desc);
|
||
|
for (i = 0; i < len; i++)
|
||
|
fprintf(stderr, " %02x", expect[i]);
|
||
|
fprintf(stderr, "\ngot %s: ", desc);
|
||
|
for (i = 0; i < len; i++)
|
||
|
fprintf(stderr, " %02x", got[i]);
|
||
|
fprintf(stderr, "\n");
|
||
|
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
static int dectest(const void *dec, int decbits, int crc_every, const char *enc)
|
||
|
{
|
||
|
uint8_t dest[32];
|
||
|
int destbits = decbits > 0 ? decbits : sizeof(dest) * 8;
|
||
|
int wantbits = decbits > 0 ? decbits : 5 * strlen(enc);
|
||
|
int gotbits = base32_decode(dest, destbits, enc, crc_every);
|
||
|
|
||
|
TEST_ASSERT(gotbits == wantbits);
|
||
|
if (gotbits != wantbits)
|
||
|
return -1;
|
||
|
return cmpbytes(dec, dest, (decbits + 7) / 8, "decode");
|
||
|
}
|
||
|
|
||
|
#define DECTEST(a, b, c, d) TEST_ASSERT(dectest(a, b, c, d) == 0)
|
||
|
|
||
|
static int test_decode(void)
|
||
|
{
|
||
|
uint8_t dec[32];
|
||
|
|
||
|
/* Decode tests, dest-limited */
|
||
|
DECTEST("\xf8", 5, 0, "97");
|
||
|
DECTEST("\x08", 5, 0, "BCDS");
|
||
|
DECTEST("\x08\x80", 10, 0, "BCDS");
|
||
|
DECTEST("\x08\x86", 15, 0, "BCDS");
|
||
|
DECTEST("\xff", 8, 0, "96");
|
||
|
DECTEST("\x08\x87", 16, 0, "BCDS");
|
||
|
DECTEST("\xff\x00\xff\x00\xff", 40, 0, "96AR8AH9");
|
||
|
DECTEST("\xff\x00\xff\x00\xfe", 39, 4, "96ARU8AH8P");
|
||
|
|
||
|
/* Decode ignores whitespace and dashes */
|
||
|
DECTEST("\xff\x00\xff\x00\xff", 40, 0, " 96\tA-R\r8A H9\n");
|
||
|
|
||
|
/* Invalid symbol fails */
|
||
|
TEST_ASSERT(base32_decode(dec, 16, "AI", 0) == -1);
|
||
|
|
||
|
/* If dest buffer is big, use all the source bits */
|
||
|
DECTEST("", 0, 0, "");
|
||
|
DECTEST("\xf8", 0, 0, "9");
|
||
|
DECTEST("\x07\xc0", 0, 0, "A9");
|
||
|
DECTEST("\x00\x3e", 0, 0, "AA9");
|
||
|
DECTEST("\x00\x01\xf0", 0, 0, "AAA9");
|
||
|
DECTEST("\xff\x00\xff\x00\xff", 0, 0, "96AR8AH9");
|
||
|
|
||
|
/* Decode always overwrites destination */
|
||
|
memset(dec, 0xff, sizeof(dec));
|
||
|
DECTEST("\x00\x00\x00\x00\x00", 0, 0, "AAAAAAAA");
|
||
|
memset(dec, 0x00, sizeof(dec));
|
||
|
DECTEST("\xff\xff\xff\xff\xff", 0, 0, "99999999");
|
||
|
|
||
|
/* Good CRCs */
|
||
|
DECTEST("\xff\x00\xff\x00\xff", 40, 4, "96ARU8AH9D");
|
||
|
DECTEST("\xff\x00\xff\x00\xff", 40, 8, "96AR8AH9L");
|
||
|
|
||
|
/* CRC requires exact multiple of symbol count */
|
||
|
TEST_ASSERT(base32_decode(dec, 40, "96ARL8AH9", 4) == -1);
|
||
|
/* But what matters is symbol count, not bit count */
|
||
|
DECTEST("\xff\x00\xff\x00\xfe", 39, 4, "96ARU8AH8P");
|
||
|
|
||
|
/* Detect errors in data, CRC, and transposition */
|
||
|
TEST_ASSERT(base32_decode(dec, 40, "96AQL", 4) == -1);
|
||
|
TEST_ASSERT(base32_decode(dec, 40, "96ARM", 4) == -1);
|
||
|
TEST_ASSERT(base32_decode(dec, 40, "96RAL", 4) == -1);
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
void run_test(void)
|
||
|
{
|
||
|
test_reset();
|
||
|
|
||
|
RUN_TEST(test_crc5);
|
||
|
RUN_TEST(test_encode);
|
||
|
RUN_TEST(test_decode);
|
||
|
|
||
|
test_print_result();
|
||
|
}
|