From d79b3436609eb619247a8a682acf1fdd5e4d93fa Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 19 Mar 2012 10:17:48 +0000 Subject: adding API for short (256-bit) hash codes --- src/datastore/datastore.h | 4 +- src/exit/exit.h | 6 +- src/fs/gnunet-service-fs.h | 2 +- src/include/block_dns.h | 2 +- src/include/gnunet_common.h | 8 +- src/include/gnunet_crypto_lib.h | 99 ++++++++++++++++++- src/include/gnunet_strings_lib.h | 4 +- src/util/crypto_hash.c | 202 ++++++++++++++++++++++----------------- src/util/gnunet-rsa.c | 18 ++++ src/util/strings.c | 16 +++- src/vpn/vpn.h | 2 +- 11 files changed, 254 insertions(+), 109 deletions(-) (limited to 'src') diff --git a/src/datastore/datastore.h b/src/datastore/datastore.h index 1126027f8..c8b2c722b 100644 --- a/src/datastore/datastore.h +++ b/src/datastore/datastore.h @@ -130,7 +130,7 @@ struct GetMessage * Desired key (optional). Check the "size" of the * header to see if the key is actually present. */ - GNUNET_HashCode key GNUNET_PACKED; + GNUNET_HashCode key; }; @@ -253,7 +253,7 @@ struct DataMessage /** * Key under which the item can be found. */ - GNUNET_HashCode key GNUNET_PACKED; + GNUNET_HashCode key; }; GNUNET_NETWORK_STRUCT_END diff --git a/src/exit/exit.h b/src/exit/exit.h index dcc50f1b3..90df26d7d 100644 --- a/src/exit/exit.h +++ b/src/exit/exit.h @@ -49,7 +49,7 @@ struct GNUNET_EXIT_TcpServiceStartMessage /** * Identification for the desired service. */ - GNUNET_HashCode service_descriptor GNUNET_PACKED; + GNUNET_HashCode service_descriptor; /** * Skeleton of the TCP header to send. Port numbers are to @@ -142,7 +142,7 @@ struct GNUNET_EXIT_UdpServiceMessage /** * Identification for the desired service. */ - GNUNET_HashCode service_descriptor GNUNET_PACKED; + GNUNET_HashCode service_descriptor; /* followed by UDP payload */ }; @@ -230,7 +230,7 @@ struct GNUNET_EXIT_IcmpServiceMessage /** * Identification for the desired service. */ - GNUNET_HashCode service_descriptor GNUNET_PACKED; + GNUNET_HashCode service_descriptor; /** * ICMP header to use. diff --git a/src/fs/gnunet-service-fs.h b/src/fs/gnunet-service-fs.h index 5ea73ee28..0c796bf9c 100644 --- a/src/fs/gnunet-service-fs.h +++ b/src/fs/gnunet-service-fs.h @@ -129,7 +129,7 @@ struct GetMessage * Hashcodes of the file(s) we're looking for. * Details depend on the query type. */ - GNUNET_HashCode query GNUNET_PACKED; + GNUNET_HashCode query; /* this is followed by hash codes as specified in the "hash_bitmap"; * after that, an optional bloomfilter (with bits set for replies diff --git a/src/include/block_dns.h b/src/include/block_dns.h index 4c2f1a3f3..e047779c5 100644 --- a/src/include/block_dns.h +++ b/src/include/block_dns.h @@ -64,7 +64,7 @@ struct GNUNET_DNS_Record * The descriptor for the service * (a peer may provide more than one service) */ - GNUNET_HashCode service_descriptor GNUNET_PACKED; + GNUNET_HashCode service_descriptor; /** * When does this record expire? diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h index f26d6bc98..141df1a5d 100644 --- a/src/include/gnunet_common.h +++ b/src/include/gnunet_common.h @@ -208,27 +208,25 @@ struct GNUNET_MessageHeader uint16_t type GNUNET_PACKED; }; -GNUNET_NETWORK_STRUCT_END + /** * @brief 512-bit hashcode */ -typedef struct +typedef struct GNUNET_HashCode { uint32_t bits[512 / 8 / sizeof (uint32_t)]; /* = 16 */ } GNUNET_HashCode; -GNUNET_NETWORK_STRUCT_BEGIN - /** * The identity of the host (basically the SHA-512 hashcode of * it's public key). */ struct GNUNET_PeerIdentity { - GNUNET_HashCode hashPubKey GNUNET_PACKED; + GNUNET_HashCode hashPubKey; }; GNUNET_NETWORK_STRUCT_END diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h index 6224546b9..8270c89dd 100644 --- a/src/include/gnunet_crypto_lib.h +++ b/src/include/gnunet_crypto_lib.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Christian Grothoff (and other contributing authors) + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -138,6 +138,26 @@ struct GNUNET_CRYPTO_HashAsciiEncoded + +/** + * @brief 256-bit hashcode + */ +struct GNUNET_CRYPTO_ShortHashCode +{ + uint32_t bits[256 / 8 / sizeof (uint32_t)]; /* = 8 */ +}; + + +/** + * @brief 0-terminated ASCII encoding of a 'struct GNUNET_ShortHashCode'. + */ +struct GNUNET_CRYPTO_ShortHashAsciiEncoded +{ + unsigned char short_encoding[53]; +}; + + + /** * @brief an RSA signature */ @@ -433,7 +453,19 @@ GNUNET_CRYPTO_hash_to_enc (const GNUNET_HashCode * block, /** - * Convert ASCII encoding back to GNUNET_CRYPTO_hash + * Convert short hash to ASCII encoding. + * + * @param block the hash code + * @param result where to store the encoding (struct GNUNET_CRYPTO_ShortHashAsciiEncoded can be + * safely cast to char*, a '\\0' termination is set). + */ +void +GNUNET_CRYPTO_short_hash_to_enc (const struct GNUNET_CRYPTO_ShortHashCode * block, + struct GNUNET_CRYPTO_ShortHashAsciiEncoded *result); + + +/** + * Convert ASCII encoding back to a 'GNUNET_HashCode' * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) @@ -446,15 +478,40 @@ GNUNET_CRYPTO_hash_from_string2 (const char *enc, size_t enclen, /** - * Convert ASCII encoding back to GNUNET_CRYPTO_hash + * Convert ASCII encoding back to a 'struct GNUNET_CRYPTO_ShortHash' + * * @param enc the encoding + * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) * @param result where to store the GNUNET_CRYPTO_hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ +int +GNUNET_CRYPTO_short_hash_from_string2 (const char *enc, size_t enclen, + struct GNUNET_CRYPTO_ShortHashCode * result); + + +/** + * Convert ASCII encoding back to GNUNET_HashCode + * + * @param enc the encoding + * @param result where to store the hash code + * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding + */ #define GNUNET_CRYPTO_hash_from_string(enc, result) \ GNUNET_CRYPTO_hash_from_string2 (enc, strlen(enc), result) +/** + * Convert ASCII encoding back to a 'struct GNUNET_CRYPTO_ShortHash' + * + * @param enc the encoding + * @param result where to store the GNUNET_CRYPTO_ShortHash + * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding + */ +#define GNUNET_CRYPTO_short_hash_from_string(enc, result) \ + GNUNET_CRYPTO_short_hash_from_string2 (enc, strlen(enc), result) + + /** * Compute the distance between 2 hashcodes. * The computation must be fast, not involve @@ -482,6 +539,42 @@ void GNUNET_CRYPTO_hash (const void *block, size_t size, GNUNET_HashCode * ret); +/** + * Compute short (256-bit) hash of a given block. + * + * @param block the data to hash + * @param size size of the block + * @param ret pointer to where to write the hashcode + */ +void +GNUNET_CRYPTO_short_hash (const void *block, size_t size, + struct GNUNET_CRYPTO_ShortHashCode * ret); + + +/** + * Double short (256-bit) hash to create a long hash. + * + * @param sh short hash to double + * @param dh where to store the (doubled) long hash (not really a hash) + */ +void +GNUNET_CRYPTO_short_hash_double (const struct GNUNET_CRYPTO_ShortHashCode *sh, + struct GNUNET_HashCode *dh); + + +/** + * Truncate doubled short hash back to a short hash. + * + * @param lh doubled short hash to reduce again + * @param sh where to store the short hash + * @return GNUNET_OK on success, GNUNET_SYSERR if this was not a + * doubled short hash + */ +int +GNUNET_CRYPTO_short_hash_from_truncation (const struct GNUNET_HashCode *dh, + struct GNUNET_CRYPTO_ShortHashCode *sh); + + /** * Calculate HMAC of a message (RFC 2104) * diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h index 997ca7dd9..55b96fc2c 100644 --- a/src/include/gnunet_strings_lib.h +++ b/src/include/gnunet_strings_lib.h @@ -230,8 +230,8 @@ GNUNET_STRINGS_get_short_name (const char *filename); * @return pointer to the next byte in 'out' or NULL on error. */ char * -GNUNET_STRINGS_data_to_string (unsigned char *data, size_t size, - char *out, size_t out_size); +GNUNET_STRINGS_data_to_string (const unsigned char *data, size_t size, + char *out, size_t out_size); /** diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c index f89639045..aaf5175d7 100644 --- a/src/util/crypto_hash.c +++ b/src/util/crypto_hash.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -34,6 +34,7 @@ #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_disk_lib.h" +#include "gnunet_strings_lib.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) @@ -54,6 +55,21 @@ GNUNET_CRYPTO_hash (const void *block, size_t size, GNUNET_HashCode * ret) } +/** + * Compute short (256-bit) hash of a given block. + * + * @param block the data to GNUNET_CRYPTO_hash, length is given as a second argument + * @param size the length of the data to GNUNET_CRYPTO_hash + * @param ret pointer to where to write the hashcode + */ +void +GNUNET_CRYPTO_short_hash (const void *block, size_t size, + struct GNUNET_CRYPTO_ShortHashCode * ret) +{ + gcry_md_hash_buffer (GCRY_MD_SHA256, ret, block, size); +} + + /** * Context used when hashing a file. */ @@ -243,24 +259,6 @@ GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc) /* ***************** binary-ASCII encoding *************** */ -/* FIXME: should use GNUNET_STRINGS_data_to_string and strings_to_data below!!! */ - -/** - * Get the numeric value corresponding to a character. - * - * @param a a character - * @return corresponding numeric value - */ -static unsigned int -getValue__ (unsigned char a) -{ - if ((a >= '0') && (a <= '9')) - return a - '0'; - if ((a >= 'A') && (a <= 'V')) - return (a - 'A' + 10); - return -1; -} - /** * Convert GNUNET_CRYPTO_hash to ASCII encoding. The ASCII encoding is rather @@ -277,88 +275,32 @@ void GNUNET_CRYPTO_hash_to_enc (const GNUNET_HashCode * block, struct GNUNET_CRYPTO_HashAsciiEncoded *result) { - /** - * 32 characters for encoding (GNUNET_CRYPTO_hash => 32 characters) - */ - static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; - unsigned int wpos; - unsigned int rpos; - unsigned int bits; - unsigned int vbit; - - GNUNET_assert (block != NULL); - GNUNET_assert (result != NULL); - vbit = 0; - wpos = 0; - rpos = 0; - bits = 0; - while ((rpos < sizeof (GNUNET_HashCode)) || (vbit > 0)) - { - if ((rpos < sizeof (GNUNET_HashCode)) && (vbit < 5)) - { - bits = (bits << 8) | ((unsigned char *) block)[rpos++]; /* eat 8 more bits */ - vbit += 8; - } - if (vbit < 5) - { - bits <<= (5 - vbit); /* zero-padding */ - GNUNET_assert (vbit == 2); /* padding by 3: 512+3 mod 5 == 0 */ - vbit = 5; - } - GNUNET_assert (wpos < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); - result->encoding[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; - vbit -= 5; - } - GNUNET_assert (wpos == sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); - GNUNET_assert (vbit == 0); - result->encoding[wpos] = '\0'; + char *np; + + np = GNUNET_STRINGS_data_to_string ((const unsigned char *) block, + sizeof (struct GNUNET_HashCode), + (char*) result, + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); + GNUNET_assert (NULL != np); + *np = '\0'; } /** - * Convert ASCII encoding back to GNUNET_CRYPTO_hash + * Convert ASCII encoding back to hash code. * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) - * @param result where to store the GNUNET_CRYPTO_hash code + * @param result where to store the hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ int GNUNET_CRYPTO_hash_from_string2 (const char *enc, size_t enclen, GNUNET_HashCode * result) { - unsigned int rpos; - unsigned int wpos; - unsigned int bits; - unsigned int vbit; - int ret; - - if (enclen != sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1) - return GNUNET_SYSERR; - - vbit = 2; /* padding! */ - wpos = sizeof (GNUNET_HashCode); - rpos = sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1; - bits = (ret = getValue__ (enc[--rpos])) >> 3; - if (-1 == ret) - return GNUNET_SYSERR; - while (wpos > 0) - { - GNUNET_assert (rpos > 0); - bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits; - if (-1 == ret) - return GNUNET_SYSERR; - vbit += 5; - if (vbit >= 8) - { - ((unsigned char *) result)[--wpos] = (unsigned char) bits; - bits >>= 8; - vbit -= 8; - } - } - GNUNET_assert (rpos == 0); - GNUNET_assert (vbit == 0); - return GNUNET_OK; + return GNUNET_STRINGS_string_to_data (enc, enclen, + (unsigned char*) result, + sizeof (struct GNUNET_HashCode)); } @@ -645,4 +587,88 @@ GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key, } + +/** + * Double short (256-bit) hash to create a long hash. + * + * @param sh short hash to double + * @param dh where to store the (doubled) long hash (not really a hash) + */ +void +GNUNET_CRYPTO_short_hash_double (const struct GNUNET_CRYPTO_ShortHashCode *sh, + struct GNUNET_HashCode *dh) +{ + char *ptr; + + ptr = (char*) dh; + memcpy (ptr, sh, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); + memcpy (&ptr[sizeof (struct GNUNET_CRYPTO_ShortHashCode)], sh, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); +} + + +/** + * Truncate doubled short hash back to a short hash. + * + * @param lh doubled short hash to reduce again + * @param sh where to store the short hash + * @return GNUNET_OK on success, GNUNET_SYSERR if this was not a + * doubled short hash + */ +int +GNUNET_CRYPTO_short_hash_from_truncation (const struct GNUNET_HashCode *dh, + struct GNUNET_CRYPTO_ShortHashCode *sh) +{ + const struct GNUNET_CRYPTO_ShortHashCode *s; + + s = (const struct GNUNET_CRYPTO_ShortHashCode *) dh; + if (0 != memcmp (&s[0], + &s[1], + sizeof (struct GNUNET_CRYPTO_ShortHashCode))) + return GNUNET_SYSERR; + *sh = *s; + return GNUNET_OK; +} + + +/** + * Convert ASCII encoding back to a 'struct GNUNET_CRYPTO_ShortHash' + * + * @param enc the encoding + * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) + * @param result where to store the GNUNET_CRYPTO_hash code + * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding + */ +int +GNUNET_CRYPTO_short_hash_from_string2 (const char *enc, size_t enclen, + struct GNUNET_CRYPTO_ShortHashCode * result) +{ + return GNUNET_STRINGS_string_to_data (enc, enclen, + (unsigned char*) result, + sizeof (struct GNUNET_CRYPTO_ShortHashCode)); +} + + +/** + * Convert short hash to ASCII encoding. + * + * @param block the hash code + * @param result where to store the encoding (struct GNUNET_CRYPTO_ShortHashAsciiEncoded can be + * safely cast to char*, a '\\0' termination is set). + */ +void +GNUNET_CRYPTO_short_hash_to_enc (const struct GNUNET_CRYPTO_ShortHashCode * block, + struct GNUNET_CRYPTO_ShortHashAsciiEncoded *result) +{ + char *np; + + np = GNUNET_STRINGS_data_to_string ((const unsigned char *) block, + sizeof (struct GNUNET_CRYPTO_ShortHashCode), + (char*) result, + sizeof (struct GNUNET_CRYPTO_ShortHashAsciiEncoded) - 1); + GNUNET_assert (NULL != np); + *np = '\0'; +} + + + /* end of crypto_hash.c */ diff --git a/src/util/gnunet-rsa.c b/src/util/gnunet-rsa.c index bfd854e65..f3cd83a8b 100644 --- a/src/util/gnunet-rsa.c +++ b/src/util/gnunet-rsa.c @@ -37,6 +37,11 @@ static int print_public_key; */ static int print_peer_identity; +/** + * Flag for printing short hash of public key. + */ +static int print_short_identity; + /** * Main function that will be run by the scheduler. @@ -78,6 +83,16 @@ run (void *cls, char *const *args, const char *cfgfile, GNUNET_CRYPTO_hash_to_enc (&pid.hashPubKey, &enc); fprintf (stdout, "%s\n", enc.encoding); } + if (print_short_identity) + { + struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc; + struct GNUNET_CRYPTO_ShortHashCode sh; + + GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); + GNUNET_CRYPTO_short_hash (&pub, sizeof (pub), &sh); + GNUNET_CRYPTO_short_hash_to_enc (&sh, &enc); + fprintf (stdout, "%s\n", enc.short_encoding); + } GNUNET_CRYPTO_rsa_key_free (pk); } @@ -99,6 +114,9 @@ main (int argc, char *const *argv) { 'P', "print-peer-identity", NULL, gettext_noop ("print the hash of the public key in ASCII format"), 0, &GNUNET_GETOPT_set_one, &print_peer_identity }, + { 's', "print-short-identity", NULL, + gettext_noop ("print the short hash of the public key in ASCII format"), + 0, &GNUNET_GETOPT_set_one, &print_short_identity }, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == diff --git a/src/util/strings.c b/src/util/strings.c index 2ed1a0da3..40968956e 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -643,10 +643,10 @@ getValue__ (unsigned char a) * @return pointer to the next byte in 'out' or NULL on error. */ char * -GNUNET_STRINGS_data_to_string (unsigned char *data, size_t size, char *out, size_t out_size) +GNUNET_STRINGS_data_to_string (const unsigned char *data, size_t size, char *out, size_t out_size) { /** - * 32 characters for encoding (GNUNET_CRYPTO_hash => 32 characters) + * 32 characters for encoding */ static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; unsigned int wpos; @@ -656,7 +656,11 @@ GNUNET_STRINGS_data_to_string (unsigned char *data, size_t size, char *out, size GNUNET_assert (data != NULL); GNUNET_assert (out != NULL); - GNUNET_assert (out_size >= (((size*8) + ((size*8) % 5)) % 5)); + if (out_size < (((size*8) + ((size*8) % 5)) % 5)) + { + GNUNET_break (0); + return NULL; + } vbit = 0; wpos = 0; rpos = 0; @@ -675,12 +679,18 @@ GNUNET_STRINGS_data_to_string (unsigned char *data, size_t size, char *out, size vbit = 5; } if (wpos >= out_size) + { + GNUNET_break (0); return NULL; + } out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; vbit -= 5; } if (wpos != out_size) + { + GNUNET_break (0); return NULL; + } GNUNET_assert (vbit == 0); return &out[wpos]; } diff --git a/src/vpn/vpn.h b/src/vpn/vpn.h index e937f5ef5..bec3a5b59 100644 --- a/src/vpn/vpn.h +++ b/src/vpn/vpn.h @@ -115,7 +115,7 @@ struct RedirectToServiceRequestMessage /** * Service descriptor identifying the service. */ - GNUNET_HashCode service_descriptor GNUNET_PACKED; + GNUNET_HashCode service_descriptor; /** * Unique ID to match a future response to this request. -- cgit v1.2.3