From d7a90c513dd34b39c1be760301cd0613b255e878 Mon Sep 17 00:00:00 2001 From: xethyrion Date: Thu, 10 Nov 2016 00:53:11 +0200 Subject: [PATCH] added ipfs support with proper base58 --- base58.c | 203 +++++++++++++++++++++++------------------------ base58.h | 59 +++++++++----- protoutils.h | 218 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 314 insertions(+), 166 deletions(-) diff --git a/base58.c b/base58.c index 394b8c6..1b17041 100644 --- a/base58.c +++ b/base58.c @@ -5,20 +5,12 @@ * under the terms of the standard MIT license. See COPYING for more details. */ -#ifndef WIN32 -#include -#else -#include -#endif - -#include -#include -#include #include +#include +#include +#include -#include "base58.h" - -bool (*b58_sha256_impl)(void *, const void *, size_t) = NULL; +static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; static const int8_t b58digits_map[] = { -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, @@ -31,11 +23,19 @@ static const int8_t b58digits_map[] = { 47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1, }; -bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) +/** + * convert a base58 encoded string into a binary array + * @param b58 the base58 encoded string + * @param base58_size the size of the encoded string + * @param bin the results buffer + * @param binszp the size of the results buffer + * @returns true(1) on success + */ +int libp2p_crypto_encoding_base58_decode(const char* b58, size_t base58_size, unsigned char** bin, size_t* binszp) { size_t binsz = *binszp; - const unsigned char *b58u = (void*)b58; - unsigned char *binu = bin; + const unsigned char* b58u = (const void*)b58; + unsigned char* binu = *bin; size_t outisz = (binsz + 3) / 4; uint32_t outi[outisz]; uint64_t t; @@ -44,157 +44,158 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) uint8_t bytesleft = binsz % 4; uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; unsigned zerocount = 0; + size_t b58sz; - if (!b58sz) - b58sz = strlen(b58); + b58sz = strlen(b58); memset(outi, 0, outisz * sizeof(*outi)); // Leading zeros, just count - for (i = 0; i < b58sz && b58u[i] == '1'; ++i) + for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i) { ++zerocount; + } - for ( ; i < b58sz; ++i) - { - if (b58u[i] & 0x80) + for (; i < b58sz; ++i) { + if (b58u[i] & 0x80) { // High-bit set on invalid digit - return false; - if (b58digits_map[b58u[i]] == -1) + return 0; + } + if (b58digits_map[b58u[i]] == -1) { // Invalid base58 digit - return false; + return 0; + } c = (unsigned)b58digits_map[b58u[i]]; - for (j = outisz; j--; ) - { + for (j = outisz; j--;) { t = ((uint64_t)outi[j]) * 58 + c; c = (t & 0x3f00000000) >> 32; outi[j] = t & 0xffffffff; } - if (c) + if (c) { // Output number too big (carry to the next int32) - return false; - if (outi[0] & zeromask) + memset(outi, 0, outisz * sizeof(*outi)); + return 0; + } + if (outi[0] & zeromask) { // Output number too big (last int32 filled too far) - return false; + memset(outi, 0, outisz * sizeof(*outi)); + return 0; + } } j = 0; switch (bytesleft) { case 3: - *(binu++) = (outi[0] & 0xff0000) >> 16; + *(binu++) = (outi[0] & 0xff0000) >> 16; case 2: - *(binu++) = (outi[0] & 0xff00) >> 8; + *(binu++) = (outi[0] & 0xff00) >> 8; case 1: - *(binu++) = (outi[0] & 0xff); + *(binu++) = (outi[0] & 0xff); ++j; default: break; } - for (; j < outisz; ++j) - { + for (; j < outisz; ++j) { *(binu++) = (outi[j] >> 0x18) & 0xff; *(binu++) = (outi[j] >> 0x10) & 0xff; - *(binu++) = (outi[j] >> 8) & 0xff; - *(binu++) = (outi[j] >> 0) & 0xff; + *(binu++) = (outi[j] >> 8) & 0xff; + *(binu++) = (outi[j] >> 0) & 0xff; } // Count canonical base58 byte count - binu = bin; - for (i = 0; i < binsz; ++i) - { - if (binu[i]) + binu = *bin; + for (i = 0; i < binsz; ++i) { + if (binu[i]) { break; + } --*binszp; } *binszp += zerocount; - return true; + memset(outi, 0, outisz * sizeof(*outi)); + return 1; } -static -bool my_dblsha256(void *hash, const void *data, size_t datasz) +/** + * encode an array of bytes into a base58 string + * @param binary_data the data to be encoded + * @param binary_data_size the size of the data to be encoded + * @param base58 the results buffer + * @param base58_size the size of the results buffer + * @returns true(1) on success + */ +//int libp2p_crypto_encoding_base58_encode(const unsigned char* binary_data, size_t binary_data_size, unsigned char* base58, size_t* base58_size) +int libp2p_crypto_encoding_base58_encode(const unsigned char* data, size_t binsz, unsigned char** b58, size_t* b58sz) { - uint8_t buf[0x20]; - return b58_sha256_impl(buf, data, datasz) && b58_sha256_impl(hash, buf, sizeof(buf)); -} - -int b58check(const void *bin, size_t binsz, const char *base58str, size_t b58sz) -{ - unsigned char buf[32]; - const uint8_t *binc = bin; - unsigned i; - if (binsz < 4) - return -4; - if (!my_dblsha256(buf, bin, binsz - 4)) - return -2; - if (memcmp(&binc[binsz - 4], buf, 4)) - return -1; - - // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) - for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) - {} // Just finding the end of zeros, nothing to do in loop - if (binc[i] == '\0' || base58str[i] == '1') - return -3; - - return binc[0]; -} - -static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - -bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) -{ - const uint8_t *bin = data; + const uint8_t* bin = data; int carry; ssize_t i, j, high, zcount = 0; size_t size; - while (zcount < binsz && !bin[zcount]) + while (zcount < (ssize_t)binsz && !bin[zcount]) { ++zcount; + } size = (binsz - zcount) * 138 / 100 + 1; uint8_t buf[size]; memset(buf, 0, size); - for (i = zcount, high = size - 1; i < binsz; ++i, high = j) - { - for (carry = bin[i], j = size - 1; (j > high) || carry; --j) - { + for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) { + for (carry = bin[i], j = size - 1; (j > high) || carry; --j) { carry += 256 * buf[j]; buf[j] = carry % 58; carry /= 58; } } - for (j = 0; j < size && !buf[j]; ++j); + for (j = 0; j < (ssize_t)size && !buf[j]; ++j) + ; - if (*b58sz <= zcount + size - j) - { + if (*b58sz <= zcount + size - j) { *b58sz = zcount + size - j + 1; - return false; + memset(buf, 0, size); + return 0; } - if (zcount) + if (zcount) { memset(b58, '1', zcount); - for (i = zcount; j < size; ++i, ++j) - b58[i] = b58digits_ordered[buf[j]]; - b58[i] = '\0'; + } + for (i = zcount; j < (ssize_t)size; ++i, ++j) { + (*b58)[i] = b58digits_ordered[buf[j]]; + } + (*b58)[i] = '\0'; *b58sz = i + 1; - return true; + memset(buf, 0, size); + return 1; } -bool b58check_enc(char *b58c, size_t *b58c_sz, uint8_t ver, const void *data, size_t datasz) -{ - uint8_t buf[1 + datasz + 0x20]; - uint8_t *hash = &buf[1 + datasz]; +/*** + * calculate the size of the binary results based on an incoming base58 string + * @param base58_string the string + * @returns the size in bytes had the string been decoded + */ +size_t libp2p_crypto_encoding_base58_decode_size(const unsigned char* base58_string) { + size_t string_length = strlen((char*)base58_string); + size_t decoded_length = 0; + size_t radix = strlen(b58digits_ordered); + double bits_per_digit = log2(radix); - buf[0] = ver; - memcpy(&buf[1], data, datasz); - if (!my_dblsha256(hash, buf, datasz + 1)) - { - *b58c_sz = 0; - return false; - } + decoded_length = floor(string_length * bits_per_digit / 8); + return decoded_length; +} + +/** + * calculate the max length in bytes of an encoding of n source bits + * @param base58_string the string + * @returns the maximum size in bytes had the string been decoded + */ +size_t libp2p_crypto_encoding_base58_decode_max_size(const unsigned char* base58_string) { + size_t string_length = strlen((char*)base58_string); + size_t decoded_length = 0; + size_t radix = strlen(b58digits_ordered); + double bits_per_digit = log2(radix); - return b58enc(b58c, b58c_sz, buf, 1 + datasz + 4); -} \ No newline at end of file + decoded_length = ceil(string_length * bits_per_digit / 8); + return decoded_length; +} diff --git a/base58.h b/base58.h index d6cd7b4..421a5a4 100644 --- a/base58.h +++ b/base58.h @@ -1,24 +1,47 @@ -#ifndef LIBBASE58_H -#define LIBBASE58_H +// +// base58.h +// libp2p_xcode +// +// Created by John Jones on 11/7/16. +// Copyright © 2016 JMJAtlanta. All rights reserved. +// -#include -#include -#include +#ifndef base58_h +#define base58_h +#include "varint.h" +/** + * convert a base58 encoded string into a binary array + * @param base58 the base58 encoded string + * @param base58_size the size of the encoded string + * @param binary_data the results buffer + * @param binary_data_size the size of the results buffer + * @returns true(1) on success + */ +int libp2p_crypto_encoding_base58_decode(const unsigned char* base58, size_t base58_size, unsigned char** binary_data, size_t *binary_data_size); -#ifdef __cplusplus -extern "C" { -#endif +/** + * encode an array of bytes into a base58 string + * @param binary_data the data to be encoded + * @param binary_data_size the size of the data to be encoded + * @param base58 the results buffer + * @param base58_size the size of the results buffer + * @returns true(1) on success + */ +int libp2p_crypto_encoding_base58_encode(const unsigned char* binary_data, size_t binary_data_size, unsigned char** base58, size_t* base58_size); -extern bool (*b58_sha256_impl)(void *, const void *, size_t); +/*** + * calculate the size of the binary results based on an incoming base58 string with no initial padding + * @param base58_string the string + * @returns the size in bytes had the string been decoded + */ +size_t libp2p_crypto_encoding_base58_decode_size(const unsigned char* base58_string); -extern bool b58tobin(void *bin, size_t *binsz, const char *b58, size_t b58sz); -extern int b58check(const void *bin, size_t binsz, const char *b58, size_t b58sz); +/** + * calculate the max length in bytes of an encoding of n source bits + * @param base58_string the string + * @returns the maximum size in bytes had the string been decoded + */ +size_t libp2p_crypto_encoding_base58_decode_max_size(const unsigned char* base58_string); -extern bool b58enc(char *b58, size_t *b58sz, const void *bin, size_t binsz); -extern bool b58check_enc(char *b58c, size_t *b58c_sz, uint8_t ver, const void *data, size_t datasz); -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file +#endif /* base58_h */ \ No newline at end of file diff --git a/protoutils.h b/protoutils.h index ae026db..ec1a972 100644 --- a/protoutils.h +++ b/protoutils.h @@ -9,8 +9,44 @@ #include "base58.h" #include "varhexutils.h" #include "protocols.h" -//IP2INT +////////////////////////////////////////////////////////// +char ASCII2bits(char ch) { + if (ch >= '0' && ch <= '9') { + return (ch - '0'); + } else if (ch >= 'a' && ch <= 'z') { + return (ch - 'a') + 10; + } else if (ch >= 'A' && ch <= 'Z') { + return (ch - 'A') + 10; + } + return 0; // fail +} +void hex2bin (char *dst, char *src, int len) +{ + while (len--) { + *dst = ASCII2bits(*src++) << 4; // higher bits + *dst++ |= ASCII2bits(*src++); // lower bits + } +} + +char bits2ASCII(char b) { + if (b >= 0 && b < 10) { + return (b + '0'); + } else if (b >= 10 && b <= 15) { + return (b - 10 + 'a'); + } + return 0; // fail +} + +void bin2hex (char *dst, char *src, int len) +{ + while (len--) { + *dst++ = bits2ASCII((*src >> 4) & 0xf); // higher bits + *dst++ = bits2ASCII(*src++ & 0xf); // lower bits + } + *dst = '\0'; +} +////////////////////////////////////////////////////////// //IPv4 VALIDATOR #define DELIM "." @@ -196,7 +232,6 @@ int is_valid_ipv6(char *str) return(err==0); } -///Still in work uint64_t ip2int(char * ipconvertint) { uint64_t final_result =0; @@ -289,55 +324,104 @@ int bytes_to_string(char * resultzx, uint8_t * catx,int xbsize) struct protocol * PID; PID = NULL; PID = proto_with_deccode(Hex_To_Int(pid)); - lastpos = lastpos+2; - char address[(PID->size/4)+1]; - bzero(address,(PID->size/4)+1); - address[(PID->size/4)]='\0'; - int x=0; - //printf("\nHEX TO DECODE: %s\n",hex); - for(int i = lastpos;i<(PID->size/4)+lastpos;i++) + if(strcmp(PID->name,"ipfs")!=0) { - address[x] = hex[i]; - //printf("HEX[%d]=%c\n",i,hex[i]); - x++; - } -//////////Stage 3 Process it back to string - //printf("Protocol: %s\n", PID->name); - //printf("Address : %s\n", address); - lastpos= lastpos+(PID->size/4); - //printf("lastpos: %d",lastpos); - -//////////Address: - //Keeping Valgrind happy - char name[30]; - bzero(name,30); - strcpy(name, PID->name); - // - strcat(resultzx, "/"); - strcat(resultzx, name); - strcat(resultzx, "/"); - if(strcmp(name, "ip4")==0) - { - strcat(resultzx,int2ip(Hex_To_Int(address))); - } - else if(strcmp(name, "tcp")==0) - { - char a[5]; + lastpos = lastpos+2; + char address[(PID->size/4)+1]; + bzero(address,(PID->size/4)+1); + address[(PID->size/4)]='\0'; + int x=0; + //printf("\nHEX TO DECODE: %s\n",hex); + for(int i = lastpos;i<(PID->size/4)+lastpos;i++) + { + address[x] = hex[i]; + //printf("HEX[%d]=%c\n",i,hex[i]); + x++; + } + //////////Stage 3 Process it back to string + //printf("Protocol: %s\n", PID->name); + //printf("Address : %s\n", address); + lastpos= lastpos+(PID->size/4); + //printf("lastpos: %d",lastpos); + + //////////Address: + //Keeping Valgrind happy + char name[30]; + bzero(name,30); + strcpy(name, PID->name); + // + strcat(resultzx, "/"); + strcat(resultzx, name); + strcat(resultzx, "/"); + if(strcmp(name, "ip4")==0) + { + strcat(resultzx,int2ip(Hex_To_Int(address))); + } + else if(strcmp(name, "tcp")==0) + { + char a[5]; + sprintf(a,"%lu",Hex_To_Int(address)); + strcat(resultzx,a); + } + else if(strcmp(name, "udp")==0) + { + char a[5]; sprintf(a,"%lu",Hex_To_Int(address)); strcat(resultzx,a); + } + //printf("Address(hex):%s\n",address); + //printf("TESTING: %s\n",resultzx); + /////////////Done processing this, move to next if there is more. + if(lastposname); + strcat(resultzx, "/"); + strcat(resultzx, rezultat); } } strcat(resultzx, "/"); @@ -475,8 +559,48 @@ char * address_string_to_bytes(struct protocol * xx, char * abc,size_t getsznow) } case 42://IPFS - !!! { + - return "ERR"; + char * x_data = NULL; + x_data = abc; + size_t x_data_length = strlen(x_data); + size_t result_buffer_length = libp2p_crypto_encoding_base58_decode_max_size(x_data); + unsigned char result_buffer[result_buffer_length]; + unsigned char* ptr_to_result = result_buffer; + memset(result_buffer, 0, result_buffer_length); + // now get the decoded address + int return_value = libp2p_crypto_encoding_base58_decode(x_data, x_data_length, &ptr_to_result, &result_buffer_length); + if (return_value == 0) + { + return "ERR"; + } + // throw everything in a hex string so we can debug the results + static char returning_result[300]; + bzero(returning_result,300); + char ADDR_ENCODED[300]; + bzero(ADDR_ENCODED,300); + int ilen = 0; + bzero(returning_result,300); + for(int i = 0; i < result_buffer_length; i++) + { + // get the char so we can see it in the debugger + unsigned char c = ptr_to_result[i]; + char miu[3]; + bzero(miu, 3); + miu[3] = '\0'; + sprintf(miu,"%02x", c); + + strcat(ADDR_ENCODED, miu); + } + ilen = strlen(ADDR_ENCODED); + char prefixed[3]; + strcpy(prefixed,Num_To_HexVar_32(ilen)); + prefixed[3] = '\0'; + strcat(returning_result, prefixed); + strcat(returning_result, ADDR_ENCODED); + //printf("ADDRESS: %s\nSIZEADDR: %d\n",ADDR_ENCODED,ilen); + //printf("NOW DECODED VARINT: %d", HexVar_To_Num_32(prefixed)); + return returning_result; break; } case 480://http