/* 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 #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(); }