paulo@0: /* paulo@0: * $Id: base32.c,v 1.2 2004/03/27 00:34:25 mkern Exp $ paulo@0: * paulo@0: * Copyright (C) 2003-2004 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: #include "encoding/base32.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* base32 alphabet */ paulo@0: static const char *ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; paulo@0: paulo@0: static uint8_t base32_bits[256] = { 0 }; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* convert 5 bytes to 8 characters in base 32 */ paulo@0: static void bin_to_base32 (const uint8_t *in, char *out) paulo@0: { paulo@0: out[0] = ALPHA[(in[0] ) >> 3]; paulo@0: out[1] = ALPHA[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6]; paulo@0: out[2] = ALPHA[(in[1] & 0x3e) >> 1]; paulo@0: out[3] = ALPHA[(in[1] & 0x01) << 4 | (in[2] & 0xf0) >> 4]; paulo@0: out[4] = ALPHA[(in[2] & 0x0f) << 1 | (in[3] & 0x80) >> 7]; paulo@0: out[5] = ALPHA[(in[3] & 0x7c) >> 2]; paulo@0: out[6] = ALPHA[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5]; paulo@0: out[7] = ALPHA[(in[4] & 0x1f)]; paulo@0: } paulo@0: paulo@0: /* convert 8 characters in base 32 to 5 bytes */ paulo@0: static void base32_to_bin (const char *base32, uint8_t *out) paulo@0: { paulo@0: const unsigned char *in = base32; paulo@0: const uint8_t *bits = base32_bits; paulo@0: paulo@0: out[0] = ((bits[in[0]] ) << 3) | (bits[in[1]] & 0x1C) >> 2; paulo@0: out[1] = ((bits[in[1]] & 0x03) << 6) | (bits[in[2]] ) << 1 paulo@0: | (bits[in[3]] & 0x10) >> 4; paulo@0: out[2] = ((bits[in[3]] & 0x0F) << 4) | (bits[in[4]] & 0x1E) >> 1; paulo@0: out[3] = ((bits[in[4]] & 0x01) << 7) | (bits[in[5]] ) << 2 paulo@0: | (bits[in[6]] & 0x18) >> 3; paulo@0: out[4] = ((bits[in[6]] & 0x07) << 5) | (bits[in[7]]); paulo@0: } paulo@0: paulo@0: static void init_base32_bits (void) paulo@0: { paulo@0: int i; paulo@0: char *pos; paulo@0: paulo@0: /* set the each char's corresponding bit value in a lookup table */ paulo@0: for (i = 0; i < sizeof(base32_bits); i++) paulo@0: { paulo@0: if ((pos = strchr (ALPHA, toupper (i)))) paulo@0: base32_bits[i] = pos - ALPHA; paulo@0: } paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: BOOL gt_base32_valid (const char *base32, size_t len) paulo@0: { paulo@0: while (len > 0) paulo@0: { paulo@0: unsigned char c = toupper (*base32); paulo@0: paulo@0: if (!((c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7'))) paulo@0: break; paulo@0: paulo@0: base32++; paulo@0: len--; paulo@0: } paulo@0: paulo@0: return (len > 0 ? FALSE : TRUE); paulo@0: } paulo@0: paulo@0: void gt_base32_encode (const uint8_t *in, size_t in_len, paulo@0: char *out, size_t out_len) paulo@0: { paulo@0: assert (in_len == 20); paulo@0: assert (out_len == 32); paulo@0: paulo@0: bin_to_base32 (in, out); paulo@0: bin_to_base32 (in + 5, out + 8); paulo@0: bin_to_base32 (in + 10, out + 16); paulo@0: bin_to_base32 (in + 15, out + 24); paulo@0: } paulo@0: paulo@0: void gt_base32_decode (const char *in, size_t in_len, paulo@0: uint8_t *out, size_t out_len) paulo@0: { paulo@0: /* initialize lookup table */ paulo@0: if (base32_bits['b'] == 0) paulo@0: init_base32_bits (); paulo@0: paulo@0: assert (in_len == 32); paulo@0: assert (out_len == 20); paulo@0: paulo@0: base32_to_bin (in , out ); paulo@0: base32_to_bin (in + 8, out + 5); paulo@0: base32_to_bin (in + 16, out + 10); paulo@0: base32_to_bin (in + 24, out + 15); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: #if 0 paulo@0: static void test_str (const char *test) paulo@0: { paulo@0: unsigned char bin[20]; paulo@0: char hash[33]; paulo@0: paulo@0: hash[32] = 0; paulo@0: paulo@0: gt_base32_decode (test, strlen (test), bin, sizeof(bin)); paulo@0: gt_base32_encode (bin, sizeof(bin), hash, sizeof(hash) - 1); paulo@0: paulo@0: if (!gt_base32_valid (hash, 32)) paulo@0: abort (); paulo@0: paulo@0: if (strcmp (hash, test) != 0) paulo@0: { paulo@0: printf ("\ntest=%s(%d)\nhash=%s(%d)\n", test, paulo@0: strlen (test), hash, strlen (hash)); paulo@0: fflush (stdout); paulo@0: } paulo@0: } paulo@0: paulo@0: int main (int argc, char **argv) paulo@0: { paulo@0: int i, j; paulo@0: char str[33]; paulo@0: int len = strlen (ALPHA); paulo@0: paulo@0: str[sizeof (str) - 1] = 0; paulo@0: paulo@0: test_str (ALPHA); paulo@0: paulo@0: for (i = 1; i <= 100000; i++) paulo@0: { paulo@0: for (j = 0; j < 32; j++) paulo@0: str[j] = ALPHA[rand () % len]; paulo@0: paulo@0: if (!gt_base32_valid (str, 32)) paulo@0: abort (); paulo@0: paulo@0: printf ("%i\r", i); paulo@0: fflush (stdout); paulo@0: test_str (str); paulo@0: usleep (1); paulo@0: } paulo@0: paulo@0: printf ("\n"); paulo@0: return 0; paulo@0: } paulo@0: #endif