#include #include #include #include #include #include "ptwist.h" #include "rserv.h" /* Check the given tag with the given context and private key. Return 0 if the tag is properly formed, non-0 if not. If the tag is correct, set key to the resulting secret key. */ int check_tag(byte key[16], const byte privkey[PTWIST_BYTES], const byte tag[PTWIST_TAG_BYTES], const byte *context, size_t context_len) { int ret = -1; byte sharedsec[PTWIST_BYTES+context_len]; byte taghashout[32]; #if PTWIST_PUZZLE_STRENGTH > 0 byte hashout[32]; size_t puzzle_len = 16+PTWIST_RESP_BYTES; byte value_to_hash[puzzle_len]; unsigned int firstbits; int firstpass = 0; #endif /* Compute the shared secret privkey*TAG */ ptwist_pointmul(sharedsec, tag, privkey); /* Create the hash tag keys */ memmove(sharedsec+PTWIST_BYTES, context, context_len); SHA256(sharedsec, PTWIST_BYTES, taghashout); #if PTWIST_PUZZLE_STRENGTH > 0 /* Construct the proposed solution to the puzzle */ memmove(value_to_hash, taghashout, 16); memmove(value_to_hash+16, tag+PTWIST_BYTES, PTWIST_RESP_BYTES); value_to_hash[16+PTWIST_RESP_BYTES-1] &= PTWIST_RESP_MASK; /* Hash the proposed solution and see if it is correct; that is, the * hash should start with PTWIST_PUZZLE_STRENGTH bits of 0s, * followed by the last PTWIST_HASH_SHOWBITS of the tag. */ md_map_sh256(hashout, value_to_hash, puzzle_len); #if PTWIST_PUZZLE_STRENGTH < 32 /* This assumes that you're on an architecture that doesn't care * about alignment, and is little endian. */ firstbits = *(unsigned int*)hashout; if ((firstbits & PTWIST_PUZZLE_MASK) == 0) { firstpass = 1; } #else #error "Code assumes PTWIST_PUZZLE_STRENGTH < 32" #endif if (firstpass) { bn_t Hbn, Tbn; bn_new(Hbn); bn_new(Tbn); hashout[PTWIST_HASH_TOTBYTES-1] &= PTWIST_HASH_MASK; bn_read_bin(Hbn, hashout, PTWIST_HASH_TOTBYTES, BN_POS); bn_rsh(Hbn, Hbn, PTWIST_PUZZLE_STRENGTH); bn_read_bin(Tbn, tag+PTWIST_BYTES, PTWIST_TAG_BYTES-PTWIST_BYTES, BN_POS); bn_rsh(Tbn, Tbn, PTWIST_RESP_BITS); ret = (bn_cmp(Tbn,Hbn) != CMP_EQ); bn_free(Hbn); bn_free(Tbn); } #else /* We're not using a client puzzle, so just check that the first * PTWIST_HASH_SHOWBITS bits of the above hash fill out the rest * of the tag. If there's no puzzle, PTWIST_HASH_SHOWBITS must be * a multiple of 8. */ ret = (memcmp(tag+PTWIST_BYTES, taghashout, PTWIST_HASH_SHOWBITS/8) != 0); #endif if (ret == 0) { memmove(key, taghashout+16, 16); } return ret; }