📄 hashing.c
字号:
} /* Zeroize sensitive information. */ memset (sctx, 0, sizeof (struct sha512_ctx));}/** * Hash block of given size. * * @param block the data to GNUNET_hash, length is given as a second argument * @param size the length of the data to GNUNET_hash * @param ret pointer to where to write the hashcode */voidGNUNET_hash (const void *block, unsigned int size, GNUNET_HashCode * ret){ struct sha512_ctx ctx; sha512_init (&ctx); sha512_update (&ctx, block, size); sha512_final (&ctx, (unsigned char *) ret);}/** * Compute the GNUNET_hash of an entire file. Does NOT load the entire file * into memory but instead processes it in blocks. Very important for * large files. * * @return GNUNET_OK on success, GNUNET_SYSERR on error */intGNUNET_hash_file (struct GNUNET_GE_Context *ectx, const char *filename, GNUNET_HashCode * ret){ unsigned char *buf; unsigned long long len; unsigned long long pos; unsigned int delta; int fh; struct sha512_ctx ctx; if (GNUNET_OK != GNUNET_disk_file_test (ectx, filename)) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_disk_file_size (ectx, filename, &len, GNUNET_NO)) return GNUNET_SYSERR; fh = GNUNET_disk_file_open (ectx, filename, O_RDONLY | O_LARGEFILE); if (fh == -1) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_REQUEST, "open", filename); return GNUNET_SYSERR; } sha512_init (&ctx); pos = 0; buf = GNUNET_malloc (65536); while (pos < len) { delta = 65536; if (len - pos < delta) delta = len - pos; if (delta != READ (fh, buf, delta)) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "read", filename); if (0 != CLOSE (fh)) GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "close", filename); GNUNET_free (buf); return GNUNET_SYSERR; } if (GNUNET_YES == GNUNET_shutdown_test ()) { if (0 != CLOSE (fh)) GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "close", filename); GNUNET_free (buf); return GNUNET_SYSERR; } sha512_update (&ctx, buf, delta); if (pos + delta > pos) pos += delta; else break; } if (0 != CLOSE (fh)) GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "close", filename); sha512_final (&ctx, (unsigned char *) ret); GNUNET_free (buf); return GNUNET_OK;}/* ***************** binary-ASCII encoding *************** *//** * 32 characters for encoding (GNUNET_hash => 32 characters) */static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV";static unsigned intgetValue__ (unsigned char a){ if ((a >= '0') && (a <= '9')) return a - '0'; if ((a >= 'A') && (a <= 'V')) return (a - 'A' + 10); return -1;}/** * Convert GNUNET_hash to ASCII encoding. The ASCII encoding is rather * GNUnet specific. It was chosen such that it only uses characters * in [0-9A-V], can be produced without complex arithmetics and uses a * small number of characters. The GNUnet encoding uses 102 * characters plus a null terminator. * * @param block the GNUNET_hash code * @param result where to store the encoding (GNUNET_EncName can be * safely cast to char*, a '\0' termination is set). */voidGNUNET_hash_to_enc (const GNUNET_HashCode * block, GNUNET_EncName * result){ unsigned int wpos; unsigned int rpos; unsigned int bits; unsigned int vbit; GNUNET_GE_ASSERT (NULL, block != NULL); GNUNET_GE_ASSERT (NULL, 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_GE_ASSERT (NULL, vbit == 2); /* padding by 3: 512+3 mod 5 == 0 */ vbit = 5; } GNUNET_GE_ASSERT (NULL, wpos < sizeof (GNUNET_EncName) - 1); result->encoding[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; vbit -= 5; } GNUNET_GE_ASSERT (NULL, wpos == sizeof (GNUNET_EncName) - 1); GNUNET_GE_ASSERT (NULL, vbit == 0); result->encoding[wpos] = '\0';}/** * Convert ASCII encoding back to GNUNET_hash * * @param enc the encoding * @param result where to store the GNUNET_hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */intGNUNET_enc_to_hash (const char *enc, GNUNET_HashCode * result){ unsigned int rpos; unsigned int wpos; unsigned int bits; unsigned int vbit; if (strlen (enc) != sizeof (GNUNET_EncName) - 1) return GNUNET_SYSERR; vbit = 2; /* padding! */ wpos = sizeof (GNUNET_HashCode); rpos = sizeof (GNUNET_EncName) - 1; bits = getValue__ (enc[--rpos]) >> 3; while (wpos > 0) { GNUNET_GE_ASSERT (NULL, rpos > 0); bits = (getValue__ (enc[--rpos]) << vbit) | bits; vbit += 5; if (vbit >= 8) { ((unsigned char *) result)[--wpos] = (unsigned char) bits; bits >>= 8; vbit -= 8; } } GNUNET_GE_ASSERT (NULL, rpos == 0); GNUNET_GE_ASSERT (NULL, vbit == 0); return GNUNET_OK;}/** * Compute the distance between 2 hashcodes. The computation must be * fast, not involve bits[0] or bits[4] (they're used elsewhere), and be * somewhat consistent. And of course, the result should be a positive * number. * * @returns a positive number which is a measure for * hashcode proximity. */unsigned intGNUNET_hash_distance_u32 (const GNUNET_HashCode * a, const GNUNET_HashCode * b){ unsigned int x = (a->bits[1] - b->bits[1]) >> 16; return ((x * x) >> 16);}voidGNUNET_create_random_hash (GNUNET_HashCode * result){ int i; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) result->bits[i] = rand ();}voidGNUNET_hash_difference (const GNUNET_HashCode * a, const GNUNET_HashCode * b, GNUNET_HashCode * result){ int i; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) result->bits[i] = b->bits[i] - a->bits[i];}voidGNUNET_hash_sum (const GNUNET_HashCode * a, const GNUNET_HashCode * delta, GNUNET_HashCode * result){ int i; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) result->bits[i] = delta->bits[i] + a->bits[i];}voidGNUNET_hash_xor (const GNUNET_HashCode * a, const GNUNET_HashCode * b, GNUNET_HashCode * result){ int i; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) result->bits[i] = a->bits[i] ^ b->bits[i];}/** * Convert a hashcode into a key. */voidGNUNET_hash_to_AES_key (const GNUNET_HashCode * hc, GNUNET_AES_SessionKey * skey, GNUNET_AES_InitializationVector * iv){ GNUNET_GE_ASSERT (NULL, sizeof (GNUNET_HashCode) >= GNUNET_SESSIONKEY_LEN + sizeof (GNUNET_AES_InitializationVector)); memcpy (skey, hc, GNUNET_SESSIONKEY_LEN); skey->crc32 = htonl (GNUNET_crc32_n (skey, GNUNET_SESSIONKEY_LEN)); memcpy (iv, &((char *) hc)[GNUNET_SESSIONKEY_LEN], sizeof (GNUNET_AES_InitializationVector));}/** * Obtain a bit from a hashcode. * @param code the GNUNET_hash to index bit-wise * @param bit index into the hashcode, [0...511] * @return Bit \a bit from hashcode \a code, -1 for invalid index */intGNUNET_hash_get_bit (const GNUNET_HashCode * code, unsigned int bit){ if (bit >= 8 * sizeof (GNUNET_HashCode)) { GNUNET_GE_ASSERT (NULL, 0); return -1; /* error */ } return (((unsigned char *) code)[bit >> 3] & (1 << bit & 7)) > 0;}/** * Compare function for HashCodes, producing a total ordering * of all hashcodes. * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2. */intGNUNET_hash_cmp (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2){ unsigned int *i1; unsigned int *i2; int i; i1 = (unsigned int *) h1; i2 = (unsigned int *) h2; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) { if (i1[i] > i2[i]) return 1; if (i1[i] < i2[i]) return -1; } return 0;}/** * Find out which of the two GNUNET_hash codes is closer to target * in the XOR metric (Kademlia). * @return -1 if h1 is closer, 1 if h2 is closer and 0 if h1==h2. */intGNUNET_hash_xorcmp (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2, const GNUNET_HashCode * target){ int i; unsigned int d1; unsigned int d2; for (i = sizeof (GNUNET_HashCode) / sizeof (unsigned int) - 1; i >= 0; i--) { d1 = ((unsigned int *) h1)[i] ^ ((unsigned int *) target)[i]; d2 = ((unsigned int *) h2)[i] ^ ((unsigned int *) target)[i]; if (d1 > d2) return 1; else if (d1 < d2) return -1; } return 0;}/* end of hashing.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -